Print this page
grub patch
Split |
Close |
Expand all |
Collapse all |
--- old/grub/grub-core/fs/zfs/zfs.c
+++ new/grub/grub-core/fs/zfs/zfs.c
1 1 /*
2 2 * GRUB -- GRand Unified Bootloader
3 3 * Copyright (C) 1999,2000,2001,2002,2003,2004,2009,2010,2011 Free Software Foundation, Inc.
4 4 * Copyright 2010 Sun Microsystems, Inc.
5 + * Copyright 2012 Daniil Lunev
5 6 *
6 7 * GRUB is free software; you can redistribute it and/or modify
7 8 * it under the terms of the GNU General Public License as published by
8 9 * the Free Software Foundation; either version 3 of the License, or
9 10 * (at your option) any later version.
10 11 *
11 12 * GRUB is distributed in the hope that it will be useful,
12 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 15 * GNU General Public License for more details.
15 16 *
16 17 * You should have received a copy of the GNU General Public License
17 18 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
18 19 */
19 20 /*
20 21 * The zfs plug-in routines for GRUB are:
21 22 *
22 23 * zfs_mount() - locates a valid uberblock of the root pool and reads
23 24 * in its MOS at the memory address MOS.
24 25 *
25 26 * zfs_open() - locates a plain file object by following the MOS
26 27 * and places its dnode at the memory address DNODE.
27 28 *
28 29 * zfs_read() - read in the data blocks pointed by the DNODE.
29 30 *
30 31 */
31 32
32 33 #include <grub/err.h>
33 34 #include <grub/file.h>
34 35 #include <grub/mm.h>
35 36 #include <grub/misc.h>
36 37 #include <grub/disk.h>
37 38 #include <grub/partition.h>
38 39 #include <grub/dl.h>
39 40 #include <grub/types.h>
40 41 #include <grub/zfs/zfs.h>
41 42 #include <grub/zfs/zio.h>
42 43 #include <grub/zfs/dnode.h>
43 44 #include <grub/zfs/uberblock_impl.h>
44 45 #include <grub/zfs/vdev_impl.h>
45 46 #include <grub/zfs/zio_checksum.h>
46 47 #include <grub/zfs/zap_impl.h>
47 48 #include <grub/zfs/zap_leaf.h>
48 49 #include <grub/zfs/zfs_znode.h>
49 50 #include <grub/zfs/dmu.h>
50 51 #include <grub/zfs/dmu_objset.h>
51 52 #include <grub/zfs/sa_impl.h>
52 53 #include <grub/zfs/dsl_dir.h>
53 54 #include <grub/zfs/dsl_dataset.h>
54 55 #include <grub/deflate.h>
55 56 #include <grub/crypto.h>
56 57 #include <grub/i18n.h>
57 58
58 59 GRUB_MOD_LICENSE ("GPLv3+");
59 60
60 61 #define ZPOOL_PROP_BOOTFS "bootfs"
61 62
62 63 /*
63 64 * For nvlist manipulation. (from nvpair.h)
64 65 */
65 66 #define NV_ENCODE_NATIVE 0
66 67 #define NV_ENCODE_XDR 1
67 68 #define NV_BIG_ENDIAN 0
68 69 #define NV_LITTLE_ENDIAN 1
69 70 #define DATA_TYPE_UINT64 8
70 71 #define DATA_TYPE_STRING 9
71 72 #define DATA_TYPE_NVLIST 19
72 73 #define DATA_TYPE_NVLIST_ARRAY 20
73 74
74 75 #ifndef GRUB_UTIL
75 76 static grub_dl_t my_mod;
76 77 #endif
77 78
78 79 #define P2PHASE(x, align) ((x) & ((align) - 1))
79 80
80 81 static inline grub_disk_addr_t
81 82 DVA_OFFSET_TO_PHYS_SECTOR (grub_disk_addr_t offset)
82 83 {
83 84 return ((offset + VDEV_LABEL_START_SIZE) >> SPA_MINBLOCKSHIFT);
84 85 }
85 86
86 87 /*
87 88 * FAT ZAP data structures
88 89 */
89 90 #define ZFS_CRC64_POLY 0xC96C5795D7870F42ULL /* ECMA-182, reflected form */
90 91 static inline grub_uint64_t
91 92 ZAP_HASH_IDX (grub_uint64_t hash, grub_uint64_t n)
92 93 {
93 94 return (((n) == 0) ? 0 : ((hash) >> (64 - (n))));
94 95 }
95 96
96 97 #define CHAIN_END 0xffff /* end of the chunk chain */
97 98
98 99 /*
99 100 * The amount of space within the chunk available for the array is:
100 101 * chunk size - space for type (1) - space for next pointer (2)
101 102 */
102 103 #define ZAP_LEAF_ARRAY_BYTES (ZAP_LEAF_CHUNKSIZE - 3)
103 104
104 105 static inline int
105 106 ZAP_LEAF_HASH_SHIFT (int bs)
106 107 {
107 108 return bs - 5;
108 109 }
109 110
110 111 static inline int
111 112 ZAP_LEAF_HASH_NUMENTRIES (int bs)
112 113 {
113 114 return 1 << ZAP_LEAF_HASH_SHIFT(bs);
114 115 }
115 116
116 117 static inline grub_size_t
117 118 LEAF_HASH (int bs, grub_uint64_t h, zap_leaf_phys_t *l)
118 119 {
119 120 return ((ZAP_LEAF_HASH_NUMENTRIES (bs)-1)
120 121 & ((h) >> (64 - ZAP_LEAF_HASH_SHIFT (bs) - l->l_hdr.lh_prefix_len)));
121 122 }
122 123
123 124 /*
124 125 * The amount of space available for chunks is:
125 126 * block size shift - hash entry size (2) * number of hash
126 127 * entries - header space (2*chunksize)
127 128 */
128 129 static inline int
129 130 ZAP_LEAF_NUMCHUNKS (int bs)
130 131 {
131 132 return (((1 << bs) - 2 * ZAP_LEAF_HASH_NUMENTRIES (bs)) /
132 133 ZAP_LEAF_CHUNKSIZE - 2);
133 134 }
134 135
135 136 /*
136 137 * The chunks start immediately after the hash table. The end of the
137 138 * hash table is at l_hash + HASH_NUMENTRIES, which we simply cast to a
138 139 * chunk_t.
139 140 */
140 141 static inline zap_leaf_chunk_t *
141 142 ZAP_LEAF_CHUNK (zap_leaf_phys_t *l, int bs, int idx)
142 143 {
143 144 return &((zap_leaf_chunk_t *) (l->l_entries
144 145 + (ZAP_LEAF_HASH_NUMENTRIES(bs) * 2)
145 146 / sizeof (grub_properly_aligned_t)))[idx];
146 147 }
147 148
148 149 static inline struct zap_leaf_entry *
149 150 ZAP_LEAF_ENTRY(zap_leaf_phys_t *l, int bs, int idx)
150 151 {
151 152 return &ZAP_LEAF_CHUNK(l, bs, idx)->l_entry;
152 153 }
153 154
154 155
155 156 /*
156 157 * Decompression Entry - lzjb
157 158 */
158 159
159 160 extern grub_err_t lzjb_decompress (void *, void *, grub_size_t, grub_size_t);
160 161
161 162 typedef grub_err_t zfs_decomp_func_t (void *s_start, void *d_start,
162 163 grub_size_t s_len, grub_size_t d_len);
163 164 typedef struct decomp_entry
164 165 {
165 166 const char *name;
166 167 zfs_decomp_func_t *decomp_func;
167 168 } decomp_entry_t;
168 169
169 170 /*
170 171 * Signature for checksum functions.
171 172 */
172 173 typedef void zio_checksum_t(const void *data, grub_uint64_t size,
173 174 grub_zfs_endian_t endian, zio_cksum_t *zcp);
174 175
175 176 /*
176 177 * Information about each checksum function.
177 178 */
178 179 typedef struct zio_checksum_info {
179 180 zio_checksum_t *ci_func; /* checksum function for each byteorder */
180 181 int ci_correctable; /* number of correctable bits */
181 182 int ci_eck; /* uses zio embedded checksum? */
182 183 const char *ci_name; /* descriptive name */
183 184 } zio_checksum_info_t;
184 185
185 186 typedef struct dnode_end
186 187 {
187 188 dnode_phys_t dn;
188 189 grub_zfs_endian_t endian;
189 190 } dnode_end_t;
190 191
191 192 struct grub_zfs_device_desc
192 193 {
193 194 enum { DEVICE_LEAF, DEVICE_MIRROR, DEVICE_RAIDZ } type;
194 195 grub_uint64_t id;
195 196 grub_uint64_t guid;
196 197 unsigned ashift;
197 198 unsigned max_children_ashift;
198 199
199 200 /* Valid only for non-leafs. */
200 201 unsigned n_children;
201 202 struct grub_zfs_device_desc *children;
202 203
203 204 /* Valid only for RAIDZ. */
204 205 unsigned nparity;
205 206
206 207 /* Valid only for leaf devices. */
207 208 grub_device_t dev;
208 209 grub_disk_addr_t vdev_phys_sector;
209 210 uberblock_t current_uberblock;
210 211 int original;
211 212 };
212 213
213 214 struct subvolume
214 215 {
215 216 dnode_end_t mdn;
216 217 grub_uint64_t obj;
↓ open down ↓ |
202 lines elided |
↑ open up ↑ |
217 218 grub_uint64_t case_insensitive;
218 219 grub_size_t nkeys;
219 220 struct
220 221 {
221 222 grub_crypto_cipher_handle_t cipher;
222 223 grub_uint64_t txg;
223 224 grub_uint64_t algo;
224 225 } *keyring;
225 226 };
226 227
228 +static const char * feature_list[] = {
229 + "localhost:unknown_feature",
230 + NULL,
231 +};
232 +
233 +typedef enum zfs_feature_id {
234 + ZFS_FEATURE_UNKNOWN,
235 +} zfs_feature_id_t;
236 +
237 +struct enabled_feature_list {
238 + struct enabled_feature_list * next;
239 + zfs_feature_id_t id;
240 +};
241 +
227 242 struct grub_zfs_data
228 243 {
229 244 /* cache for a file block of the currently zfs_open()-ed file */
230 245 char *file_buf;
231 246 grub_uint64_t file_start;
232 247 grub_uint64_t file_end;
233 248
234 249 /* cache for a dnode block */
235 250 dnode_phys_t *dnode_buf;
236 251 dnode_phys_t *dnode_mdn;
237 252 grub_uint64_t dnode_start;
238 253 grub_uint64_t dnode_end;
239 254 grub_zfs_endian_t dnode_endian;
240 255
241 256 dnode_end_t mos;
↓ open down ↓ |
5 lines elided |
↑ open up ↑ |
242 257 dnode_end_t dnode;
243 258 struct subvolume subvol;
244 259
245 260 struct grub_zfs_device_desc *devices_attached;
246 261 unsigned n_devices_attached;
247 262 unsigned n_devices_allocated;
248 263 struct grub_zfs_device_desc *device_original;
249 264
250 265 uberblock_t current_uberblock;
251 266
267 + struct enabled_feature_list * feature_list;
268 +
252 269 int mounted;
253 270 grub_uint64_t guid;
254 271 };
255 272
256 273 grub_err_t (*grub_zfs_decrypt) (grub_crypto_cipher_handle_t cipher,
257 274 grub_uint64_t algo,
258 275 void *nonce,
259 276 char *buf, grub_size_t size,
260 277 const grub_uint32_t *expected_mac,
261 278 grub_zfs_endian_t endian) = NULL;
262 279 grub_crypto_cipher_handle_t (*grub_zfs_load_key) (const struct grub_zfs_key *key,
263 280 grub_size_t keysize,
264 281 grub_uint64_t salt,
265 282 grub_uint64_t algo) = NULL;
266 283
267 284 static grub_err_t
268 285 zlib_decompress (void *s, void *d,
269 286 grub_size_t slen, grub_size_t dlen)
270 287 {
271 288 if (grub_zlib_decompress (s, slen, 0, d, dlen) < 0)
272 289 return grub_errno;
273 290 return GRUB_ERR_NONE;
274 291 }
275 292
276 293 static grub_err_t
277 294 zle_decompress (void *s, void *d,
278 295 grub_size_t slen, grub_size_t dlen)
279 296 {
280 297 grub_uint8_t *iptr, *optr;
281 298 grub_size_t clen;
282 299 for (iptr = s, optr = d; iptr < (grub_uint8_t *) s + slen
283 300 && optr < (grub_uint8_t *) d + dlen;)
284 301 {
285 302 if (*iptr & 0x80)
286 303 clen = ((*iptr) & 0x7f) + 0x41;
287 304 else
288 305 clen = ((*iptr) & 0x3f) + 1;
289 306 if ((grub_ssize_t) clen > (grub_uint8_t *) d + dlen - optr)
290 307 clen = (grub_uint8_t *) d + dlen - optr;
291 308 if (*iptr & 0x40 || *iptr & 0x80)
292 309 {
293 310 grub_memset (optr, 0, clen);
294 311 iptr++;
295 312 optr += clen;
296 313 continue;
297 314 }
298 315 if ((grub_ssize_t) clen > (grub_uint8_t *) s + slen - iptr - 1)
299 316 clen = (grub_uint8_t *) s + slen - iptr - 1;
300 317 grub_memcpy (optr, iptr + 1, clen);
301 318 optr += clen;
302 319 iptr += clen + 1;
303 320 }
304 321 if (optr < (grub_uint8_t *) d + dlen)
305 322 grub_memset (optr, 0, (grub_uint8_t *) d + dlen - optr);
306 323 return GRUB_ERR_NONE;
307 324 }
308 325
309 326 static decomp_entry_t decomp_table[ZIO_COMPRESS_FUNCTIONS] = {
310 327 {"inherit", NULL}, /* ZIO_COMPRESS_INHERIT */
311 328 {"on", lzjb_decompress}, /* ZIO_COMPRESS_ON */
312 329 {"off", NULL}, /* ZIO_COMPRESS_OFF */
313 330 {"lzjb", lzjb_decompress}, /* ZIO_COMPRESS_LZJB */
314 331 {"empty", NULL}, /* ZIO_COMPRESS_EMPTY */
315 332 {"gzip-1", zlib_decompress}, /* ZIO_COMPRESS_GZIP1 */
316 333 {"gzip-2", zlib_decompress}, /* ZIO_COMPRESS_GZIP2 */
317 334 {"gzip-3", zlib_decompress}, /* ZIO_COMPRESS_GZIP3 */
318 335 {"gzip-4", zlib_decompress}, /* ZIO_COMPRESS_GZIP4 */
319 336 {"gzip-5", zlib_decompress}, /* ZIO_COMPRESS_GZIP5 */
320 337 {"gzip-6", zlib_decompress}, /* ZIO_COMPRESS_GZIP6 */
321 338 {"gzip-7", zlib_decompress}, /* ZIO_COMPRESS_GZIP7 */
322 339 {"gzip-8", zlib_decompress}, /* ZIO_COMPRESS_GZIP8 */
323 340 {"gzip-9", zlib_decompress}, /* ZIO_COMPRESS_GZIP9 */
324 341 {"zle", zle_decompress}, /* ZIO_COMPRESS_ZLE */
325 342 };
326 343
327 344 static grub_err_t zio_read_data (blkptr_t * bp, grub_zfs_endian_t endian,
328 345 void *buf, struct grub_zfs_data *data);
329 346
330 347 /*
331 348 * Our own version of log2(). Same thing as highbit()-1.
332 349 */
333 350 static int
334 351 zfs_log2 (grub_uint64_t num)
335 352 {
336 353 int i = 0;
337 354
338 355 while (num > 1)
339 356 {
340 357 i++;
341 358 num = num >> 1;
342 359 }
343 360
344 361 return (i);
345 362 }
346 363
347 364 /* Checksum Functions */
348 365 static void
349 366 zio_checksum_off (const void *buf __attribute__ ((unused)),
350 367 grub_uint64_t size __attribute__ ((unused)),
351 368 grub_zfs_endian_t endian __attribute__ ((unused)),
352 369 zio_cksum_t * zcp)
353 370 {
354 371 ZIO_SET_CHECKSUM (zcp, 0, 0, 0, 0);
355 372 }
356 373
357 374 /* Checksum Table and Values */
358 375 static zio_checksum_info_t zio_checksum_table[ZIO_CHECKSUM_FUNCTIONS] = {
359 376 {NULL, 0, 0, "inherit"},
360 377 {NULL, 0, 0, "on"},
361 378 {zio_checksum_off, 0, 0, "off"},
362 379 {zio_checksum_SHA256, 1, 1, "label"},
363 380 {zio_checksum_SHA256, 1, 1, "gang_header"},
364 381 {NULL, 0, 0, "zilog"},
365 382 {fletcher_2, 0, 0, "fletcher2"},
366 383 {fletcher_4, 1, 0, "fletcher4"},
367 384 {zio_checksum_SHA256, 1, 0, "SHA256"},
368 385 {NULL, 0, 0, "zilog2"},
369 386 {zio_checksum_SHA256, 1, 0, "SHA256+MAC"},
370 387 };
371 388
372 389 /*
373 390 * zio_checksum_verify: Provides support for checksum verification.
374 391 *
375 392 * Fletcher2, Fletcher4, and SHA256 are supported.
376 393 *
377 394 */
378 395 static grub_err_t
379 396 zio_checksum_verify (zio_cksum_t zc, grub_uint32_t checksum,
380 397 grub_zfs_endian_t endian,
381 398 char *buf, grub_size_t size)
382 399 {
383 400 zio_eck_t *zec = (zio_eck_t *) (buf + size) - 1;
384 401 zio_checksum_info_t *ci = &zio_checksum_table[checksum];
385 402 zio_cksum_t actual_cksum, expected_cksum;
386 403
387 404 if (checksum >= ZIO_CHECKSUM_FUNCTIONS || ci->ci_func == NULL)
388 405 {
389 406 grub_dprintf ("zfs", "unknown checksum function %d\n", checksum);
390 407 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
391 408 "unknown checksum function %d", checksum);
392 409 }
393 410
394 411 if (ci->ci_eck)
395 412 {
396 413 expected_cksum = zec->zec_cksum;
397 414 zec->zec_cksum = zc;
398 415 ci->ci_func (buf, size, endian, &actual_cksum);
399 416 zec->zec_cksum = expected_cksum;
400 417 zc = expected_cksum;
401 418 }
402 419 else
403 420 ci->ci_func (buf, size, endian, &actual_cksum);
404 421
405 422 if (grub_memcmp (&actual_cksum, &zc,
406 423 checksum != ZIO_CHECKSUM_SHA256_MAC ? 32 : 20) != 0)
407 424 {
408 425 grub_dprintf ("zfs", "checksum %s verification failed\n", ci->ci_name);
409 426 grub_dprintf ("zfs", "actual checksum %016llx %016llx %016llx %016llx\n",
410 427 (unsigned long long) actual_cksum.zc_word[0],
411 428 (unsigned long long) actual_cksum.zc_word[1],
412 429 (unsigned long long) actual_cksum.zc_word[2],
413 430 (unsigned long long) actual_cksum.zc_word[3]);
414 431 grub_dprintf ("zfs", "expected checksum %016llx %016llx %016llx %016llx\n",
415 432 (unsigned long long) zc.zc_word[0],
416 433 (unsigned long long) zc.zc_word[1],
417 434 (unsigned long long) zc.zc_word[2],
418 435 (unsigned long long) zc.zc_word[3]);
419 436 return grub_error (GRUB_ERR_BAD_FS, N_("checksum verification failed"));
420 437 }
421 438
422 439 return GRUB_ERR_NONE;
423 440 }
424 441
425 442 /*
426 443 * vdev_uberblock_compare takes two uberblock structures and returns an integer
427 444 * indicating the more recent of the two.
428 445 * Return Value = 1 if ub2 is more recent
429 446 * Return Value = -1 if ub1 is more recent
430 447 * The most recent uberblock is determined using its transaction number and
431 448 * timestamp. The uberblock with the highest transaction number is
432 449 * considered "newer". If the transaction numbers of the two blocks match, the
433 450 * timestamps are compared to determine the "newer" of the two.
434 451 */
435 452 static int
436 453 vdev_uberblock_compare (uberblock_t * ub1, uberblock_t * ub2)
437 454 {
438 455 grub_zfs_endian_t ub1_endian, ub2_endian;
439 456 if (grub_zfs_to_cpu64 (ub1->ub_magic, GRUB_ZFS_LITTLE_ENDIAN)
440 457 == UBERBLOCK_MAGIC)
441 458 ub1_endian = GRUB_ZFS_LITTLE_ENDIAN;
442 459 else
443 460 ub1_endian = GRUB_ZFS_BIG_ENDIAN;
444 461 if (grub_zfs_to_cpu64 (ub2->ub_magic, GRUB_ZFS_LITTLE_ENDIAN)
445 462 == UBERBLOCK_MAGIC)
446 463 ub2_endian = GRUB_ZFS_LITTLE_ENDIAN;
447 464 else
448 465 ub2_endian = GRUB_ZFS_BIG_ENDIAN;
449 466
450 467 if (grub_zfs_to_cpu64 (ub1->ub_txg, ub1_endian)
451 468 < grub_zfs_to_cpu64 (ub2->ub_txg, ub2_endian))
452 469 return (-1);
453 470 if (grub_zfs_to_cpu64 (ub1->ub_txg, ub1_endian)
454 471 > grub_zfs_to_cpu64 (ub2->ub_txg, ub2_endian))
455 472 return (1);
456 473
457 474 if (grub_zfs_to_cpu64 (ub1->ub_timestamp, ub1_endian)
458 475 < grub_zfs_to_cpu64 (ub2->ub_timestamp, ub2_endian))
459 476 return (-1);
460 477 if (grub_zfs_to_cpu64 (ub1->ub_timestamp, ub1_endian)
461 478 > grub_zfs_to_cpu64 (ub2->ub_timestamp, ub2_endian))
462 479 return (1);
463 480
464 481 return (0);
465 482 }
466 483
467 484 /*
468 485 * Three pieces of information are needed to verify an uberblock: the magic
469 486 * number, the version number, and the checksum.
470 487 *
471 488 * Currently Implemented: version number, magic number, checksum
472 489 *
473 490 */
474 491 static grub_err_t
↓ open down ↓ |
213 lines elided |
↑ open up ↑ |
475 492 uberblock_verify (uberblock_phys_t * ub, grub_uint64_t offset,
476 493 grub_size_t s)
477 494 {
478 495 uberblock_t *uber = &ub->ubp_uberblock;
479 496 grub_err_t err;
480 497 grub_zfs_endian_t endian = GRUB_ZFS_UNKNOWN_ENDIAN;
481 498 zio_cksum_t zc;
482 499
483 500 if (grub_zfs_to_cpu64 (uber->ub_magic, GRUB_ZFS_LITTLE_ENDIAN)
484 501 == UBERBLOCK_MAGIC
485 - && grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_LITTLE_ENDIAN) > 0
486 - && grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_LITTLE_ENDIAN)
487 - <= SPA_VERSION)
502 + && grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_LITTLE_ENDIAN) > 0)
488 503 endian = GRUB_ZFS_LITTLE_ENDIAN;
489 504
490 505 if (grub_zfs_to_cpu64 (uber->ub_magic, GRUB_ZFS_BIG_ENDIAN) == UBERBLOCK_MAGIC
491 - && grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_BIG_ENDIAN) > 0
492 - && grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_BIG_ENDIAN)
493 - <= SPA_VERSION)
506 + && grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_BIG_ENDIAN) > 0)
494 507 endian = GRUB_ZFS_BIG_ENDIAN;
495 508
496 509 if (endian == GRUB_ZFS_UNKNOWN_ENDIAN)
497 510 return grub_error (GRUB_ERR_BAD_FS, "invalid uberblock magic");
498 511
499 512 grub_memset (&zc, 0, sizeof (zc));
500 513
501 514 zc.zc_word[0] = grub_cpu_to_zfs64 (offset, endian);
502 515 err = zio_checksum_verify (zc, ZIO_CHECKSUM_LABEL, endian,
503 516 (char *) ub, s);
504 517
505 518 return err;
506 519 }
507 520
508 521 /*
509 522 * Find the best uberblock.
510 523 * Return:
511 524 * Success - Pointer to the best uberblock.
512 525 * Failure - NULL
513 526 */
514 527 static uberblock_phys_t *
515 528 find_bestub (uberblock_phys_t * ub_array,
516 529 const struct grub_zfs_device_desc *desc)
517 530 {
518 531 uberblock_phys_t *ubbest = NULL, *ubptr;
519 532 int i;
520 533 grub_disk_addr_t offset;
521 534 grub_err_t err = GRUB_ERR_NONE;
522 535 int ub_shift;
523 536
524 537 ub_shift = desc->ashift;
525 538 if (ub_shift < VDEV_UBERBLOCK_SHIFT)
526 539 ub_shift = VDEV_UBERBLOCK_SHIFT;
527 540
528 541 for (i = 0; i < (VDEV_UBERBLOCK_RING >> ub_shift); i++)
529 542 {
530 543 offset = (desc->vdev_phys_sector << SPA_MINBLOCKSHIFT) + VDEV_PHYS_SIZE
531 544 + (i << ub_shift);
532 545
533 546 ubptr = (uberblock_phys_t *) ((grub_properly_aligned_t *) ub_array
534 547 + ((i << ub_shift)
535 548 / sizeof (grub_properly_aligned_t)));
536 549 err = uberblock_verify (ubptr, offset, 1 << ub_shift);
537 550 if (err)
538 551 {
539 552 grub_errno = GRUB_ERR_NONE;
540 553 continue;
541 554 }
542 555 if (ubbest == NULL
543 556 || vdev_uberblock_compare (&(ubptr->ubp_uberblock),
544 557 &(ubbest->ubp_uberblock)) > 0)
545 558 ubbest = ubptr;
546 559 }
547 560 if (!ubbest)
548 561 grub_errno = err;
549 562
550 563 return (ubbest);
551 564 }
552 565
553 566 static inline grub_size_t
554 567 get_psize (blkptr_t * bp, grub_zfs_endian_t endian)
555 568 {
556 569 return ((((grub_zfs_to_cpu64 ((bp)->blk_prop, endian) >> 16) & 0xffff) + 1)
557 570 << SPA_MINBLOCKSHIFT);
558 571 }
559 572
560 573 static grub_uint64_t
561 574 dva_get_offset (const dva_t *dva, grub_zfs_endian_t endian)
562 575 {
563 576 grub_dprintf ("zfs", "dva=%llx, %llx\n",
564 577 (unsigned long long) dva->dva_word[0],
565 578 (unsigned long long) dva->dva_word[1]);
566 579 return grub_zfs_to_cpu64 ((dva)->dva_word[1],
567 580 endian) << SPA_MINBLOCKSHIFT;
568 581 }
569 582
570 583 static grub_err_t
571 584 zfs_fetch_nvlist (struct grub_zfs_device_desc *diskdesc, char **nvlist)
572 585 {
573 586 grub_err_t err;
574 587
575 588 *nvlist = 0;
576 589
577 590 if (!diskdesc->dev)
578 591 return grub_error (GRUB_ERR_BUG, "member drive unknown");
579 592
580 593 *nvlist = grub_malloc (VDEV_PHYS_SIZE);
581 594
582 595 /* Read in the vdev name-value pair list (112K). */
583 596 err = grub_disk_read (diskdesc->dev->disk, diskdesc->vdev_phys_sector, 0,
584 597 VDEV_PHYS_SIZE, *nvlist);
585 598 if (err)
586 599 {
587 600 grub_free (*nvlist);
588 601 *nvlist = 0;
589 602 return err;
590 603 }
591 604 return GRUB_ERR_NONE;
592 605 }
593 606
594 607 static grub_err_t
595 608 fill_vdev_info_real (struct grub_zfs_data *data,
596 609 const char *nvlist,
597 610 struct grub_zfs_device_desc *fill,
598 611 struct grub_zfs_device_desc *insert,
599 612 int *inserted,
600 613 unsigned ashift)
601 614 {
602 615 char *type;
603 616
604 617 type = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_TYPE);
605 618
606 619 if (!type)
607 620 return grub_errno;
608 621
609 622 if (!grub_zfs_nvlist_lookup_uint64 (nvlist, "id", &(fill->id)))
610 623 {
611 624 grub_free (type);
612 625 return grub_error (GRUB_ERR_BAD_FS, "couldn't find vdev id");
613 626 }
614 627
615 628 if (!grub_zfs_nvlist_lookup_uint64 (nvlist, "guid", &(fill->guid)))
616 629 {
617 630 grub_free (type);
618 631 return grub_error (GRUB_ERR_BAD_FS, "couldn't find vdev id");
619 632 }
620 633
621 634 {
622 635 grub_uint64_t par;
623 636 if (grub_zfs_nvlist_lookup_uint64 (nvlist, "ashift", &par))
624 637 fill->ashift = par;
625 638 else if (ashift != 0xffffffff)
626 639 fill->ashift = ashift;
627 640 else
628 641 {
629 642 grub_free (type);
630 643 return grub_error (GRUB_ERR_BAD_FS, "couldn't find ashift");
631 644 }
632 645 }
633 646
634 647 fill->max_children_ashift = 0;
635 648
636 649 if (grub_strcmp (type, VDEV_TYPE_DISK) == 0
637 650 || grub_strcmp (type, VDEV_TYPE_FILE) == 0)
638 651 {
639 652 fill->type = DEVICE_LEAF;
640 653
641 654 if (!fill->dev && fill->guid == insert->guid)
642 655 {
643 656 fill->dev = insert->dev;
644 657 fill->vdev_phys_sector = insert->vdev_phys_sector;
645 658 fill->current_uberblock = insert->current_uberblock;
646 659 fill->original = insert->original;
647 660 if (!data->device_original)
648 661 data->device_original = fill;
649 662 insert->ashift = fill->ashift;
650 663 *inserted = 1;
651 664 }
652 665
653 666 grub_free (type);
654 667
655 668 return GRUB_ERR_NONE;
656 669 }
657 670
658 671 if (grub_strcmp (type, VDEV_TYPE_MIRROR) == 0
659 672 || grub_strcmp (type, VDEV_TYPE_RAIDZ) == 0)
660 673 {
661 674 int nelm, i;
662 675
663 676 if (grub_strcmp (type, VDEV_TYPE_MIRROR) == 0)
664 677 fill->type = DEVICE_MIRROR;
665 678 else
666 679 {
667 680 grub_uint64_t par;
668 681 fill->type = DEVICE_RAIDZ;
669 682 if (!grub_zfs_nvlist_lookup_uint64 (nvlist, "nparity", &par))
670 683 {
671 684 grub_free (type);
672 685 return grub_error (GRUB_ERR_BAD_FS, "couldn't find raidz parity");
673 686 }
674 687 fill->nparity = par;
675 688 }
676 689
677 690 nelm = grub_zfs_nvlist_lookup_nvlist_array_get_nelm (nvlist,
678 691 ZPOOL_CONFIG_CHILDREN);
679 692
680 693 if (nelm <= 0)
681 694 {
682 695 grub_free (type);
683 696 return grub_error (GRUB_ERR_BAD_FS, "incorrect mirror VDEV");
684 697 }
685 698
686 699 if (!fill->children)
687 700 {
688 701 fill->n_children = nelm;
689 702
690 703 fill->children = grub_zalloc (fill->n_children
691 704 * sizeof (fill->children[0]));
692 705 }
693 706
694 707 for (i = 0; i < nelm; i++)
695 708 {
696 709 char *child;
697 710 grub_err_t err;
698 711
699 712 child = grub_zfs_nvlist_lookup_nvlist_array
700 713 (nvlist, ZPOOL_CONFIG_CHILDREN, i);
701 714
702 715 err = fill_vdev_info_real (data, child, &fill->children[i], insert,
703 716 inserted, fill->ashift);
704 717
705 718 grub_free (child);
706 719
707 720 if (err)
708 721 {
709 722 grub_free (type);
710 723 return err;
711 724 }
712 725 if (fill->children[i].ashift > fill->max_children_ashift)
713 726 fill->max_children_ashift = fill->children[i].ashift;
714 727 }
715 728 grub_free (type);
716 729 return GRUB_ERR_NONE;
717 730 }
718 731
719 732 grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "vdev %s isn't supported", type);
720 733 grub_free (type);
721 734 return grub_errno;
722 735 }
723 736
724 737 static grub_err_t
725 738 fill_vdev_info (struct grub_zfs_data *data,
726 739 char *nvlist, struct grub_zfs_device_desc *diskdesc,
727 740 int *inserted)
728 741 {
729 742 grub_uint64_t id;
730 743 unsigned i;
731 744
732 745 *inserted = 0;
733 746
734 747 if (!grub_zfs_nvlist_lookup_uint64 (nvlist, "id", &id))
735 748 return grub_error (GRUB_ERR_BAD_FS, "couldn't find vdev id");
736 749
737 750 for (i = 0; i < data->n_devices_attached; i++)
738 751 if (data->devices_attached[i].id == id)
739 752 return fill_vdev_info_real (data, nvlist, &data->devices_attached[i],
740 753 diskdesc, inserted, 0xffffffff);
741 754
742 755 data->n_devices_attached++;
743 756 if (data->n_devices_attached > data->n_devices_allocated)
744 757 {
745 758 void *tmp;
746 759 data->n_devices_allocated = 2 * data->n_devices_attached + 1;
747 760 data->devices_attached
748 761 = grub_realloc (tmp = data->devices_attached,
749 762 data->n_devices_allocated
750 763 * sizeof (data->devices_attached[0]));
751 764 if (!data->devices_attached)
752 765 {
753 766 data->devices_attached = tmp;
754 767 return grub_errno;
755 768 }
756 769 }
757 770
758 771 grub_memset (&data->devices_attached[data->n_devices_attached - 1],
759 772 0, sizeof (data->devices_attached[data->n_devices_attached - 1]));
760 773
761 774 return fill_vdev_info_real (data, nvlist,
762 775 &data->devices_attached[data->n_devices_attached - 1],
763 776 diskdesc, inserted, 0xffffffff);
764 777 }
765 778
766 779 /*
767 780 * Check the disk label information and retrieve needed vdev name-value pairs.
768 781 *
769 782 */
770 783 static grub_err_t
771 784 check_pool_label (struct grub_zfs_data *data,
772 785 struct grub_zfs_device_desc *diskdesc,
773 786 int *inserted)
774 787 {
775 788 grub_uint64_t pool_state, txg = 0;
776 789 char *nvlist;
777 790 #if 0
778 791 char *nv;
779 792 #endif
780 793 grub_uint64_t poolguid;
781 794 grub_uint64_t version;
782 795 int found;
783 796 grub_err_t err;
784 797
785 798 *inserted = 0;
786 799
787 800 err = zfs_fetch_nvlist (diskdesc, &nvlist);
788 801 if (err)
789 802 return err;
790 803
791 804 grub_dprintf ("zfs", "check 2 passed\n");
792 805
793 806 found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_STATE,
794 807 &pool_state);
795 808 if (! found)
796 809 {
797 810 grub_free (nvlist);
798 811 if (! grub_errno)
799 812 grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_POOL_STATE " not found");
800 813 return grub_errno;
801 814 }
802 815 grub_dprintf ("zfs", "check 3 passed\n");
803 816
804 817 if (pool_state == POOL_STATE_DESTROYED)
805 818 {
806 819 grub_free (nvlist);
807 820 return grub_error (GRUB_ERR_BAD_FS, "zpool is marked as destroyed");
808 821 }
809 822 grub_dprintf ("zfs", "check 4 passed\n");
810 823
811 824 found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_TXG, &txg);
812 825 if (!found)
813 826 {
814 827 grub_free (nvlist);
815 828 if (! grub_errno)
816 829 grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_POOL_TXG " not found");
817 830 return grub_errno;
818 831 }
819 832 grub_dprintf ("zfs", "check 6 passed\n");
820 833
821 834 /* not an active device */
822 835 if (txg == 0)
823 836 {
824 837 grub_free (nvlist);
825 838 return grub_error (GRUB_ERR_BAD_FS, "zpool isn't active");
826 839 }
827 840 grub_dprintf ("zfs", "check 7 passed\n");
828 841
↓ open down ↓ |
325 lines elided |
↑ open up ↑ |
829 842 found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_VERSION,
830 843 &version);
831 844 if (! found)
832 845 {
833 846 grub_free (nvlist);
834 847 if (! grub_errno)
835 848 grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_VERSION " not found");
836 849 return grub_errno;
837 850 }
838 851 grub_dprintf ("zfs", "check 8 passed\n");
839 -
840 - if (version > SPA_VERSION)
841 - {
842 - grub_free (nvlist);
843 - return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
844 - "too new version %llu > %llu",
845 - (unsigned long long) version,
846 - (unsigned long long) SPA_VERSION);
847 - }
848 852 grub_dprintf ("zfs", "check 9 passed\n");
849 853
850 854 found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_GUID,
851 855 &(diskdesc->guid));
852 856 if (! found)
853 857 {
854 858 grub_free (nvlist);
855 859 if (! grub_errno)
856 860 grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_GUID " not found");
857 861 return grub_errno;
858 862 }
859 863
860 864 found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_GUID,
861 865 &poolguid);
862 866 if (! found)
863 867 {
864 868 grub_free (nvlist);
865 869 if (! grub_errno)
866 870 grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_POOL_GUID " not found");
867 871 return grub_errno;
868 872 }
869 873
870 874 grub_dprintf ("zfs", "check 11 passed\n");
871 875
872 876 if (data->mounted && data->guid != poolguid)
873 877 return grub_error (GRUB_ERR_BAD_FS, "another zpool");
874 878 else
875 879 data->guid = poolguid;
876 880
877 881 {
878 882 char *nv;
879 883 nv = grub_zfs_nvlist_lookup_nvlist (nvlist, ZPOOL_CONFIG_VDEV_TREE);
880 884
881 885 if (!nv)
882 886 {
883 887 grub_free (nvlist);
884 888 return grub_error (GRUB_ERR_BAD_FS, "couldn't find vdev tree");
885 889 }
886 890 err = fill_vdev_info (data, nv, diskdesc, inserted);
887 891 if (err)
888 892 {
889 893 grub_free (nv);
890 894 grub_free (nvlist);
891 895 return err;
892 896 }
893 897 grub_free (nv);
894 898 }
895 899 grub_dprintf ("zfs", "check 10 passed\n");
896 900
897 901 grub_free (nvlist);
898 902
899 903 return GRUB_ERR_NONE;
900 904 }
901 905
902 906 static grub_err_t
903 907 scan_disk (grub_device_t dev, struct grub_zfs_data *data,
904 908 int original, int *inserted)
905 909 {
906 910 int label = 0;
907 911 uberblock_phys_t *ub_array, *ubbest = NULL;
908 912 vdev_boot_header_t *bh;
909 913 grub_err_t err;
910 914 int vdevnum;
911 915 struct grub_zfs_device_desc desc;
912 916
913 917 ub_array = grub_malloc (VDEV_UBERBLOCK_RING);
914 918 if (!ub_array)
915 919 return grub_errno;
916 920
917 921 bh = grub_malloc (VDEV_BOOT_HEADER_SIZE);
918 922 if (!bh)
919 923 {
920 924 grub_free (ub_array);
921 925 return grub_errno;
922 926 }
923 927
924 928 vdevnum = VDEV_LABELS;
925 929
926 930 desc.dev = dev;
927 931 desc.original = original;
928 932
929 933 /* Don't check back labels on CDROM. */
930 934 if (grub_disk_get_size (dev->disk) == GRUB_DISK_SIZE_UNKNOWN)
931 935 vdevnum = VDEV_LABELS / 2;
932 936
933 937 for (label = 0; ubbest == NULL && label < vdevnum; label++)
934 938 {
935 939 desc.vdev_phys_sector
936 940 = label * (sizeof (vdev_label_t) >> SPA_MINBLOCKSHIFT)
937 941 + ((VDEV_SKIP_SIZE + VDEV_BOOT_HEADER_SIZE) >> SPA_MINBLOCKSHIFT)
938 942 + (label < VDEV_LABELS / 2 ? 0 :
939 943 ALIGN_DOWN (grub_disk_get_size (dev->disk), sizeof (vdev_label_t))
940 944 - VDEV_LABELS * (sizeof (vdev_label_t) >> SPA_MINBLOCKSHIFT));
941 945
942 946 /* Read in the uberblock ring (128K). */
943 947 err = grub_disk_read (dev->disk, desc.vdev_phys_sector
944 948 + (VDEV_PHYS_SIZE >> SPA_MINBLOCKSHIFT),
945 949 0, VDEV_UBERBLOCK_RING, (char *) ub_array);
946 950 if (err)
947 951 {
948 952 grub_errno = GRUB_ERR_NONE;
949 953 continue;
950 954 }
951 955 grub_dprintf ("zfs", "label ok %d\n", label);
952 956
953 957 err = check_pool_label (data, &desc, inserted);
954 958 if (err || !*inserted)
955 959 {
956 960 grub_errno = GRUB_ERR_NONE;
957 961 continue;
958 962 }
959 963
960 964 ubbest = find_bestub (ub_array, &desc);
961 965 if (!ubbest)
962 966 {
963 967 grub_dprintf ("zfs", "No uberblock found\n");
964 968 grub_errno = GRUB_ERR_NONE;
965 969 continue;
966 970 }
967 971
968 972 grub_memmove (&(desc.current_uberblock),
969 973 &ubbest->ubp_uberblock, sizeof (uberblock_t));
970 974 if (original)
971 975 grub_memmove (&(data->current_uberblock),
972 976 &ubbest->ubp_uberblock, sizeof (uberblock_t));
973 977
974 978 #if 0
975 979 if (find_best_root &&
976 980 vdev_uberblock_compare (&ubbest->ubp_uberblock,
977 981 &(current_uberblock)) <= 0)
978 982 continue;
979 983 #endif
980 984 grub_free (ub_array);
981 985 grub_free (bh);
982 986 return GRUB_ERR_NONE;
983 987 }
984 988
985 989 grub_free (ub_array);
986 990 grub_free (bh);
987 991
988 992 return grub_error (GRUB_ERR_BAD_FS, "couldn't find a valid label");
989 993 }
990 994
991 995 static grub_err_t
992 996 scan_devices (struct grub_zfs_data *data)
993 997 {
994 998 auto int hook (const char *name);
995 999 int hook (const char *name)
996 1000 {
997 1001 grub_device_t dev;
998 1002 grub_err_t err;
999 1003 int inserted;
1000 1004 dev = grub_device_open (name);
1001 1005 if (!dev)
1002 1006 return 0;
1003 1007 if (!dev->disk)
1004 1008 {
1005 1009 grub_device_close (dev);
1006 1010 return 0;
1007 1011 }
1008 1012 err = scan_disk (dev, data, 0, &inserted);
1009 1013 if (err == GRUB_ERR_BAD_FS)
1010 1014 {
1011 1015 grub_device_close (dev);
1012 1016 grub_errno = GRUB_ERR_NONE;
1013 1017 return 0;
1014 1018 }
1015 1019 if (err)
1016 1020 {
1017 1021 grub_device_close (dev);
1018 1022 grub_print_error ();
1019 1023 return 0;
1020 1024 }
1021 1025
1022 1026 if (!inserted)
1023 1027 grub_device_close (dev);
1024 1028
1025 1029 return 0;
1026 1030 }
1027 1031 grub_device_iterate (hook);
1028 1032 return GRUB_ERR_NONE;
1029 1033 }
1030 1034
1031 1035 /* x**y. */
1032 1036 static grub_uint8_t powx[255 * 2];
1033 1037 /* Such an s that x**s = y */
1034 1038 static int powx_inv[256];
1035 1039 static const grub_uint8_t poly = 0x1d;
1036 1040
1037 1041 /* perform the operation a ^= b * (x ** (known_idx * recovery_pow) ) */
1038 1042 static inline void
1039 1043 xor_out (grub_uint8_t *a, const grub_uint8_t *b, grub_size_t s,
1040 1044 int known_idx, int recovery_pow)
1041 1045 {
1042 1046 int add;
1043 1047
1044 1048 /* Simple xor. */
1045 1049 if (known_idx == 0 || recovery_pow == 0)
1046 1050 {
1047 1051 grub_crypto_xor (a, a, b, s);
1048 1052 return;
1049 1053 }
1050 1054 add = (known_idx * recovery_pow) % 255;
1051 1055 for (;s--; b++, a++)
1052 1056 if (*b)
1053 1057 *a ^= powx[powx_inv[*b] + add];
1054 1058 }
1055 1059
1056 1060 static inline grub_uint8_t
1057 1061 gf_mul (grub_uint8_t a, grub_uint8_t b)
1058 1062 {
1059 1063 if (a == 0 || b == 0)
1060 1064 return 0;
1061 1065 return powx[powx_inv[a] + powx_inv[b]];
1062 1066 }
1063 1067
1064 1068 static inline grub_err_t
1065 1069 recovery (grub_uint8_t *bufs[4], grub_size_t s, const int nbufs,
1066 1070 const unsigned *powers,
1067 1071 const int *idx)
1068 1072 {
1069 1073 grub_dprintf ("zfs", "recovering %u buffers\n", nbufs);
1070 1074 /* Now we have */
1071 1075 /* b_i = sum (r_j* (x ** (powers[i] * idx[j])))*/
1072 1076 /* Let's invert the matrix in question. */
1073 1077 switch (nbufs)
1074 1078 {
1075 1079 /* Easy: r_0 = bufs[0] / (x << (powers[i] * idx[j])). */
1076 1080 case 1:
1077 1081 {
1078 1082 int add;
1079 1083 grub_uint8_t *a;
1080 1084 if (powers[0] == 0 || idx[0] == 0)
1081 1085 return GRUB_ERR_NONE;
1082 1086 add = 255 - ((powers[0] * idx[0]) % 255);
1083 1087 for (a = bufs[0]; s--; a++)
1084 1088 if (*a)
1085 1089 *a = powx[powx_inv[*a] + add];
1086 1090 return GRUB_ERR_NONE;
1087 1091 }
1088 1092 /* Case 2x2: Let's use the determinant formula. */
1089 1093 case 2:
1090 1094 {
1091 1095 grub_uint8_t det, det_inv;
1092 1096 grub_uint8_t matrixinv[2][2];
1093 1097 unsigned i;
1094 1098 /* The determinant is: */
1095 1099 det = (powx[(powers[0] * idx[0] + powers[1] * idx[1]) % 255]
1096 1100 ^ powx[(powers[0] * idx[1] + powers[1] * idx[0]) % 255]);
1097 1101 if (det == 0)
1098 1102 return grub_error (GRUB_ERR_BAD_FS, "singular recovery matrix");
1099 1103 det_inv = powx[255 - powx_inv[det]];
1100 1104 matrixinv[0][0] = gf_mul (powx[(powers[1] * idx[1]) % 255], det_inv);
1101 1105 matrixinv[1][1] = gf_mul (powx[(powers[0] * idx[0]) % 255], det_inv);
1102 1106 matrixinv[0][1] = gf_mul (powx[(powers[0] * idx[1]) % 255], det_inv);
1103 1107 matrixinv[1][0] = gf_mul (powx[(powers[1] * idx[0]) % 255], det_inv);
1104 1108 for (i = 0; i < s; i++)
1105 1109 {
1106 1110 grub_uint8_t b0, b1;
1107 1111 b0 = bufs[0][i];
1108 1112 b1 = bufs[1][i];
1109 1113
1110 1114 bufs[0][i] = (gf_mul (b0, matrixinv[0][0])
1111 1115 ^ gf_mul (b1, matrixinv[0][1]));
1112 1116 bufs[1][i] = (gf_mul (b0, matrixinv[1][0])
1113 1117 ^ gf_mul (b1, matrixinv[1][1]));
1114 1118 }
1115 1119 return GRUB_ERR_NONE;
1116 1120 }
1117 1121 /* Otherwise use Gauss. */
1118 1122 default:
1119 1123 {
1120 1124 grub_uint8_t matrix1[nbufs][nbufs], matrix2[nbufs][nbufs];
1121 1125 int i, j, k;
1122 1126
1123 1127 for (i = 0; i < nbufs; i++)
1124 1128 for (j = 0; j < nbufs; j++)
1125 1129 matrix1[i][j] = powx[(powers[i] * idx[j]) % 255];
1126 1130 for (i = 0; i < nbufs; i++)
1127 1131 for (j = 0; j < nbufs; j++)
1128 1132 matrix2[i][j] = 0;
1129 1133 for (i = 0; i < nbufs; i++)
1130 1134 matrix2[i][i] = 1;
1131 1135
1132 1136 for (i = 0; i < nbufs; i++)
1133 1137 {
1134 1138 grub_uint8_t mul;
1135 1139 for (j = i; j < nbufs; j++)
1136 1140 if (matrix1[i][j])
1137 1141 break;
1138 1142 if (j == nbufs)
1139 1143 return grub_error (GRUB_ERR_BAD_FS, "singular recovery matrix");
1140 1144 if (j != i)
1141 1145 {
1142 1146 int xchng;
1143 1147 xchng = j;
1144 1148 for (j = 0; j < nbufs; j++)
1145 1149 {
1146 1150 grub_uint8_t t;
1147 1151 t = matrix1[xchng][j];
1148 1152 matrix1[xchng][j] = matrix1[i][j];
1149 1153 matrix1[i][j] = t;
1150 1154 }
1151 1155 for (j = 0; j < nbufs; j++)
1152 1156 {
1153 1157 grub_uint8_t t;
1154 1158 t = matrix2[xchng][j];
1155 1159 matrix2[xchng][j] = matrix2[i][j];
1156 1160 matrix2[i][j] = t;
1157 1161 }
1158 1162 }
1159 1163 mul = powx[255 - powx_inv[matrix1[i][i]]];
1160 1164 for (j = 0; j < nbufs; j++)
1161 1165 matrix1[i][j] = gf_mul (matrix1[i][j], mul);
1162 1166 for (j = 0; j < nbufs; j++)
1163 1167 matrix2[i][j] = gf_mul (matrix2[i][j], mul);
1164 1168 for (j = i + 1; j < nbufs; j++)
1165 1169 {
1166 1170 mul = matrix1[j][i];
1167 1171 for (k = 0; k < nbufs; k++)
1168 1172 matrix1[j][k] ^= gf_mul (matrix1[i][k], mul);
1169 1173 for (k = 0; k < nbufs; k++)
1170 1174 matrix2[j][k] ^= gf_mul (matrix2[i][k], mul);
1171 1175 }
1172 1176 }
1173 1177 for (i = nbufs - 1; i >= 0; i--)
1174 1178 {
1175 1179 for (j = 0; j < i; j++)
1176 1180 {
1177 1181 grub_uint8_t mul;
1178 1182 mul = matrix1[j][i];
1179 1183 for (k = 0; k < nbufs; k++)
1180 1184 matrix1[j][k] ^= gf_mul (matrix1[i][k], mul);
1181 1185 for (k = 0; k < nbufs; k++)
1182 1186 matrix2[j][k] ^= gf_mul (matrix2[i][k], mul);
1183 1187 }
1184 1188 }
1185 1189
1186 1190 for (i = 0; i < (int) s; i++)
1187 1191 {
1188 1192 grub_uint8_t b[nbufs];
1189 1193 for (j = 0; j < nbufs; j++)
1190 1194 b[j] = bufs[j][i];
1191 1195 for (j = 0; j < nbufs; j++)
1192 1196 {
1193 1197 bufs[j][i] = 0;
1194 1198 for (k = 0; k < nbufs; k++)
1195 1199 bufs[j][i] ^= gf_mul (matrix2[j][k], b[k]);
1196 1200 }
1197 1201 }
1198 1202 return GRUB_ERR_NONE;
1199 1203 }
1200 1204 }
1201 1205 }
1202 1206
1203 1207 static grub_err_t
1204 1208 read_device (grub_uint64_t offset, struct grub_zfs_device_desc *desc,
1205 1209 grub_size_t len, void *buf)
1206 1210 {
1207 1211 switch (desc->type)
1208 1212 {
1209 1213 case DEVICE_LEAF:
1210 1214 {
1211 1215 grub_uint64_t sector;
1212 1216 sector = DVA_OFFSET_TO_PHYS_SECTOR (offset);
1213 1217 if (!desc->dev)
1214 1218 {
1215 1219 return grub_error (GRUB_ERR_BAD_FS,
1216 1220 N_("couldn't find a necessary member device "
1217 1221 "of multi-device filesystem"));
1218 1222 }
1219 1223 /* read in a data block */
1220 1224 return grub_disk_read (desc->dev->disk, sector, 0, len, buf);
1221 1225 }
1222 1226 case DEVICE_MIRROR:
1223 1227 {
1224 1228 grub_err_t err = GRUB_ERR_NONE;
1225 1229 unsigned i;
1226 1230 if (desc->n_children <= 0)
1227 1231 return grub_error (GRUB_ERR_BAD_FS,
1228 1232 "non-positive number of mirror children");
1229 1233 for (i = 0; i < desc->n_children; i++)
1230 1234 {
1231 1235 err = read_device (offset, &desc->children[i],
1232 1236 len, buf);
1233 1237 if (!err)
1234 1238 break;
1235 1239 grub_errno = GRUB_ERR_NONE;
1236 1240 }
1237 1241 return (grub_errno = err);
1238 1242 }
1239 1243 case DEVICE_RAIDZ:
1240 1244 {
1241 1245 unsigned c = 0;
1242 1246 grub_uint64_t high;
1243 1247 grub_uint64_t devn;
1244 1248 grub_uint64_t m;
1245 1249 grub_uint32_t s, orig_s;
1246 1250 void *orig_buf = buf;
1247 1251 grub_size_t orig_len = len;
1248 1252 grub_uint8_t *recovery_buf[4];
1249 1253 grub_size_t recovery_len[4];
1250 1254 int recovery_idx[4];
1251 1255 unsigned failed_devices = 0;
1252 1256 int idx, orig_idx;
1253 1257
1254 1258 if (desc->nparity < 1 || desc->nparity > 3)
1255 1259 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
1256 1260 "raidz%d is not supported", desc->nparity);
1257 1261
1258 1262 orig_s = (((len + (1 << desc->ashift) - 1) >> desc->ashift)
1259 1263 + (desc->n_children - desc->nparity) - 1);
1260 1264 s = orig_s;
1261 1265
1262 1266 high = grub_divmod64 ((offset >> desc->ashift),
1263 1267 desc->n_children, &m);
1264 1268 if (desc->nparity == 2)
1265 1269 c = 2;
1266 1270 if (desc->nparity == 3)
1267 1271 c = 3;
1268 1272 if (((len + (1 << desc->ashift) - 1) >> desc->ashift)
1269 1273 >= (desc->n_children - desc->nparity))
1270 1274 idx = (desc->n_children - desc->nparity - 1);
1271 1275 else
1272 1276 idx = ((len + (1 << desc->ashift) - 1) >> desc->ashift) - 1;
1273 1277 orig_idx = idx;
1274 1278 while (len > 0)
1275 1279 {
1276 1280 grub_size_t csize;
1277 1281 grub_uint32_t bsize;
1278 1282 grub_err_t err;
1279 1283 bsize = s / (desc->n_children - desc->nparity);
1280 1284
1281 1285 if (desc->nparity == 1
1282 1286 && ((offset >> (desc->ashift + 20 - desc->max_children_ashift))
1283 1287 & 1) == c)
1284 1288 c++;
1285 1289
1286 1290 high = grub_divmod64 ((offset >> desc->ashift) + c,
1287 1291 desc->n_children, &devn);
1288 1292 csize = bsize << desc->ashift;
1289 1293 if (csize > len)
1290 1294 csize = len;
1291 1295
1292 1296 grub_dprintf ("zfs", "RAIDZ mapping 0x%" PRIxGRUB_UINT64_T
1293 1297 "+%u (%" PRIxGRUB_SIZE ", %" PRIxGRUB_UINT32_T
1294 1298 ") -> (0x%" PRIxGRUB_UINT64_T ", 0x%"
1295 1299 PRIxGRUB_UINT64_T ")\n",
1296 1300 offset >> desc->ashift, c, len, bsize, high,
1297 1301 devn);
1298 1302 err = read_device ((high << desc->ashift)
1299 1303 | (offset & ((1 << desc->ashift) - 1)),
1300 1304 &desc->children[devn],
1301 1305 csize, buf);
1302 1306 if (err && failed_devices < desc->nparity)
1303 1307 {
1304 1308 recovery_buf[failed_devices] = buf;
1305 1309 recovery_len[failed_devices] = csize;
1306 1310 recovery_idx[failed_devices] = idx;
1307 1311 failed_devices++;
1308 1312 grub_errno = err = 0;
1309 1313 }
1310 1314 if (err)
1311 1315 return err;
1312 1316
1313 1317 c++;
1314 1318 idx--;
1315 1319 s--;
1316 1320 buf = (char *) buf + csize;
1317 1321 len -= csize;
1318 1322 }
1319 1323 if (failed_devices)
1320 1324 {
1321 1325 unsigned redundancy_pow[4];
1322 1326 unsigned cur_redundancy_pow = 0;
1323 1327 unsigned n_redundancy = 0;
1324 1328 unsigned i, j;
1325 1329 grub_err_t err;
1326 1330
1327 1331 /* Compute mul. x**s has a period of 255. */
1328 1332 if (powx[0] == 0)
1329 1333 {
1330 1334 grub_uint8_t cur = 1;
1331 1335 for (i = 0; i < 255; i++)
1332 1336 {
1333 1337 powx[i] = cur;
1334 1338 powx[i + 255] = cur;
1335 1339 powx_inv[cur] = i;
1336 1340 if (cur & 0x80)
1337 1341 cur = (cur << 1) ^ poly;
1338 1342 else
1339 1343 cur <<= 1;
1340 1344 }
1341 1345 }
1342 1346
1343 1347 /* Read redundancy data. */
1344 1348 for (n_redundancy = 0, cur_redundancy_pow = 0;
1345 1349 n_redundancy < failed_devices;
1346 1350 cur_redundancy_pow++)
1347 1351 {
1348 1352 high = grub_divmod64 ((offset >> desc->ashift)
1349 1353 + cur_redundancy_pow
1350 1354 + ((desc->nparity == 1)
1351 1355 && ((offset >> (desc->ashift + 20
1352 1356 - desc->max_children_ashift))
1353 1357 & 1)),
1354 1358 desc->n_children, &devn);
1355 1359 err = read_device ((high << desc->ashift)
1356 1360 | (offset & ((1 << desc->ashift) - 1)),
1357 1361 &desc->children[devn],
1358 1362 recovery_len[n_redundancy],
1359 1363 recovery_buf[n_redundancy]);
1360 1364 /* Ignore error if we may still have enough devices. */
1361 1365 if (err && n_redundancy + desc->nparity - cur_redundancy_pow - 1
1362 1366 >= failed_devices)
1363 1367 {
1364 1368 grub_errno = GRUB_ERR_NONE;
1365 1369 continue;
1366 1370 }
1367 1371 if (err)
1368 1372 return err;
1369 1373 redundancy_pow[n_redundancy] = cur_redundancy_pow;
1370 1374 n_redundancy++;
1371 1375 }
1372 1376 /* Now xor-our the parts we already know. */
1373 1377 buf = orig_buf;
1374 1378 len = orig_len;
1375 1379 s = orig_s;
1376 1380 idx = orig_idx;
1377 1381
1378 1382 while (len > 0)
1379 1383 {
1380 1384 grub_size_t csize;
1381 1385 csize = ((s / (desc->n_children - desc->nparity))
1382 1386 << desc->ashift);
1383 1387 if (csize > len)
1384 1388 csize = len;
1385 1389
1386 1390 for (j = 0; j < failed_devices; j++)
1387 1391 if (buf == recovery_buf[j])
1388 1392 break;
1389 1393
1390 1394 if (j == failed_devices)
1391 1395 for (j = 0; j < failed_devices; j++)
1392 1396 xor_out (recovery_buf[j], buf,
1393 1397 csize < recovery_len[j] ? csize : recovery_len[j],
1394 1398 idx, redundancy_pow[j]);
1395 1399
1396 1400 s--;
1397 1401 buf = (char *) buf + csize;
1398 1402 len -= csize;
1399 1403 idx--;
1400 1404 }
1401 1405 for (i = 0; i < failed_devices
1402 1406 && recovery_len[i] == recovery_len[0];
1403 1407 i++);
1404 1408 /* Since the chunks have variable length handle the last block
1405 1409 separately. */
1406 1410 if (i != failed_devices)
1407 1411 {
1408 1412 grub_uint8_t *tmp_recovery_buf[4];
1409 1413 for (j = 0; j < i; j++)
1410 1414 tmp_recovery_buf[j] = recovery_buf[j] + recovery_len[failed_devices - 1];
1411 1415 err = recovery (tmp_recovery_buf, recovery_len[0] - recovery_len[failed_devices - 1], i, redundancy_pow,
1412 1416 recovery_idx);
1413 1417 if (err)
1414 1418 return err;
1415 1419 }
1416 1420 err = recovery (recovery_buf, recovery_len[failed_devices - 1],
1417 1421 failed_devices, redundancy_pow, recovery_idx);
1418 1422 if (err)
1419 1423 return err;
1420 1424 }
1421 1425 return GRUB_ERR_NONE;
1422 1426 }
1423 1427 }
1424 1428 return grub_error (GRUB_ERR_BAD_FS, "unsupported device type");
1425 1429 }
1426 1430
1427 1431 static grub_err_t
1428 1432 read_dva (const dva_t *dva,
1429 1433 grub_zfs_endian_t endian, struct grub_zfs_data *data,
1430 1434 void *buf, grub_size_t len)
1431 1435 {
1432 1436 grub_uint64_t offset;
1433 1437 unsigned i;
1434 1438 grub_err_t err = 0;
1435 1439 int try = 0;
1436 1440 offset = dva_get_offset (dva, endian);
1437 1441
1438 1442 for (try = 0; try < 2; try++)
1439 1443 {
1440 1444 for (i = 0; i < data->n_devices_attached; i++)
1441 1445 if (data->devices_attached[i].id == DVA_GET_VDEV (dva))
1442 1446 {
1443 1447 err = read_device (offset, &data->devices_attached[i], len, buf);
1444 1448 if (!err)
1445 1449 return GRUB_ERR_NONE;
1446 1450 break;
1447 1451 }
1448 1452 if (try == 1)
1449 1453 break;
1450 1454 err = scan_devices (data);
1451 1455 if (err)
1452 1456 return err;
1453 1457 }
1454 1458 if (!err)
1455 1459 return grub_error (GRUB_ERR_BAD_FS, "unknown device %d",
1456 1460 (int) DVA_GET_VDEV (dva));
1457 1461 return err;
1458 1462 }
1459 1463
1460 1464 /*
1461 1465 * Read a block of data based on the gang block address dva,
1462 1466 * and put its data in buf.
1463 1467 *
1464 1468 */
1465 1469 static grub_err_t
1466 1470 zio_read_gang (blkptr_t * bp, grub_zfs_endian_t endian, dva_t * dva, void *buf,
1467 1471 struct grub_zfs_data *data)
1468 1472 {
1469 1473 zio_gbh_phys_t *zio_gb;
1470 1474 unsigned i;
1471 1475 grub_err_t err;
1472 1476 zio_cksum_t zc;
1473 1477
1474 1478 grub_memset (&zc, 0, sizeof (zc));
1475 1479
1476 1480 zio_gb = grub_malloc (SPA_GANGBLOCKSIZE);
1477 1481 if (!zio_gb)
1478 1482 return grub_errno;
1479 1483 grub_dprintf ("zfs", endian == GRUB_ZFS_LITTLE_ENDIAN ? "little-endian gang\n"
1480 1484 :"big-endian gang\n");
1481 1485
1482 1486 err = read_dva (dva, endian, data, zio_gb, SPA_GANGBLOCKSIZE);
1483 1487 if (err)
1484 1488 {
1485 1489 grub_free (zio_gb);
1486 1490 return err;
1487 1491 }
1488 1492
1489 1493 /* XXX */
1490 1494 /* self checksuming the gang block header */
1491 1495 ZIO_SET_CHECKSUM (&zc, DVA_GET_VDEV (dva),
1492 1496 dva_get_offset (dva, endian), bp->blk_birth, 0);
1493 1497 err = zio_checksum_verify (zc, ZIO_CHECKSUM_GANG_HEADER, endian,
1494 1498 (char *) zio_gb, SPA_GANGBLOCKSIZE);
1495 1499 if (err)
1496 1500 {
1497 1501 grub_free (zio_gb);
1498 1502 return err;
1499 1503 }
1500 1504
1501 1505 endian = (grub_zfs_to_cpu64 (bp->blk_prop, endian) >> 63) & 1;
1502 1506
1503 1507 for (i = 0; i < SPA_GBH_NBLKPTRS; i++)
1504 1508 {
1505 1509 if (zio_gb->zg_blkptr[i].blk_birth == 0)
1506 1510 continue;
1507 1511
1508 1512 err = zio_read_data (&zio_gb->zg_blkptr[i], endian, buf, data);
1509 1513 if (err)
1510 1514 {
1511 1515 grub_free (zio_gb);
1512 1516 return err;
1513 1517 }
1514 1518 buf = (char *) buf + get_psize (&zio_gb->zg_blkptr[i], endian);
1515 1519 }
1516 1520 grub_free (zio_gb);
1517 1521 return GRUB_ERR_NONE;
1518 1522 }
1519 1523
1520 1524 /*
1521 1525 * Read in a block of raw data to buf.
1522 1526 */
1523 1527 static grub_err_t
1524 1528 zio_read_data (blkptr_t * bp, grub_zfs_endian_t endian, void *buf,
1525 1529 struct grub_zfs_data *data)
1526 1530 {
1527 1531 int i, psize;
1528 1532 grub_err_t err = GRUB_ERR_NONE;
1529 1533
1530 1534 psize = get_psize (bp, endian);
1531 1535
1532 1536 /* pick a good dva from the block pointer */
1533 1537 for (i = 0; i < SPA_DVAS_PER_BP; i++)
1534 1538 {
1535 1539 if (bp->blk_dva[i].dva_word[0] == 0 && bp->blk_dva[i].dva_word[1] == 0)
1536 1540 continue;
1537 1541
1538 1542 if ((grub_zfs_to_cpu64 (bp->blk_dva[i].dva_word[1], endian)>>63) & 1)
1539 1543 err = zio_read_gang (bp, endian, &bp->blk_dva[i], buf, data);
1540 1544 else
1541 1545 err = read_dva (&bp->blk_dva[i], endian, data, buf, psize);
1542 1546 if (!err)
1543 1547 return GRUB_ERR_NONE;
1544 1548 grub_errno = GRUB_ERR_NONE;
1545 1549 }
1546 1550
1547 1551 if (!err)
1548 1552 err = grub_error (GRUB_ERR_BAD_FS, "couldn't find a valid DVA");
1549 1553 grub_errno = err;
1550 1554
1551 1555 return err;
1552 1556 }
1553 1557
1554 1558 /*
1555 1559 * Read in a block of data, verify its checksum, decompress if needed,
1556 1560 * and put the uncompressed data in buf.
1557 1561 */
1558 1562 static grub_err_t
1559 1563 zio_read (blkptr_t *bp, grub_zfs_endian_t endian, void **buf,
1560 1564 grub_size_t *size, struct grub_zfs_data *data)
1561 1565 {
1562 1566 grub_size_t lsize, psize;
1563 1567 unsigned int comp, encrypted;
1564 1568 char *compbuf = NULL;
1565 1569 grub_err_t err;
1566 1570 zio_cksum_t zc = bp->blk_cksum;
1567 1571 grub_uint32_t checksum;
1568 1572
1569 1573 *buf = NULL;
1570 1574
1571 1575 checksum = (grub_zfs_to_cpu64((bp)->blk_prop, endian) >> 40) & 0xff;
1572 1576 comp = (grub_zfs_to_cpu64((bp)->blk_prop, endian)>>32) & 0xff;
1573 1577 encrypted = ((grub_zfs_to_cpu64((bp)->blk_prop, endian) >> 60) & 3);
1574 1578 lsize = (BP_IS_HOLE(bp) ? 0 :
1575 1579 (((grub_zfs_to_cpu64 ((bp)->blk_prop, endian) & 0xffff) + 1)
1576 1580 << SPA_MINBLOCKSHIFT));
1577 1581 psize = get_psize (bp, endian);
1578 1582
1579 1583 if (size)
1580 1584 *size = lsize;
1581 1585
1582 1586 if (comp >= ZIO_COMPRESS_FUNCTIONS)
1583 1587 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
1584 1588 "compression algorithm %u not supported\n", (unsigned int) comp);
1585 1589
1586 1590 if (comp != ZIO_COMPRESS_OFF && decomp_table[comp].decomp_func == NULL)
1587 1591 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
1588 1592 "compression algorithm %s not supported\n", decomp_table[comp].name);
1589 1593
1590 1594 if (comp != ZIO_COMPRESS_OFF)
1591 1595 {
1592 1596 /* It's not really necessary to align to 16, just for safety. */
1593 1597 compbuf = grub_malloc (ALIGN_UP (psize, 16));
1594 1598 if (! compbuf)
1595 1599 return grub_errno;
1596 1600 }
1597 1601 else
1598 1602 compbuf = *buf = grub_malloc (lsize);
1599 1603
1600 1604 grub_dprintf ("zfs", "endian = %d\n", endian);
1601 1605 err = zio_read_data (bp, endian, compbuf, data);
1602 1606 if (err)
1603 1607 {
1604 1608 grub_free (compbuf);
1605 1609 *buf = NULL;
1606 1610 return err;
1607 1611 }
1608 1612 grub_memset (compbuf, 0, ALIGN_UP (psize, 16) - psize);
1609 1613
1610 1614 err = zio_checksum_verify (zc, checksum, endian,
1611 1615 compbuf, psize);
1612 1616 if (err)
1613 1617 {
1614 1618 grub_dprintf ("zfs", "incorrect checksum\n");
1615 1619 grub_free (compbuf);
1616 1620 *buf = NULL;
1617 1621 return err;
1618 1622 }
1619 1623
1620 1624 if (encrypted)
1621 1625 {
1622 1626 if (!grub_zfs_decrypt)
1623 1627 err = grub_error (GRUB_ERR_BAD_FS,
1624 1628 N_("module `%s' isn't loaded"),
1625 1629 "zfscrypt");
1626 1630 else
1627 1631 {
1628 1632 unsigned i, besti = 0;
1629 1633 grub_uint64_t bestval = 0;
1630 1634 for (i = 0; i < data->subvol.nkeys; i++)
1631 1635 if (data->subvol.keyring[i].txg <= grub_zfs_to_cpu64 (bp->blk_birth,
1632 1636 endian)
1633 1637 && data->subvol.keyring[i].txg > bestval)
1634 1638 {
1635 1639 besti = i;
1636 1640 bestval = data->subvol.keyring[i].txg;
1637 1641 }
1638 1642 if (bestval == 0)
1639 1643 {
1640 1644 grub_free (compbuf);
1641 1645 *buf = NULL;
1642 1646 grub_dprintf ("zfs", "no key for txg %" PRIxGRUB_UINT64_T "\n",
1643 1647 grub_zfs_to_cpu64 (bp->blk_birth,
1644 1648 endian));
1645 1649 return grub_error (GRUB_ERR_BAD_FS, "no key found in keychain");
1646 1650 }
1647 1651 grub_dprintf ("zfs", "using key %u (%" PRIxGRUB_UINT64_T
1648 1652 ", %p) for txg %" PRIxGRUB_UINT64_T "\n",
1649 1653 besti, data->subvol.keyring[besti].txg,
1650 1654 data->subvol.keyring[besti].cipher,
1651 1655 grub_zfs_to_cpu64 (bp->blk_birth,
1652 1656 endian));
1653 1657 err = grub_zfs_decrypt (data->subvol.keyring[besti].cipher,
1654 1658 data->subvol.keyring[besti].algo,
1655 1659 &(bp)->blk_dva[encrypted],
1656 1660 compbuf, psize, ((grub_uint32_t *) &zc + 5),
1657 1661 endian);
1658 1662 }
1659 1663 if (err)
1660 1664 {
1661 1665 grub_free (compbuf);
1662 1666 *buf = NULL;
1663 1667 return err;
1664 1668 }
1665 1669 }
1666 1670
1667 1671 if (comp != ZIO_COMPRESS_OFF)
1668 1672 {
1669 1673 *buf = grub_malloc (lsize);
1670 1674 if (!*buf)
1671 1675 {
1672 1676 grub_free (compbuf);
1673 1677 return grub_errno;
1674 1678 }
1675 1679
1676 1680 err = decomp_table[comp].decomp_func (compbuf, *buf, psize, lsize);
1677 1681 grub_free (compbuf);
1678 1682 if (err)
1679 1683 {
1680 1684 grub_free (*buf);
1681 1685 *buf = NULL;
1682 1686 return err;
1683 1687 }
1684 1688 }
1685 1689
1686 1690 return GRUB_ERR_NONE;
1687 1691 }
1688 1692
1689 1693 /*
1690 1694 * Get the block from a block id.
1691 1695 * push the block onto the stack.
1692 1696 *
1693 1697 */
1694 1698 static grub_err_t
1695 1699 dmu_read (dnode_end_t * dn, grub_uint64_t blkid, void **buf,
1696 1700 grub_zfs_endian_t *endian_out, struct grub_zfs_data *data)
1697 1701 {
1698 1702 int level;
1699 1703 grub_off_t idx;
1700 1704 blkptr_t *bp_array = dn->dn.dn_blkptr;
1701 1705 int epbs = dn->dn.dn_indblkshift - SPA_BLKPTRSHIFT;
1702 1706 blkptr_t *bp;
1703 1707 void *tmpbuf = 0;
1704 1708 grub_zfs_endian_t endian;
1705 1709 grub_err_t err = GRUB_ERR_NONE;
1706 1710
1707 1711 bp = grub_malloc (sizeof (blkptr_t));
1708 1712 if (!bp)
1709 1713 return grub_errno;
1710 1714
1711 1715 endian = dn->endian;
1712 1716 for (level = dn->dn.dn_nlevels - 1; level >= 0; level--)
1713 1717 {
1714 1718 grub_dprintf ("zfs", "endian = %d\n", endian);
1715 1719 idx = (blkid >> (epbs * level)) & ((1 << epbs) - 1);
1716 1720 *bp = bp_array[idx];
1717 1721 if (bp_array != dn->dn.dn_blkptr)
1718 1722 {
1719 1723 grub_free (bp_array);
1720 1724 bp_array = 0;
1721 1725 }
1722 1726
1723 1727 if (BP_IS_HOLE (bp))
1724 1728 {
1725 1729 grub_size_t size = grub_zfs_to_cpu16 (dn->dn.dn_datablkszsec,
1726 1730 dn->endian)
1727 1731 << SPA_MINBLOCKSHIFT;
1728 1732 *buf = grub_malloc (size);
1729 1733 if (*buf)
1730 1734 {
1731 1735 err = grub_errno;
1732 1736 break;
1733 1737 }
1734 1738 grub_memset (*buf, 0, size);
1735 1739 endian = (grub_zfs_to_cpu64 (bp->blk_prop, endian) >> 63) & 1;
1736 1740 break;
1737 1741 }
1738 1742 if (level == 0)
1739 1743 {
1740 1744 grub_dprintf ("zfs", "endian = %d\n", endian);
1741 1745 err = zio_read (bp, endian, buf, 0, data);
1742 1746 endian = (grub_zfs_to_cpu64 (bp->blk_prop, endian) >> 63) & 1;
1743 1747 break;
1744 1748 }
1745 1749 grub_dprintf ("zfs", "endian = %d\n", endian);
1746 1750 err = zio_read (bp, endian, &tmpbuf, 0, data);
1747 1751 endian = (grub_zfs_to_cpu64 (bp->blk_prop, endian) >> 63) & 1;
1748 1752 if (err)
1749 1753 break;
1750 1754 bp_array = tmpbuf;
1751 1755 }
1752 1756 if (bp_array != dn->dn.dn_blkptr)
1753 1757 grub_free (bp_array);
1754 1758 if (endian_out)
1755 1759 *endian_out = endian;
1756 1760
1757 1761 grub_free (bp);
1758 1762 return err;
1759 1763 }
1760 1764
1761 1765 /*
1762 1766 * mzap_lookup: Looks up property described by "name" and returns the value
1763 1767 * in "value".
1764 1768 */
1765 1769 static grub_err_t
1766 1770 mzap_lookup (mzap_phys_t * zapobj, grub_zfs_endian_t endian,
↓ open down ↓ |
909 lines elided |
↑ open up ↑ |
1767 1771 int objsize, const char *name, grub_uint64_t * value,
1768 1772 int case_insensitive)
1769 1773 {
1770 1774 int i, chunks;
1771 1775 mzap_ent_phys_t *mzap_ent = zapobj->mz_chunk;
1772 1776
1773 1777 chunks = objsize / MZAP_ENT_LEN - 1;
1774 1778 for (i = 0; i < chunks; i++)
1775 1779 {
1776 1780 if (case_insensitive ? (grub_strcasecmp (mzap_ent[i].mze_name, name) == 0)
1777 - : (grub_strcmp (mzap_ent[i].mze_name, name) == 0))
1778 - {
1779 - *value = grub_zfs_to_cpu64 (mzap_ent[i].mze_value, endian);
1780 - return GRUB_ERR_NONE;
1781 - }
1781 + : (grub_strcmp (mzap_ent[i].mze_name, name) == 0))
1782 + {
1783 + *value = grub_zfs_to_cpu64 (mzap_ent[i].mze_value, endian);
1784 + return GRUB_ERR_NONE;
1785 + }
1782 1786 }
1783 1787
1784 1788 return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file `%s' not found"), name);
1785 1789 }
1786 1790
1787 1791 static int
1788 1792 mzap_iterate (mzap_phys_t * zapobj, grub_zfs_endian_t endian, int objsize,
1789 1793 int NESTED_FUNC_ATTR (*hook) (const char *name,
1790 1794 grub_uint64_t val))
1791 1795 {
1792 1796 int i, chunks;
1793 1797 mzap_ent_phys_t *mzap_ent = zapobj->mz_chunk;
1794 1798
1795 1799 chunks = objsize / MZAP_ENT_LEN - 1;
1796 1800 for (i = 0; i < chunks; i++)
1797 1801 {
1798 1802 grub_dprintf ("zfs", "zap: name = %s, value = %llx, cd = %x\n",
1799 1803 mzap_ent[i].mze_name, (long long)mzap_ent[i].mze_value,
1800 1804 (int)mzap_ent[i].mze_cd);
1801 1805 if (hook (mzap_ent[i].mze_name,
1802 1806 grub_zfs_to_cpu64 (mzap_ent[i].mze_value, endian)))
1803 1807 return 1;
1804 1808 }
1805 1809
1806 1810 return 0;
1807 1811 }
1808 1812
1809 1813 static grub_uint64_t
1810 1814 zap_hash (grub_uint64_t salt, const char *name,
1811 1815 int case_insensitive)
1812 1816 {
1813 1817 static grub_uint64_t table[256];
1814 1818 const grub_uint8_t *cp;
1815 1819 grub_uint8_t c;
1816 1820 grub_uint64_t crc = salt;
1817 1821
1818 1822 if (table[128] == 0)
1819 1823 {
1820 1824 grub_uint64_t *ct;
1821 1825 int i, j;
1822 1826 for (i = 0; i < 256; i++)
1823 1827 {
1824 1828 for (ct = table + i, *ct = i, j = 8; j > 0; j--)
1825 1829 *ct = (*ct >> 1) ^ (-(*ct & 1) & ZFS_CRC64_POLY);
1826 1830 }
1827 1831 }
1828 1832
1829 1833 if (case_insensitive)
1830 1834 for (cp = (const grub_uint8_t *) name; (c = *cp) != '\0'; cp++)
1831 1835 crc = (crc >> 8) ^ table[(crc ^ grub_toupper (c)) & 0xFF];
1832 1836 else
1833 1837 for (cp = (const grub_uint8_t *) name; (c = *cp) != '\0'; cp++)
1834 1838 crc = (crc >> 8) ^ table[(crc ^ c) & 0xFF];
1835 1839
1836 1840 /*
1837 1841 * Only use 28 bits, since we need 4 bits in the cookie for the
1838 1842 * collision differentiator. We MUST use the high bits, since
1839 1843 * those are the onces that we first pay attention to when
1840 1844 * chosing the bucket.
1841 1845 */
1842 1846 crc &= ~((1ULL << (64 - ZAP_HASHBITS)) - 1);
1843 1847
1844 1848 return (crc);
1845 1849 }
1846 1850
1847 1851 /*
1848 1852 * Only to be used on 8-bit arrays.
1849 1853 * array_len is actual len in bytes (not encoded le_value_length).
1850 1854 * buf is null-terminated.
1851 1855 */
1852 1856
1853 1857 static inline int
1854 1858 name_cmp (const char *s1, const char *s2, grub_size_t n,
1855 1859 int case_insensitive)
1856 1860 {
1857 1861 const char *t1 = (const char *) s1;
1858 1862 const char *t2 = (const char *) s2;
1859 1863
1860 1864 if (!case_insensitive)
1861 1865 return grub_memcmp (t1, t2, n);
1862 1866
1863 1867 while (n--)
1864 1868 {
1865 1869 if (grub_toupper (*t1) != grub_toupper (*t2))
1866 1870 return (int) grub_toupper (*t1) - (int) grub_toupper (*t2);
1867 1871
1868 1872 t1++;
1869 1873 t2++;
1870 1874 }
1871 1875
1872 1876 return 0;
1873 1877 }
1874 1878
1875 1879 /* XXX */
1876 1880 static int
1877 1881 zap_leaf_array_equal (zap_leaf_phys_t * l, grub_zfs_endian_t endian,
1878 1882 int blksft, int chunk, grub_size_t array_len,
1879 1883 const char *buf, int case_insensitive)
1880 1884 {
1881 1885 grub_size_t bseen = 0;
1882 1886
1883 1887 while (bseen < array_len)
1884 1888 {
1885 1889 struct zap_leaf_array *la = &ZAP_LEAF_CHUNK (l, blksft, chunk)->l_array;
1886 1890 grub_size_t toread = array_len - bseen;
1887 1891
1888 1892 if (toread > ZAP_LEAF_ARRAY_BYTES)
1889 1893 toread = ZAP_LEAF_ARRAY_BYTES;
1890 1894
1891 1895 if (chunk >= ZAP_LEAF_NUMCHUNKS (blksft))
1892 1896 return 0;
1893 1897
1894 1898 if (name_cmp ((char *) la->la_array, buf + bseen, toread,
1895 1899 case_insensitive) != 0)
1896 1900 break;
1897 1901 chunk = grub_zfs_to_cpu16 (la->la_next, endian);
1898 1902 bseen += toread;
1899 1903 }
1900 1904 return (bseen == array_len);
1901 1905 }
1902 1906
1903 1907 /* XXX */
1904 1908 static grub_err_t
1905 1909 zap_leaf_array_get (zap_leaf_phys_t * l, grub_zfs_endian_t endian, int blksft,
1906 1910 int chunk, grub_size_t array_len, char *buf)
1907 1911 {
1908 1912 grub_size_t bseen = 0;
1909 1913
1910 1914 while (bseen < array_len)
1911 1915 {
1912 1916 struct zap_leaf_array *la = &ZAP_LEAF_CHUNK (l, blksft, chunk)->l_array;
1913 1917 grub_size_t toread = array_len - bseen;
1914 1918
1915 1919 if (toread > ZAP_LEAF_ARRAY_BYTES)
1916 1920 toread = ZAP_LEAF_ARRAY_BYTES;
1917 1921
1918 1922 if (chunk >= ZAP_LEAF_NUMCHUNKS (blksft))
1919 1923 /* Don't use grub_error because this error is to be ignored. */
1920 1924 return GRUB_ERR_BAD_FS;
1921 1925
1922 1926 grub_memcpy (buf + bseen,la->la_array, toread);
1923 1927 chunk = grub_zfs_to_cpu16 (la->la_next, endian);
1924 1928 bseen += toread;
1925 1929 }
1926 1930 return GRUB_ERR_NONE;
1927 1931 }
1928 1932
1929 1933
1930 1934 /*
1931 1935 * Given a zap_leaf_phys_t, walk thru the zap leaf chunks to get the
1932 1936 * value for the property "name".
1933 1937 *
1934 1938 */
1935 1939 /* XXX */
1936 1940 static grub_err_t
1937 1941 zap_leaf_lookup (zap_leaf_phys_t * l, grub_zfs_endian_t endian,
1938 1942 int blksft, grub_uint64_t h,
1939 1943 const char *name, grub_uint64_t * value,
1940 1944 int case_insensitive)
1941 1945 {
1942 1946 grub_uint16_t chunk;
1943 1947 struct zap_leaf_entry *le;
1944 1948
1945 1949 /* Verify if this is a valid leaf block */
1946 1950 if (grub_zfs_to_cpu64 (l->l_hdr.lh_block_type, endian) != ZBT_LEAF)
1947 1951 return grub_error (GRUB_ERR_BAD_FS, "invalid leaf type");
1948 1952 if (grub_zfs_to_cpu32 (l->l_hdr.lh_magic, endian) != ZAP_LEAF_MAGIC)
1949 1953 return grub_error (GRUB_ERR_BAD_FS, "invalid leaf magic");
1950 1954
1951 1955 for (chunk = grub_zfs_to_cpu16 (l->l_hash[LEAF_HASH (blksft, h, l)], endian);
1952 1956 chunk != CHAIN_END; chunk = grub_zfs_to_cpu16 (le->le_next, endian))
1953 1957 {
1954 1958
1955 1959 if (chunk >= ZAP_LEAF_NUMCHUNKS (blksft))
1956 1960 return grub_error (GRUB_ERR_BAD_FS, "invalid chunk number");
1957 1961
1958 1962 le = ZAP_LEAF_ENTRY (l, blksft, chunk);
1959 1963
1960 1964 /* Verify the chunk entry */
1961 1965 if (le->le_type != ZAP_CHUNK_ENTRY)
1962 1966 return grub_error (GRUB_ERR_BAD_FS, "invalid chunk entry");
1963 1967
1964 1968 if (grub_zfs_to_cpu64 (le->le_hash,endian) != h)
1965 1969 continue;
1966 1970
1967 1971 grub_dprintf ("zfs", "fzap: length %d\n", (int) le->le_name_length);
1968 1972
1969 1973 if (zap_leaf_array_equal (l, endian, blksft,
1970 1974 grub_zfs_to_cpu16 (le->le_name_chunk,endian),
1971 1975 grub_zfs_to_cpu16 (le->le_name_length, endian),
1972 1976 name, case_insensitive))
1973 1977 {
1974 1978 struct zap_leaf_array *la;
1975 1979
1976 1980 if (le->le_int_size != 8 || grub_zfs_to_cpu16 (le->le_value_length,
1977 1981 endian) != 1)
1978 1982 return grub_error (GRUB_ERR_BAD_FS, "invalid leaf chunk entry");
1979 1983
1980 1984 /* get the uint64_t property value */
1981 1985 la = &ZAP_LEAF_CHUNK (l, blksft, le->le_value_chunk)->l_array;
1982 1986
1983 1987 *value = grub_be_to_cpu64 (la->la_array64);
1984 1988
1985 1989 return GRUB_ERR_NONE;
1986 1990 }
1987 1991 }
1988 1992
1989 1993 return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file `%s' not found"), name);
1990 1994 }
1991 1995
1992 1996
1993 1997 /* Verify if this is a fat zap header block */
1994 1998 static grub_err_t
1995 1999 zap_verify (zap_phys_t *zap, grub_zfs_endian_t endian)
1996 2000 {
1997 2001 if (grub_zfs_to_cpu64 (zap->zap_magic, endian) != (grub_uint64_t) ZAP_MAGIC)
1998 2002 return grub_error (GRUB_ERR_BAD_FS, "bad ZAP magic");
1999 2003
2000 2004 if (zap->zap_salt == 0)
2001 2005 return grub_error (GRUB_ERR_BAD_FS, "bad ZAP salt");
2002 2006
2003 2007 return GRUB_ERR_NONE;
2004 2008 }
2005 2009
2006 2010 /*
2007 2011 * Fat ZAP lookup
2008 2012 *
2009 2013 */
2010 2014 /* XXX */
2011 2015 static grub_err_t
2012 2016 fzap_lookup (dnode_end_t * zap_dnode, zap_phys_t * zap,
2013 2017 const char *name, grub_uint64_t * value,
2014 2018 struct grub_zfs_data *data, int case_insensitive)
2015 2019 {
2016 2020 void *l;
2017 2021 grub_uint64_t hash, idx, blkid;
2018 2022 int blksft = zfs_log2 (grub_zfs_to_cpu16 (zap_dnode->dn.dn_datablkszsec,
2019 2023 zap_dnode->endian) << DNODE_SHIFT);
2020 2024 grub_err_t err;
2021 2025 grub_zfs_endian_t leafendian;
2022 2026
2023 2027 err = zap_verify (zap, zap_dnode->endian);
2024 2028 if (err)
2025 2029 return err;
2026 2030
2027 2031 hash = zap_hash (zap->zap_salt, name, case_insensitive);
2028 2032
2029 2033 /* get block id from index */
2030 2034 if (zap->zap_ptrtbl.zt_numblks != 0)
2031 2035 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
2032 2036 "external pointer tables not supported");
2033 2037 idx = ZAP_HASH_IDX (hash, zap->zap_ptrtbl.zt_shift);
2034 2038 blkid = grub_zfs_to_cpu64 (((grub_uint64_t *) zap)[idx + (1 << (blksft - 3 - 1))], zap_dnode->endian);
2035 2039
2036 2040 /* Get the leaf block */
2037 2041 if ((1U << blksft) < sizeof (zap_leaf_phys_t))
2038 2042 return grub_error (GRUB_ERR_BAD_FS, "ZAP leaf is too small");
2039 2043 err = dmu_read (zap_dnode, blkid, &l, &leafendian, data);
2040 2044 if (err)
2041 2045 return err;
2042 2046
2043 2047 err = zap_leaf_lookup (l, leafendian, blksft, hash, name, value,
2044 2048 case_insensitive);
2045 2049 grub_free (l);
2046 2050 return err;
2047 2051 }
2048 2052
2049 2053 /* XXX */
2050 2054 static int
2051 2055 fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap,
2052 2056 grub_size_t name_elem_length,
2053 2057 int NESTED_FUNC_ATTR (*hook) (const void *name,
2054 2058 grub_size_t name_length,
2055 2059 const void *val_in,
2056 2060 grub_size_t nelem,
2057 2061 grub_size_t elemsize),
2058 2062 struct grub_zfs_data *data)
2059 2063 {
2060 2064 zap_leaf_phys_t *l;
2061 2065 void *l_in;
2062 2066 grub_uint64_t idx, idx2, blkid;
2063 2067 grub_uint16_t chunk;
2064 2068 int blksft = zfs_log2 (grub_zfs_to_cpu16 (zap_dnode->dn.dn_datablkszsec,
2065 2069 zap_dnode->endian) << DNODE_SHIFT);
2066 2070 grub_err_t err;
2067 2071 grub_zfs_endian_t endian;
2068 2072
2069 2073 if (zap_verify (zap, zap_dnode->endian))
2070 2074 return 0;
2071 2075
2072 2076 /* get block id from index */
2073 2077 if (zap->zap_ptrtbl.zt_numblks != 0)
2074 2078 {
2075 2079 grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
2076 2080 "external pointer tables not supported");
2077 2081 return 0;
2078 2082 }
2079 2083 /* Get the leaf block */
2080 2084 if ((1U << blksft) < sizeof (zap_leaf_phys_t))
2081 2085 {
2082 2086 grub_error (GRUB_ERR_BAD_FS, "ZAP leaf is too small");
2083 2087 return 0;
2084 2088 }
2085 2089 for (idx = 0; idx < (1ULL << zap->zap_ptrtbl.zt_shift); idx++)
2086 2090 {
2087 2091 blkid = grub_zfs_to_cpu64 (((grub_uint64_t *) zap)[idx + (1 << (blksft - 3 - 1))],
2088 2092 zap_dnode->endian);
2089 2093
2090 2094 for (idx2 = 0; idx2 < idx; idx2++)
2091 2095 if (blkid == grub_zfs_to_cpu64 (((grub_uint64_t *) zap)[idx2 + (1 << (blksft - 3 - 1))],
2092 2096 zap_dnode->endian))
2093 2097 break;
2094 2098 if (idx2 != idx)
2095 2099 continue;
2096 2100
2097 2101 err = dmu_read (zap_dnode, blkid, &l_in, &endian, data);
2098 2102 l = l_in;
2099 2103 if (err)
2100 2104 {
2101 2105 grub_errno = GRUB_ERR_NONE;
2102 2106 continue;
2103 2107 }
2104 2108
2105 2109 /* Verify if this is a valid leaf block */
2106 2110 if (grub_zfs_to_cpu64 (l->l_hdr.lh_block_type, endian) != ZBT_LEAF)
2107 2111 {
2108 2112 grub_free (l);
2109 2113 continue;
2110 2114 }
2111 2115 if (grub_zfs_to_cpu32 (l->l_hdr.lh_magic, endian) != ZAP_LEAF_MAGIC)
2112 2116 {
2113 2117 grub_free (l);
2114 2118 continue;
2115 2119 }
2116 2120
2117 2121 for (chunk = 0; chunk < ZAP_LEAF_NUMCHUNKS (blksft); chunk++)
2118 2122 {
2119 2123 char *buf;
2120 2124 struct zap_leaf_entry *le;
2121 2125 char *val;
2122 2126 grub_size_t val_length;
2123 2127 le = ZAP_LEAF_ENTRY (l, blksft, chunk);
2124 2128
2125 2129 /* Verify the chunk entry */
2126 2130 if (le->le_type != ZAP_CHUNK_ENTRY)
2127 2131 continue;
2128 2132
2129 2133 buf = grub_malloc (grub_zfs_to_cpu16 (le->le_name_length, endian)
2130 2134 * name_elem_length + 1);
2131 2135 if (zap_leaf_array_get (l, endian, blksft,
2132 2136 grub_zfs_to_cpu16 (le->le_name_chunk,
2133 2137 endian),
2134 2138 grub_zfs_to_cpu16 (le->le_name_length,
2135 2139 endian)
2136 2140 * name_elem_length, buf))
2137 2141 {
2138 2142 grub_free (buf);
2139 2143 continue;
2140 2144 }
2141 2145 buf[le->le_name_length * name_elem_length] = 0;
2142 2146
2143 2147 val_length = ((int) le->le_value_length
2144 2148 * (int) le->le_int_size);
2145 2149 val = grub_malloc (grub_zfs_to_cpu16 (val_length, endian));
2146 2150 if (zap_leaf_array_get (l, endian, blksft,
2147 2151 grub_zfs_to_cpu16 (le->le_value_chunk,
2148 2152 endian),
2149 2153 val_length, val))
2150 2154 {
2151 2155 grub_free (buf);
2152 2156 grub_free (val);
2153 2157 continue;
2154 2158 }
2155 2159
2156 2160 if (hook (buf, le->le_name_length,
2157 2161 val, le->le_value_length, le->le_int_size))
2158 2162 {
2159 2163 grub_free (l);
2160 2164 return 1;
2161 2165 }
2162 2166 grub_free (buf);
2163 2167 grub_free (val);
2164 2168 }
2165 2169 grub_free (l);
2166 2170 }
2167 2171 return 0;
2168 2172 }
2169 2173
2170 2174 /*
2171 2175 * Read in the data of a zap object and find the value for a matching
2172 2176 * property name.
2173 2177 *
2174 2178 */
2175 2179 static grub_err_t
2176 2180 zap_lookup (dnode_end_t * zap_dnode, const char *name, grub_uint64_t *val,
2177 2181 struct grub_zfs_data *data, int case_insensitive)
2178 2182 {
2179 2183 grub_uint64_t block_type;
2180 2184 int size;
2181 2185 void *zapbuf;
2182 2186 grub_err_t err;
2183 2187 grub_zfs_endian_t endian;
2184 2188
2185 2189 grub_dprintf ("zfs", "looking for '%s'\n", name);
2186 2190
2187 2191 /* Read in the first block of the zap object data. */
2188 2192 size = grub_zfs_to_cpu16 (zap_dnode->dn.dn_datablkszsec,
2189 2193 zap_dnode->endian) << SPA_MINBLOCKSHIFT;
2190 2194 err = dmu_read (zap_dnode, 0, &zapbuf, &endian, data);
2191 2195 if (err)
2192 2196 return err;
2193 2197 block_type = grub_zfs_to_cpu64 (*((grub_uint64_t *) zapbuf), endian);
2194 2198
2195 2199 grub_dprintf ("zfs", "zap read\n");
2196 2200
2197 2201 if (block_type == ZBT_MICRO)
2198 2202 {
2199 2203 grub_dprintf ("zfs", "micro zap\n");
2200 2204 err = mzap_lookup (zapbuf, endian, size, name, val,
2201 2205 case_insensitive);
2202 2206 grub_dprintf ("zfs", "returned %d\n", err);
2203 2207 grub_free (zapbuf);
2204 2208 return err;
2205 2209 }
2206 2210 else if (block_type == ZBT_HEADER)
2207 2211 {
2208 2212 grub_dprintf ("zfs", "fat zap\n");
2209 2213 /* this is a fat zap */
2210 2214 err = fzap_lookup (zap_dnode, zapbuf, name, val, data,
2211 2215 case_insensitive);
2212 2216 grub_dprintf ("zfs", "returned %d\n", err);
2213 2217 grub_free (zapbuf);
2214 2218 return err;
2215 2219 }
2216 2220
2217 2221 return grub_error (GRUB_ERR_BAD_FS, "unknown ZAP type");
2218 2222 }
2219 2223
2220 2224 static int
2221 2225 zap_iterate_u64 (dnode_end_t * zap_dnode,
2222 2226 int NESTED_FUNC_ATTR (*hook) (const char *name,
2223 2227 grub_uint64_t val),
2224 2228 struct grub_zfs_data *data)
2225 2229 {
2226 2230 grub_uint64_t block_type;
2227 2231 int size;
2228 2232 void *zapbuf;
2229 2233 grub_err_t err;
2230 2234 int ret;
2231 2235 grub_zfs_endian_t endian;
2232 2236
2233 2237 auto int NESTED_FUNC_ATTR transform (const void *name,
2234 2238 grub_size_t namelen,
2235 2239 const void *val_in,
2236 2240 grub_size_t nelem,
2237 2241 grub_size_t elemsize);
2238 2242
2239 2243 int NESTED_FUNC_ATTR transform (const void *name,
2240 2244 grub_size_t namelen __attribute__ ((unused)),
2241 2245 const void *val_in,
2242 2246 grub_size_t nelem,
2243 2247 grub_size_t elemsize)
2244 2248 {
2245 2249 if (elemsize != sizeof (grub_uint64_t) || nelem != 1)
2246 2250 return 0;
2247 2251 return hook (name, grub_be_to_cpu64 (*(const grub_uint64_t *) val_in));
2248 2252 }
2249 2253
2250 2254 /* Read in the first block of the zap object data. */
2251 2255 size = grub_zfs_to_cpu16 (zap_dnode->dn.dn_datablkszsec, zap_dnode->endian) << SPA_MINBLOCKSHIFT;
2252 2256 err = dmu_read (zap_dnode, 0, &zapbuf, &endian, data);
2253 2257 if (err)
2254 2258 return 0;
2255 2259 block_type = grub_zfs_to_cpu64 (*((grub_uint64_t *) zapbuf), endian);
2256 2260
2257 2261 grub_dprintf ("zfs", "zap iterate\n");
2258 2262
2259 2263 if (block_type == ZBT_MICRO)
2260 2264 {
2261 2265 grub_dprintf ("zfs", "micro zap\n");
2262 2266 ret = mzap_iterate (zapbuf, endian, size, hook);
2263 2267 grub_free (zapbuf);
2264 2268 return ret;
2265 2269 }
2266 2270 else if (block_type == ZBT_HEADER)
2267 2271 {
2268 2272 grub_dprintf ("zfs", "fat zap\n");
2269 2273 /* this is a fat zap */
2270 2274 ret = fzap_iterate (zap_dnode, zapbuf, 1, transform, data);
2271 2275 grub_free (zapbuf);
2272 2276 return ret;
2273 2277 }
2274 2278 grub_error (GRUB_ERR_BAD_FS, "unknown ZAP type");
2275 2279 return 0;
2276 2280 }
2277 2281
2278 2282 static int
2279 2283 zap_iterate (dnode_end_t * zap_dnode,
2280 2284 grub_size_t nameelemlen,
2281 2285 int NESTED_FUNC_ATTR (*hook) (const void *name,
2282 2286 grub_size_t namelen,
2283 2287 const void *val_in,
2284 2288 grub_size_t nelem,
2285 2289 grub_size_t elemsize),
2286 2290 struct grub_zfs_data *data)
2287 2291 {
2288 2292 grub_uint64_t block_type;
2289 2293 void *zapbuf;
2290 2294 grub_err_t err;
2291 2295 int ret;
2292 2296 grub_zfs_endian_t endian;
2293 2297
2294 2298 /* Read in the first block of the zap object data. */
2295 2299 err = dmu_read (zap_dnode, 0, &zapbuf, &endian, data);
2296 2300 if (err)
2297 2301 return 0;
2298 2302 block_type = grub_zfs_to_cpu64 (*((grub_uint64_t *) zapbuf), endian);
2299 2303
2300 2304 grub_dprintf ("zfs", "zap iterate\n");
2301 2305
2302 2306 if (block_type == ZBT_MICRO)
2303 2307 {
2304 2308 grub_error (GRUB_ERR_BAD_FS, "micro ZAP where FAT ZAP expected");
2305 2309 return 0;
2306 2310 }
2307 2311 if (block_type == ZBT_HEADER)
2308 2312 {
2309 2313 grub_dprintf ("zfs", "fat zap\n");
2310 2314 /* this is a fat zap */
2311 2315 ret = fzap_iterate (zap_dnode, zapbuf, nameelemlen, hook, data);
2312 2316 grub_free (zapbuf);
2313 2317 return ret;
2314 2318 }
2315 2319 grub_error (GRUB_ERR_BAD_FS, "unknown ZAP type");
2316 2320 return 0;
2317 2321 }
2318 2322
2319 2323
2320 2324 /*
2321 2325 * Get the dnode of an object number from the metadnode of an object set.
2322 2326 *
2323 2327 * Input
2324 2328 * mdn - metadnode to get the object dnode
2325 2329 * objnum - object number for the object dnode
2326 2330 * buf - data buffer that holds the returning dnode
2327 2331 */
2328 2332 static grub_err_t
2329 2333 dnode_get (dnode_end_t * mdn, grub_uint64_t objnum, grub_uint8_t type,
2330 2334 dnode_end_t * buf, struct grub_zfs_data *data)
2331 2335 {
2332 2336 grub_uint64_t blkid, blksz; /* the block id this object dnode is in */
2333 2337 int epbs; /* shift of number of dnodes in a block */
2334 2338 int idx; /* index within a block */
2335 2339 void *dnbuf;
2336 2340 grub_err_t err;
2337 2341 grub_zfs_endian_t endian;
2338 2342
2339 2343 blksz = grub_zfs_to_cpu16 (mdn->dn.dn_datablkszsec,
2340 2344 mdn->endian) << SPA_MINBLOCKSHIFT;
2341 2345 epbs = zfs_log2 (blksz) - DNODE_SHIFT;
2342 2346 blkid = objnum >> epbs;
2343 2347 idx = objnum & ((1 << epbs) - 1);
2344 2348
2345 2349 if (data->dnode_buf != NULL && grub_memcmp (data->dnode_mdn, mdn,
2346 2350 sizeof (*mdn)) == 0
2347 2351 && objnum >= data->dnode_start && objnum < data->dnode_end)
2348 2352 {
2349 2353 grub_memmove (&(buf->dn), &(data->dnode_buf)[idx], DNODE_SIZE);
2350 2354 buf->endian = data->dnode_endian;
2351 2355 if (type && buf->dn.dn_type != type)
2352 2356 return grub_error(GRUB_ERR_BAD_FS, "incorrect dnode type");
2353 2357 return GRUB_ERR_NONE;
2354 2358 }
2355 2359
2356 2360 grub_dprintf ("zfs", "endian = %d, blkid=%llx\n", mdn->endian,
2357 2361 (unsigned long long) blkid);
2358 2362 err = dmu_read (mdn, blkid, &dnbuf, &endian, data);
2359 2363 if (err)
2360 2364 return err;
2361 2365 grub_dprintf ("zfs", "alive\n");
2362 2366
2363 2367 grub_free (data->dnode_buf);
2364 2368 grub_free (data->dnode_mdn);
2365 2369 data->dnode_mdn = grub_malloc (sizeof (*mdn));
2366 2370 if (! data->dnode_mdn)
2367 2371 {
2368 2372 grub_errno = GRUB_ERR_NONE;
2369 2373 data->dnode_buf = 0;
2370 2374 }
2371 2375 else
2372 2376 {
2373 2377 grub_memcpy (data->dnode_mdn, mdn, sizeof (*mdn));
2374 2378 data->dnode_buf = dnbuf;
2375 2379 data->dnode_start = blkid << epbs;
2376 2380 data->dnode_end = (blkid + 1) << epbs;
2377 2381 data->dnode_endian = endian;
2378 2382 }
2379 2383
2380 2384 grub_memmove (&(buf->dn), (dnode_phys_t *) dnbuf + idx, DNODE_SIZE);
2381 2385 buf->endian = endian;
2382 2386 if (type && buf->dn.dn_type != type)
2383 2387 return grub_error(GRUB_ERR_BAD_FS, "incorrect dnode type");
2384 2388
2385 2389 return GRUB_ERR_NONE;
2386 2390 }
2387 2391
2388 2392 #pragma GCC diagnostic ignored "-Wstrict-aliasing"
2389 2393
2390 2394 /*
2391 2395 * Get the file dnode for a given file name where mdn is the meta dnode
2392 2396 * for this ZFS object set. When found, place the file dnode in dn.
2393 2397 * The 'path' argument will be mangled.
2394 2398 *
2395 2399 */
2396 2400 static grub_err_t
2397 2401 dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn,
2398 2402 struct grub_zfs_data *data)
2399 2403 {
2400 2404 grub_uint64_t objnum, version;
2401 2405 char *cname, ch;
2402 2406 grub_err_t err = GRUB_ERR_NONE;
2403 2407 char *path, *path_buf;
2404 2408 struct dnode_chain
2405 2409 {
2406 2410 struct dnode_chain *next;
2407 2411 dnode_end_t dn;
2408 2412 };
2409 2413 struct dnode_chain *dnode_path = 0, *dn_new, *root;
2410 2414
2411 2415 dn_new = grub_malloc (sizeof (*dn_new));
2412 2416 if (! dn_new)
2413 2417 return grub_errno;
2414 2418 dn_new->next = 0;
2415 2419 dnode_path = root = dn_new;
2416 2420
2417 2421 err = dnode_get (&subvol->mdn, MASTER_NODE_OBJ, DMU_OT_MASTER_NODE,
2418 2422 &(dnode_path->dn), data);
2419 2423 if (err)
2420 2424 {
2421 2425 grub_free (dn_new);
2422 2426 return err;
2423 2427 }
2424 2428
2425 2429 err = zap_lookup (&(dnode_path->dn), ZPL_VERSION_STR, &version,
2426 2430 data, 0);
2427 2431 if (err)
2428 2432 {
2429 2433 grub_free (dn_new);
2430 2434 return err;
2431 2435 }
2432 2436
2433 2437 if (version > ZPL_VERSION)
2434 2438 {
2435 2439 grub_free (dn_new);
2436 2440 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "too new ZPL version");
2437 2441 }
2438 2442
2439 2443 err = zap_lookup (&(dnode_path->dn), "casesensitivity",
2440 2444 &subvol->case_insensitive,
2441 2445 data, 0);
2442 2446 if (err == GRUB_ERR_FILE_NOT_FOUND)
2443 2447 {
2444 2448 grub_errno = GRUB_ERR_NONE;
2445 2449 subvol->case_insensitive = 0;
2446 2450 }
2447 2451
2448 2452 err = zap_lookup (&(dnode_path->dn), ZFS_ROOT_OBJ, &objnum, data, 0);
2449 2453 if (err)
2450 2454 {
2451 2455 grub_free (dn_new);
2452 2456 return err;
2453 2457 }
2454 2458
2455 2459 err = dnode_get (&subvol->mdn, objnum, 0, &(dnode_path->dn), data);
2456 2460 if (err)
2457 2461 {
2458 2462 grub_free (dn_new);
2459 2463 return err;
2460 2464 }
2461 2465
2462 2466 path = path_buf = grub_strdup (path_in);
2463 2467 if (!path_buf)
2464 2468 {
2465 2469 grub_free (dn_new);
2466 2470 return grub_errno;
2467 2471 }
2468 2472
2469 2473 while (1)
2470 2474 {
2471 2475 /* skip leading slashes */
2472 2476 while (*path == '/')
2473 2477 path++;
2474 2478 if (!*path)
2475 2479 break;
2476 2480 /* get the next component name */
2477 2481 cname = path;
2478 2482 while (*path && *path != '/')
2479 2483 path++;
2480 2484 /* Skip dot. */
2481 2485 if (cname + 1 == path && cname[0] == '.')
2482 2486 continue;
2483 2487 /* Handle double dot. */
2484 2488 if (cname + 2 == path && cname[0] == '.' && cname[1] == '.')
2485 2489 {
2486 2490 if (dn_new->next)
2487 2491 {
2488 2492 dn_new = dnode_path;
2489 2493 dnode_path = dn_new->next;
2490 2494 grub_free (dn_new);
2491 2495 }
2492 2496 else
2493 2497 {
2494 2498 err = grub_error (GRUB_ERR_FILE_NOT_FOUND,
2495 2499 "can't resolve ..");
2496 2500 break;
2497 2501 }
2498 2502 continue;
2499 2503 }
2500 2504
2501 2505 ch = *path;
2502 2506 *path = 0; /* ensure null termination */
2503 2507
2504 2508 if (dnode_path->dn.dn.dn_type != DMU_OT_DIRECTORY_CONTENTS)
2505 2509 {
2506 2510 grub_free (path_buf);
2507 2511 return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory"));
2508 2512 }
2509 2513 err = zap_lookup (&(dnode_path->dn), cname, &objnum,
2510 2514 data, subvol->case_insensitive);
2511 2515 if (err)
2512 2516 break;
2513 2517
2514 2518 dn_new = grub_malloc (sizeof (*dn_new));
2515 2519 if (! dn_new)
2516 2520 {
2517 2521 err = grub_errno;
2518 2522 break;
2519 2523 }
2520 2524 dn_new->next = dnode_path;
2521 2525 dnode_path = dn_new;
2522 2526
2523 2527 objnum = ZFS_DIRENT_OBJ (objnum);
2524 2528 err = dnode_get (&subvol->mdn, objnum, 0, &(dnode_path->dn), data);
2525 2529 if (err)
2526 2530 break;
2527 2531
2528 2532 *path = ch;
2529 2533 if (dnode_path->dn.dn.dn_bonustype == DMU_OT_ZNODE
2530 2534 && ((grub_zfs_to_cpu64(((znode_phys_t *) DN_BONUS (&dnode_path->dn.dn))->zp_mode, dnode_path->dn.endian) >> 12) & 0xf) == 0xa)
2531 2535 {
2532 2536 char *sym_value;
2533 2537 grub_size_t sym_sz;
2534 2538 int free_symval = 0;
2535 2539 char *oldpath = path, *oldpathbuf = path_buf;
2536 2540 sym_value = ((char *) DN_BONUS (&dnode_path->dn.dn) + sizeof (struct znode_phys));
2537 2541
2538 2542 sym_sz = grub_zfs_to_cpu64 (((znode_phys_t *) DN_BONUS (&dnode_path->dn.dn))->zp_size, dnode_path->dn.endian);
2539 2543
2540 2544 if (dnode_path->dn.dn.dn_flags & 1)
2541 2545 {
2542 2546 grub_size_t block;
2543 2547 grub_size_t blksz;
2544 2548 blksz = (grub_zfs_to_cpu16 (dnode_path->dn.dn.dn_datablkszsec,
2545 2549 dnode_path->dn.endian)
2546 2550 << SPA_MINBLOCKSHIFT);
2547 2551
2548 2552 sym_value = grub_malloc (sym_sz);
2549 2553 if (!sym_value)
2550 2554 return grub_errno;
2551 2555 for (block = 0; block < (sym_sz + blksz - 1) / blksz; block++)
2552 2556 {
2553 2557 void *t;
2554 2558 grub_size_t movesize;
2555 2559
2556 2560 err = dmu_read (&(dnode_path->dn), block, &t, 0, data);
2557 2561 if (err)
2558 2562 return err;
2559 2563
2560 2564 movesize = sym_sz - block * blksz;
2561 2565 if (movesize > blksz)
2562 2566 movesize = blksz;
2563 2567
2564 2568 grub_memcpy (sym_value + block * blksz, t, movesize);
2565 2569 grub_free (t);
2566 2570 }
2567 2571 free_symval = 1;
2568 2572 }
2569 2573 path = path_buf = grub_malloc (sym_sz + grub_strlen (oldpath) + 1);
2570 2574 if (!path_buf)
2571 2575 {
2572 2576 grub_free (oldpathbuf);
2573 2577 return grub_errno;
2574 2578 }
2575 2579 grub_memcpy (path, sym_value, sym_sz);
2576 2580 if (free_symval)
2577 2581 grub_free (sym_value);
2578 2582 path [sym_sz] = 0;
2579 2583 grub_memcpy (path + grub_strlen (path), oldpath,
2580 2584 grub_strlen (oldpath) + 1);
2581 2585
2582 2586 grub_free (oldpathbuf);
2583 2587 if (path[0] != '/')
2584 2588 {
2585 2589 dn_new = dnode_path;
2586 2590 dnode_path = dn_new->next;
2587 2591 grub_free (dn_new);
2588 2592 }
2589 2593 else while (dnode_path != root)
2590 2594 {
2591 2595 dn_new = dnode_path;
2592 2596 dnode_path = dn_new->next;
2593 2597 grub_free (dn_new);
2594 2598 }
2595 2599 }
2596 2600 if (dnode_path->dn.dn.dn_bonustype == DMU_OT_SA)
2597 2601 {
2598 2602 void *sahdrp;
2599 2603 int hdrsize;
2600 2604
2601 2605 if (dnode_path->dn.dn.dn_bonuslen != 0)
2602 2606 {
2603 2607 sahdrp = DN_BONUS (&dnode_path->dn.dn);
2604 2608 }
2605 2609 else if (dnode_path->dn.dn.dn_flags & DNODE_FLAG_SPILL_BLKPTR)
2606 2610 {
2607 2611 blkptr_t *bp = &dnode_path->dn.dn.dn_spill;
2608 2612
2609 2613 err = zio_read (bp, dnode_path->dn.endian, &sahdrp, NULL, data);
2610 2614 if (err)
2611 2615 return err;
2612 2616 }
2613 2617 else
2614 2618 {
2615 2619 return grub_error (GRUB_ERR_BAD_FS, "filesystem is corrupt");
2616 2620 }
2617 2621
2618 2622 hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp));
2619 2623
2620 2624 if (((grub_zfs_to_cpu64 (grub_get_unaligned64 ((char *) sahdrp
2621 2625 + hdrsize
2622 2626 + SA_TYPE_OFFSET),
2623 2627 dnode_path->dn.endian) >> 12) & 0xf) == 0xa)
2624 2628 {
2625 2629 char *sym_value = (char *) sahdrp + hdrsize + SA_SYMLINK_OFFSET;
2626 2630 grub_size_t sym_sz =
2627 2631 grub_zfs_to_cpu64 (grub_get_unaligned64 ((char *) sahdrp
2628 2632 + hdrsize
2629 2633 + SA_SIZE_OFFSET),
2630 2634 dnode_path->dn.endian);
2631 2635 char *oldpath = path, *oldpathbuf = path_buf;
2632 2636 path = path_buf = grub_malloc (sym_sz + grub_strlen (oldpath) + 1);
2633 2637 if (!path_buf)
2634 2638 {
2635 2639 grub_free (oldpathbuf);
2636 2640 return grub_errno;
2637 2641 }
2638 2642 grub_memcpy (path, sym_value, sym_sz);
2639 2643 path [sym_sz] = 0;
2640 2644 grub_memcpy (path + grub_strlen (path), oldpath,
2641 2645 grub_strlen (oldpath) + 1);
2642 2646
2643 2647 grub_free (oldpathbuf);
2644 2648 if (path[0] != '/')
2645 2649 {
2646 2650 dn_new = dnode_path;
2647 2651 dnode_path = dn_new->next;
2648 2652 grub_free (dn_new);
2649 2653 }
2650 2654 else while (dnode_path != root)
2651 2655 {
2652 2656 dn_new = dnode_path;
2653 2657 dnode_path = dn_new->next;
2654 2658 grub_free (dn_new);
2655 2659 }
2656 2660 }
2657 2661 }
2658 2662 }
2659 2663
2660 2664 if (!err)
2661 2665 grub_memcpy (dn, &(dnode_path->dn), sizeof (*dn));
2662 2666
↓ open down ↓ |
871 lines elided |
↑ open up ↑ |
2663 2667 while (dnode_path)
2664 2668 {
2665 2669 dn_new = dnode_path->next;
2666 2670 grub_free (dnode_path);
2667 2671 dnode_path = dn_new;
2668 2672 }
2669 2673 grub_free (path_buf);
2670 2674 return err;
2671 2675 }
2672 2676
2673 -#if 0
2677 +#if 1
2674 2678 /*
2675 2679 * Get the default 'bootfs' property value from the rootpool.
2676 2680 *
2677 2681 */
2678 2682 static grub_err_t
2679 -get_default_bootfsobj (dnode_phys_t * mosmdn, grub_uint64_t * obj,
2683 +get_default_bootfsobj (dnode_end_t * mosmdn, grub_uint64_t * obj,
2680 2684 struct grub_zfs_data *data)
2681 2685 {
2682 2686 grub_uint64_t objnum = 0;
2683 - dnode_phys_t *dn;
2684 - if (!dn)
2685 - return grub_errno;
2687 + dnode_end_t dn;
2686 2688
2687 2689 if ((grub_errno = dnode_get (mosmdn, DMU_POOL_DIRECTORY_OBJECT,
2688 - DMU_OT_OBJECT_DIRECTORY, dn, data)))
2690 + DMU_OT_OBJECT_DIRECTORY, &dn, data)))
2689 2691 {
2690 - grub_free (dn);
2691 2692 return (grub_errno);
2692 2693 }
2693 -
2694 2694 /*
2695 2695 * find the object number for 'pool_props', and get the dnode
2696 2696 * of the 'pool_props'.
2697 2697 */
2698 - if (zap_lookup (dn, DMU_POOL_PROPS, &objnum, data))
2698 + if (zap_lookup (&dn, DMU_POOL_PROPS, &objnum, data, 0))
2699 2699 {
2700 - grub_free (dn);
2701 2700 return (GRUB_ERR_BAD_FS);
2702 2701 }
2703 - if ((grub_errno = dnode_get (mosmdn, objnum, DMU_OT_POOL_PROPS, dn, data)))
2702 + if ((grub_errno = dnode_get (mosmdn, objnum, DMU_OT_POOL_PROPS, &dn, data)))
2704 2703 {
2705 - grub_free (dn);
2706 2704 return (grub_errno);
2707 2705 }
2708 - if (zap_lookup (dn, ZPOOL_PROP_BOOTFS, &objnum, data))
2706 + if (zap_lookup (&dn, ZPOOL_PROP_BOOTFS, &objnum, data,0))
2709 2707 {
2710 - grub_free (dn);
2711 2708 return (GRUB_ERR_BAD_FS);
2712 2709 }
2713 2710
2714 2711 if (!objnum)
2715 2712 {
2716 - grub_free (dn);
2717 2713 return (GRUB_ERR_BAD_FS);
2718 2714 }
2719 2715
2720 2716 *obj = objnum;
2721 2717 return (0);
2722 2718 }
2719 +
2723 2720 #endif
2724 2721 /*
2725 2722 * Given a MOS metadnode, get the metadnode of a given filesystem name (fsname),
2726 2723 * e.g. pool/rootfs, or a given object number (obj), e.g. the object number
2727 2724 * of pool/rootfs.
2728 2725 *
2729 2726 * If no fsname and no obj are given, return the DSL_DIR metadnode.
2730 2727 * If fsname is given, return its metadnode and its matching object number.
2731 2728 * If only obj is given, return the metadnode for this object number.
2732 2729 *
2733 2730 */
2734 2731 static grub_err_t
2735 2732 get_filesystem_dnode (dnode_end_t * mosmdn, char *fsname,
2736 2733 dnode_end_t * mdn, struct grub_zfs_data *data)
2737 2734 {
2738 2735 grub_uint64_t objnum;
2739 2736 grub_err_t err;
2740 2737
2741 2738 grub_dprintf ("zfs", "endian = %d\n", mosmdn->endian);
2742 2739
2743 2740 err = dnode_get (mosmdn, DMU_POOL_DIRECTORY_OBJECT,
2744 2741 DMU_OT_OBJECT_DIRECTORY, mdn, data);
2745 2742 if (err)
2746 2743 return err;
2747 2744
2748 2745 grub_dprintf ("zfs", "alive\n");
2749 2746
2750 2747 err = zap_lookup (mdn, DMU_POOL_ROOT_DATASET, &objnum, data, 0);
2751 2748 if (err)
2752 2749 return err;
2753 2750
2754 2751 grub_dprintf ("zfs", "alive\n");
2755 2752
2756 2753 err = dnode_get (mosmdn, objnum, DMU_OT_DSL_DIR, mdn, data);
2757 2754 if (err)
2758 2755 return err;
2759 2756
2760 2757 grub_dprintf ("zfs", "alive\n");
2761 2758
2762 2759 while (*fsname)
2763 2760 {
2764 2761 grub_uint64_t childobj;
2765 2762 char *cname, ch;
2766 2763
2767 2764 while (*fsname == '/')
2768 2765 fsname++;
2769 2766
2770 2767 if (! *fsname || *fsname == '@')
2771 2768 break;
2772 2769
2773 2770 cname = fsname;
2774 2771 while (*fsname && *fsname != '/')
2775 2772 fsname++;
2776 2773 ch = *fsname;
2777 2774 *fsname = 0;
2778 2775
2779 2776 childobj = grub_zfs_to_cpu64 ((((dsl_dir_phys_t *) DN_BONUS (&mdn->dn)))->dd_child_dir_zapobj, mdn->endian);
2780 2777 err = dnode_get (mosmdn, childobj,
2781 2778 DMU_OT_DSL_DIR_CHILD_MAP, mdn, data);
2782 2779 if (err)
2783 2780 return err;
2784 2781
2785 2782 err = zap_lookup (mdn, cname, &objnum, data, 0);
2786 2783 if (err)
2787 2784 return err;
2788 2785
2789 2786 err = dnode_get (mosmdn, objnum, DMU_OT_DSL_DIR, mdn, data);
2790 2787 if (err)
2791 2788 return err;
2792 2789
2793 2790 *fsname = ch;
2794 2791 }
2795 2792 return GRUB_ERR_NONE;
2796 2793 }
2797 2794
2798 2795 static grub_err_t
2799 2796 make_mdn (dnode_end_t * mdn, struct grub_zfs_data *data)
2800 2797 {
2801 2798 void *osp;
2802 2799 blkptr_t *bp;
2803 2800 grub_size_t ospsize;
2804 2801 grub_err_t err;
2805 2802
2806 2803 grub_dprintf ("zfs", "endian = %d\n", mdn->endian);
2807 2804
2808 2805 bp = &(((dsl_dataset_phys_t *) DN_BONUS (&mdn->dn))->ds_bp);
2809 2806 err = zio_read (bp, mdn->endian, &osp, &ospsize, data);
2810 2807 if (err)
2811 2808 return err;
2812 2809 if (ospsize < OBJSET_PHYS_SIZE_V14)
2813 2810 {
2814 2811 grub_free (osp);
2815 2812 return grub_error (GRUB_ERR_BAD_FS, "too small osp");
2816 2813 }
2817 2814
2818 2815 mdn->endian = (grub_zfs_to_cpu64 (bp->blk_prop, mdn->endian)>>63) & 1;
2819 2816 grub_memmove ((char *) &(mdn->dn),
2820 2817 (char *) &((objset_phys_t *) osp)->os_meta_dnode, DNODE_SIZE);
2821 2818 grub_free (osp);
2822 2819 return GRUB_ERR_NONE;
2823 2820 }
2824 2821
2825 2822 static grub_err_t
2826 2823 dnode_get_fullpath (const char *fullpath, struct subvolume *subvol,
2827 2824 dnode_end_t * dn, int *isfs,
2828 2825 struct grub_zfs_data *data)
2829 2826 {
2830 2827 char *fsname, *snapname;
2831 2828 const char *ptr_at, *filename;
2832 2829 grub_uint64_t headobj;
2833 2830 grub_uint64_t keychainobj;
2834 2831 grub_uint64_t salt;
2835 2832 grub_err_t err;
2836 2833 int keyn = 0;
2837 2834
2838 2835 auto int NESTED_FUNC_ATTR count_zap_keys (const void *name,
2839 2836 grub_size_t namelen,
2840 2837 const void *val_in,
2841 2838 grub_size_t nelem,
2842 2839 grub_size_t elemsize);
2843 2840 int NESTED_FUNC_ATTR count_zap_keys (const void *name __attribute__ ((unused)),
2844 2841 grub_size_t namelen __attribute__ ((unused)),
2845 2842 const void *val_in __attribute__ ((unused)),
2846 2843 grub_size_t nelem __attribute__ ((unused)),
2847 2844 grub_size_t elemsize __attribute__ ((unused)))
2848 2845 {
2849 2846 subvol->nkeys++;
2850 2847 return 0;
2851 2848 }
2852 2849
2853 2850 auto int NESTED_FUNC_ATTR load_zap_key (const void *name,
2854 2851 grub_size_t namelen,
2855 2852 const void *val_in,
2856 2853 grub_size_t nelem,
2857 2854 grub_size_t elemsize);
2858 2855 int NESTED_FUNC_ATTR load_zap_key (const void *name,
2859 2856 grub_size_t namelen,
2860 2857 const void *val_in,
2861 2858 grub_size_t nelem,
2862 2859 grub_size_t elemsize)
2863 2860 {
2864 2861 if (namelen != 1)
2865 2862 {
2866 2863 grub_dprintf ("zfs", "Unexpected key index size %" PRIuGRUB_SIZE "\n",
2867 2864 namelen);
2868 2865 return 0;
2869 2866 }
2870 2867
2871 2868 if (elemsize != 1)
2872 2869 {
2873 2870 grub_dprintf ("zfs", "Unexpected key element size %" PRIuGRUB_SIZE "\n",
2874 2871 elemsize);
2875 2872 return 0;
2876 2873 }
2877 2874
2878 2875 subvol->keyring[keyn].txg = grub_be_to_cpu64 (*(grub_uint64_t *) name);
2879 2876 subvol->keyring[keyn].algo = grub_le_to_cpu64 (*(grub_uint64_t *) val_in);
2880 2877 subvol->keyring[keyn].cipher = grub_zfs_load_key (val_in, nelem, salt,
2881 2878 subvol->keyring[keyn].algo);
2882 2879 keyn++;
2883 2880 return 0;
2884 2881 }
2885 2882
2886 2883 ptr_at = grub_strchr (fullpath, '@');
2887 2884 if (! ptr_at)
2888 2885 {
2889 2886 *isfs = 1;
2890 2887 filename = 0;
2891 2888 snapname = 0;
2892 2889 fsname = grub_strdup (fullpath);
2893 2890 }
2894 2891 else
2895 2892 {
2896 2893 const char *ptr_slash = grub_strchr (ptr_at, '/');
2897 2894
2898 2895 *isfs = 0;
2899 2896 fsname = grub_malloc (ptr_at - fullpath + 1);
2900 2897 if (!fsname)
2901 2898 return grub_errno;
2902 2899 grub_memcpy (fsname, fullpath, ptr_at - fullpath);
2903 2900 fsname[ptr_at - fullpath] = 0;
2904 2901 if (ptr_at[1] && ptr_at[1] != '/')
2905 2902 {
2906 2903 snapname = grub_malloc (ptr_slash - ptr_at);
2907 2904 if (!snapname)
2908 2905 {
2909 2906 grub_free (fsname);
2910 2907 return grub_errno;
2911 2908 }
2912 2909 grub_memcpy (snapname, ptr_at + 1, ptr_slash - ptr_at - 1);
2913 2910 snapname[ptr_slash - ptr_at - 1] = 0;
2914 2911 }
2915 2912 else
2916 2913 snapname = 0;
2917 2914 if (ptr_slash)
2918 2915 filename = ptr_slash;
2919 2916 else
2920 2917 filename = "/";
2921 2918 grub_dprintf ("zfs", "fsname = '%s' snapname='%s' filename = '%s'\n",
2922 2919 fsname, snapname, filename);
2923 2920 }
2924 2921 grub_dprintf ("zfs", "alive\n");
2925 2922 err = get_filesystem_dnode (&(data->mos), fsname, dn, data);
2926 2923 if (err)
2927 2924 {
2928 2925 grub_free (fsname);
2929 2926 grub_free (snapname);
2930 2927 return err;
2931 2928 }
2932 2929
2933 2930 grub_dprintf ("zfs", "alive\n");
2934 2931
2935 2932 headobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&dn->dn))->dd_head_dataset_obj, dn->endian);
2936 2933
2937 2934 grub_dprintf ("zfs", "endian = %d\n", subvol->mdn.endian);
2938 2935
2939 2936 err = dnode_get (&(data->mos), headobj, DMU_OT_DSL_DATASET, &subvol->mdn,
2940 2937 data);
2941 2938 if (err)
2942 2939 {
2943 2940 grub_free (fsname);
2944 2941 grub_free (snapname);
2945 2942 return err;
2946 2943 }
2947 2944 grub_dprintf ("zfs", "endian = %d\n", subvol->mdn.endian);
2948 2945
2949 2946 keychainobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&dn->dn))->keychain, dn->endian);
2950 2947 if (grub_zfs_load_key && keychainobj)
2951 2948 {
2952 2949 dnode_end_t keychain_dn, props_dn;
2953 2950 grub_uint64_t propsobj;
2954 2951 propsobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&dn->dn))->dd_props_zapobj, dn->endian);
2955 2952
2956 2953 err = dnode_get (&(data->mos), propsobj, DMU_OT_DSL_PROPS,
2957 2954 &props_dn, data);
2958 2955 if (err)
2959 2956 {
2960 2957 grub_free (fsname);
2961 2958 grub_free (snapname);
2962 2959 return err;
2963 2960 }
2964 2961
2965 2962 err = zap_lookup (&props_dn, "salt", &salt, data, 0);
2966 2963 if (err == GRUB_ERR_FILE_NOT_FOUND)
2967 2964 {
2968 2965 err = 0;
2969 2966 grub_errno = 0;
2970 2967 salt = 0;
2971 2968 }
2972 2969 if (err)
2973 2970 {
2974 2971 grub_dprintf ("zfs", "failed here\n");
2975 2972 return err;
2976 2973 }
2977 2974
2978 2975 err = dnode_get (&(data->mos), keychainobj, DMU_OT_DSL_KEYCHAIN,
2979 2976 &keychain_dn, data);
2980 2977 if (err)
2981 2978 {
2982 2979 grub_free (fsname);
2983 2980 grub_free (snapname);
2984 2981 return err;
2985 2982 }
2986 2983 subvol->nkeys = 0;
2987 2984 zap_iterate (&keychain_dn, 8, count_zap_keys, data);
2988 2985 subvol->keyring = grub_zalloc (subvol->nkeys * sizeof (subvol->keyring[0]));
2989 2986 if (!subvol->keyring)
2990 2987 {
2991 2988 grub_free (fsname);
2992 2989 grub_free (snapname);
2993 2990 return err;
2994 2991 }
2995 2992 zap_iterate (&keychain_dn, 8, load_zap_key, data);
2996 2993 }
2997 2994
2998 2995 if (snapname)
2999 2996 {
3000 2997 grub_uint64_t snapobj;
3001 2998
3002 2999 snapobj = grub_zfs_to_cpu64 (((dsl_dataset_phys_t *) DN_BONUS (&subvol->mdn.dn))->ds_snapnames_zapobj, subvol->mdn.endian);
3003 3000
3004 3001 err = dnode_get (&(data->mos), snapobj,
3005 3002 DMU_OT_DSL_DS_SNAP_MAP, &subvol->mdn, data);
3006 3003 if (!err)
3007 3004 err = zap_lookup (&subvol->mdn, snapname, &headobj, data, 0);
3008 3005 if (!err)
3009 3006 err = dnode_get (&(data->mos), headobj, DMU_OT_DSL_DATASET,
3010 3007 &subvol->mdn, data);
3011 3008 if (err)
3012 3009 {
3013 3010 grub_free (fsname);
3014 3011 grub_free (snapname);
3015 3012 return err;
3016 3013 }
3017 3014 }
3018 3015
3019 3016 subvol->obj = headobj;
3020 3017
3021 3018 make_mdn (&subvol->mdn, data);
3022 3019
3023 3020 grub_dprintf ("zfs", "endian = %d\n", subvol->mdn.endian);
3024 3021
3025 3022 if (*isfs)
3026 3023 {
3027 3024 grub_free (fsname);
3028 3025 grub_free (snapname);
3029 3026 return GRUB_ERR_NONE;
3030 3027 }
3031 3028 err = dnode_get_path (subvol, filename, dn, data);
3032 3029 grub_free (fsname);
3033 3030 grub_free (snapname);
3034 3031 return err;
3035 3032 }
3036 3033
3037 3034 /*
3038 3035 * For a given XDR packed nvlist, verify the first 4 bytes and move on.
3039 3036 *
3040 3037 * An XDR packed nvlist is encoded as (comments from nvs_xdr_create) :
3041 3038 *
3042 3039 * encoding method/host endian (4 bytes)
3043 3040 * nvl_version (4 bytes)
3044 3041 * nvl_nvflag (4 bytes)
3045 3042 * encoded nvpairs:
3046 3043 * encoded size of the nvpair (4 bytes)
3047 3044 * decoded size of the nvpair (4 bytes)
3048 3045 * name string size (4 bytes)
3049 3046 * name string data (sizeof(NV_ALIGN4(string))
3050 3047 * data type (4 bytes)
3051 3048 * # of elements in the nvpair (4 bytes)
3052 3049 * data
3053 3050 * 2 zero's for the last nvpair
3054 3051 * (end of the entire list) (8 bytes)
3055 3052 *
3056 3053 */
3057 3054
3058 3055 static int
3059 3056 nvlist_find_value (const char *nvlist_in, const char *name,
3060 3057 int valtype, char **val,
3061 3058 grub_size_t *size_out, grub_size_t *nelm_out)
3062 3059 {
3063 3060 int name_len, type, encode_size;
3064 3061 const char *nvpair, *nvp_name, *nvlist = nvlist_in;
3065 3062
3066 3063 /* Verify if the 1st and 2nd byte in the nvlist are valid. */
3067 3064 /* NOTE: independently of what endianness header announces all
3068 3065 subsequent values are big-endian. */
3069 3066 if (nvlist[0] != NV_ENCODE_XDR || (nvlist[1] != NV_LITTLE_ENDIAN
3070 3067 && nvlist[1] != NV_BIG_ENDIAN))
3071 3068 {
3072 3069 grub_dprintf ("zfs", "incorrect nvlist header\n");
3073 3070 grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist");
3074 3071 return 0;
3075 3072 }
3076 3073
3077 3074 /* skip the header, nvl_version, and nvl_nvflag */
3078 3075 nvlist = nvlist + 4 * 3;
3079 3076 /*
3080 3077 * Loop thru the nvpair list
3081 3078 * The XDR representation of an integer is in big-endian byte order.
3082 3079 */
3083 3080 while ((encode_size = grub_be_to_cpu32 (grub_get_unaligned32 (nvlist))))
3084 3081 {
3085 3082 int nelm;
3086 3083
3087 3084 if (nvlist + 4 * 4 >= nvlist_in + VDEV_PHYS_SIZE)
3088 3085 {
3089 3086 grub_dprintf ("zfs", "nvlist overflow\n");
3090 3087 grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist");
3091 3088 return 0;
3092 3089 }
3093 3090
3094 3091 nvpair = nvlist + 4 * 2; /* skip the encode/decode size */
3095 3092
3096 3093 name_len = grub_be_to_cpu32 (grub_get_unaligned32 (nvpair));
3097 3094 nvpair += 4;
3098 3095
3099 3096 nvp_name = nvpair;
3100 3097 nvpair = nvpair + ((name_len + 3) & ~3); /* align */
3101 3098
3102 3099 if (nvpair + 8 >= nvlist_in + VDEV_PHYS_SIZE
3103 3100 || encode_size < 0
3104 3101 || nvpair + 8 + encode_size > nvlist_in + VDEV_PHYS_SIZE)
3105 3102 {
3106 3103 grub_dprintf ("zfs", "nvlist overflow\n");
3107 3104 grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist");
3108 3105 return 0;
3109 3106 }
3110 3107
3111 3108 type = grub_be_to_cpu32 (grub_get_unaligned32 (nvpair));
3112 3109 nvpair += 4;
3113 3110
3114 3111 nelm = grub_be_to_cpu32 (grub_get_unaligned32 (nvpair));
3115 3112 if (nelm < 1)
3116 3113 {
3117 3114 grub_error (GRUB_ERR_BAD_FS, "empty nvpair");
3118 3115 return 0;
3119 3116 }
3120 3117
3121 3118 nvpair += 4;
3122 3119
3123 3120 if ((grub_strncmp (nvp_name, name, name_len) == 0) && type == valtype)
3124 3121 {
3125 3122 *val = (char *) nvpair;
3126 3123 *size_out = encode_size;
3127 3124 if (nelm_out)
3128 3125 *nelm_out = nelm;
3129 3126 return 1;
3130 3127 }
3131 3128
3132 3129 nvlist += encode_size; /* goto the next nvpair */
3133 3130 }
3134 3131 return 0;
3135 3132 }
3136 3133
3137 3134 int
3138 3135 grub_zfs_nvlist_lookup_uint64 (const char *nvlist, const char *name,
3139 3136 grub_uint64_t * out)
3140 3137 {
3141 3138 char *nvpair;
3142 3139 grub_size_t size;
3143 3140 int found;
3144 3141
3145 3142 found = nvlist_find_value (nvlist, name, DATA_TYPE_UINT64, &nvpair, &size, 0);
3146 3143 if (!found)
3147 3144 return 0;
3148 3145 if (size < sizeof (grub_uint64_t))
3149 3146 {
3150 3147 grub_error (GRUB_ERR_BAD_FS, "invalid uint64");
3151 3148 return 0;
3152 3149 }
3153 3150
3154 3151 *out = grub_be_to_cpu64 (grub_get_unaligned64 (nvpair));
3155 3152 return 1;
3156 3153 }
3157 3154
3158 3155 char *
3159 3156 grub_zfs_nvlist_lookup_string (const char *nvlist, const char *name)
3160 3157 {
3161 3158 char *nvpair;
3162 3159 char *ret;
3163 3160 grub_size_t slen;
3164 3161 grub_size_t size;
3165 3162 int found;
3166 3163
3167 3164 found = nvlist_find_value (nvlist, name, DATA_TYPE_STRING, &nvpair, &size, 0);
3168 3165 if (!found)
3169 3166 return 0;
3170 3167 if (size < 4)
3171 3168 {
3172 3169 grub_error (GRUB_ERR_BAD_FS, "invalid string");
3173 3170 return 0;
3174 3171 }
3175 3172 slen = grub_be_to_cpu32 (grub_get_unaligned32 (nvpair));
3176 3173 if (slen > size - 4)
3177 3174 slen = size - 4;
3178 3175 ret = grub_malloc (slen + 1);
3179 3176 if (!ret)
3180 3177 return 0;
3181 3178 grub_memcpy (ret, nvpair + 4, slen);
3182 3179 ret[slen] = 0;
3183 3180 return ret;
3184 3181 }
3185 3182
3186 3183 char *
3187 3184 grub_zfs_nvlist_lookup_nvlist (const char *nvlist, const char *name)
3188 3185 {
3189 3186 char *nvpair;
3190 3187 char *ret;
3191 3188 grub_size_t size;
3192 3189 int found;
3193 3190
3194 3191 found = nvlist_find_value (nvlist, name, DATA_TYPE_NVLIST, &nvpair,
3195 3192 &size, 0);
3196 3193 if (!found)
3197 3194 return 0;
3198 3195 ret = grub_zalloc (size + 3 * sizeof (grub_uint32_t));
3199 3196 if (!ret)
3200 3197 return 0;
3201 3198 grub_memcpy (ret, nvlist, sizeof (grub_uint32_t));
3202 3199
3203 3200 grub_memcpy (ret + sizeof (grub_uint32_t), nvpair, size);
3204 3201 return ret;
3205 3202 }
3206 3203
3207 3204 int
3208 3205 grub_zfs_nvlist_lookup_nvlist_array_get_nelm (const char *nvlist,
3209 3206 const char *name)
3210 3207 {
3211 3208 char *nvpair;
3212 3209 grub_size_t nelm, size;
3213 3210 int found;
3214 3211
3215 3212 found = nvlist_find_value (nvlist, name, DATA_TYPE_NVLIST_ARRAY, &nvpair,
3216 3213 &size, &nelm);
3217 3214 if (! found)
3218 3215 return -1;
3219 3216 return nelm;
3220 3217 }
3221 3218
3222 3219 static int
3223 3220 get_nvlist_size (const char *beg, const char *limit)
3224 3221 {
3225 3222 const char *ptr;
3226 3223 grub_uint32_t encode_size;
3227 3224
3228 3225 ptr = beg + 8;
3229 3226
3230 3227 while (ptr < limit
3231 3228 && (encode_size = grub_be_to_cpu32 (grub_get_unaligned32 (ptr))))
3232 3229 ptr += encode_size; /* goto the next nvpair */
3233 3230 ptr += 8;
3234 3231 return (ptr > limit) ? -1 : (ptr - beg);
3235 3232 }
3236 3233
3237 3234 char *
3238 3235 grub_zfs_nvlist_lookup_nvlist_array (const char *nvlist, const char *name,
3239 3236 grub_size_t index)
3240 3237 {
3241 3238 char *nvpair, *nvpairptr;
3242 3239 int found;
3243 3240 char *ret;
3244 3241 grub_size_t size;
3245 3242 unsigned i;
3246 3243 grub_size_t nelm;
3247 3244 int elemsize = 0;
3248 3245
3249 3246 found = nvlist_find_value (nvlist, name, DATA_TYPE_NVLIST_ARRAY, &nvpair,
3250 3247 &size, &nelm);
3251 3248 if (!found)
3252 3249 return 0;
3253 3250 if (index >= nelm)
3254 3251 {
3255 3252 grub_error (GRUB_ERR_OUT_OF_RANGE, "trying to lookup past nvlist array");
3256 3253 return 0;
3257 3254 }
3258 3255
3259 3256 nvpairptr = nvpair;
3260 3257
3261 3258 for (i = 0; i < index; i++)
3262 3259 {
3263 3260 int r;
3264 3261 r = get_nvlist_size (nvpairptr, nvpair + size);
3265 3262
3266 3263 if (r < 0)
3267 3264 {
3268 3265 grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist array");
3269 3266 return NULL;
3270 3267 }
3271 3268 nvpairptr += r;
3272 3269 }
3273 3270
3274 3271 elemsize = get_nvlist_size (nvpairptr, nvpair + size);
3275 3272
3276 3273 if (elemsize < 0)
3277 3274 {
3278 3275 grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist array");
3279 3276 return 0;
3280 3277 }
3281 3278
3282 3279 ret = grub_zalloc (elemsize + sizeof (grub_uint32_t));
3283 3280 if (!ret)
3284 3281 return 0;
3285 3282 grub_memcpy (ret, nvlist, sizeof (grub_uint32_t));
3286 3283
3287 3284 grub_memcpy (ret + sizeof (grub_uint32_t), nvpairptr, elemsize);
3288 3285 return ret;
3289 3286 }
3290 3287
3291 3288 static void
3292 3289 unmount_device (struct grub_zfs_device_desc *desc)
3293 3290 {
3294 3291 unsigned i;
3295 3292 switch (desc->type)
3296 3293 {
3297 3294 case DEVICE_LEAF:
3298 3295 if (!desc->original && desc->dev)
3299 3296 grub_device_close (desc->dev);
3300 3297 return;
3301 3298 case DEVICE_RAIDZ:
3302 3299 case DEVICE_MIRROR:
3303 3300 for (i = 0; i < desc->n_children; i++)
3304 3301 unmount_device (&desc->children[i]);
3305 3302 grub_free (desc->children);
3306 3303 return;
3307 3304 }
3308 3305 }
3309 3306
3310 3307 static void
3311 3308 zfs_unmount (struct grub_zfs_data *data)
3312 3309 {
↓ open down ↓ |
580 lines elided |
↑ open up ↑ |
3313 3310 unsigned i;
3314 3311 for (i = 0; i < data->n_devices_attached; i++)
3315 3312 unmount_device (&data->devices_attached[i]);
3316 3313 grub_free (data->devices_attached);
3317 3314 grub_free (data->dnode_buf);
3318 3315 grub_free (data->dnode_mdn);
3319 3316 grub_free (data->file_buf);
3320 3317 for (i = 0; i < data->subvol.nkeys; i++)
3321 3318 grub_crypto_cipher_close (data->subvol.keyring[i].cipher);
3322 3319 grub_free (data->subvol.keyring);
3320 + while (data->feature_list) {
3321 + struct enabled_feature_list * tmp = data->feature_list;
3322 + data->feature_list = data->feature_list->next;
3323 + grub_free(tmp);
3324 + }
3323 3325 grub_free (data);
3324 3326 }
3325 3327
3328 +static int
3329 +add_feature (struct grub_zfs_data * data, zfs_feature_id_t id)
3330 +{
3331 + struct enabled_feature_list * list = data->feature_list;
3332 +
3333 + while (list->next) {
3334 + if (list->next->id == id)
3335 + return id;
3336 + list = list->next;
3337 + }
3338 +
3339 + list->next = (struct enabled_feature_list *) grub_zalloc (sizeof (struct enabled_feature_list));
3340 +
3341 + if (! list->next)
3342 + return (-1);
3343 +
3344 + list->next->id = id;
3345 + list->next->next = NULL;
3346 +
3347 + return 0;
3348 +}
3349 +
3350 +static zfs_feature_id_t
3351 +check_feature (const char * feature)
3352 +{
3353 + int i = 0;
3354 + for ( ; i < ZFS_FEATURE_UNKNOWN; ++i)
3355 + if (! grub_strcmp (feature, feature_list[i]))
3356 + return i;
3357 +
3358 + return ZFS_FEATURE_UNKNOWN;
3359 +}
3360 +
3361 +/*
3362 + * zfs_get_features_list() get feature list and check compatability
3363 + */
3364 +static grub_err_t
3365 +zfs_get_features_list (struct grub_zfs_data * data)
3366 +{
3367 + dnode_end_t dn;
3368 + dnode_end_t * mos = &(data->mos);
3369 + grub_err_t err;
3370 + grub_uint64_t objnum;
3371 + int ret;
3372 +
3373 + int NESTED_FUNC_ATTR feature_hook (const char * cname, grub_uint64_t val)
3374 + {
3375 + grub_err_t iret = 0;
3376 +
3377 + zfs_feature_id_t id;
3378 +
3379 + if (! (*cname))
3380 + goto out;
3381 +
3382 + // retrieve feature number
3383 + id = check_feature (cname);
3384 +
3385 + // if grub doesn't support such feature, return error
3386 + if (id == ZFS_FEATURE_UNKNOWN) {
3387 + if (val == 0) {
3388 + grub_error(GRUB_ERR_BAD_FS,
3389 + "Unsupported feature %s was enabled,"
3390 + " but haven't been activated yet. You will not be able to boot"
3391 + " if this feature are activated.", cname);
3392 + } else {
3393 + grub_error(GRUB_ERR_BAD_FS,
3394 + "Unsupported feature %s is activated. Booting failed",cname);
3395 + iret = 1;
3396 + }
3397 + goto out;
3398 + }
3399 +
3400 + // add feature to list
3401 + iret = add_feature(data, id);
3402 +
3403 + out:
3404 + return iret;
3405 + }
3406 +
3407 + // get object directory
3408 + err = dnode_get (mos, DMU_POOL_DIRECTORY_OBJECT,
3409 + DMU_OT_OBJECT_DIRECTORY, &dn, data);
3410 + if (err)
3411 + return err;
3412 +
3413 + // retrieve pool properties object numer
3414 + err = zap_lookup (&dn, DMU_POOL_FEATURES_FOR_READ, &objnum, data, 0);
3415 + if (err)
3416 + return err;
3417 +
3418 + // get "features for read" zap dnode
3419 + err = dnode_get (mos, objnum, DMU_OTN_ZAP_METADATA, &dn, data);
3420 + if (err)
3421 + return err;
3422 +
3423 + // itterate zap to fetch feature list
3424 + ret = zap_iterate_u64 (&dn, feature_hook, data);
3425 + if (ret)
3426 + return grub_error(GRUB_ERR_BAD_FS, "There are enabled unsupported features");
3427 +
3428 + return GRUB_ERR_NONE;
3429 +}
3430 +
3326 3431 /*
3327 3432 * zfs_mount() locates a valid uberblock of the root pool and read in its MOS
3328 3433 * to the memory address MOS.
3329 3434 *
3330 3435 */
3331 3436 static struct grub_zfs_data *
3332 3437 zfs_mount (grub_device_t dev)
3333 3438 {
3334 3439 struct grub_zfs_data *data = 0;
3335 3440 grub_err_t err;
3336 3441 void *osp = 0;
3337 3442 grub_size_t ospsize;
3338 3443 grub_zfs_endian_t ub_endian = GRUB_ZFS_UNKNOWN_ENDIAN;
3339 3444 uberblock_t *ub;
3340 3445 int inserted;
3341 3446
3342 3447 if (! dev->disk)
3343 3448 {
3344 3449 grub_error (GRUB_ERR_BAD_DEVICE, "not a disk");
3345 3450 return 0;
3346 3451 }
↓ open down ↓ |
11 lines elided |
↑ open up ↑ |
3347 3452
3348 3453 data = grub_zalloc (sizeof (*data));
3349 3454 if (!data)
3350 3455 return 0;
3351 3456 #if 0
3352 3457 /* if it's our first time here, zero the best uberblock out */
3353 3458 if (data->best_drive == 0 && data->best_part == 0 && find_best_root)
3354 3459 grub_memset (¤t_uberblock, 0, sizeof (uberblock_t));
3355 3460 #endif
3356 3461
3462 + data->feature_list = NULL;
3357 3463 data->n_devices_allocated = 16;
3358 3464 data->devices_attached = grub_malloc (sizeof (data->devices_attached[0])
3359 3465 * data->n_devices_allocated);
3360 3466 data->n_devices_attached = 0;
3361 3467 err = scan_disk (dev, data, 1, &inserted);
3362 3468 if (err)
3363 3469 {
3364 3470 zfs_unmount (data);
3365 3471 return NULL;
3366 3472 }
3367 3473
3368 3474 ub = &(data->current_uberblock);
3369 3475 ub_endian = (grub_zfs_to_cpu64 (ub->ub_magic,
3370 3476 GRUB_ZFS_LITTLE_ENDIAN) == UBERBLOCK_MAGIC
3371 3477 ? GRUB_ZFS_LITTLE_ENDIAN : GRUB_ZFS_BIG_ENDIAN);
3372 3478
3373 3479 err = zio_read (&ub->ub_rootbp, ub_endian,
3374 3480 &osp, &ospsize, data);
3375 3481 if (err)
3376 3482 {
3377 3483 zfs_unmount (data);
3378 3484 return NULL;
3379 3485 }
3380 3486
3381 3487 if (ospsize < OBJSET_PHYS_SIZE_V14)
3382 3488 {
3383 3489 grub_error (GRUB_ERR_BAD_FS, "OSP too small");
3384 3490 grub_free (osp);
↓ open down ↓ |
18 lines elided |
↑ open up ↑ |
3385 3491 zfs_unmount (data);
3386 3492 return NULL;
3387 3493 }
3388 3494
3389 3495 /* Got the MOS. Save it at the memory addr MOS. */
3390 3496 grub_memmove (&(data->mos.dn), &((objset_phys_t *) osp)->os_meta_dnode,
3391 3497 DNODE_SIZE);
3392 3498 data->mos.endian = (grub_zfs_to_cpu64 (ub->ub_rootbp.blk_prop,
3393 3499 ub_endian) >> 63) & 1;
3394 3500 grub_free (osp);
3395 -
3501 +
3396 3502 data->mounted = 1;
3397 3503
3504 + if (grub_zfs_to_cpu64(ub->ub_version, ub_endian) == SPA_FEATURE_VERSION) {
3505 + data->feature_list = (struct enabled_feature_list*) grub_zalloc (
3506 + sizeof (struct enabled_feature_list));
3507 + data->feature_list->next = NULL;
3508 + err = zfs_get_features_list(data);
3509 +
3510 + if (err) {
3511 + data->mounted = 0;
3512 + zfs_unmount (data);
3513 + return NULL;
3514 + }
3515 + }
3516 +
3398 3517 return data;
3399 3518 }
3400 3519
3520 +static grub_err_t
3521 +find_default_dataset_path(char * path, grub_uint64_t * mdnobj, struct grub_zfs_data *data)
3522 +{
3523 + grub_uint64_t obj, pobj, zobj;
3524 + grub_err_t err;
3525 + dnode_end_t mdn, *mosmdn;
3526 + char buf[512];
3527 +
3528 + int NESTED_FUNC_ATTR hook (const char * name, grub_uint64_t val) {
3529 + if (val == obj) {
3530 + grub_strcpy(buf, name);
3531 + return 1;
3532 + }
3533 + return 0;
3534 + }
3535 +
3536 + obj = *mdnobj;
3537 + mosmdn = &(data->mos);
3538 + buf[0] = '\0';
3539 + path[0] = '\0';
3540 +
3541 + // get object's data dir
3542 + err = dnode_get(mosmdn, obj, DMU_OT_DSL_DATASET, &mdn, data);
3543 + if (err)
3544 + return err;
3545 + obj = grub_zfs_to_cpu64((((dsl_dataset_phys_t*)DN_BONUS (&mdn.dn)))->ds_dir_obj, mdn.endian);
3546 +
3547 + for (;;) {
3548 + // get object dnode
3549 + err = dnode_get(mosmdn, obj, DMU_OT_DSL_DIR, &mdn, data);
3550 + if (err)
3551 + return err;
3552 +
3553 + // find out its parent's objnum
3554 + pobj = grub_zfs_to_cpu64((((dsl_dir_phys_t*)DN_BONUS (&mdn.dn)))->dd_parent_obj, mdn.endian);
3555 + if (obj == pobj)
3556 + break;
3557 +
3558 + // if pobj is 0 then we have reached top dataset
3559 + if (! pobj)
3560 + break;
3561 +
3562 + // get object's parent dnode
3563 + err = dnode_get(mosmdn, pobj, DMU_OT_DSL_DIR, &mdn, data);
3564 + if (err)
3565 + return err;
3566 +
3567 + // find out parent's zap objnum
3568 + zobj = grub_zfs_to_cpu64((((dsl_dir_phys_t*)DN_BONUS (&mdn.dn)))->dd_child_dir_zapobj, mdn.endian);
3569 +
3570 + // get zap's dnode
3571 + err = dnode_get(mosmdn, zobj, DMU_OT_DSL_DIR_CHILD_MAP, &mdn, data);
3572 + if (err)
3573 + return err;
3574 +
3575 + // lookup zap to get name
3576 + err = zap_iterate_u64(&mdn, hook, data);
3577 + if (err == 0)
3578 + return err;
3579 +
3580 + // pobj becomes obj now
3581 + obj = pobj;
3582 +
3583 + // append new intermediate dnode to path
3584 + grub_strcat(buf, path);
3585 + grub_strcpy(path, "/");
3586 + grub_strcat(path, buf);
3587 + }
3588 +
3589 + return GRUB_ERR_NONE;
3590 +}
3591 +
3592 +grub_err_t
3593 +get_default_bootfs_obj(grub_device_t dev, char * path, grub_uint64_t * mdnobj)
3594 +{
3595 + struct grub_zfs_data * data;
3596 + grub_err_t err = 0;
3597 + data = zfs_mount(dev);
3598 + if (data) {
3599 + err = get_default_bootfsobj(&(data->mos), mdnobj, data);
3600 + if (err)
3601 + return err;
3602 + err = find_default_dataset_path(path, mdnobj, data);
3603 + zfs_unmount(data);
3604 + return err;
3605 + } else {
3606 + return grub_errno;
3607 + }
3608 + return 0;
3609 +}
3610 +
3401 3611 grub_err_t
3402 3612 grub_zfs_fetch_nvlist (grub_device_t dev, char **nvlist)
3403 3613 {
3404 3614 struct grub_zfs_data *zfs;
3405 3615 grub_err_t err;
3406 3616
3407 3617 zfs = zfs_mount (dev);
3408 3618 if (!zfs)
3409 3619 return grub_errno;
3410 3620 err = zfs_fetch_nvlist (zfs->device_original, nvlist);
3411 3621 zfs_unmount (zfs);
3412 3622 return err;
3413 3623 }
3414 3624
3415 3625 static grub_err_t
3416 3626 zfs_label (grub_device_t device, char **label)
3417 3627 {
3418 3628 char *nvlist;
3419 3629 grub_err_t err;
3420 3630 struct grub_zfs_data *data;
3421 3631
3422 3632 data = zfs_mount (device);
3423 3633 if (! data)
3424 3634 return grub_errno;
3425 3635
3426 3636 err = zfs_fetch_nvlist (data->device_original, &nvlist);
3427 3637 if (err)
3428 3638 {
3429 3639 zfs_unmount (data);
3430 3640 return err;
3431 3641 }
3432 3642
3433 3643 *label = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_POOL_NAME);
3434 3644 grub_free (nvlist);
3435 3645 zfs_unmount (data);
3436 3646 return grub_errno;
3437 3647 }
3438 3648
3439 3649 static grub_err_t
3440 3650 zfs_uuid (grub_device_t device, char **uuid)
3441 3651 {
3442 3652 struct grub_zfs_data *data;
3443 3653
3444 3654 *uuid = 0;
3445 3655
3446 3656 data = zfs_mount (device);
3447 3657 if (! data)
3448 3658 return grub_errno;
3449 3659
3450 3660 *uuid = grub_xasprintf ("%016llx", (long long unsigned) data->guid);
3451 3661 zfs_unmount (data);
3452 3662 if (! *uuid)
3453 3663 return grub_errno;
3454 3664 return GRUB_ERR_NONE;
3455 3665 }
3456 3666
3457 3667 static grub_err_t
3458 3668 zfs_mtime (grub_device_t device, grub_int32_t *mt)
3459 3669 {
3460 3670 struct grub_zfs_data *data;
3461 3671 grub_zfs_endian_t ub_endian = GRUB_ZFS_UNKNOWN_ENDIAN;
3462 3672 uberblock_t *ub;
3463 3673
3464 3674 *mt = 0;
3465 3675
3466 3676 data = zfs_mount (device);
3467 3677 if (! data)
3468 3678 return grub_errno;
3469 3679
3470 3680 ub = &(data->current_uberblock);
3471 3681 ub_endian = (grub_zfs_to_cpu64 (ub->ub_magic,
3472 3682 GRUB_ZFS_LITTLE_ENDIAN) == UBERBLOCK_MAGIC
3473 3683 ? GRUB_ZFS_LITTLE_ENDIAN : GRUB_ZFS_BIG_ENDIAN);
3474 3684
3475 3685 *mt = grub_zfs_to_cpu64 (ub->ub_timestamp, ub_endian);
3476 3686 zfs_unmount (data);
3477 3687 return GRUB_ERR_NONE;
3478 3688 }
3479 3689
3480 3690 /*
3481 3691 * zfs_open() locates a file in the rootpool by following the
3482 3692 * MOS and places the dnode of the file in the memory address DNODE.
3483 3693 */
3484 3694 static grub_err_t
3485 3695 grub_zfs_open (struct grub_file *file, const char *fsfilename)
3486 3696 {
3487 3697 struct grub_zfs_data *data;
3488 3698 grub_err_t err;
3489 3699 int isfs;
3490 3700
3491 3701 data = zfs_mount (file->device);
3492 3702 if (! data)
3493 3703 return grub_errno;
3494 3704
3495 3705 err = dnode_get_fullpath (fsfilename, &(data->subvol),
3496 3706 &(data->dnode), &isfs, data);
3497 3707 if (err)
3498 3708 {
3499 3709 zfs_unmount (data);
3500 3710 return err;
3501 3711 }
3502 3712
3503 3713 if (isfs)
3504 3714 {
3505 3715 zfs_unmount (data);
3506 3716 return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("missing `%c' symbol"), '@');
3507 3717 }
3508 3718
3509 3719 /* We found the dnode for this file. Verify if it is a plain file. */
3510 3720 if (data->dnode.dn.dn_type != DMU_OT_PLAIN_FILE_CONTENTS)
3511 3721 {
3512 3722 zfs_unmount (data);
3513 3723 return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a regular file"));
3514 3724 }
3515 3725
3516 3726 /* get the file size and set the file position to 0 */
3517 3727
3518 3728 /*
3519 3729 * For DMU_OT_SA we will need to locate the SIZE attribute
3520 3730 * attribute, which could be either in the bonus buffer
3521 3731 * or the "spill" block.
3522 3732 */
3523 3733 if (data->dnode.dn.dn_bonustype == DMU_OT_SA)
3524 3734 {
3525 3735 void *sahdrp;
3526 3736 int hdrsize;
3527 3737
3528 3738 if (data->dnode.dn.dn_bonuslen != 0)
3529 3739 {
3530 3740 sahdrp = (sa_hdr_phys_t *) DN_BONUS (&data->dnode.dn);
3531 3741 }
3532 3742 else if (data->dnode.dn.dn_flags & DNODE_FLAG_SPILL_BLKPTR)
3533 3743 {
3534 3744 blkptr_t *bp = &data->dnode.dn.dn_spill;
3535 3745
3536 3746 err = zio_read (bp, data->dnode.endian, &sahdrp, NULL, data);
3537 3747 if (err)
3538 3748 return err;
3539 3749 }
3540 3750 else
3541 3751 {
3542 3752 return grub_error (GRUB_ERR_BAD_FS, "filesystem is corrupt");
3543 3753 }
3544 3754
3545 3755 hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp));
3546 3756 file->size = grub_zfs_to_cpu64 (grub_get_unaligned64 ((char *) sahdrp + hdrsize + SA_SIZE_OFFSET), data->dnode.endian);
3547 3757 }
3548 3758 else if (data->dnode.dn.dn_bonustype == DMU_OT_ZNODE)
3549 3759 {
3550 3760 file->size = grub_zfs_to_cpu64 (((znode_phys_t *) DN_BONUS (&data->dnode.dn))->zp_size, data->dnode.endian);
3551 3761 }
3552 3762 else
3553 3763 return grub_error (GRUB_ERR_BAD_FS, "bad bonus type");
3554 3764
3555 3765 file->data = data;
3556 3766 file->offset = 0;
3557 3767
3558 3768 #ifndef GRUB_UTIL
3559 3769 grub_dl_ref (my_mod);
3560 3770 #endif
3561 3771
3562 3772 return GRUB_ERR_NONE;
3563 3773 }
3564 3774
3565 3775 static grub_ssize_t
3566 3776 grub_zfs_read (grub_file_t file, char *buf, grub_size_t len)
3567 3777 {
3568 3778 struct grub_zfs_data *data = (struct grub_zfs_data *) file->data;
3569 3779 grub_size_t blksz, movesize;
3570 3780 grub_size_t length;
3571 3781 grub_size_t read;
3572 3782 grub_err_t err;
3573 3783
3574 3784 /*
3575 3785 * If offset is in memory, move it into the buffer provided and return.
3576 3786 */
3577 3787 if (file->offset >= data->file_start
3578 3788 && file->offset + len <= data->file_end)
3579 3789 {
3580 3790 grub_memmove (buf, data->file_buf + file->offset - data->file_start,
3581 3791 len);
3582 3792 return len;
3583 3793 }
3584 3794
3585 3795 blksz = grub_zfs_to_cpu16 (data->dnode.dn.dn_datablkszsec,
3586 3796 data->dnode.endian) << SPA_MINBLOCKSHIFT;
3587 3797
3588 3798 /*
3589 3799 * Entire Dnode is too big to fit into the space available. We
3590 3800 * will need to read it in chunks. This could be optimized to
3591 3801 * read in as large a chunk as there is space available, but for
3592 3802 * now, this only reads in one data block at a time.
3593 3803 */
3594 3804 length = len;
3595 3805 read = 0;
3596 3806 while (length)
3597 3807 {
3598 3808 void *t;
3599 3809 /*
3600 3810 * Find requested blkid and the offset within that block.
3601 3811 */
3602 3812 grub_uint64_t blkid = grub_divmod64 (file->offset + read, blksz, 0);
3603 3813 grub_free (data->file_buf);
3604 3814 data->file_buf = 0;
3605 3815
3606 3816 err = dmu_read (&(data->dnode), blkid, &t,
3607 3817 0, data);
3608 3818 data->file_buf = t;
3609 3819 if (err)
3610 3820 {
3611 3821 data->file_buf = NULL;
3612 3822 data->file_start = data->file_end = 0;
3613 3823 return -1;
3614 3824 }
3615 3825
3616 3826 data->file_start = blkid * blksz;
3617 3827 data->file_end = data->file_start + blksz;
3618 3828
3619 3829 movesize = data->file_end - file->offset - read;
3620 3830 if (movesize > length)
3621 3831 movesize = length;
3622 3832
3623 3833 grub_memmove (buf, data->file_buf + file->offset + read
3624 3834 - data->file_start, movesize);
3625 3835 buf += movesize;
3626 3836 length -= movesize;
3627 3837 read += movesize;
3628 3838 }
3629 3839
3630 3840 return len;
3631 3841 }
3632 3842
3633 3843 static grub_err_t
3634 3844 grub_zfs_close (grub_file_t file)
3635 3845 {
3636 3846 zfs_unmount ((struct grub_zfs_data *) file->data);
3637 3847
3638 3848 #ifndef GRUB_UTIL
3639 3849 grub_dl_unref (my_mod);
3640 3850 #endif
3641 3851
3642 3852 return GRUB_ERR_NONE;
3643 3853 }
3644 3854
3645 3855 grub_err_t
3646 3856 grub_zfs_getmdnobj (grub_device_t dev, const char *fsfilename,
3647 3857 grub_uint64_t *mdnobj)
3648 3858 {
3649 3859 struct grub_zfs_data *data;
3650 3860 grub_err_t err;
3651 3861 int isfs;
3652 3862
3653 3863 data = zfs_mount (dev);
3654 3864 if (! data)
3655 3865 return grub_errno;
3656 3866
3657 3867 err = dnode_get_fullpath (fsfilename, &(data->subvol),
3658 3868 &(data->dnode), &isfs, data);
3659 3869 *mdnobj = data->subvol.obj;
3660 3870 zfs_unmount (data);
3661 3871 return err;
3662 3872 }
3663 3873
3664 3874 static void
3665 3875 fill_fs_info (struct grub_dirhook_info *info,
3666 3876 dnode_end_t mdn, struct grub_zfs_data *data)
3667 3877 {
3668 3878 grub_err_t err;
3669 3879 dnode_end_t dn;
3670 3880 grub_uint64_t objnum;
3671 3881 grub_uint64_t headobj;
3672 3882
3673 3883 grub_memset (info, 0, sizeof (*info));
3674 3884
3675 3885 info->dir = 1;
3676 3886
3677 3887 if (mdn.dn.dn_type == DMU_OT_DSL_DIR)
3678 3888 {
3679 3889 headobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&mdn.dn))->dd_head_dataset_obj, mdn.endian);
3680 3890
3681 3891 err = dnode_get (&(data->mos), headobj, DMU_OT_DSL_DATASET, &mdn, data);
3682 3892 if (err)
3683 3893 {
3684 3894 grub_dprintf ("zfs", "failed here\n");
3685 3895 return;
3686 3896 }
3687 3897 }
3688 3898 make_mdn (&mdn, data);
3689 3899 err = dnode_get (&mdn, MASTER_NODE_OBJ, DMU_OT_MASTER_NODE,
3690 3900 &dn, data);
3691 3901 if (err)
3692 3902 {
3693 3903 grub_dprintf ("zfs", "failed here\n");
3694 3904 return;
3695 3905 }
3696 3906
3697 3907 err = zap_lookup (&dn, ZFS_ROOT_OBJ, &objnum, data, 0);
3698 3908 if (err)
3699 3909 {
3700 3910 grub_dprintf ("zfs", "failed here\n");
3701 3911 return;
3702 3912 }
3703 3913
3704 3914 err = dnode_get (&mdn, objnum, 0, &dn, data);
3705 3915 if (err)
3706 3916 {
3707 3917 grub_dprintf ("zfs", "failed here\n");
3708 3918 return;
3709 3919 }
3710 3920
3711 3921 if (dn.dn.dn_bonustype == DMU_OT_SA)
3712 3922 {
3713 3923 void *sahdrp;
3714 3924 int hdrsize;
3715 3925
3716 3926 if (dn.dn.dn_bonuslen != 0)
3717 3927 {
3718 3928 sahdrp = (sa_hdr_phys_t *) DN_BONUS (&dn.dn);
3719 3929 }
3720 3930 else if (dn.dn.dn_flags & DNODE_FLAG_SPILL_BLKPTR)
3721 3931 {
3722 3932 blkptr_t *bp = &dn.dn.dn_spill;
3723 3933
3724 3934 err = zio_read (bp, dn.endian, &sahdrp, NULL, data);
3725 3935 if (err)
3726 3936 return;
3727 3937 }
3728 3938 else
3729 3939 {
3730 3940 grub_error (GRUB_ERR_BAD_FS, "filesystem is corrupt");
3731 3941 return;
3732 3942 }
3733 3943
3734 3944 hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp));
3735 3945 info->mtimeset = 1;
3736 3946 info->mtime = grub_zfs_to_cpu64 (grub_get_unaligned64 ((char *) sahdrp + hdrsize + SA_MTIME_OFFSET), dn.endian);
3737 3947 }
3738 3948
3739 3949 if (dn.dn.dn_bonustype == DMU_OT_ZNODE)
3740 3950 {
3741 3951 info->mtimeset = 1;
3742 3952 info->mtime = grub_zfs_to_cpu64 (((znode_phys_t *) DN_BONUS (&dn.dn))->zp_mtime[0], dn.endian);
3743 3953 }
3744 3954 return;
3745 3955 }
3746 3956
3747 3957 static grub_err_t
3748 3958 grub_zfs_dir (grub_device_t device, const char *path,
3749 3959 int (*hook) (const char *, const struct grub_dirhook_info *))
3750 3960 {
3751 3961 struct grub_zfs_data *data;
3752 3962 grub_err_t err;
3753 3963 int isfs;
3754 3964 auto int NESTED_FUNC_ATTR iterate_zap (const char *name, grub_uint64_t val);
3755 3965 auto int NESTED_FUNC_ATTR iterate_zap_fs (const char *name,
3756 3966 grub_uint64_t val);
3757 3967 auto int NESTED_FUNC_ATTR iterate_zap_snap (const char *name,
3758 3968 grub_uint64_t val);
3759 3969
3760 3970 int NESTED_FUNC_ATTR iterate_zap (const char *name, grub_uint64_t val)
3761 3971 {
3762 3972 struct grub_dirhook_info info;
3763 3973 dnode_end_t dn;
3764 3974 grub_memset (&info, 0, sizeof (info));
3765 3975
3766 3976 dnode_get (&(data->subvol.mdn), val, 0, &dn, data);
3767 3977
3768 3978 if (dn.dn.dn_bonustype == DMU_OT_SA)
3769 3979 {
3770 3980 void *sahdrp;
3771 3981 int hdrsize;
3772 3982
3773 3983 if (dn.dn.dn_bonuslen != 0)
3774 3984 {
3775 3985 sahdrp = (sa_hdr_phys_t *) DN_BONUS (&data->dnode.dn);
3776 3986 }
3777 3987 else if (dn.dn.dn_flags & DNODE_FLAG_SPILL_BLKPTR)
3778 3988 {
3779 3989 blkptr_t *bp = &dn.dn.dn_spill;
3780 3990
3781 3991 err = zio_read (bp, dn.endian, &sahdrp, NULL, data);
3782 3992 if (err)
3783 3993 {
3784 3994 grub_print_error ();
3785 3995 return 0;
3786 3996 }
3787 3997 }
3788 3998 else
3789 3999 {
3790 4000 grub_error (GRUB_ERR_BAD_FS, "filesystem is corrupt");
3791 4001 grub_print_error ();
3792 4002 return 0;
3793 4003 }
3794 4004
3795 4005 hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp));
3796 4006 info.mtimeset = 1;
3797 4007 info.mtime = grub_zfs_to_cpu64 (grub_get_unaligned64 ((char *) sahdrp + hdrsize + SA_MTIME_OFFSET), dn.endian);
3798 4008 info.case_insensitive = data->subvol.case_insensitive;
3799 4009 }
3800 4010
3801 4011 if (dn.dn.dn_bonustype == DMU_OT_ZNODE)
3802 4012 {
3803 4013 info.mtimeset = 1;
3804 4014 info.mtime = grub_zfs_to_cpu64 (((znode_phys_t *) DN_BONUS (&dn.dn))->zp_mtime[0],
3805 4015 dn.endian);
3806 4016 }
3807 4017 info.dir = (dn.dn.dn_type == DMU_OT_DIRECTORY_CONTENTS);
3808 4018 grub_dprintf ("zfs", "type=%d, name=%s\n",
3809 4019 (int)dn.dn.dn_type, (char *)name);
3810 4020 return hook (name, &info);
3811 4021 }
3812 4022
3813 4023 int NESTED_FUNC_ATTR iterate_zap_fs (const char *name, grub_uint64_t val)
3814 4024 {
3815 4025 struct grub_dirhook_info info;
3816 4026 dnode_end_t mdn;
3817 4027 err = dnode_get (&(data->mos), val, 0, &mdn, data);
3818 4028 if (err)
3819 4029 return 0;
3820 4030 if (mdn.dn.dn_type != DMU_OT_DSL_DIR)
3821 4031 return 0;
3822 4032
3823 4033 fill_fs_info (&info, mdn, data);
3824 4034 return hook (name, &info);
3825 4035 }
3826 4036 int NESTED_FUNC_ATTR iterate_zap_snap (const char *name, grub_uint64_t val)
3827 4037 {
3828 4038 struct grub_dirhook_info info;
3829 4039 char *name2;
3830 4040 int ret;
3831 4041 dnode_end_t mdn;
3832 4042
3833 4043 err = dnode_get (&(data->mos), val, 0, &mdn, data);
3834 4044 if (err)
3835 4045 return 0;
3836 4046
3837 4047 if (mdn.dn.dn_type != DMU_OT_DSL_DATASET)
3838 4048 return 0;
3839 4049
3840 4050 fill_fs_info (&info, mdn, data);
3841 4051
3842 4052 name2 = grub_malloc (grub_strlen (name) + 2);
3843 4053 name2[0] = '@';
3844 4054 grub_memcpy (name2 + 1, name, grub_strlen (name) + 1);
3845 4055 ret = hook (name2, &info);
3846 4056 grub_free (name2);
3847 4057 return ret;
3848 4058 }
3849 4059
3850 4060 data = zfs_mount (device);
3851 4061 if (! data)
3852 4062 return grub_errno;
3853 4063 err = dnode_get_fullpath (path, &(data->subvol), &(data->dnode), &isfs, data);
3854 4064 if (err)
3855 4065 {
3856 4066 zfs_unmount (data);
3857 4067 return err;
3858 4068 }
3859 4069 if (isfs)
3860 4070 {
3861 4071 grub_uint64_t childobj, headobj;
3862 4072 grub_uint64_t snapobj;
3863 4073 dnode_end_t dn;
3864 4074 struct grub_dirhook_info info;
3865 4075
3866 4076 fill_fs_info (&info, data->dnode, data);
3867 4077 hook ("@", &info);
3868 4078
3869 4079 childobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&data->dnode.dn))->dd_child_dir_zapobj, data->dnode.endian);
3870 4080 headobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&data->dnode.dn))->dd_head_dataset_obj, data->dnode.endian);
3871 4081 err = dnode_get (&(data->mos), childobj,
3872 4082 DMU_OT_DSL_DIR_CHILD_MAP, &dn, data);
3873 4083 if (err)
3874 4084 {
3875 4085 zfs_unmount (data);
3876 4086 return err;
3877 4087 }
3878 4088
3879 4089 zap_iterate_u64 (&dn, iterate_zap_fs, data);
3880 4090
3881 4091 err = dnode_get (&(data->mos), headobj, DMU_OT_DSL_DATASET, &dn, data);
3882 4092 if (err)
3883 4093 {
3884 4094 zfs_unmount (data);
3885 4095 return err;
3886 4096 }
3887 4097
3888 4098 snapobj = grub_zfs_to_cpu64 (((dsl_dataset_phys_t *) DN_BONUS (&dn.dn))->ds_snapnames_zapobj, dn.endian);
3889 4099
3890 4100 err = dnode_get (&(data->mos), snapobj,
3891 4101 DMU_OT_DSL_DS_SNAP_MAP, &dn, data);
3892 4102 if (err)
3893 4103 {
3894 4104 zfs_unmount (data);
3895 4105 return err;
3896 4106 }
3897 4107
3898 4108 zap_iterate_u64 (&dn, iterate_zap_snap, data);
3899 4109 }
3900 4110 else
3901 4111 {
3902 4112 if (data->dnode.dn.dn_type != DMU_OT_DIRECTORY_CONTENTS)
3903 4113 {
3904 4114 zfs_unmount (data);
3905 4115 return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory"));
3906 4116 }
3907 4117 zap_iterate_u64 (&(data->dnode), iterate_zap, data);
3908 4118 }
3909 4119 zfs_unmount (data);
3910 4120 return grub_errno;
3911 4121 }
3912 4122
3913 4123 #ifdef GRUB_UTIL
3914 4124 static grub_err_t
3915 4125 grub_zfs_embed (grub_device_t device __attribute__ ((unused)),
3916 4126 unsigned int *nsectors,
3917 4127 unsigned int max_nsectors,
3918 4128 grub_embed_type_t embed_type,
3919 4129 grub_disk_addr_t **sectors)
3920 4130 {
3921 4131 unsigned i;
3922 4132
3923 4133 if (embed_type != GRUB_EMBED_PCBIOS)
3924 4134 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
3925 4135 "ZFS currently supports only PC-BIOS embedding");
3926 4136
3927 4137 if ((VDEV_BOOT_SIZE >> GRUB_DISK_SECTOR_BITS) < *nsectors)
3928 4138 return grub_error (GRUB_ERR_OUT_OF_RANGE,
3929 4139 N_("your core.img is unusually large. "
3930 4140 "It won't fit in the embedding area"));
3931 4141
3932 4142 *nsectors = (VDEV_BOOT_SIZE >> GRUB_DISK_SECTOR_BITS);
3933 4143 if (*nsectors > max_nsectors)
3934 4144 *nsectors = max_nsectors;
3935 4145 *sectors = grub_malloc (*nsectors * sizeof (**sectors));
3936 4146 if (!*sectors)
3937 4147 return grub_errno;
3938 4148 for (i = 0; i < *nsectors; i++)
3939 4149 (*sectors)[i] = i + (VDEV_BOOT_OFFSET >> GRUB_DISK_SECTOR_BITS);
3940 4150
3941 4151 return GRUB_ERR_NONE;
3942 4152 }
3943 4153 #endif
3944 4154
3945 4155 static struct grub_fs grub_zfs_fs = {
3946 4156 .name = "zfs",
3947 4157 .dir = grub_zfs_dir,
3948 4158 .open = grub_zfs_open,
3949 4159 .read = grub_zfs_read,
3950 4160 .close = grub_zfs_close,
3951 4161 .label = zfs_label,
3952 4162 .uuid = zfs_uuid,
3953 4163 .mtime = zfs_mtime,
3954 4164 #ifdef GRUB_UTIL
3955 4165 .embed = grub_zfs_embed,
3956 4166 .reserved_first_sector = 1,
3957 4167 .blocklist_install = 0,
3958 4168 #endif
3959 4169 .next = 0
3960 4170 };
3961 4171
3962 4172 GRUB_MOD_INIT (zfs)
3963 4173 {
3964 4174 COMPILE_TIME_ASSERT (sizeof (zap_leaf_chunk_t) == ZAP_LEAF_CHUNKSIZE);
3965 4175 grub_fs_register (&grub_zfs_fs);
3966 4176 #ifndef GRUB_UTIL
3967 4177 my_mod = mod;
3968 4178 #endif
3969 4179 }
3970 4180
3971 4181 GRUB_MOD_FINI (zfs)
3972 4182 {
3973 4183 grub_fs_unregister (&grub_zfs_fs);
3974 4184 }
↓ open down ↓ |
564 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX