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