Upgraded GRUB2 to 2.00 release.
[AROS.git] / arch / all-pc / boot / grub2-aros / grub-core / fs / zfs / zfs.c
blobba0554abd761dac9b6cbf1a8cdbb6799e01f4568
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.
6 * GRUB is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
20 * The zfs plug-in routines for GRUB are:
22 * zfs_mount() - locates a valid uberblock of the root pool and reads
23 * in its MOS at the memory address MOS.
25 * zfs_open() - locates a plain file object by following the MOS
26 * and places its dnode at the memory address DNODE.
28 * zfs_read() - read in the data blocks pointed by the DNODE.
32 #include <grub/err.h>
33 #include <grub/file.h>
34 #include <grub/mm.h>
35 #include <grub/misc.h>
36 #include <grub/disk.h>
37 #include <grub/partition.h>
38 #include <grub/dl.h>
39 #include <grub/types.h>
40 #include <grub/zfs/zfs.h>
41 #include <grub/zfs/zio.h>
42 #include <grub/zfs/dnode.h>
43 #include <grub/zfs/uberblock_impl.h>
44 #include <grub/zfs/vdev_impl.h>
45 #include <grub/zfs/zio_checksum.h>
46 #include <grub/zfs/zap_impl.h>
47 #include <grub/zfs/zap_leaf.h>
48 #include <grub/zfs/zfs_znode.h>
49 #include <grub/zfs/dmu.h>
50 #include <grub/zfs/dmu_objset.h>
51 #include <grub/zfs/sa_impl.h>
52 #include <grub/zfs/dsl_dir.h>
53 #include <grub/zfs/dsl_dataset.h>
54 #include <grub/deflate.h>
55 #include <grub/crypto.h>
56 #include <grub/i18n.h>
58 GRUB_MOD_LICENSE ("GPLv3+");
60 #define ZPOOL_PROP_BOOTFS "bootfs"
63 * For nvlist manipulation. (from nvpair.h)
65 #define NV_ENCODE_NATIVE 0
66 #define NV_ENCODE_XDR 1
67 #define NV_BIG_ENDIAN 0
68 #define NV_LITTLE_ENDIAN 1
69 #define DATA_TYPE_UINT64 8
70 #define DATA_TYPE_STRING 9
71 #define DATA_TYPE_NVLIST 19
72 #define DATA_TYPE_NVLIST_ARRAY 20
74 #ifndef GRUB_UTIL
75 static grub_dl_t my_mod;
76 #endif
78 #define P2PHASE(x, align) ((x) & ((align) - 1))
80 static inline grub_disk_addr_t
81 DVA_OFFSET_TO_PHYS_SECTOR (grub_disk_addr_t offset)
83 return ((offset + VDEV_LABEL_START_SIZE) >> SPA_MINBLOCKSHIFT);
87 * FAT ZAP data structures
89 #define ZFS_CRC64_POLY 0xC96C5795D7870F42ULL /* ECMA-182, reflected form */
90 static inline grub_uint64_t
91 ZAP_HASH_IDX (grub_uint64_t hash, grub_uint64_t n)
93 return (((n) == 0) ? 0 : ((hash) >> (64 - (n))));
96 #define CHAIN_END 0xffff /* end of the chunk chain */
99 * The amount of space within the chunk available for the array is:
100 * chunk size - space for type (1) - space for next pointer (2)
102 #define ZAP_LEAF_ARRAY_BYTES (ZAP_LEAF_CHUNKSIZE - 3)
104 static inline int
105 ZAP_LEAF_HASH_SHIFT (int bs)
107 return bs - 5;
110 static inline int
111 ZAP_LEAF_HASH_NUMENTRIES (int bs)
113 return 1 << ZAP_LEAF_HASH_SHIFT(bs);
116 static inline grub_size_t
117 LEAF_HASH (int bs, grub_uint64_t h, zap_leaf_phys_t *l)
119 return ((ZAP_LEAF_HASH_NUMENTRIES (bs)-1)
120 & ((h) >> (64 - ZAP_LEAF_HASH_SHIFT (bs) - l->l_hdr.lh_prefix_len)));
124 * The amount of space available for chunks is:
125 * block size shift - hash entry size (2) * number of hash
126 * entries - header space (2*chunksize)
128 static inline int
129 ZAP_LEAF_NUMCHUNKS (int bs)
131 return (((1 << bs) - 2 * ZAP_LEAF_HASH_NUMENTRIES (bs)) /
132 ZAP_LEAF_CHUNKSIZE - 2);
136 * The chunks start immediately after the hash table. The end of the
137 * hash table is at l_hash + HASH_NUMENTRIES, which we simply cast to a
138 * chunk_t.
140 static inline zap_leaf_chunk_t *
141 ZAP_LEAF_CHUNK (zap_leaf_phys_t *l, int bs, int idx)
143 return &((zap_leaf_chunk_t *) (l->l_entries
144 + (ZAP_LEAF_HASH_NUMENTRIES(bs) * 2)
145 / sizeof (grub_properly_aligned_t)))[idx];
148 static inline struct zap_leaf_entry *
149 ZAP_LEAF_ENTRY(zap_leaf_phys_t *l, int bs, int idx)
151 return &ZAP_LEAF_CHUNK(l, bs, idx)->l_entry;
156 * Decompression Entry - lzjb
159 extern grub_err_t lzjb_decompress (void *, void *, grub_size_t, grub_size_t);
161 typedef grub_err_t zfs_decomp_func_t (void *s_start, void *d_start,
162 grub_size_t s_len, grub_size_t d_len);
163 typedef struct decomp_entry
165 const char *name;
166 zfs_decomp_func_t *decomp_func;
167 } decomp_entry_t;
170 * Signature for checksum functions.
172 typedef void zio_checksum_t(const void *data, grub_uint64_t size,
173 grub_zfs_endian_t endian, zio_cksum_t *zcp);
176 * Information about each checksum function.
178 typedef struct zio_checksum_info {
179 zio_checksum_t *ci_func; /* checksum function for each byteorder */
180 int ci_correctable; /* number of correctable bits */
181 int ci_eck; /* uses zio embedded checksum? */
182 const char *ci_name; /* descriptive name */
183 } zio_checksum_info_t;
185 typedef struct dnode_end
187 dnode_phys_t dn;
188 grub_zfs_endian_t endian;
189 } dnode_end_t;
191 struct grub_zfs_device_desc
193 enum { DEVICE_LEAF, DEVICE_MIRROR, DEVICE_RAIDZ } type;
194 grub_uint64_t id;
195 grub_uint64_t guid;
196 unsigned ashift;
197 unsigned max_children_ashift;
199 /* Valid only for non-leafs. */
200 unsigned n_children;
201 struct grub_zfs_device_desc *children;
203 /* Valid only for RAIDZ. */
204 unsigned nparity;
206 /* Valid only for leaf devices. */
207 grub_device_t dev;
208 grub_disk_addr_t vdev_phys_sector;
209 uberblock_t current_uberblock;
210 int original;
213 struct subvolume
215 dnode_end_t mdn;
216 grub_uint64_t obj;
217 grub_uint64_t case_insensitive;
218 grub_size_t nkeys;
219 struct
221 grub_crypto_cipher_handle_t cipher;
222 grub_uint64_t txg;
223 grub_uint64_t algo;
224 } *keyring;
227 struct grub_zfs_data
229 /* cache for a file block of the currently zfs_open()-ed file */
230 char *file_buf;
231 grub_uint64_t file_start;
232 grub_uint64_t file_end;
234 /* cache for a dnode block */
235 dnode_phys_t *dnode_buf;
236 dnode_phys_t *dnode_mdn;
237 grub_uint64_t dnode_start;
238 grub_uint64_t dnode_end;
239 grub_zfs_endian_t dnode_endian;
241 dnode_end_t mos;
242 dnode_end_t dnode;
243 struct subvolume subvol;
245 struct grub_zfs_device_desc *devices_attached;
246 unsigned n_devices_attached;
247 unsigned n_devices_allocated;
248 struct grub_zfs_device_desc *device_original;
250 uberblock_t current_uberblock;
252 int mounted;
253 grub_uint64_t guid;
256 grub_err_t (*grub_zfs_decrypt) (grub_crypto_cipher_handle_t cipher,
257 grub_uint64_t algo,
258 void *nonce,
259 char *buf, grub_size_t size,
260 const grub_uint32_t *expected_mac,
261 grub_zfs_endian_t endian) = NULL;
262 grub_crypto_cipher_handle_t (*grub_zfs_load_key) (const struct grub_zfs_key *key,
263 grub_size_t keysize,
264 grub_uint64_t salt,
265 grub_uint64_t algo) = NULL;
267 static grub_err_t
268 zlib_decompress (void *s, void *d,
269 grub_size_t slen, grub_size_t dlen)
271 if (grub_zlib_decompress (s, slen, 0, d, dlen) < 0)
272 return grub_errno;
273 return GRUB_ERR_NONE;
276 static grub_err_t
277 zle_decompress (void *s, void *d,
278 grub_size_t slen, grub_size_t dlen)
280 grub_uint8_t *iptr, *optr;
281 grub_size_t clen;
282 for (iptr = s, optr = d; iptr < (grub_uint8_t *) s + slen
283 && optr < (grub_uint8_t *) d + dlen;)
285 if (*iptr & 0x80)
286 clen = ((*iptr) & 0x7f) + 0x41;
287 else
288 clen = ((*iptr) & 0x3f) + 1;
289 if ((grub_ssize_t) clen > (grub_uint8_t *) d + dlen - optr)
290 clen = (grub_uint8_t *) d + dlen - optr;
291 if (*iptr & 0x40 || *iptr & 0x80)
293 grub_memset (optr, 0, clen);
294 iptr++;
295 optr += clen;
296 continue;
298 if ((grub_ssize_t) clen > (grub_uint8_t *) s + slen - iptr - 1)
299 clen = (grub_uint8_t *) s + slen - iptr - 1;
300 grub_memcpy (optr, iptr + 1, clen);
301 optr += clen;
302 iptr += clen + 1;
304 if (optr < (grub_uint8_t *) d + dlen)
305 grub_memset (optr, 0, (grub_uint8_t *) d + dlen - optr);
306 return GRUB_ERR_NONE;
309 static decomp_entry_t decomp_table[ZIO_COMPRESS_FUNCTIONS] = {
310 {"inherit", NULL}, /* ZIO_COMPRESS_INHERIT */
311 {"on", lzjb_decompress}, /* ZIO_COMPRESS_ON */
312 {"off", NULL}, /* ZIO_COMPRESS_OFF */
313 {"lzjb", lzjb_decompress}, /* ZIO_COMPRESS_LZJB */
314 {"empty", NULL}, /* ZIO_COMPRESS_EMPTY */
315 {"gzip-1", zlib_decompress}, /* ZIO_COMPRESS_GZIP1 */
316 {"gzip-2", zlib_decompress}, /* ZIO_COMPRESS_GZIP2 */
317 {"gzip-3", zlib_decompress}, /* ZIO_COMPRESS_GZIP3 */
318 {"gzip-4", zlib_decompress}, /* ZIO_COMPRESS_GZIP4 */
319 {"gzip-5", zlib_decompress}, /* ZIO_COMPRESS_GZIP5 */
320 {"gzip-6", zlib_decompress}, /* ZIO_COMPRESS_GZIP6 */
321 {"gzip-7", zlib_decompress}, /* ZIO_COMPRESS_GZIP7 */
322 {"gzip-8", zlib_decompress}, /* ZIO_COMPRESS_GZIP8 */
323 {"gzip-9", zlib_decompress}, /* ZIO_COMPRESS_GZIP9 */
324 {"zle", zle_decompress}, /* ZIO_COMPRESS_ZLE */
327 static grub_err_t zio_read_data (blkptr_t * bp, grub_zfs_endian_t endian,
328 void *buf, struct grub_zfs_data *data);
331 * Our own version of log2(). Same thing as highbit()-1.
333 static int
334 zfs_log2 (grub_uint64_t num)
336 int i = 0;
338 while (num > 1)
340 i++;
341 num = num >> 1;
344 return (i);
347 /* Checksum Functions */
348 static void
349 zio_checksum_off (const void *buf __attribute__ ((unused)),
350 grub_uint64_t size __attribute__ ((unused)),
351 grub_zfs_endian_t endian __attribute__ ((unused)),
352 zio_cksum_t * zcp)
354 ZIO_SET_CHECKSUM (zcp, 0, 0, 0, 0);
357 /* Checksum Table and Values */
358 static zio_checksum_info_t zio_checksum_table[ZIO_CHECKSUM_FUNCTIONS] = {
359 {NULL, 0, 0, "inherit"},
360 {NULL, 0, 0, "on"},
361 {zio_checksum_off, 0, 0, "off"},
362 {zio_checksum_SHA256, 1, 1, "label"},
363 {zio_checksum_SHA256, 1, 1, "gang_header"},
364 {NULL, 0, 0, "zilog"},
365 {fletcher_2, 0, 0, "fletcher2"},
366 {fletcher_4, 1, 0, "fletcher4"},
367 {zio_checksum_SHA256, 1, 0, "SHA256"},
368 {NULL, 0, 0, "zilog2"},
369 {zio_checksum_SHA256, 1, 0, "SHA256+MAC"},
373 * zio_checksum_verify: Provides support for checksum verification.
375 * Fletcher2, Fletcher4, and SHA256 are supported.
378 static grub_err_t
379 zio_checksum_verify (zio_cksum_t zc, grub_uint32_t checksum,
380 grub_zfs_endian_t endian,
381 char *buf, grub_size_t size)
383 zio_eck_t *zec = (zio_eck_t *) (buf + size) - 1;
384 zio_checksum_info_t *ci = &zio_checksum_table[checksum];
385 zio_cksum_t actual_cksum, expected_cksum;
387 if (checksum >= ZIO_CHECKSUM_FUNCTIONS || ci->ci_func == NULL)
389 grub_dprintf ("zfs", "unknown checksum function %d\n", checksum);
390 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
391 "unknown checksum function %d", checksum);
394 if (ci->ci_eck)
396 expected_cksum = zec->zec_cksum;
397 zec->zec_cksum = zc;
398 ci->ci_func (buf, size, endian, &actual_cksum);
399 zec->zec_cksum = expected_cksum;
400 zc = expected_cksum;
402 else
403 ci->ci_func (buf, size, endian, &actual_cksum);
405 if (grub_memcmp (&actual_cksum, &zc,
406 checksum != ZIO_CHECKSUM_SHA256_MAC ? 32 : 20) != 0)
408 grub_dprintf ("zfs", "checksum %s verification failed\n", ci->ci_name);
409 grub_dprintf ("zfs", "actual checksum %016llx %016llx %016llx %016llx\n",
410 (unsigned long long) actual_cksum.zc_word[0],
411 (unsigned long long) actual_cksum.zc_word[1],
412 (unsigned long long) actual_cksum.zc_word[2],
413 (unsigned long long) actual_cksum.zc_word[3]);
414 grub_dprintf ("zfs", "expected checksum %016llx %016llx %016llx %016llx\n",
415 (unsigned long long) zc.zc_word[0],
416 (unsigned long long) zc.zc_word[1],
417 (unsigned long long) zc.zc_word[2],
418 (unsigned long long) zc.zc_word[3]);
419 return grub_error (GRUB_ERR_BAD_FS, N_("checksum verification failed"));
422 return GRUB_ERR_NONE;
426 * vdev_uberblock_compare takes two uberblock structures and returns an integer
427 * indicating the more recent of the two.
428 * Return Value = 1 if ub2 is more recent
429 * Return Value = -1 if ub1 is more recent
430 * The most recent uberblock is determined using its transaction number and
431 * timestamp. The uberblock with the highest transaction number is
432 * considered "newer". If the transaction numbers of the two blocks match, the
433 * timestamps are compared to determine the "newer" of the two.
435 static int
436 vdev_uberblock_compare (uberblock_t * ub1, uberblock_t * ub2)
438 grub_zfs_endian_t ub1_endian, ub2_endian;
439 if (grub_zfs_to_cpu64 (ub1->ub_magic, GRUB_ZFS_LITTLE_ENDIAN)
440 == UBERBLOCK_MAGIC)
441 ub1_endian = GRUB_ZFS_LITTLE_ENDIAN;
442 else
443 ub1_endian = GRUB_ZFS_BIG_ENDIAN;
444 if (grub_zfs_to_cpu64 (ub2->ub_magic, GRUB_ZFS_LITTLE_ENDIAN)
445 == UBERBLOCK_MAGIC)
446 ub2_endian = GRUB_ZFS_LITTLE_ENDIAN;
447 else
448 ub2_endian = GRUB_ZFS_BIG_ENDIAN;
450 if (grub_zfs_to_cpu64 (ub1->ub_txg, ub1_endian)
451 < grub_zfs_to_cpu64 (ub2->ub_txg, ub2_endian))
452 return (-1);
453 if (grub_zfs_to_cpu64 (ub1->ub_txg, ub1_endian)
454 > grub_zfs_to_cpu64 (ub2->ub_txg, ub2_endian))
455 return (1);
457 if (grub_zfs_to_cpu64 (ub1->ub_timestamp, ub1_endian)
458 < grub_zfs_to_cpu64 (ub2->ub_timestamp, ub2_endian))
459 return (-1);
460 if (grub_zfs_to_cpu64 (ub1->ub_timestamp, ub1_endian)
461 > grub_zfs_to_cpu64 (ub2->ub_timestamp, ub2_endian))
462 return (1);
464 return (0);
468 * Three pieces of information are needed to verify an uberblock: the magic
469 * number, the version number, and the checksum.
471 * Currently Implemented: version number, magic number, checksum
474 static grub_err_t
475 uberblock_verify (uberblock_phys_t * ub, grub_uint64_t offset,
476 grub_size_t s)
478 uberblock_t *uber = &ub->ubp_uberblock;
479 grub_err_t err;
480 grub_zfs_endian_t endian = GRUB_ZFS_UNKNOWN_ENDIAN;
481 zio_cksum_t zc;
483 if (grub_zfs_to_cpu64 (uber->ub_magic, GRUB_ZFS_LITTLE_ENDIAN)
484 == UBERBLOCK_MAGIC
485 && grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_LITTLE_ENDIAN) > 0
486 && grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_LITTLE_ENDIAN)
487 <= SPA_VERSION)
488 endian = GRUB_ZFS_LITTLE_ENDIAN;
490 if (grub_zfs_to_cpu64 (uber->ub_magic, GRUB_ZFS_BIG_ENDIAN) == UBERBLOCK_MAGIC
491 && grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_BIG_ENDIAN) > 0
492 && grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_BIG_ENDIAN)
493 <= SPA_VERSION)
494 endian = GRUB_ZFS_BIG_ENDIAN;
496 if (endian == GRUB_ZFS_UNKNOWN_ENDIAN)
497 return grub_error (GRUB_ERR_BAD_FS, "invalid uberblock magic");
499 grub_memset (&zc, 0, sizeof (zc));
501 zc.zc_word[0] = grub_cpu_to_zfs64 (offset, endian);
502 err = zio_checksum_verify (zc, ZIO_CHECKSUM_LABEL, endian,
503 (char *) ub, s);
505 return err;
509 * Find the best uberblock.
510 * Return:
511 * Success - Pointer to the best uberblock.
512 * Failure - NULL
514 static uberblock_phys_t *
515 find_bestub (uberblock_phys_t * ub_array,
516 const struct grub_zfs_device_desc *desc)
518 uberblock_phys_t *ubbest = NULL, *ubptr;
519 int i;
520 grub_disk_addr_t offset;
521 grub_err_t err = GRUB_ERR_NONE;
522 int ub_shift;
524 ub_shift = desc->ashift;
525 if (ub_shift < VDEV_UBERBLOCK_SHIFT)
526 ub_shift = VDEV_UBERBLOCK_SHIFT;
528 for (i = 0; i < (VDEV_UBERBLOCK_RING >> ub_shift); i++)
530 offset = (desc->vdev_phys_sector << SPA_MINBLOCKSHIFT) + VDEV_PHYS_SIZE
531 + (i << ub_shift);
533 ubptr = (uberblock_phys_t *) ((grub_properly_aligned_t *) ub_array
534 + ((i << ub_shift)
535 / sizeof (grub_properly_aligned_t)));
536 err = uberblock_verify (ubptr, offset, 1 << ub_shift);
537 if (err)
539 grub_errno = GRUB_ERR_NONE;
540 continue;
542 if (ubbest == NULL
543 || vdev_uberblock_compare (&(ubptr->ubp_uberblock),
544 &(ubbest->ubp_uberblock)) > 0)
545 ubbest = ubptr;
547 if (!ubbest)
548 grub_errno = err;
550 return (ubbest);
553 static inline grub_size_t
554 get_psize (blkptr_t * bp, grub_zfs_endian_t endian)
556 return ((((grub_zfs_to_cpu64 ((bp)->blk_prop, endian) >> 16) & 0xffff) + 1)
557 << SPA_MINBLOCKSHIFT);
560 static grub_uint64_t
561 dva_get_offset (const dva_t *dva, grub_zfs_endian_t endian)
563 grub_dprintf ("zfs", "dva=%llx, %llx\n",
564 (unsigned long long) dva->dva_word[0],
565 (unsigned long long) dva->dva_word[1]);
566 return grub_zfs_to_cpu64 ((dva)->dva_word[1],
567 endian) << SPA_MINBLOCKSHIFT;
570 static grub_err_t
571 zfs_fetch_nvlist (struct grub_zfs_device_desc *diskdesc, char **nvlist)
573 grub_err_t err;
575 *nvlist = 0;
577 if (!diskdesc->dev)
578 return grub_error (GRUB_ERR_BUG, "member drive unknown");
580 *nvlist = grub_malloc (VDEV_PHYS_SIZE);
582 /* Read in the vdev name-value pair list (112K). */
583 err = grub_disk_read (diskdesc->dev->disk, diskdesc->vdev_phys_sector, 0,
584 VDEV_PHYS_SIZE, *nvlist);
585 if (err)
587 grub_free (*nvlist);
588 *nvlist = 0;
589 return err;
591 return GRUB_ERR_NONE;
594 static grub_err_t
595 fill_vdev_info_real (struct grub_zfs_data *data,
596 const char *nvlist,
597 struct grub_zfs_device_desc *fill,
598 struct grub_zfs_device_desc *insert,
599 int *inserted,
600 unsigned ashift)
602 char *type;
604 type = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_TYPE);
606 if (!type)
607 return grub_errno;
609 if (!grub_zfs_nvlist_lookup_uint64 (nvlist, "id", &(fill->id)))
611 grub_free (type);
612 return grub_error (GRUB_ERR_BAD_FS, "couldn't find vdev id");
615 if (!grub_zfs_nvlist_lookup_uint64 (nvlist, "guid", &(fill->guid)))
617 grub_free (type);
618 return grub_error (GRUB_ERR_BAD_FS, "couldn't find vdev id");
622 grub_uint64_t par;
623 if (grub_zfs_nvlist_lookup_uint64 (nvlist, "ashift", &par))
624 fill->ashift = par;
625 else if (ashift != 0xffffffff)
626 fill->ashift = ashift;
627 else
629 grub_free (type);
630 return grub_error (GRUB_ERR_BAD_FS, "couldn't find ashift");
634 fill->max_children_ashift = 0;
636 if (grub_strcmp (type, VDEV_TYPE_DISK) == 0
637 || grub_strcmp (type, VDEV_TYPE_FILE) == 0)
639 fill->type = DEVICE_LEAF;
641 if (!fill->dev && fill->guid == insert->guid)
643 fill->dev = insert->dev;
644 fill->vdev_phys_sector = insert->vdev_phys_sector;
645 fill->current_uberblock = insert->current_uberblock;
646 fill->original = insert->original;
647 if (!data->device_original)
648 data->device_original = fill;
649 insert->ashift = fill->ashift;
650 *inserted = 1;
653 grub_free (type);
655 return GRUB_ERR_NONE;
658 if (grub_strcmp (type, VDEV_TYPE_MIRROR) == 0
659 || grub_strcmp (type, VDEV_TYPE_RAIDZ) == 0)
661 int nelm, i;
663 if (grub_strcmp (type, VDEV_TYPE_MIRROR) == 0)
664 fill->type = DEVICE_MIRROR;
665 else
667 grub_uint64_t par;
668 fill->type = DEVICE_RAIDZ;
669 if (!grub_zfs_nvlist_lookup_uint64 (nvlist, "nparity", &par))
671 grub_free (type);
672 return grub_error (GRUB_ERR_BAD_FS, "couldn't find raidz parity");
674 fill->nparity = par;
677 nelm = grub_zfs_nvlist_lookup_nvlist_array_get_nelm (nvlist,
678 ZPOOL_CONFIG_CHILDREN);
680 if (nelm <= 0)
682 grub_free (type);
683 return grub_error (GRUB_ERR_BAD_FS, "incorrect mirror VDEV");
686 if (!fill->children)
688 fill->n_children = nelm;
690 fill->children = grub_zalloc (fill->n_children
691 * sizeof (fill->children[0]));
694 for (i = 0; i < nelm; i++)
696 char *child;
697 grub_err_t err;
699 child = grub_zfs_nvlist_lookup_nvlist_array
700 (nvlist, ZPOOL_CONFIG_CHILDREN, i);
702 err = fill_vdev_info_real (data, child, &fill->children[i], insert,
703 inserted, fill->ashift);
705 grub_free (child);
707 if (err)
709 grub_free (type);
710 return err;
712 if (fill->children[i].ashift > fill->max_children_ashift)
713 fill->max_children_ashift = fill->children[i].ashift;
715 grub_free (type);
716 return GRUB_ERR_NONE;
719 grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "vdev %s isn't supported", type);
720 grub_free (type);
721 return grub_errno;
724 static grub_err_t
725 fill_vdev_info (struct grub_zfs_data *data,
726 char *nvlist, struct grub_zfs_device_desc *diskdesc,
727 int *inserted)
729 grub_uint64_t id;
730 unsigned i;
732 *inserted = 0;
734 if (!grub_zfs_nvlist_lookup_uint64 (nvlist, "id", &id))
735 return grub_error (GRUB_ERR_BAD_FS, "couldn't find vdev id");
737 for (i = 0; i < data->n_devices_attached; i++)
738 if (data->devices_attached[i].id == id)
739 return fill_vdev_info_real (data, nvlist, &data->devices_attached[i],
740 diskdesc, inserted, 0xffffffff);
742 data->n_devices_attached++;
743 if (data->n_devices_attached > data->n_devices_allocated)
745 void *tmp;
746 data->n_devices_allocated = 2 * data->n_devices_attached + 1;
747 data->devices_attached
748 = grub_realloc (tmp = data->devices_attached,
749 data->n_devices_allocated
750 * sizeof (data->devices_attached[0]));
751 if (!data->devices_attached)
753 data->devices_attached = tmp;
754 return grub_errno;
758 grub_memset (&data->devices_attached[data->n_devices_attached - 1],
759 0, sizeof (data->devices_attached[data->n_devices_attached - 1]));
761 return fill_vdev_info_real (data, nvlist,
762 &data->devices_attached[data->n_devices_attached - 1],
763 diskdesc, inserted, 0xffffffff);
767 * Check the disk label information and retrieve needed vdev name-value pairs.
770 static grub_err_t
771 check_pool_label (struct grub_zfs_data *data,
772 struct grub_zfs_device_desc *diskdesc,
773 int *inserted)
775 grub_uint64_t pool_state, txg = 0;
776 char *nvlist;
777 #if 0
778 char *nv;
779 #endif
780 grub_uint64_t poolguid;
781 grub_uint64_t version;
782 int found;
783 grub_err_t err;
785 *inserted = 0;
787 err = zfs_fetch_nvlist (diskdesc, &nvlist);
788 if (err)
789 return err;
791 grub_dprintf ("zfs", "check 2 passed\n");
793 found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_STATE,
794 &pool_state);
795 if (! found)
797 grub_free (nvlist);
798 if (! grub_errno)
799 grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_POOL_STATE " not found");
800 return grub_errno;
802 grub_dprintf ("zfs", "check 3 passed\n");
804 if (pool_state == POOL_STATE_DESTROYED)
806 grub_free (nvlist);
807 return grub_error (GRUB_ERR_BAD_FS, "zpool is marked as destroyed");
809 grub_dprintf ("zfs", "check 4 passed\n");
811 found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_TXG, &txg);
812 if (!found)
814 grub_free (nvlist);
815 if (! grub_errno)
816 grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_POOL_TXG " not found");
817 return grub_errno;
819 grub_dprintf ("zfs", "check 6 passed\n");
821 /* not an active device */
822 if (txg == 0)
824 grub_free (nvlist);
825 return grub_error (GRUB_ERR_BAD_FS, "zpool isn't active");
827 grub_dprintf ("zfs", "check 7 passed\n");
829 found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_VERSION,
830 &version);
831 if (! found)
833 grub_free (nvlist);
834 if (! grub_errno)
835 grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_VERSION " not found");
836 return grub_errno;
838 grub_dprintf ("zfs", "check 8 passed\n");
840 if (version > SPA_VERSION)
842 grub_free (nvlist);
843 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
844 "too new version %llu > %llu",
845 (unsigned long long) version,
846 (unsigned long long) SPA_VERSION);
848 grub_dprintf ("zfs", "check 9 passed\n");
850 found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_GUID,
851 &(diskdesc->guid));
852 if (! found)
854 grub_free (nvlist);
855 if (! grub_errno)
856 grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_GUID " not found");
857 return grub_errno;
860 found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_GUID,
861 &poolguid);
862 if (! found)
864 grub_free (nvlist);
865 if (! grub_errno)
866 grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_POOL_GUID " not found");
867 return grub_errno;
870 grub_dprintf ("zfs", "check 11 passed\n");
872 if (data->mounted && data->guid != poolguid)
873 return grub_error (GRUB_ERR_BAD_FS, "another zpool");
874 else
875 data->guid = poolguid;
878 char *nv;
879 nv = grub_zfs_nvlist_lookup_nvlist (nvlist, ZPOOL_CONFIG_VDEV_TREE);
881 if (!nv)
883 grub_free (nvlist);
884 return grub_error (GRUB_ERR_BAD_FS, "couldn't find vdev tree");
886 err = fill_vdev_info (data, nv, diskdesc, inserted);
887 if (err)
889 grub_free (nv);
890 grub_free (nvlist);
891 return err;
893 grub_free (nv);
895 grub_dprintf ("zfs", "check 10 passed\n");
897 grub_free (nvlist);
899 return GRUB_ERR_NONE;
902 static grub_err_t
903 scan_disk (grub_device_t dev, struct grub_zfs_data *data,
904 int original, int *inserted)
906 int label = 0;
907 uberblock_phys_t *ub_array, *ubbest = NULL;
908 vdev_boot_header_t *bh;
909 grub_err_t err;
910 int vdevnum;
911 struct grub_zfs_device_desc desc;
913 ub_array = grub_malloc (VDEV_UBERBLOCK_RING);
914 if (!ub_array)
915 return grub_errno;
917 bh = grub_malloc (VDEV_BOOT_HEADER_SIZE);
918 if (!bh)
920 grub_free (ub_array);
921 return grub_errno;
924 vdevnum = VDEV_LABELS;
926 desc.dev = dev;
927 desc.original = original;
929 /* Don't check back labels on CDROM. */
930 if (grub_disk_get_size (dev->disk) == GRUB_DISK_SIZE_UNKNOWN)
931 vdevnum = VDEV_LABELS / 2;
933 for (label = 0; ubbest == NULL && label < vdevnum; label++)
935 desc.vdev_phys_sector
936 = label * (sizeof (vdev_label_t) >> SPA_MINBLOCKSHIFT)
937 + ((VDEV_SKIP_SIZE + VDEV_BOOT_HEADER_SIZE) >> SPA_MINBLOCKSHIFT)
938 + (label < VDEV_LABELS / 2 ? 0 :
939 ALIGN_DOWN (grub_disk_get_size (dev->disk), sizeof (vdev_label_t))
940 - VDEV_LABELS * (sizeof (vdev_label_t) >> SPA_MINBLOCKSHIFT));
942 /* Read in the uberblock ring (128K). */
943 err = grub_disk_read (dev->disk, desc.vdev_phys_sector
944 + (VDEV_PHYS_SIZE >> SPA_MINBLOCKSHIFT),
945 0, VDEV_UBERBLOCK_RING, (char *) ub_array);
946 if (err)
948 grub_errno = GRUB_ERR_NONE;
949 continue;
951 grub_dprintf ("zfs", "label ok %d\n", label);
953 err = check_pool_label (data, &desc, inserted);
954 if (err || !*inserted)
956 grub_errno = GRUB_ERR_NONE;
957 continue;
960 ubbest = find_bestub (ub_array, &desc);
961 if (!ubbest)
963 grub_dprintf ("zfs", "No uberblock found\n");
964 grub_errno = GRUB_ERR_NONE;
965 continue;
968 grub_memmove (&(desc.current_uberblock),
969 &ubbest->ubp_uberblock, sizeof (uberblock_t));
970 if (original)
971 grub_memmove (&(data->current_uberblock),
972 &ubbest->ubp_uberblock, sizeof (uberblock_t));
974 #if 0
975 if (find_best_root &&
976 vdev_uberblock_compare (&ubbest->ubp_uberblock,
977 &(current_uberblock)) <= 0)
978 continue;
979 #endif
980 grub_free (ub_array);
981 grub_free (bh);
982 return GRUB_ERR_NONE;
985 grub_free (ub_array);
986 grub_free (bh);
988 return grub_error (GRUB_ERR_BAD_FS, "couldn't find a valid label");
991 static grub_err_t
992 scan_devices (struct grub_zfs_data *data)
994 auto int hook (const char *name);
995 int hook (const char *name)
997 grub_device_t dev;
998 grub_err_t err;
999 int inserted;
1000 dev = grub_device_open (name);
1001 if (!dev)
1002 return 0;
1003 if (!dev->disk)
1005 grub_device_close (dev);
1006 return 0;
1008 err = scan_disk (dev, data, 0, &inserted);
1009 if (err == GRUB_ERR_BAD_FS)
1011 grub_device_close (dev);
1012 grub_errno = GRUB_ERR_NONE;
1013 return 0;
1015 if (err)
1017 grub_device_close (dev);
1018 grub_print_error ();
1019 return 0;
1022 if (!inserted)
1023 grub_device_close (dev);
1025 return 0;
1027 grub_device_iterate (hook);
1028 return GRUB_ERR_NONE;
1031 /* x**y. */
1032 static grub_uint8_t powx[255 * 2];
1033 /* Such an s that x**s = y */
1034 static int powx_inv[256];
1035 static const grub_uint8_t poly = 0x1d;
1037 /* perform the operation a ^= b * (x ** (known_idx * recovery_pow) ) */
1038 static inline void
1039 xor_out (grub_uint8_t *a, const grub_uint8_t *b, grub_size_t s,
1040 int known_idx, int recovery_pow)
1042 int add;
1044 /* Simple xor. */
1045 if (known_idx == 0 || recovery_pow == 0)
1047 grub_crypto_xor (a, a, b, s);
1048 return;
1050 add = (known_idx * recovery_pow) % 255;
1051 for (;s--; b++, a++)
1052 if (*b)
1053 *a ^= powx[powx_inv[*b] + add];
1056 static inline grub_uint8_t
1057 gf_mul (grub_uint8_t a, grub_uint8_t b)
1059 if (a == 0 || b == 0)
1060 return 0;
1061 return powx[powx_inv[a] + powx_inv[b]];
1064 static inline grub_err_t
1065 recovery (grub_uint8_t *bufs[4], grub_size_t s, const int nbufs,
1066 const unsigned *powers,
1067 const int *idx)
1069 grub_dprintf ("zfs", "recovering %u buffers\n", nbufs);
1070 /* Now we have */
1071 /* b_i = sum (r_j* (x ** (powers[i] * idx[j])))*/
1072 /* Let's invert the matrix in question. */
1073 switch (nbufs)
1075 /* Easy: r_0 = bufs[0] / (x << (powers[i] * idx[j])). */
1076 case 1:
1078 int add;
1079 grub_uint8_t *a;
1080 if (powers[0] == 0 || idx[0] == 0)
1081 return GRUB_ERR_NONE;
1082 add = 255 - ((powers[0] * idx[0]) % 255);
1083 for (a = bufs[0]; s--; a++)
1084 if (*a)
1085 *a = powx[powx_inv[*a] + add];
1086 return GRUB_ERR_NONE;
1088 /* Case 2x2: Let's use the determinant formula. */
1089 case 2:
1091 grub_uint8_t det, det_inv;
1092 grub_uint8_t matrixinv[2][2];
1093 unsigned i;
1094 /* The determinant is: */
1095 det = (powx[(powers[0] * idx[0] + powers[1] * idx[1]) % 255]
1096 ^ powx[(powers[0] * idx[1] + powers[1] * idx[0]) % 255]);
1097 if (det == 0)
1098 return grub_error (GRUB_ERR_BAD_FS, "singular recovery matrix");
1099 det_inv = powx[255 - powx_inv[det]];
1100 matrixinv[0][0] = gf_mul (powx[(powers[1] * idx[1]) % 255], det_inv);
1101 matrixinv[1][1] = gf_mul (powx[(powers[0] * idx[0]) % 255], det_inv);
1102 matrixinv[0][1] = gf_mul (powx[(powers[0] * idx[1]) % 255], det_inv);
1103 matrixinv[1][0] = gf_mul (powx[(powers[1] * idx[0]) % 255], det_inv);
1104 for (i = 0; i < s; i++)
1106 grub_uint8_t b0, b1;
1107 b0 = bufs[0][i];
1108 b1 = bufs[1][i];
1110 bufs[0][i] = (gf_mul (b0, matrixinv[0][0])
1111 ^ gf_mul (b1, matrixinv[0][1]));
1112 bufs[1][i] = (gf_mul (b0, matrixinv[1][0])
1113 ^ gf_mul (b1, matrixinv[1][1]));
1115 return GRUB_ERR_NONE;
1117 /* Otherwise use Gauss. */
1118 default:
1120 grub_uint8_t matrix1[nbufs][nbufs], matrix2[nbufs][nbufs];
1121 int i, j, k;
1123 for (i = 0; i < nbufs; i++)
1124 for (j = 0; j < nbufs; j++)
1125 matrix1[i][j] = powx[(powers[i] * idx[j]) % 255];
1126 for (i = 0; i < nbufs; i++)
1127 for (j = 0; j < nbufs; j++)
1128 matrix2[i][j] = 0;
1129 for (i = 0; i < nbufs; i++)
1130 matrix2[i][i] = 1;
1132 for (i = 0; i < nbufs; i++)
1134 grub_uint8_t mul;
1135 for (j = i; j < nbufs; j++)
1136 if (matrix1[i][j])
1137 break;
1138 if (j == nbufs)
1139 return grub_error (GRUB_ERR_BAD_FS, "singular recovery matrix");
1140 if (j != i)
1142 int xchng;
1143 xchng = j;
1144 for (j = 0; j < nbufs; j++)
1146 grub_uint8_t t;
1147 t = matrix1[xchng][j];
1148 matrix1[xchng][j] = matrix1[i][j];
1149 matrix1[i][j] = t;
1151 for (j = 0; j < nbufs; j++)
1153 grub_uint8_t t;
1154 t = matrix2[xchng][j];
1155 matrix2[xchng][j] = matrix2[i][j];
1156 matrix2[i][j] = t;
1159 mul = powx[255 - powx_inv[matrix1[i][i]]];
1160 for (j = 0; j < nbufs; j++)
1161 matrix1[i][j] = gf_mul (matrix1[i][j], mul);
1162 for (j = 0; j < nbufs; j++)
1163 matrix2[i][j] = gf_mul (matrix2[i][j], mul);
1164 for (j = i + 1; j < nbufs; j++)
1166 mul = matrix1[j][i];
1167 for (k = 0; k < nbufs; k++)
1168 matrix1[j][k] ^= gf_mul (matrix1[i][k], mul);
1169 for (k = 0; k < nbufs; k++)
1170 matrix2[j][k] ^= gf_mul (matrix2[i][k], mul);
1173 for (i = nbufs - 1; i >= 0; i--)
1175 for (j = 0; j < i; j++)
1177 grub_uint8_t mul;
1178 mul = matrix1[j][i];
1179 for (k = 0; k < nbufs; k++)
1180 matrix1[j][k] ^= gf_mul (matrix1[i][k], mul);
1181 for (k = 0; k < nbufs; k++)
1182 matrix2[j][k] ^= gf_mul (matrix2[i][k], mul);
1186 for (i = 0; i < (int) s; i++)
1188 grub_uint8_t b[nbufs];
1189 for (j = 0; j < nbufs; j++)
1190 b[j] = bufs[j][i];
1191 for (j = 0; j < nbufs; j++)
1193 bufs[j][i] = 0;
1194 for (k = 0; k < nbufs; k++)
1195 bufs[j][i] ^= gf_mul (matrix2[j][k], b[k]);
1198 return GRUB_ERR_NONE;
1203 static grub_err_t
1204 read_device (grub_uint64_t offset, struct grub_zfs_device_desc *desc,
1205 grub_size_t len, void *buf)
1207 switch (desc->type)
1209 case DEVICE_LEAF:
1211 grub_uint64_t sector;
1212 sector = DVA_OFFSET_TO_PHYS_SECTOR (offset);
1213 if (!desc->dev)
1215 return grub_error (GRUB_ERR_BAD_FS,
1216 N_("couldn't find a necessary member device "
1217 "of multi-device filesystem"));
1219 /* read in a data block */
1220 return grub_disk_read (desc->dev->disk, sector, 0, len, buf);
1222 case DEVICE_MIRROR:
1224 grub_err_t err = GRUB_ERR_NONE;
1225 unsigned i;
1226 if (desc->n_children <= 0)
1227 return grub_error (GRUB_ERR_BAD_FS,
1228 "non-positive number of mirror children");
1229 for (i = 0; i < desc->n_children; i++)
1231 err = read_device (offset, &desc->children[i],
1232 len, buf);
1233 if (!err)
1234 break;
1235 grub_errno = GRUB_ERR_NONE;
1237 return (grub_errno = err);
1239 case DEVICE_RAIDZ:
1241 unsigned c = 0;
1242 grub_uint64_t high;
1243 grub_uint64_t devn;
1244 grub_uint64_t m;
1245 grub_uint32_t s, orig_s;
1246 void *orig_buf = buf;
1247 grub_size_t orig_len = len;
1248 grub_uint8_t *recovery_buf[4];
1249 grub_size_t recovery_len[4];
1250 int recovery_idx[4];
1251 unsigned failed_devices = 0;
1252 int idx, orig_idx;
1254 if (desc->nparity < 1 || desc->nparity > 3)
1255 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
1256 "raidz%d is not supported", desc->nparity);
1258 orig_s = (((len + (1 << desc->ashift) - 1) >> desc->ashift)
1259 + (desc->n_children - desc->nparity) - 1);
1260 s = orig_s;
1262 high = grub_divmod64 ((offset >> desc->ashift),
1263 desc->n_children, &m);
1264 if (desc->nparity == 2)
1265 c = 2;
1266 if (desc->nparity == 3)
1267 c = 3;
1268 if (((len + (1 << desc->ashift) - 1) >> desc->ashift)
1269 >= (desc->n_children - desc->nparity))
1270 idx = (desc->n_children - desc->nparity - 1);
1271 else
1272 idx = ((len + (1 << desc->ashift) - 1) >> desc->ashift) - 1;
1273 orig_idx = idx;
1274 while (len > 0)
1276 grub_size_t csize;
1277 grub_uint32_t bsize;
1278 grub_err_t err;
1279 bsize = s / (desc->n_children - desc->nparity);
1281 if (desc->nparity == 1
1282 && ((offset >> (desc->ashift + 20 - desc->max_children_ashift))
1283 & 1) == c)
1284 c++;
1286 high = grub_divmod64 ((offset >> desc->ashift) + c,
1287 desc->n_children, &devn);
1288 csize = bsize << desc->ashift;
1289 if (csize > len)
1290 csize = len;
1292 grub_dprintf ("zfs", "RAIDZ mapping 0x%" PRIxGRUB_UINT64_T
1293 "+%u (%" PRIxGRUB_SIZE ", %" PRIxGRUB_UINT32_T
1294 ") -> (0x%" PRIxGRUB_UINT64_T ", 0x%"
1295 PRIxGRUB_UINT64_T ")\n",
1296 offset >> desc->ashift, c, len, bsize, high,
1297 devn);
1298 err = read_device ((high << desc->ashift)
1299 | (offset & ((1 << desc->ashift) - 1)),
1300 &desc->children[devn],
1301 csize, buf);
1302 if (err && failed_devices < desc->nparity)
1304 recovery_buf[failed_devices] = buf;
1305 recovery_len[failed_devices] = csize;
1306 recovery_idx[failed_devices] = idx;
1307 failed_devices++;
1308 grub_errno = err = 0;
1310 if (err)
1311 return err;
1313 c++;
1314 idx--;
1315 s--;
1316 buf = (char *) buf + csize;
1317 len -= csize;
1319 if (failed_devices)
1321 unsigned redundancy_pow[4];
1322 unsigned cur_redundancy_pow = 0;
1323 unsigned n_redundancy = 0;
1324 unsigned i, j;
1325 grub_err_t err;
1327 /* Compute mul. x**s has a period of 255. */
1328 if (powx[0] == 0)
1330 grub_uint8_t cur = 1;
1331 for (i = 0; i < 255; i++)
1333 powx[i] = cur;
1334 powx[i + 255] = cur;
1335 powx_inv[cur] = i;
1336 if (cur & 0x80)
1337 cur = (cur << 1) ^ poly;
1338 else
1339 cur <<= 1;
1343 /* Read redundancy data. */
1344 for (n_redundancy = 0, cur_redundancy_pow = 0;
1345 n_redundancy < failed_devices;
1346 cur_redundancy_pow++)
1348 high = grub_divmod64 ((offset >> desc->ashift)
1349 + cur_redundancy_pow
1350 + ((desc->nparity == 1)
1351 && ((offset >> (desc->ashift + 20
1352 - desc->max_children_ashift))
1353 & 1)),
1354 desc->n_children, &devn);
1355 err = read_device ((high << desc->ashift)
1356 | (offset & ((1 << desc->ashift) - 1)),
1357 &desc->children[devn],
1358 recovery_len[n_redundancy],
1359 recovery_buf[n_redundancy]);
1360 /* Ignore error if we may still have enough devices. */
1361 if (err && n_redundancy + desc->nparity - cur_redundancy_pow - 1
1362 >= failed_devices)
1364 grub_errno = GRUB_ERR_NONE;
1365 continue;
1367 if (err)
1368 return err;
1369 redundancy_pow[n_redundancy] = cur_redundancy_pow;
1370 n_redundancy++;
1372 /* Now xor-our the parts we already know. */
1373 buf = orig_buf;
1374 len = orig_len;
1375 s = orig_s;
1376 idx = orig_idx;
1378 while (len > 0)
1380 grub_size_t csize;
1381 csize = ((s / (desc->n_children - desc->nparity))
1382 << desc->ashift);
1383 if (csize > len)
1384 csize = len;
1386 for (j = 0; j < failed_devices; j++)
1387 if (buf == recovery_buf[j])
1388 break;
1390 if (j == failed_devices)
1391 for (j = 0; j < failed_devices; j++)
1392 xor_out (recovery_buf[j], buf,
1393 csize < recovery_len[j] ? csize : recovery_len[j],
1394 idx, redundancy_pow[j]);
1396 s--;
1397 buf = (char *) buf + csize;
1398 len -= csize;
1399 idx--;
1401 for (i = 0; i < failed_devices
1402 && recovery_len[i] == recovery_len[0];
1403 i++);
1404 /* Since the chunks have variable length handle the last block
1405 separately. */
1406 if (i != failed_devices)
1408 grub_uint8_t *tmp_recovery_buf[4];
1409 for (j = 0; j < i; j++)
1410 tmp_recovery_buf[j] = recovery_buf[j] + recovery_len[failed_devices - 1];
1411 err = recovery (tmp_recovery_buf, recovery_len[0] - recovery_len[failed_devices - 1], i, redundancy_pow,
1412 recovery_idx);
1413 if (err)
1414 return err;
1416 err = recovery (recovery_buf, recovery_len[failed_devices - 1],
1417 failed_devices, redundancy_pow, recovery_idx);
1418 if (err)
1419 return err;
1421 return GRUB_ERR_NONE;
1424 return grub_error (GRUB_ERR_BAD_FS, "unsupported device type");
1427 static grub_err_t
1428 read_dva (const dva_t *dva,
1429 grub_zfs_endian_t endian, struct grub_zfs_data *data,
1430 void *buf, grub_size_t len)
1432 grub_uint64_t offset;
1433 unsigned i;
1434 grub_err_t err = 0;
1435 int try = 0;
1436 offset = dva_get_offset (dva, endian);
1438 for (try = 0; try < 2; try++)
1440 for (i = 0; i < data->n_devices_attached; i++)
1441 if (data->devices_attached[i].id == DVA_GET_VDEV (dva))
1443 err = read_device (offset, &data->devices_attached[i], len, buf);
1444 if (!err)
1445 return GRUB_ERR_NONE;
1446 break;
1448 if (try == 1)
1449 break;
1450 err = scan_devices (data);
1451 if (err)
1452 return err;
1454 if (!err)
1455 return grub_error (GRUB_ERR_BAD_FS, "unknown device %d",
1456 (int) DVA_GET_VDEV (dva));
1457 return err;
1461 * Read a block of data based on the gang block address dva,
1462 * and put its data in buf.
1465 static grub_err_t
1466 zio_read_gang (blkptr_t * bp, grub_zfs_endian_t endian, dva_t * dva, void *buf,
1467 struct grub_zfs_data *data)
1469 zio_gbh_phys_t *zio_gb;
1470 unsigned i;
1471 grub_err_t err;
1472 zio_cksum_t zc;
1474 grub_memset (&zc, 0, sizeof (zc));
1476 zio_gb = grub_malloc (SPA_GANGBLOCKSIZE);
1477 if (!zio_gb)
1478 return grub_errno;
1479 grub_dprintf ("zfs", endian == GRUB_ZFS_LITTLE_ENDIAN ? "little-endian gang\n"
1480 :"big-endian gang\n");
1482 err = read_dva (dva, endian, data, zio_gb, SPA_GANGBLOCKSIZE);
1483 if (err)
1485 grub_free (zio_gb);
1486 return err;
1489 /* XXX */
1490 /* self checksuming the gang block header */
1491 ZIO_SET_CHECKSUM (&zc, DVA_GET_VDEV (dva),
1492 dva_get_offset (dva, endian), bp->blk_birth, 0);
1493 err = zio_checksum_verify (zc, ZIO_CHECKSUM_GANG_HEADER, endian,
1494 (char *) zio_gb, SPA_GANGBLOCKSIZE);
1495 if (err)
1497 grub_free (zio_gb);
1498 return err;
1501 endian = (grub_zfs_to_cpu64 (bp->blk_prop, endian) >> 63) & 1;
1503 for (i = 0; i < SPA_GBH_NBLKPTRS; i++)
1505 if (zio_gb->zg_blkptr[i].blk_birth == 0)
1506 continue;
1508 err = zio_read_data (&zio_gb->zg_blkptr[i], endian, buf, data);
1509 if (err)
1511 grub_free (zio_gb);
1512 return err;
1514 buf = (char *) buf + get_psize (&zio_gb->zg_blkptr[i], endian);
1516 grub_free (zio_gb);
1517 return GRUB_ERR_NONE;
1521 * Read in a block of raw data to buf.
1523 static grub_err_t
1524 zio_read_data (blkptr_t * bp, grub_zfs_endian_t endian, void *buf,
1525 struct grub_zfs_data *data)
1527 int i, psize;
1528 grub_err_t err = GRUB_ERR_NONE;
1530 psize = get_psize (bp, endian);
1532 /* pick a good dva from the block pointer */
1533 for (i = 0; i < SPA_DVAS_PER_BP; i++)
1535 if (bp->blk_dva[i].dva_word[0] == 0 && bp->blk_dva[i].dva_word[1] == 0)
1536 continue;
1538 if ((grub_zfs_to_cpu64 (bp->blk_dva[i].dva_word[1], endian)>>63) & 1)
1539 err = zio_read_gang (bp, endian, &bp->blk_dva[i], buf, data);
1540 else
1541 err = read_dva (&bp->blk_dva[i], endian, data, buf, psize);
1542 if (!err)
1543 return GRUB_ERR_NONE;
1544 grub_errno = GRUB_ERR_NONE;
1547 if (!err)
1548 err = grub_error (GRUB_ERR_BAD_FS, "couldn't find a valid DVA");
1549 grub_errno = err;
1551 return err;
1555 * Read in a block of data, verify its checksum, decompress if needed,
1556 * and put the uncompressed data in buf.
1558 static grub_err_t
1559 zio_read (blkptr_t *bp, grub_zfs_endian_t endian, void **buf,
1560 grub_size_t *size, struct grub_zfs_data *data)
1562 grub_size_t lsize, psize;
1563 unsigned int comp, encrypted;
1564 char *compbuf = NULL;
1565 grub_err_t err;
1566 zio_cksum_t zc = bp->blk_cksum;
1567 grub_uint32_t checksum;
1569 *buf = NULL;
1571 checksum = (grub_zfs_to_cpu64((bp)->blk_prop, endian) >> 40) & 0xff;
1572 comp = (grub_zfs_to_cpu64((bp)->blk_prop, endian)>>32) & 0xff;
1573 encrypted = ((grub_zfs_to_cpu64((bp)->blk_prop, endian) >> 60) & 3);
1574 lsize = (BP_IS_HOLE(bp) ? 0 :
1575 (((grub_zfs_to_cpu64 ((bp)->blk_prop, endian) & 0xffff) + 1)
1576 << SPA_MINBLOCKSHIFT));
1577 psize = get_psize (bp, endian);
1579 if (size)
1580 *size = lsize;
1582 if (comp >= ZIO_COMPRESS_FUNCTIONS)
1583 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
1584 "compression algorithm %u not supported\n", (unsigned int) comp);
1586 if (comp != ZIO_COMPRESS_OFF && decomp_table[comp].decomp_func == NULL)
1587 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
1588 "compression algorithm %s not supported\n", decomp_table[comp].name);
1590 if (comp != ZIO_COMPRESS_OFF)
1592 /* It's not really necessary to align to 16, just for safety. */
1593 compbuf = grub_malloc (ALIGN_UP (psize, 16));
1594 if (! compbuf)
1595 return grub_errno;
1597 else
1598 compbuf = *buf = grub_malloc (lsize);
1600 grub_dprintf ("zfs", "endian = %d\n", endian);
1601 err = zio_read_data (bp, endian, compbuf, data);
1602 if (err)
1604 grub_free (compbuf);
1605 *buf = NULL;
1606 return err;
1608 grub_memset (compbuf, 0, ALIGN_UP (psize, 16) - psize);
1610 err = zio_checksum_verify (zc, checksum, endian,
1611 compbuf, psize);
1612 if (err)
1614 grub_dprintf ("zfs", "incorrect checksum\n");
1615 grub_free (compbuf);
1616 *buf = NULL;
1617 return err;
1620 if (encrypted)
1622 if (!grub_zfs_decrypt)
1623 err = grub_error (GRUB_ERR_BAD_FS,
1624 N_("module `%s' isn't loaded"),
1625 "zfscrypt");
1626 else
1628 unsigned i, besti = 0;
1629 grub_uint64_t bestval = 0;
1630 for (i = 0; i < data->subvol.nkeys; i++)
1631 if (data->subvol.keyring[i].txg <= grub_zfs_to_cpu64 (bp->blk_birth,
1632 endian)
1633 && data->subvol.keyring[i].txg > bestval)
1635 besti = i;
1636 bestval = data->subvol.keyring[i].txg;
1638 if (bestval == 0)
1640 grub_free (compbuf);
1641 *buf = NULL;
1642 grub_dprintf ("zfs", "no key for txg %" PRIxGRUB_UINT64_T "\n",
1643 grub_zfs_to_cpu64 (bp->blk_birth,
1644 endian));
1645 return grub_error (GRUB_ERR_BAD_FS, "no key found in keychain");
1647 grub_dprintf ("zfs", "using key %u (%" PRIxGRUB_UINT64_T
1648 ", %p) for txg %" PRIxGRUB_UINT64_T "\n",
1649 besti, data->subvol.keyring[besti].txg,
1650 data->subvol.keyring[besti].cipher,
1651 grub_zfs_to_cpu64 (bp->blk_birth,
1652 endian));
1653 err = grub_zfs_decrypt (data->subvol.keyring[besti].cipher,
1654 data->subvol.keyring[besti].algo,
1655 &(bp)->blk_dva[encrypted],
1656 compbuf, psize, ((grub_uint32_t *) &zc + 5),
1657 endian);
1659 if (err)
1661 grub_free (compbuf);
1662 *buf = NULL;
1663 return err;
1667 if (comp != ZIO_COMPRESS_OFF)
1669 *buf = grub_malloc (lsize);
1670 if (!*buf)
1672 grub_free (compbuf);
1673 return grub_errno;
1676 err = decomp_table[comp].decomp_func (compbuf, *buf, psize, lsize);
1677 grub_free (compbuf);
1678 if (err)
1680 grub_free (*buf);
1681 *buf = NULL;
1682 return err;
1686 return GRUB_ERR_NONE;
1690 * Get the block from a block id.
1691 * push the block onto the stack.
1694 static grub_err_t
1695 dmu_read (dnode_end_t * dn, grub_uint64_t blkid, void **buf,
1696 grub_zfs_endian_t *endian_out, struct grub_zfs_data *data)
1698 int level;
1699 grub_off_t idx;
1700 blkptr_t *bp_array = dn->dn.dn_blkptr;
1701 int epbs = dn->dn.dn_indblkshift - SPA_BLKPTRSHIFT;
1702 blkptr_t *bp;
1703 void *tmpbuf = 0;
1704 grub_zfs_endian_t endian;
1705 grub_err_t err = GRUB_ERR_NONE;
1707 bp = grub_malloc (sizeof (blkptr_t));
1708 if (!bp)
1709 return grub_errno;
1711 endian = dn->endian;
1712 for (level = dn->dn.dn_nlevels - 1; level >= 0; level--)
1714 grub_dprintf ("zfs", "endian = %d\n", endian);
1715 idx = (blkid >> (epbs * level)) & ((1 << epbs) - 1);
1716 *bp = bp_array[idx];
1717 if (bp_array != dn->dn.dn_blkptr)
1719 grub_free (bp_array);
1720 bp_array = 0;
1723 if (BP_IS_HOLE (bp))
1725 grub_size_t size = grub_zfs_to_cpu16 (dn->dn.dn_datablkszsec,
1726 dn->endian)
1727 << SPA_MINBLOCKSHIFT;
1728 *buf = grub_malloc (size);
1729 if (*buf)
1731 err = grub_errno;
1732 break;
1734 grub_memset (*buf, 0, size);
1735 endian = (grub_zfs_to_cpu64 (bp->blk_prop, endian) >> 63) & 1;
1736 break;
1738 if (level == 0)
1740 grub_dprintf ("zfs", "endian = %d\n", endian);
1741 err = zio_read (bp, endian, buf, 0, data);
1742 endian = (grub_zfs_to_cpu64 (bp->blk_prop, endian) >> 63) & 1;
1743 break;
1745 grub_dprintf ("zfs", "endian = %d\n", endian);
1746 err = zio_read (bp, endian, &tmpbuf, 0, data);
1747 endian = (grub_zfs_to_cpu64 (bp->blk_prop, endian) >> 63) & 1;
1748 if (err)
1749 break;
1750 bp_array = tmpbuf;
1752 if (bp_array != dn->dn.dn_blkptr)
1753 grub_free (bp_array);
1754 if (endian_out)
1755 *endian_out = endian;
1757 grub_free (bp);
1758 return err;
1762 * mzap_lookup: Looks up property described by "name" and returns the value
1763 * in "value".
1765 static grub_err_t
1766 mzap_lookup (mzap_phys_t * zapobj, grub_zfs_endian_t endian,
1767 int objsize, const char *name, grub_uint64_t * value,
1768 int case_insensitive)
1770 int i, chunks;
1771 mzap_ent_phys_t *mzap_ent = zapobj->mz_chunk;
1773 chunks = objsize / MZAP_ENT_LEN - 1;
1774 for (i = 0; i < chunks; i++)
1776 if (case_insensitive ? (grub_strcasecmp (mzap_ent[i].mze_name, name) == 0)
1777 : (grub_strcmp (mzap_ent[i].mze_name, name) == 0))
1779 *value = grub_zfs_to_cpu64 (mzap_ent[i].mze_value, endian);
1780 return GRUB_ERR_NONE;
1784 return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file `%s' not found"), name);
1787 static int
1788 mzap_iterate (mzap_phys_t * zapobj, grub_zfs_endian_t endian, int objsize,
1789 int NESTED_FUNC_ATTR (*hook) (const char *name,
1790 grub_uint64_t val))
1792 int i, chunks;
1793 mzap_ent_phys_t *mzap_ent = zapobj->mz_chunk;
1795 chunks = objsize / MZAP_ENT_LEN - 1;
1796 for (i = 0; i < chunks; i++)
1798 grub_dprintf ("zfs", "zap: name = %s, value = %llx, cd = %x\n",
1799 mzap_ent[i].mze_name, (long long)mzap_ent[i].mze_value,
1800 (int)mzap_ent[i].mze_cd);
1801 if (hook (mzap_ent[i].mze_name,
1802 grub_zfs_to_cpu64 (mzap_ent[i].mze_value, endian)))
1803 return 1;
1806 return 0;
1809 static grub_uint64_t
1810 zap_hash (grub_uint64_t salt, const char *name,
1811 int case_insensitive)
1813 static grub_uint64_t table[256];
1814 const grub_uint8_t *cp;
1815 grub_uint8_t c;
1816 grub_uint64_t crc = salt;
1818 if (table[128] == 0)
1820 grub_uint64_t *ct;
1821 int i, j;
1822 for (i = 0; i < 256; i++)
1824 for (ct = table + i, *ct = i, j = 8; j > 0; j--)
1825 *ct = (*ct >> 1) ^ (-(*ct & 1) & ZFS_CRC64_POLY);
1829 if (case_insensitive)
1830 for (cp = (const grub_uint8_t *) name; (c = *cp) != '\0'; cp++)
1831 crc = (crc >> 8) ^ table[(crc ^ grub_toupper (c)) & 0xFF];
1832 else
1833 for (cp = (const grub_uint8_t *) name; (c = *cp) != '\0'; cp++)
1834 crc = (crc >> 8) ^ table[(crc ^ c) & 0xFF];
1837 * Only use 28 bits, since we need 4 bits in the cookie for the
1838 * collision differentiator. We MUST use the high bits, since
1839 * those are the onces that we first pay attention to when
1840 * chosing the bucket.
1842 crc &= ~((1ULL << (64 - ZAP_HASHBITS)) - 1);
1844 return (crc);
1848 * Only to be used on 8-bit arrays.
1849 * array_len is actual len in bytes (not encoded le_value_length).
1850 * buf is null-terminated.
1853 static inline int
1854 name_cmp (const char *s1, const char *s2, grub_size_t n,
1855 int case_insensitive)
1857 const char *t1 = (const char *) s1;
1858 const char *t2 = (const char *) s2;
1860 if (!case_insensitive)
1861 return grub_memcmp (t1, t2, n);
1863 while (n--)
1865 if (grub_toupper (*t1) != grub_toupper (*t2))
1866 return (int) grub_toupper (*t1) - (int) grub_toupper (*t2);
1868 t1++;
1869 t2++;
1872 return 0;
1875 /* XXX */
1876 static int
1877 zap_leaf_array_equal (zap_leaf_phys_t * l, grub_zfs_endian_t endian,
1878 int blksft, int chunk, grub_size_t array_len,
1879 const char *buf, int case_insensitive)
1881 grub_size_t bseen = 0;
1883 while (bseen < array_len)
1885 struct zap_leaf_array *la = &ZAP_LEAF_CHUNK (l, blksft, chunk)->l_array;
1886 grub_size_t toread = array_len - bseen;
1888 if (toread > ZAP_LEAF_ARRAY_BYTES)
1889 toread = ZAP_LEAF_ARRAY_BYTES;
1891 if (chunk >= ZAP_LEAF_NUMCHUNKS (blksft))
1892 return 0;
1894 if (name_cmp ((char *) la->la_array, buf + bseen, toread,
1895 case_insensitive) != 0)
1896 break;
1897 chunk = grub_zfs_to_cpu16 (la->la_next, endian);
1898 bseen += toread;
1900 return (bseen == array_len);
1903 /* XXX */
1904 static grub_err_t
1905 zap_leaf_array_get (zap_leaf_phys_t * l, grub_zfs_endian_t endian, int blksft,
1906 int chunk, grub_size_t array_len, char *buf)
1908 grub_size_t bseen = 0;
1910 while (bseen < array_len)
1912 struct zap_leaf_array *la = &ZAP_LEAF_CHUNK (l, blksft, chunk)->l_array;
1913 grub_size_t toread = array_len - bseen;
1915 if (toread > ZAP_LEAF_ARRAY_BYTES)
1916 toread = ZAP_LEAF_ARRAY_BYTES;
1918 if (chunk >= ZAP_LEAF_NUMCHUNKS (blksft))
1919 /* Don't use grub_error because this error is to be ignored. */
1920 return GRUB_ERR_BAD_FS;
1922 grub_memcpy (buf + bseen,la->la_array, toread);
1923 chunk = grub_zfs_to_cpu16 (la->la_next, endian);
1924 bseen += toread;
1926 return GRUB_ERR_NONE;
1931 * Given a zap_leaf_phys_t, walk thru the zap leaf chunks to get the
1932 * value for the property "name".
1935 /* XXX */
1936 static grub_err_t
1937 zap_leaf_lookup (zap_leaf_phys_t * l, grub_zfs_endian_t endian,
1938 int blksft, grub_uint64_t h,
1939 const char *name, grub_uint64_t * value,
1940 int case_insensitive)
1942 grub_uint16_t chunk;
1943 struct zap_leaf_entry *le;
1945 /* Verify if this is a valid leaf block */
1946 if (grub_zfs_to_cpu64 (l->l_hdr.lh_block_type, endian) != ZBT_LEAF)
1947 return grub_error (GRUB_ERR_BAD_FS, "invalid leaf type");
1948 if (grub_zfs_to_cpu32 (l->l_hdr.lh_magic, endian) != ZAP_LEAF_MAGIC)
1949 return grub_error (GRUB_ERR_BAD_FS, "invalid leaf magic");
1951 for (chunk = grub_zfs_to_cpu16 (l->l_hash[LEAF_HASH (blksft, h, l)], endian);
1952 chunk != CHAIN_END; chunk = grub_zfs_to_cpu16 (le->le_next, endian))
1955 if (chunk >= ZAP_LEAF_NUMCHUNKS (blksft))
1956 return grub_error (GRUB_ERR_BAD_FS, "invalid chunk number");
1958 le = ZAP_LEAF_ENTRY (l, blksft, chunk);
1960 /* Verify the chunk entry */
1961 if (le->le_type != ZAP_CHUNK_ENTRY)
1962 return grub_error (GRUB_ERR_BAD_FS, "invalid chunk entry");
1964 if (grub_zfs_to_cpu64 (le->le_hash,endian) != h)
1965 continue;
1967 grub_dprintf ("zfs", "fzap: length %d\n", (int) le->le_name_length);
1969 if (zap_leaf_array_equal (l, endian, blksft,
1970 grub_zfs_to_cpu16 (le->le_name_chunk,endian),
1971 grub_zfs_to_cpu16 (le->le_name_length, endian),
1972 name, case_insensitive))
1974 struct zap_leaf_array *la;
1976 if (le->le_int_size != 8 || grub_zfs_to_cpu16 (le->le_value_length,
1977 endian) != 1)
1978 return grub_error (GRUB_ERR_BAD_FS, "invalid leaf chunk entry");
1980 /* get the uint64_t property value */
1981 la = &ZAP_LEAF_CHUNK (l, blksft, le->le_value_chunk)->l_array;
1983 *value = grub_be_to_cpu64 (la->la_array64);
1985 return GRUB_ERR_NONE;
1989 return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file `%s' not found"), name);
1993 /* Verify if this is a fat zap header block */
1994 static grub_err_t
1995 zap_verify (zap_phys_t *zap, grub_zfs_endian_t endian)
1997 if (grub_zfs_to_cpu64 (zap->zap_magic, endian) != (grub_uint64_t) ZAP_MAGIC)
1998 return grub_error (GRUB_ERR_BAD_FS, "bad ZAP magic");
2000 if (zap->zap_salt == 0)
2001 return grub_error (GRUB_ERR_BAD_FS, "bad ZAP salt");
2003 return GRUB_ERR_NONE;
2007 * Fat ZAP lookup
2010 /* XXX */
2011 static grub_err_t
2012 fzap_lookup (dnode_end_t * zap_dnode, zap_phys_t * zap,
2013 const char *name, grub_uint64_t * value,
2014 struct grub_zfs_data *data, int case_insensitive)
2016 void *l;
2017 grub_uint64_t hash, idx, blkid;
2018 int blksft = zfs_log2 (grub_zfs_to_cpu16 (zap_dnode->dn.dn_datablkszsec,
2019 zap_dnode->endian) << DNODE_SHIFT);
2020 grub_err_t err;
2021 grub_zfs_endian_t leafendian;
2023 err = zap_verify (zap, zap_dnode->endian);
2024 if (err)
2025 return err;
2027 hash = zap_hash (zap->zap_salt, name, case_insensitive);
2029 /* get block id from index */
2030 if (zap->zap_ptrtbl.zt_numblks != 0)
2031 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
2032 "external pointer tables not supported");
2033 idx = ZAP_HASH_IDX (hash, zap->zap_ptrtbl.zt_shift);
2034 blkid = grub_zfs_to_cpu64 (((grub_uint64_t *) zap)[idx + (1 << (blksft - 3 - 1))], zap_dnode->endian);
2036 /* Get the leaf block */
2037 if ((1U << blksft) < sizeof (zap_leaf_phys_t))
2038 return grub_error (GRUB_ERR_BAD_FS, "ZAP leaf is too small");
2039 err = dmu_read (zap_dnode, blkid, &l, &leafendian, data);
2040 if (err)
2041 return err;
2043 err = zap_leaf_lookup (l, leafendian, blksft, hash, name, value,
2044 case_insensitive);
2045 grub_free (l);
2046 return err;
2049 /* XXX */
2050 static int
2051 fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap,
2052 grub_size_t name_elem_length,
2053 int NESTED_FUNC_ATTR (*hook) (const void *name,
2054 grub_size_t name_length,
2055 const void *val_in,
2056 grub_size_t nelem,
2057 grub_size_t elemsize),
2058 struct grub_zfs_data *data)
2060 zap_leaf_phys_t *l;
2061 void *l_in;
2062 grub_uint64_t idx, idx2, blkid;
2063 grub_uint16_t chunk;
2064 int blksft = zfs_log2 (grub_zfs_to_cpu16 (zap_dnode->dn.dn_datablkszsec,
2065 zap_dnode->endian) << DNODE_SHIFT);
2066 grub_err_t err;
2067 grub_zfs_endian_t endian;
2069 if (zap_verify (zap, zap_dnode->endian))
2070 return 0;
2072 /* get block id from index */
2073 if (zap->zap_ptrtbl.zt_numblks != 0)
2075 grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
2076 "external pointer tables not supported");
2077 return 0;
2079 /* Get the leaf block */
2080 if ((1U << blksft) < sizeof (zap_leaf_phys_t))
2082 grub_error (GRUB_ERR_BAD_FS, "ZAP leaf is too small");
2083 return 0;
2085 for (idx = 0; idx < (1ULL << zap->zap_ptrtbl.zt_shift); idx++)
2087 blkid = grub_zfs_to_cpu64 (((grub_uint64_t *) zap)[idx + (1 << (blksft - 3 - 1))],
2088 zap_dnode->endian);
2090 for (idx2 = 0; idx2 < idx; idx2++)
2091 if (blkid == grub_zfs_to_cpu64 (((grub_uint64_t *) zap)[idx2 + (1 << (blksft - 3 - 1))],
2092 zap_dnode->endian))
2093 break;
2094 if (idx2 != idx)
2095 continue;
2097 err = dmu_read (zap_dnode, blkid, &l_in, &endian, data);
2098 l = l_in;
2099 if (err)
2101 grub_errno = GRUB_ERR_NONE;
2102 continue;
2105 /* Verify if this is a valid leaf block */
2106 if (grub_zfs_to_cpu64 (l->l_hdr.lh_block_type, endian) != ZBT_LEAF)
2108 grub_free (l);
2109 continue;
2111 if (grub_zfs_to_cpu32 (l->l_hdr.lh_magic, endian) != ZAP_LEAF_MAGIC)
2113 grub_free (l);
2114 continue;
2117 for (chunk = 0; chunk < ZAP_LEAF_NUMCHUNKS (blksft); chunk++)
2119 char *buf;
2120 struct zap_leaf_entry *le;
2121 char *val;
2122 grub_size_t val_length;
2123 le = ZAP_LEAF_ENTRY (l, blksft, chunk);
2125 /* Verify the chunk entry */
2126 if (le->le_type != ZAP_CHUNK_ENTRY)
2127 continue;
2129 buf = grub_malloc (grub_zfs_to_cpu16 (le->le_name_length, endian)
2130 * name_elem_length + 1);
2131 if (zap_leaf_array_get (l, endian, blksft,
2132 grub_zfs_to_cpu16 (le->le_name_chunk,
2133 endian),
2134 grub_zfs_to_cpu16 (le->le_name_length,
2135 endian)
2136 * name_elem_length, buf))
2138 grub_free (buf);
2139 continue;
2141 buf[le->le_name_length * name_elem_length] = 0;
2143 val_length = ((int) le->le_value_length
2144 * (int) le->le_int_size);
2145 val = grub_malloc (grub_zfs_to_cpu16 (val_length, endian));
2146 if (zap_leaf_array_get (l, endian, blksft,
2147 grub_zfs_to_cpu16 (le->le_value_chunk,
2148 endian),
2149 val_length, val))
2151 grub_free (buf);
2152 grub_free (val);
2153 continue;
2156 if (hook (buf, le->le_name_length,
2157 val, le->le_value_length, le->le_int_size))
2159 grub_free (l);
2160 return 1;
2162 grub_free (buf);
2163 grub_free (val);
2165 grub_free (l);
2167 return 0;
2171 * Read in the data of a zap object and find the value for a matching
2172 * property name.
2175 static grub_err_t
2176 zap_lookup (dnode_end_t * zap_dnode, const char *name, grub_uint64_t *val,
2177 struct grub_zfs_data *data, int case_insensitive)
2179 grub_uint64_t block_type;
2180 int size;
2181 void *zapbuf;
2182 grub_err_t err;
2183 grub_zfs_endian_t endian;
2185 grub_dprintf ("zfs", "looking for '%s'\n", name);
2187 /* Read in the first block of the zap object data. */
2188 size = grub_zfs_to_cpu16 (zap_dnode->dn.dn_datablkszsec,
2189 zap_dnode->endian) << SPA_MINBLOCKSHIFT;
2190 err = dmu_read (zap_dnode, 0, &zapbuf, &endian, data);
2191 if (err)
2192 return err;
2193 block_type = grub_zfs_to_cpu64 (*((grub_uint64_t *) zapbuf), endian);
2195 grub_dprintf ("zfs", "zap read\n");
2197 if (block_type == ZBT_MICRO)
2199 grub_dprintf ("zfs", "micro zap\n");
2200 err = mzap_lookup (zapbuf, endian, size, name, val,
2201 case_insensitive);
2202 grub_dprintf ("zfs", "returned %d\n", err);
2203 grub_free (zapbuf);
2204 return err;
2206 else if (block_type == ZBT_HEADER)
2208 grub_dprintf ("zfs", "fat zap\n");
2209 /* this is a fat zap */
2210 err = fzap_lookup (zap_dnode, zapbuf, name, val, data,
2211 case_insensitive);
2212 grub_dprintf ("zfs", "returned %d\n", err);
2213 grub_free (zapbuf);
2214 return err;
2217 return grub_error (GRUB_ERR_BAD_FS, "unknown ZAP type");
2220 static int
2221 zap_iterate_u64 (dnode_end_t * zap_dnode,
2222 int NESTED_FUNC_ATTR (*hook) (const char *name,
2223 grub_uint64_t val),
2224 struct grub_zfs_data *data)
2226 grub_uint64_t block_type;
2227 int size;
2228 void *zapbuf;
2229 grub_err_t err;
2230 int ret;
2231 grub_zfs_endian_t endian;
2233 auto int NESTED_FUNC_ATTR transform (const void *name,
2234 grub_size_t namelen,
2235 const void *val_in,
2236 grub_size_t nelem,
2237 grub_size_t elemsize);
2239 int NESTED_FUNC_ATTR transform (const void *name,
2240 grub_size_t namelen __attribute__ ((unused)),
2241 const void *val_in,
2242 grub_size_t nelem,
2243 grub_size_t elemsize)
2245 if (elemsize != sizeof (grub_uint64_t) || nelem != 1)
2246 return 0;
2247 return hook (name, grub_be_to_cpu64 (*(const grub_uint64_t *) val_in));
2250 /* Read in the first block of the zap object data. */
2251 size = grub_zfs_to_cpu16 (zap_dnode->dn.dn_datablkszsec, zap_dnode->endian) << SPA_MINBLOCKSHIFT;
2252 err = dmu_read (zap_dnode, 0, &zapbuf, &endian, data);
2253 if (err)
2254 return 0;
2255 block_type = grub_zfs_to_cpu64 (*((grub_uint64_t *) zapbuf), endian);
2257 grub_dprintf ("zfs", "zap iterate\n");
2259 if (block_type == ZBT_MICRO)
2261 grub_dprintf ("zfs", "micro zap\n");
2262 ret = mzap_iterate (zapbuf, endian, size, hook);
2263 grub_free (zapbuf);
2264 return ret;
2266 else if (block_type == ZBT_HEADER)
2268 grub_dprintf ("zfs", "fat zap\n");
2269 /* this is a fat zap */
2270 ret = fzap_iterate (zap_dnode, zapbuf, 1, transform, data);
2271 grub_free (zapbuf);
2272 return ret;
2274 grub_error (GRUB_ERR_BAD_FS, "unknown ZAP type");
2275 return 0;
2278 static int
2279 zap_iterate (dnode_end_t * zap_dnode,
2280 grub_size_t nameelemlen,
2281 int NESTED_FUNC_ATTR (*hook) (const void *name,
2282 grub_size_t namelen,
2283 const void *val_in,
2284 grub_size_t nelem,
2285 grub_size_t elemsize),
2286 struct grub_zfs_data *data)
2288 grub_uint64_t block_type;
2289 void *zapbuf;
2290 grub_err_t err;
2291 int ret;
2292 grub_zfs_endian_t endian;
2294 /* Read in the first block of the zap object data. */
2295 err = dmu_read (zap_dnode, 0, &zapbuf, &endian, data);
2296 if (err)
2297 return 0;
2298 block_type = grub_zfs_to_cpu64 (*((grub_uint64_t *) zapbuf), endian);
2300 grub_dprintf ("zfs", "zap iterate\n");
2302 if (block_type == ZBT_MICRO)
2304 grub_error (GRUB_ERR_BAD_FS, "micro ZAP where FAT ZAP expected");
2305 return 0;
2307 if (block_type == ZBT_HEADER)
2309 grub_dprintf ("zfs", "fat zap\n");
2310 /* this is a fat zap */
2311 ret = fzap_iterate (zap_dnode, zapbuf, nameelemlen, hook, data);
2312 grub_free (zapbuf);
2313 return ret;
2315 grub_error (GRUB_ERR_BAD_FS, "unknown ZAP type");
2316 return 0;
2321 * Get the dnode of an object number from the metadnode of an object set.
2323 * Input
2324 * mdn - metadnode to get the object dnode
2325 * objnum - object number for the object dnode
2326 * buf - data buffer that holds the returning dnode
2328 static grub_err_t
2329 dnode_get (dnode_end_t * mdn, grub_uint64_t objnum, grub_uint8_t type,
2330 dnode_end_t * buf, struct grub_zfs_data *data)
2332 grub_uint64_t blkid, blksz; /* the block id this object dnode is in */
2333 int epbs; /* shift of number of dnodes in a block */
2334 int idx; /* index within a block */
2335 void *dnbuf;
2336 grub_err_t err;
2337 grub_zfs_endian_t endian;
2339 blksz = grub_zfs_to_cpu16 (mdn->dn.dn_datablkszsec,
2340 mdn->endian) << SPA_MINBLOCKSHIFT;
2341 epbs = zfs_log2 (blksz) - DNODE_SHIFT;
2342 blkid = objnum >> epbs;
2343 idx = objnum & ((1 << epbs) - 1);
2345 if (data->dnode_buf != NULL && grub_memcmp (data->dnode_mdn, mdn,
2346 sizeof (*mdn)) == 0
2347 && objnum >= data->dnode_start && objnum < data->dnode_end)
2349 grub_memmove (&(buf->dn), &(data->dnode_buf)[idx], DNODE_SIZE);
2350 buf->endian = data->dnode_endian;
2351 if (type && buf->dn.dn_type != type)
2352 return grub_error(GRUB_ERR_BAD_FS, "incorrect dnode type");
2353 return GRUB_ERR_NONE;
2356 grub_dprintf ("zfs", "endian = %d, blkid=%llx\n", mdn->endian,
2357 (unsigned long long) blkid);
2358 err = dmu_read (mdn, blkid, &dnbuf, &endian, data);
2359 if (err)
2360 return err;
2361 grub_dprintf ("zfs", "alive\n");
2363 grub_free (data->dnode_buf);
2364 grub_free (data->dnode_mdn);
2365 data->dnode_mdn = grub_malloc (sizeof (*mdn));
2366 if (! data->dnode_mdn)
2368 grub_errno = GRUB_ERR_NONE;
2369 data->dnode_buf = 0;
2371 else
2373 grub_memcpy (data->dnode_mdn, mdn, sizeof (*mdn));
2374 data->dnode_buf = dnbuf;
2375 data->dnode_start = blkid << epbs;
2376 data->dnode_end = (blkid + 1) << epbs;
2377 data->dnode_endian = endian;
2380 grub_memmove (&(buf->dn), (dnode_phys_t *) dnbuf + idx, DNODE_SIZE);
2381 buf->endian = endian;
2382 if (type && buf->dn.dn_type != type)
2383 return grub_error(GRUB_ERR_BAD_FS, "incorrect dnode type");
2385 return GRUB_ERR_NONE;
2388 #pragma GCC diagnostic ignored "-Wstrict-aliasing"
2391 * Get the file dnode for a given file name where mdn is the meta dnode
2392 * for this ZFS object set. When found, place the file dnode in dn.
2393 * The 'path' argument will be mangled.
2396 static grub_err_t
2397 dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn,
2398 struct grub_zfs_data *data)
2400 grub_uint64_t objnum, version;
2401 char *cname, ch;
2402 grub_err_t err = GRUB_ERR_NONE;
2403 char *path, *path_buf;
2404 struct dnode_chain
2406 struct dnode_chain *next;
2407 dnode_end_t dn;
2409 struct dnode_chain *dnode_path = 0, *dn_new, *root;
2411 dn_new = grub_malloc (sizeof (*dn_new));
2412 if (! dn_new)
2413 return grub_errno;
2414 dn_new->next = 0;
2415 dnode_path = root = dn_new;
2417 err = dnode_get (&subvol->mdn, MASTER_NODE_OBJ, DMU_OT_MASTER_NODE,
2418 &(dnode_path->dn), data);
2419 if (err)
2421 grub_free (dn_new);
2422 return err;
2425 err = zap_lookup (&(dnode_path->dn), ZPL_VERSION_STR, &version,
2426 data, 0);
2427 if (err)
2429 grub_free (dn_new);
2430 return err;
2433 if (version > ZPL_VERSION)
2435 grub_free (dn_new);
2436 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "too new ZPL version");
2439 err = zap_lookup (&(dnode_path->dn), "casesensitivity",
2440 &subvol->case_insensitive,
2441 data, 0);
2442 if (err == GRUB_ERR_FILE_NOT_FOUND)
2444 grub_errno = GRUB_ERR_NONE;
2445 subvol->case_insensitive = 0;
2448 err = zap_lookup (&(dnode_path->dn), ZFS_ROOT_OBJ, &objnum, data, 0);
2449 if (err)
2451 grub_free (dn_new);
2452 return err;
2455 err = dnode_get (&subvol->mdn, objnum, 0, &(dnode_path->dn), data);
2456 if (err)
2458 grub_free (dn_new);
2459 return err;
2462 path = path_buf = grub_strdup (path_in);
2463 if (!path_buf)
2465 grub_free (dn_new);
2466 return grub_errno;
2469 while (1)
2471 /* skip leading slashes */
2472 while (*path == '/')
2473 path++;
2474 if (!*path)
2475 break;
2476 /* get the next component name */
2477 cname = path;
2478 while (*path && *path != '/')
2479 path++;
2480 /* Skip dot. */
2481 if (cname + 1 == path && cname[0] == '.')
2482 continue;
2483 /* Handle double dot. */
2484 if (cname + 2 == path && cname[0] == '.' && cname[1] == '.')
2486 if (dn_new->next)
2488 dn_new = dnode_path;
2489 dnode_path = dn_new->next;
2490 grub_free (dn_new);
2492 else
2494 err = grub_error (GRUB_ERR_FILE_NOT_FOUND,
2495 "can't resolve ..");
2496 break;
2498 continue;
2501 ch = *path;
2502 *path = 0; /* ensure null termination */
2504 if (dnode_path->dn.dn.dn_type != DMU_OT_DIRECTORY_CONTENTS)
2506 grub_free (path_buf);
2507 return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory"));
2509 err = zap_lookup (&(dnode_path->dn), cname, &objnum,
2510 data, subvol->case_insensitive);
2511 if (err)
2512 break;
2514 dn_new = grub_malloc (sizeof (*dn_new));
2515 if (! dn_new)
2517 err = grub_errno;
2518 break;
2520 dn_new->next = dnode_path;
2521 dnode_path = dn_new;
2523 objnum = ZFS_DIRENT_OBJ (objnum);
2524 err = dnode_get (&subvol->mdn, objnum, 0, &(dnode_path->dn), data);
2525 if (err)
2526 break;
2528 *path = ch;
2529 if (dnode_path->dn.dn.dn_bonustype == DMU_OT_ZNODE
2530 && ((grub_zfs_to_cpu64(((znode_phys_t *) DN_BONUS (&dnode_path->dn.dn))->zp_mode, dnode_path->dn.endian) >> 12) & 0xf) == 0xa)
2532 char *sym_value;
2533 grub_size_t sym_sz;
2534 int free_symval = 0;
2535 char *oldpath = path, *oldpathbuf = path_buf;
2536 sym_value = ((char *) DN_BONUS (&dnode_path->dn.dn) + sizeof (struct znode_phys));
2538 sym_sz = grub_zfs_to_cpu64 (((znode_phys_t *) DN_BONUS (&dnode_path->dn.dn))->zp_size, dnode_path->dn.endian);
2540 if (dnode_path->dn.dn.dn_flags & 1)
2542 grub_size_t block;
2543 grub_size_t blksz;
2544 blksz = (grub_zfs_to_cpu16 (dnode_path->dn.dn.dn_datablkszsec,
2545 dnode_path->dn.endian)
2546 << SPA_MINBLOCKSHIFT);
2548 sym_value = grub_malloc (sym_sz);
2549 if (!sym_value)
2550 return grub_errno;
2551 for (block = 0; block < (sym_sz + blksz - 1) / blksz; block++)
2553 void *t;
2554 grub_size_t movesize;
2556 err = dmu_read (&(dnode_path->dn), block, &t, 0, data);
2557 if (err)
2558 return err;
2560 movesize = sym_sz - block * blksz;
2561 if (movesize > blksz)
2562 movesize = blksz;
2564 grub_memcpy (sym_value + block * blksz, t, movesize);
2565 grub_free (t);
2567 free_symval = 1;
2569 path = path_buf = grub_malloc (sym_sz + grub_strlen (oldpath) + 1);
2570 if (!path_buf)
2572 grub_free (oldpathbuf);
2573 return grub_errno;
2575 grub_memcpy (path, sym_value, sym_sz);
2576 if (free_symval)
2577 grub_free (sym_value);
2578 path [sym_sz] = 0;
2579 grub_memcpy (path + grub_strlen (path), oldpath,
2580 grub_strlen (oldpath) + 1);
2582 grub_free (oldpathbuf);
2583 if (path[0] != '/')
2585 dn_new = dnode_path;
2586 dnode_path = dn_new->next;
2587 grub_free (dn_new);
2589 else while (dnode_path != root)
2591 dn_new = dnode_path;
2592 dnode_path = dn_new->next;
2593 grub_free (dn_new);
2596 if (dnode_path->dn.dn.dn_bonustype == DMU_OT_SA)
2598 void *sahdrp;
2599 int hdrsize;
2601 if (dnode_path->dn.dn.dn_bonuslen != 0)
2603 sahdrp = DN_BONUS (&dnode_path->dn.dn);
2605 else if (dnode_path->dn.dn.dn_flags & DNODE_FLAG_SPILL_BLKPTR)
2607 blkptr_t *bp = &dnode_path->dn.dn.dn_spill;
2609 err = zio_read (bp, dnode_path->dn.endian, &sahdrp, NULL, data);
2610 if (err)
2611 return err;
2613 else
2615 return grub_error (GRUB_ERR_BAD_FS, "filesystem is corrupt");
2618 hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp));
2620 if (((grub_zfs_to_cpu64 (grub_get_unaligned64 ((char *) sahdrp
2621 + hdrsize
2622 + SA_TYPE_OFFSET),
2623 dnode_path->dn.endian) >> 12) & 0xf) == 0xa)
2625 char *sym_value = (char *) sahdrp + hdrsize + SA_SYMLINK_OFFSET;
2626 grub_size_t sym_sz =
2627 grub_zfs_to_cpu64 (grub_get_unaligned64 ((char *) sahdrp
2628 + hdrsize
2629 + SA_SIZE_OFFSET),
2630 dnode_path->dn.endian);
2631 char *oldpath = path, *oldpathbuf = path_buf;
2632 path = path_buf = grub_malloc (sym_sz + grub_strlen (oldpath) + 1);
2633 if (!path_buf)
2635 grub_free (oldpathbuf);
2636 return grub_errno;
2638 grub_memcpy (path, sym_value, sym_sz);
2639 path [sym_sz] = 0;
2640 grub_memcpy (path + grub_strlen (path), oldpath,
2641 grub_strlen (oldpath) + 1);
2643 grub_free (oldpathbuf);
2644 if (path[0] != '/')
2646 dn_new = dnode_path;
2647 dnode_path = dn_new->next;
2648 grub_free (dn_new);
2650 else while (dnode_path != root)
2652 dn_new = dnode_path;
2653 dnode_path = dn_new->next;
2654 grub_free (dn_new);
2660 if (!err)
2661 grub_memcpy (dn, &(dnode_path->dn), sizeof (*dn));
2663 while (dnode_path)
2665 dn_new = dnode_path->next;
2666 grub_free (dnode_path);
2667 dnode_path = dn_new;
2669 grub_free (path_buf);
2670 return err;
2673 #if 0
2675 * Get the default 'bootfs' property value from the rootpool.
2678 static grub_err_t
2679 get_default_bootfsobj (dnode_phys_t * mosmdn, grub_uint64_t * obj,
2680 struct grub_zfs_data *data)
2682 grub_uint64_t objnum = 0;
2683 dnode_phys_t *dn;
2684 if (!dn)
2685 return grub_errno;
2687 if ((grub_errno = dnode_get (mosmdn, DMU_POOL_DIRECTORY_OBJECT,
2688 DMU_OT_OBJECT_DIRECTORY, dn, data)))
2690 grub_free (dn);
2691 return (grub_errno);
2695 * find the object number for 'pool_props', and get the dnode
2696 * of the 'pool_props'.
2698 if (zap_lookup (dn, DMU_POOL_PROPS, &objnum, data))
2700 grub_free (dn);
2701 return (GRUB_ERR_BAD_FS);
2703 if ((grub_errno = dnode_get (mosmdn, objnum, DMU_OT_POOL_PROPS, dn, data)))
2705 grub_free (dn);
2706 return (grub_errno);
2708 if (zap_lookup (dn, ZPOOL_PROP_BOOTFS, &objnum, data))
2710 grub_free (dn);
2711 return (GRUB_ERR_BAD_FS);
2714 if (!objnum)
2716 grub_free (dn);
2717 return (GRUB_ERR_BAD_FS);
2720 *obj = objnum;
2721 return (0);
2723 #endif
2725 * Given a MOS metadnode, get the metadnode of a given filesystem name (fsname),
2726 * e.g. pool/rootfs, or a given object number (obj), e.g. the object number
2727 * of pool/rootfs.
2729 * If no fsname and no obj are given, return the DSL_DIR metadnode.
2730 * If fsname is given, return its metadnode and its matching object number.
2731 * If only obj is given, return the metadnode for this object number.
2734 static grub_err_t
2735 get_filesystem_dnode (dnode_end_t * mosmdn, char *fsname,
2736 dnode_end_t * mdn, struct grub_zfs_data *data)
2738 grub_uint64_t objnum;
2739 grub_err_t err;
2741 grub_dprintf ("zfs", "endian = %d\n", mosmdn->endian);
2743 err = dnode_get (mosmdn, DMU_POOL_DIRECTORY_OBJECT,
2744 DMU_OT_OBJECT_DIRECTORY, mdn, data);
2745 if (err)
2746 return err;
2748 grub_dprintf ("zfs", "alive\n");
2750 err = zap_lookup (mdn, DMU_POOL_ROOT_DATASET, &objnum, data, 0);
2751 if (err)
2752 return err;
2754 grub_dprintf ("zfs", "alive\n");
2756 err = dnode_get (mosmdn, objnum, DMU_OT_DSL_DIR, mdn, data);
2757 if (err)
2758 return err;
2760 grub_dprintf ("zfs", "alive\n");
2762 while (*fsname)
2764 grub_uint64_t childobj;
2765 char *cname, ch;
2767 while (*fsname == '/')
2768 fsname++;
2770 if (! *fsname || *fsname == '@')
2771 break;
2773 cname = fsname;
2774 while (*fsname && *fsname != '/')
2775 fsname++;
2776 ch = *fsname;
2777 *fsname = 0;
2779 childobj = grub_zfs_to_cpu64 ((((dsl_dir_phys_t *) DN_BONUS (&mdn->dn)))->dd_child_dir_zapobj, mdn->endian);
2780 err = dnode_get (mosmdn, childobj,
2781 DMU_OT_DSL_DIR_CHILD_MAP, mdn, data);
2782 if (err)
2783 return err;
2785 err = zap_lookup (mdn, cname, &objnum, data, 0);
2786 if (err)
2787 return err;
2789 err = dnode_get (mosmdn, objnum, DMU_OT_DSL_DIR, mdn, data);
2790 if (err)
2791 return err;
2793 *fsname = ch;
2795 return GRUB_ERR_NONE;
2798 static grub_err_t
2799 make_mdn (dnode_end_t * mdn, struct grub_zfs_data *data)
2801 void *osp;
2802 blkptr_t *bp;
2803 grub_size_t ospsize;
2804 grub_err_t err;
2806 grub_dprintf ("zfs", "endian = %d\n", mdn->endian);
2808 bp = &(((dsl_dataset_phys_t *) DN_BONUS (&mdn->dn))->ds_bp);
2809 err = zio_read (bp, mdn->endian, &osp, &ospsize, data);
2810 if (err)
2811 return err;
2812 if (ospsize < OBJSET_PHYS_SIZE_V14)
2814 grub_free (osp);
2815 return grub_error (GRUB_ERR_BAD_FS, "too small osp");
2818 mdn->endian = (grub_zfs_to_cpu64 (bp->blk_prop, mdn->endian)>>63) & 1;
2819 grub_memmove ((char *) &(mdn->dn),
2820 (char *) &((objset_phys_t *) osp)->os_meta_dnode, DNODE_SIZE);
2821 grub_free (osp);
2822 return GRUB_ERR_NONE;
2825 static grub_err_t
2826 dnode_get_fullpath (const char *fullpath, struct subvolume *subvol,
2827 dnode_end_t * dn, int *isfs,
2828 struct grub_zfs_data *data)
2830 char *fsname, *snapname;
2831 const char *ptr_at, *filename;
2832 grub_uint64_t headobj;
2833 grub_uint64_t keychainobj;
2834 grub_uint64_t salt;
2835 grub_err_t err;
2836 int keyn = 0;
2838 auto int NESTED_FUNC_ATTR count_zap_keys (const void *name,
2839 grub_size_t namelen,
2840 const void *val_in,
2841 grub_size_t nelem,
2842 grub_size_t elemsize);
2843 int NESTED_FUNC_ATTR count_zap_keys (const void *name __attribute__ ((unused)),
2844 grub_size_t namelen __attribute__ ((unused)),
2845 const void *val_in __attribute__ ((unused)),
2846 grub_size_t nelem __attribute__ ((unused)),
2847 grub_size_t elemsize __attribute__ ((unused)))
2849 subvol->nkeys++;
2850 return 0;
2853 auto int NESTED_FUNC_ATTR load_zap_key (const void *name,
2854 grub_size_t namelen,
2855 const void *val_in,
2856 grub_size_t nelem,
2857 grub_size_t elemsize);
2858 int NESTED_FUNC_ATTR load_zap_key (const void *name,
2859 grub_size_t namelen,
2860 const void *val_in,
2861 grub_size_t nelem,
2862 grub_size_t elemsize)
2864 if (namelen != 1)
2866 grub_dprintf ("zfs", "Unexpected key index size %" PRIuGRUB_SIZE "\n",
2867 namelen);
2868 return 0;
2871 if (elemsize != 1)
2873 grub_dprintf ("zfs", "Unexpected key element size %" PRIuGRUB_SIZE "\n",
2874 elemsize);
2875 return 0;
2878 subvol->keyring[keyn].txg = grub_be_to_cpu64 (*(grub_uint64_t *) name);
2879 subvol->keyring[keyn].algo = grub_le_to_cpu64 (*(grub_uint64_t *) val_in);
2880 subvol->keyring[keyn].cipher = grub_zfs_load_key (val_in, nelem, salt,
2881 subvol->keyring[keyn].algo);
2882 keyn++;
2883 return 0;
2886 ptr_at = grub_strchr (fullpath, '@');
2887 if (! ptr_at)
2889 *isfs = 1;
2890 filename = 0;
2891 snapname = 0;
2892 fsname = grub_strdup (fullpath);
2894 else
2896 const char *ptr_slash = grub_strchr (ptr_at, '/');
2898 *isfs = 0;
2899 fsname = grub_malloc (ptr_at - fullpath + 1);
2900 if (!fsname)
2901 return grub_errno;
2902 grub_memcpy (fsname, fullpath, ptr_at - fullpath);
2903 fsname[ptr_at - fullpath] = 0;
2904 if (ptr_at[1] && ptr_at[1] != '/')
2906 snapname = grub_malloc (ptr_slash - ptr_at);
2907 if (!snapname)
2909 grub_free (fsname);
2910 return grub_errno;
2912 grub_memcpy (snapname, ptr_at + 1, ptr_slash - ptr_at - 1);
2913 snapname[ptr_slash - ptr_at - 1] = 0;
2915 else
2916 snapname = 0;
2917 if (ptr_slash)
2918 filename = ptr_slash;
2919 else
2920 filename = "/";
2921 grub_dprintf ("zfs", "fsname = '%s' snapname='%s' filename = '%s'\n",
2922 fsname, snapname, filename);
2924 grub_dprintf ("zfs", "alive\n");
2925 err = get_filesystem_dnode (&(data->mos), fsname, dn, data);
2926 if (err)
2928 grub_free (fsname);
2929 grub_free (snapname);
2930 return err;
2933 grub_dprintf ("zfs", "alive\n");
2935 headobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&dn->dn))->dd_head_dataset_obj, dn->endian);
2937 grub_dprintf ("zfs", "endian = %d\n", subvol->mdn.endian);
2939 err = dnode_get (&(data->mos), headobj, DMU_OT_DSL_DATASET, &subvol->mdn,
2940 data);
2941 if (err)
2943 grub_free (fsname);
2944 grub_free (snapname);
2945 return err;
2947 grub_dprintf ("zfs", "endian = %d\n", subvol->mdn.endian);
2949 keychainobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&dn->dn))->keychain, dn->endian);
2950 if (grub_zfs_load_key && keychainobj)
2952 dnode_end_t keychain_dn, props_dn;
2953 grub_uint64_t propsobj;
2954 propsobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&dn->dn))->dd_props_zapobj, dn->endian);
2956 err = dnode_get (&(data->mos), propsobj, DMU_OT_DSL_PROPS,
2957 &props_dn, data);
2958 if (err)
2960 grub_free (fsname);
2961 grub_free (snapname);
2962 return err;
2965 err = zap_lookup (&props_dn, "salt", &salt, data, 0);
2966 if (err == GRUB_ERR_FILE_NOT_FOUND)
2968 err = 0;
2969 grub_errno = 0;
2970 salt = 0;
2972 if (err)
2974 grub_dprintf ("zfs", "failed here\n");
2975 return err;
2978 err = dnode_get (&(data->mos), keychainobj, DMU_OT_DSL_KEYCHAIN,
2979 &keychain_dn, data);
2980 if (err)
2982 grub_free (fsname);
2983 grub_free (snapname);
2984 return err;
2986 subvol->nkeys = 0;
2987 zap_iterate (&keychain_dn, 8, count_zap_keys, data);
2988 subvol->keyring = grub_zalloc (subvol->nkeys * sizeof (subvol->keyring[0]));
2989 if (!subvol->keyring)
2991 grub_free (fsname);
2992 grub_free (snapname);
2993 return err;
2995 zap_iterate (&keychain_dn, 8, load_zap_key, data);
2998 if (snapname)
3000 grub_uint64_t snapobj;
3002 snapobj = grub_zfs_to_cpu64 (((dsl_dataset_phys_t *) DN_BONUS (&subvol->mdn.dn))->ds_snapnames_zapobj, subvol->mdn.endian);
3004 err = dnode_get (&(data->mos), snapobj,
3005 DMU_OT_DSL_DS_SNAP_MAP, &subvol->mdn, data);
3006 if (!err)
3007 err = zap_lookup (&subvol->mdn, snapname, &headobj, data, 0);
3008 if (!err)
3009 err = dnode_get (&(data->mos), headobj, DMU_OT_DSL_DATASET,
3010 &subvol->mdn, data);
3011 if (err)
3013 grub_free (fsname);
3014 grub_free (snapname);
3015 return err;
3019 subvol->obj = headobj;
3021 make_mdn (&subvol->mdn, data);
3023 grub_dprintf ("zfs", "endian = %d\n", subvol->mdn.endian);
3025 if (*isfs)
3027 grub_free (fsname);
3028 grub_free (snapname);
3029 return GRUB_ERR_NONE;
3031 err = dnode_get_path (subvol, filename, dn, data);
3032 grub_free (fsname);
3033 grub_free (snapname);
3034 return err;
3038 * For a given XDR packed nvlist, verify the first 4 bytes and move on.
3040 * An XDR packed nvlist is encoded as (comments from nvs_xdr_create) :
3042 * encoding method/host endian (4 bytes)
3043 * nvl_version (4 bytes)
3044 * nvl_nvflag (4 bytes)
3045 * encoded nvpairs:
3046 * encoded size of the nvpair (4 bytes)
3047 * decoded size of the nvpair (4 bytes)
3048 * name string size (4 bytes)
3049 * name string data (sizeof(NV_ALIGN4(string))
3050 * data type (4 bytes)
3051 * # of elements in the nvpair (4 bytes)
3052 * data
3053 * 2 zero's for the last nvpair
3054 * (end of the entire list) (8 bytes)
3058 static int
3059 nvlist_find_value (const char *nvlist_in, const char *name,
3060 int valtype, char **val,
3061 grub_size_t *size_out, grub_size_t *nelm_out)
3063 int name_len, type, encode_size;
3064 const char *nvpair, *nvp_name, *nvlist = nvlist_in;
3066 /* Verify if the 1st and 2nd byte in the nvlist are valid. */
3067 /* NOTE: independently of what endianness header announces all
3068 subsequent values are big-endian. */
3069 if (nvlist[0] != NV_ENCODE_XDR || (nvlist[1] != NV_LITTLE_ENDIAN
3070 && nvlist[1] != NV_BIG_ENDIAN))
3072 grub_dprintf ("zfs", "incorrect nvlist header\n");
3073 grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist");
3074 return 0;
3077 /* skip the header, nvl_version, and nvl_nvflag */
3078 nvlist = nvlist + 4 * 3;
3080 * Loop thru the nvpair list
3081 * The XDR representation of an integer is in big-endian byte order.
3083 while ((encode_size = grub_be_to_cpu32 (grub_get_unaligned32 (nvlist))))
3085 int nelm;
3087 if (nvlist + 4 * 4 >= nvlist_in + VDEV_PHYS_SIZE)
3089 grub_dprintf ("zfs", "nvlist overflow\n");
3090 grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist");
3091 return 0;
3094 nvpair = nvlist + 4 * 2; /* skip the encode/decode size */
3096 name_len = grub_be_to_cpu32 (grub_get_unaligned32 (nvpair));
3097 nvpair += 4;
3099 nvp_name = nvpair;
3100 nvpair = nvpair + ((name_len + 3) & ~3); /* align */
3102 if (nvpair + 8 >= nvlist_in + VDEV_PHYS_SIZE
3103 || encode_size < 0
3104 || nvpair + 8 + encode_size > nvlist_in + VDEV_PHYS_SIZE)
3106 grub_dprintf ("zfs", "nvlist overflow\n");
3107 grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist");
3108 return 0;
3111 type = grub_be_to_cpu32 (grub_get_unaligned32 (nvpair));
3112 nvpair += 4;
3114 nelm = grub_be_to_cpu32 (grub_get_unaligned32 (nvpair));
3115 if (nelm < 1)
3117 grub_error (GRUB_ERR_BAD_FS, "empty nvpair");
3118 return 0;
3121 nvpair += 4;
3123 if ((grub_strncmp (nvp_name, name, name_len) == 0) && type == valtype)
3125 *val = (char *) nvpair;
3126 *size_out = encode_size;
3127 if (nelm_out)
3128 *nelm_out = nelm;
3129 return 1;
3132 nvlist += encode_size; /* goto the next nvpair */
3134 return 0;
3138 grub_zfs_nvlist_lookup_uint64 (const char *nvlist, const char *name,
3139 grub_uint64_t * out)
3141 char *nvpair;
3142 grub_size_t size;
3143 int found;
3145 found = nvlist_find_value (nvlist, name, DATA_TYPE_UINT64, &nvpair, &size, 0);
3146 if (!found)
3147 return 0;
3148 if (size < sizeof (grub_uint64_t))
3150 grub_error (GRUB_ERR_BAD_FS, "invalid uint64");
3151 return 0;
3154 *out = grub_be_to_cpu64 (grub_get_unaligned64 (nvpair));
3155 return 1;
3158 char *
3159 grub_zfs_nvlist_lookup_string (const char *nvlist, const char *name)
3161 char *nvpair;
3162 char *ret;
3163 grub_size_t slen;
3164 grub_size_t size;
3165 int found;
3167 found = nvlist_find_value (nvlist, name, DATA_TYPE_STRING, &nvpair, &size, 0);
3168 if (!found)
3169 return 0;
3170 if (size < 4)
3172 grub_error (GRUB_ERR_BAD_FS, "invalid string");
3173 return 0;
3175 slen = grub_be_to_cpu32 (grub_get_unaligned32 (nvpair));
3176 if (slen > size - 4)
3177 slen = size - 4;
3178 ret = grub_malloc (slen + 1);
3179 if (!ret)
3180 return 0;
3181 grub_memcpy (ret, nvpair + 4, slen);
3182 ret[slen] = 0;
3183 return ret;
3186 char *
3187 grub_zfs_nvlist_lookup_nvlist (const char *nvlist, const char *name)
3189 char *nvpair;
3190 char *ret;
3191 grub_size_t size;
3192 int found;
3194 found = nvlist_find_value (nvlist, name, DATA_TYPE_NVLIST, &nvpair,
3195 &size, 0);
3196 if (!found)
3197 return 0;
3198 ret = grub_zalloc (size + 3 * sizeof (grub_uint32_t));
3199 if (!ret)
3200 return 0;
3201 grub_memcpy (ret, nvlist, sizeof (grub_uint32_t));
3203 grub_memcpy (ret + sizeof (grub_uint32_t), nvpair, size);
3204 return ret;
3208 grub_zfs_nvlist_lookup_nvlist_array_get_nelm (const char *nvlist,
3209 const char *name)
3211 char *nvpair;
3212 grub_size_t nelm, size;
3213 int found;
3215 found = nvlist_find_value (nvlist, name, DATA_TYPE_NVLIST_ARRAY, &nvpair,
3216 &size, &nelm);
3217 if (! found)
3218 return -1;
3219 return nelm;
3222 static int
3223 get_nvlist_size (const char *beg, const char *limit)
3225 const char *ptr;
3226 grub_uint32_t encode_size;
3228 ptr = beg + 8;
3230 while (ptr < limit
3231 && (encode_size = grub_be_to_cpu32 (grub_get_unaligned32 (ptr))))
3232 ptr += encode_size; /* goto the next nvpair */
3233 ptr += 8;
3234 return (ptr > limit) ? -1 : (ptr - beg);
3237 char *
3238 grub_zfs_nvlist_lookup_nvlist_array (const char *nvlist, const char *name,
3239 grub_size_t index)
3241 char *nvpair, *nvpairptr;
3242 int found;
3243 char *ret;
3244 grub_size_t size;
3245 unsigned i;
3246 grub_size_t nelm;
3247 int elemsize = 0;
3249 found = nvlist_find_value (nvlist, name, DATA_TYPE_NVLIST_ARRAY, &nvpair,
3250 &size, &nelm);
3251 if (!found)
3252 return 0;
3253 if (index >= nelm)
3255 grub_error (GRUB_ERR_OUT_OF_RANGE, "trying to lookup past nvlist array");
3256 return 0;
3259 nvpairptr = nvpair;
3261 for (i = 0; i < index; i++)
3263 int r;
3264 r = get_nvlist_size (nvpairptr, nvpair + size);
3266 if (r < 0)
3268 grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist array");
3269 return NULL;
3271 nvpairptr += r;
3274 elemsize = get_nvlist_size (nvpairptr, nvpair + size);
3276 if (elemsize < 0)
3278 grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist array");
3279 return 0;
3282 ret = grub_zalloc (elemsize + sizeof (grub_uint32_t));
3283 if (!ret)
3284 return 0;
3285 grub_memcpy (ret, nvlist, sizeof (grub_uint32_t));
3287 grub_memcpy (ret + sizeof (grub_uint32_t), nvpairptr, elemsize);
3288 return ret;
3291 static void
3292 unmount_device (struct grub_zfs_device_desc *desc)
3294 unsigned i;
3295 switch (desc->type)
3297 case DEVICE_LEAF:
3298 if (!desc->original && desc->dev)
3299 grub_device_close (desc->dev);
3300 return;
3301 case DEVICE_RAIDZ:
3302 case DEVICE_MIRROR:
3303 for (i = 0; i < desc->n_children; i++)
3304 unmount_device (&desc->children[i]);
3305 grub_free (desc->children);
3306 return;
3310 static void
3311 zfs_unmount (struct grub_zfs_data *data)
3313 unsigned i;
3314 for (i = 0; i < data->n_devices_attached; i++)
3315 unmount_device (&data->devices_attached[i]);
3316 grub_free (data->devices_attached);
3317 grub_free (data->dnode_buf);
3318 grub_free (data->dnode_mdn);
3319 grub_free (data->file_buf);
3320 for (i = 0; i < data->subvol.nkeys; i++)
3321 grub_crypto_cipher_close (data->subvol.keyring[i].cipher);
3322 grub_free (data->subvol.keyring);
3323 grub_free (data);
3327 * zfs_mount() locates a valid uberblock of the root pool and read in its MOS
3328 * to the memory address MOS.
3331 static struct grub_zfs_data *
3332 zfs_mount (grub_device_t dev)
3334 struct grub_zfs_data *data = 0;
3335 grub_err_t err;
3336 void *osp = 0;
3337 grub_size_t ospsize;
3338 grub_zfs_endian_t ub_endian = GRUB_ZFS_UNKNOWN_ENDIAN;
3339 uberblock_t *ub;
3340 int inserted;
3342 if (! dev->disk)
3344 grub_error (GRUB_ERR_BAD_DEVICE, "not a disk");
3345 return 0;
3348 data = grub_zalloc (sizeof (*data));
3349 if (!data)
3350 return 0;
3351 #if 0
3352 /* if it's our first time here, zero the best uberblock out */
3353 if (data->best_drive == 0 && data->best_part == 0 && find_best_root)
3354 grub_memset (&current_uberblock, 0, sizeof (uberblock_t));
3355 #endif
3357 data->n_devices_allocated = 16;
3358 data->devices_attached = grub_malloc (sizeof (data->devices_attached[0])
3359 * data->n_devices_allocated);
3360 data->n_devices_attached = 0;
3361 err = scan_disk (dev, data, 1, &inserted);
3362 if (err)
3364 zfs_unmount (data);
3365 return NULL;
3368 ub = &(data->current_uberblock);
3369 ub_endian = (grub_zfs_to_cpu64 (ub->ub_magic,
3370 GRUB_ZFS_LITTLE_ENDIAN) == UBERBLOCK_MAGIC
3371 ? GRUB_ZFS_LITTLE_ENDIAN : GRUB_ZFS_BIG_ENDIAN);
3373 err = zio_read (&ub->ub_rootbp, ub_endian,
3374 &osp, &ospsize, data);
3375 if (err)
3377 zfs_unmount (data);
3378 return NULL;
3381 if (ospsize < OBJSET_PHYS_SIZE_V14)
3383 grub_error (GRUB_ERR_BAD_FS, "OSP too small");
3384 grub_free (osp);
3385 zfs_unmount (data);
3386 return NULL;
3389 /* Got the MOS. Save it at the memory addr MOS. */
3390 grub_memmove (&(data->mos.dn), &((objset_phys_t *) osp)->os_meta_dnode,
3391 DNODE_SIZE);
3392 data->mos.endian = (grub_zfs_to_cpu64 (ub->ub_rootbp.blk_prop,
3393 ub_endian) >> 63) & 1;
3394 grub_free (osp);
3396 data->mounted = 1;
3398 return data;
3401 grub_err_t
3402 grub_zfs_fetch_nvlist (grub_device_t dev, char **nvlist)
3404 struct grub_zfs_data *zfs;
3405 grub_err_t err;
3407 zfs = zfs_mount (dev);
3408 if (!zfs)
3409 return grub_errno;
3410 err = zfs_fetch_nvlist (zfs->device_original, nvlist);
3411 zfs_unmount (zfs);
3412 return err;
3415 static grub_err_t
3416 zfs_label (grub_device_t device, char **label)
3418 char *nvlist;
3419 grub_err_t err;
3420 struct grub_zfs_data *data;
3422 data = zfs_mount (device);
3423 if (! data)
3424 return grub_errno;
3426 err = zfs_fetch_nvlist (data->device_original, &nvlist);
3427 if (err)
3429 zfs_unmount (data);
3430 return err;
3433 *label = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_POOL_NAME);
3434 grub_free (nvlist);
3435 zfs_unmount (data);
3436 return grub_errno;
3439 static grub_err_t
3440 zfs_uuid (grub_device_t device, char **uuid)
3442 struct grub_zfs_data *data;
3444 *uuid = 0;
3446 data = zfs_mount (device);
3447 if (! data)
3448 return grub_errno;
3450 *uuid = grub_xasprintf ("%016llx", (long long unsigned) data->guid);
3451 zfs_unmount (data);
3452 if (! *uuid)
3453 return grub_errno;
3454 return GRUB_ERR_NONE;
3457 static grub_err_t
3458 zfs_mtime (grub_device_t device, grub_int32_t *mt)
3460 struct grub_zfs_data *data;
3461 grub_zfs_endian_t ub_endian = GRUB_ZFS_UNKNOWN_ENDIAN;
3462 uberblock_t *ub;
3464 *mt = 0;
3466 data = zfs_mount (device);
3467 if (! data)
3468 return grub_errno;
3470 ub = &(data->current_uberblock);
3471 ub_endian = (grub_zfs_to_cpu64 (ub->ub_magic,
3472 GRUB_ZFS_LITTLE_ENDIAN) == UBERBLOCK_MAGIC
3473 ? GRUB_ZFS_LITTLE_ENDIAN : GRUB_ZFS_BIG_ENDIAN);
3475 *mt = grub_zfs_to_cpu64 (ub->ub_timestamp, ub_endian);
3476 zfs_unmount (data);
3477 return GRUB_ERR_NONE;
3481 * zfs_open() locates a file in the rootpool by following the
3482 * MOS and places the dnode of the file in the memory address DNODE.
3484 static grub_err_t
3485 grub_zfs_open (struct grub_file *file, const char *fsfilename)
3487 struct grub_zfs_data *data;
3488 grub_err_t err;
3489 int isfs;
3491 data = zfs_mount (file->device);
3492 if (! data)
3493 return grub_errno;
3495 err = dnode_get_fullpath (fsfilename, &(data->subvol),
3496 &(data->dnode), &isfs, data);
3497 if (err)
3499 zfs_unmount (data);
3500 return err;
3503 if (isfs)
3505 zfs_unmount (data);
3506 return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("missing `%c' symbol"), '@');
3509 /* We found the dnode for this file. Verify if it is a plain file. */
3510 if (data->dnode.dn.dn_type != DMU_OT_PLAIN_FILE_CONTENTS)
3512 zfs_unmount (data);
3513 return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a regular file"));
3516 /* get the file size and set the file position to 0 */
3519 * For DMU_OT_SA we will need to locate the SIZE attribute
3520 * attribute, which could be either in the bonus buffer
3521 * or the "spill" block.
3523 if (data->dnode.dn.dn_bonustype == DMU_OT_SA)
3525 void *sahdrp;
3526 int hdrsize;
3528 if (data->dnode.dn.dn_bonuslen != 0)
3530 sahdrp = (sa_hdr_phys_t *) DN_BONUS (&data->dnode.dn);
3532 else if (data->dnode.dn.dn_flags & DNODE_FLAG_SPILL_BLKPTR)
3534 blkptr_t *bp = &data->dnode.dn.dn_spill;
3536 err = zio_read (bp, data->dnode.endian, &sahdrp, NULL, data);
3537 if (err)
3538 return err;
3540 else
3542 return grub_error (GRUB_ERR_BAD_FS, "filesystem is corrupt");
3545 hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp));
3546 file->size = grub_zfs_to_cpu64 (grub_get_unaligned64 ((char *) sahdrp + hdrsize + SA_SIZE_OFFSET), data->dnode.endian);
3548 else if (data->dnode.dn.dn_bonustype == DMU_OT_ZNODE)
3550 file->size = grub_zfs_to_cpu64 (((znode_phys_t *) DN_BONUS (&data->dnode.dn))->zp_size, data->dnode.endian);
3552 else
3553 return grub_error (GRUB_ERR_BAD_FS, "bad bonus type");
3555 file->data = data;
3556 file->offset = 0;
3558 #ifndef GRUB_UTIL
3559 grub_dl_ref (my_mod);
3560 #endif
3562 return GRUB_ERR_NONE;
3565 static grub_ssize_t
3566 grub_zfs_read (grub_file_t file, char *buf, grub_size_t len)
3568 struct grub_zfs_data *data = (struct grub_zfs_data *) file->data;
3569 grub_size_t blksz, movesize;
3570 grub_size_t length;
3571 grub_size_t read;
3572 grub_err_t err;
3575 * If offset is in memory, move it into the buffer provided and return.
3577 if (file->offset >= data->file_start
3578 && file->offset + len <= data->file_end)
3580 grub_memmove (buf, data->file_buf + file->offset - data->file_start,
3581 len);
3582 return len;
3585 blksz = grub_zfs_to_cpu16 (data->dnode.dn.dn_datablkszsec,
3586 data->dnode.endian) << SPA_MINBLOCKSHIFT;
3589 * Entire Dnode is too big to fit into the space available. We
3590 * will need to read it in chunks. This could be optimized to
3591 * read in as large a chunk as there is space available, but for
3592 * now, this only reads in one data block at a time.
3594 length = len;
3595 read = 0;
3596 while (length)
3598 void *t;
3600 * Find requested blkid and the offset within that block.
3602 grub_uint64_t blkid = grub_divmod64 (file->offset + read, blksz, 0);
3603 grub_free (data->file_buf);
3604 data->file_buf = 0;
3606 err = dmu_read (&(data->dnode), blkid, &t,
3607 0, data);
3608 data->file_buf = t;
3609 if (err)
3611 data->file_buf = NULL;
3612 data->file_start = data->file_end = 0;
3613 return -1;
3616 data->file_start = blkid * blksz;
3617 data->file_end = data->file_start + blksz;
3619 movesize = data->file_end - file->offset - read;
3620 if (movesize > length)
3621 movesize = length;
3623 grub_memmove (buf, data->file_buf + file->offset + read
3624 - data->file_start, movesize);
3625 buf += movesize;
3626 length -= movesize;
3627 read += movesize;
3630 return len;
3633 static grub_err_t
3634 grub_zfs_close (grub_file_t file)
3636 zfs_unmount ((struct grub_zfs_data *) file->data);
3638 #ifndef GRUB_UTIL
3639 grub_dl_unref (my_mod);
3640 #endif
3642 return GRUB_ERR_NONE;
3645 grub_err_t
3646 grub_zfs_getmdnobj (grub_device_t dev, const char *fsfilename,
3647 grub_uint64_t *mdnobj)
3649 struct grub_zfs_data *data;
3650 grub_err_t err;
3651 int isfs;
3653 data = zfs_mount (dev);
3654 if (! data)
3655 return grub_errno;
3657 err = dnode_get_fullpath (fsfilename, &(data->subvol),
3658 &(data->dnode), &isfs, data);
3659 *mdnobj = data->subvol.obj;
3660 zfs_unmount (data);
3661 return err;
3664 static void
3665 fill_fs_info (struct grub_dirhook_info *info,
3666 dnode_end_t mdn, struct grub_zfs_data *data)
3668 grub_err_t err;
3669 dnode_end_t dn;
3670 grub_uint64_t objnum;
3671 grub_uint64_t headobj;
3673 grub_memset (info, 0, sizeof (*info));
3675 info->dir = 1;
3677 if (mdn.dn.dn_type == DMU_OT_DSL_DIR)
3679 headobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&mdn.dn))->dd_head_dataset_obj, mdn.endian);
3681 err = dnode_get (&(data->mos), headobj, DMU_OT_DSL_DATASET, &mdn, data);
3682 if (err)
3684 grub_dprintf ("zfs", "failed here\n");
3685 return;
3688 make_mdn (&mdn, data);
3689 err = dnode_get (&mdn, MASTER_NODE_OBJ, DMU_OT_MASTER_NODE,
3690 &dn, data);
3691 if (err)
3693 grub_dprintf ("zfs", "failed here\n");
3694 return;
3697 err = zap_lookup (&dn, ZFS_ROOT_OBJ, &objnum, data, 0);
3698 if (err)
3700 grub_dprintf ("zfs", "failed here\n");
3701 return;
3704 err = dnode_get (&mdn, objnum, 0, &dn, data);
3705 if (err)
3707 grub_dprintf ("zfs", "failed here\n");
3708 return;
3711 if (dn.dn.dn_bonustype == DMU_OT_SA)
3713 void *sahdrp;
3714 int hdrsize;
3716 if (dn.dn.dn_bonuslen != 0)
3718 sahdrp = (sa_hdr_phys_t *) DN_BONUS (&dn.dn);
3720 else if (dn.dn.dn_flags & DNODE_FLAG_SPILL_BLKPTR)
3722 blkptr_t *bp = &dn.dn.dn_spill;
3724 err = zio_read (bp, dn.endian, &sahdrp, NULL, data);
3725 if (err)
3726 return;
3728 else
3730 grub_error (GRUB_ERR_BAD_FS, "filesystem is corrupt");
3731 return;
3734 hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp));
3735 info->mtimeset = 1;
3736 info->mtime = grub_zfs_to_cpu64 (grub_get_unaligned64 ((char *) sahdrp + hdrsize + SA_MTIME_OFFSET), dn.endian);
3739 if (dn.dn.dn_bonustype == DMU_OT_ZNODE)
3741 info->mtimeset = 1;
3742 info->mtime = grub_zfs_to_cpu64 (((znode_phys_t *) DN_BONUS (&dn.dn))->zp_mtime[0], dn.endian);
3744 return;
3747 static grub_err_t
3748 grub_zfs_dir (grub_device_t device, const char *path,
3749 int (*hook) (const char *, const struct grub_dirhook_info *))
3751 struct grub_zfs_data *data;
3752 grub_err_t err;
3753 int isfs;
3754 auto int NESTED_FUNC_ATTR iterate_zap (const char *name, grub_uint64_t val);
3755 auto int NESTED_FUNC_ATTR iterate_zap_fs (const char *name,
3756 grub_uint64_t val);
3757 auto int NESTED_FUNC_ATTR iterate_zap_snap (const char *name,
3758 grub_uint64_t val);
3760 int NESTED_FUNC_ATTR iterate_zap (const char *name, grub_uint64_t val)
3762 struct grub_dirhook_info info;
3763 dnode_end_t dn;
3764 grub_memset (&info, 0, sizeof (info));
3766 dnode_get (&(data->subvol.mdn), val, 0, &dn, data);
3768 if (dn.dn.dn_bonustype == DMU_OT_SA)
3770 void *sahdrp;
3771 int hdrsize;
3773 if (dn.dn.dn_bonuslen != 0)
3775 sahdrp = (sa_hdr_phys_t *) DN_BONUS (&data->dnode.dn);
3777 else if (dn.dn.dn_flags & DNODE_FLAG_SPILL_BLKPTR)
3779 blkptr_t *bp = &dn.dn.dn_spill;
3781 err = zio_read (bp, dn.endian, &sahdrp, NULL, data);
3782 if (err)
3784 grub_print_error ();
3785 return 0;
3788 else
3790 grub_error (GRUB_ERR_BAD_FS, "filesystem is corrupt");
3791 grub_print_error ();
3792 return 0;
3795 hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp));
3796 info.mtimeset = 1;
3797 info.mtime = grub_zfs_to_cpu64 (grub_get_unaligned64 ((char *) sahdrp + hdrsize + SA_MTIME_OFFSET), dn.endian);
3798 info.case_insensitive = data->subvol.case_insensitive;
3801 if (dn.dn.dn_bonustype == DMU_OT_ZNODE)
3803 info.mtimeset = 1;
3804 info.mtime = grub_zfs_to_cpu64 (((znode_phys_t *) DN_BONUS (&dn.dn))->zp_mtime[0],
3805 dn.endian);
3807 info.dir = (dn.dn.dn_type == DMU_OT_DIRECTORY_CONTENTS);
3808 grub_dprintf ("zfs", "type=%d, name=%s\n",
3809 (int)dn.dn.dn_type, (char *)name);
3810 return hook (name, &info);
3813 int NESTED_FUNC_ATTR iterate_zap_fs (const char *name, grub_uint64_t val)
3815 struct grub_dirhook_info info;
3816 dnode_end_t mdn;
3817 err = dnode_get (&(data->mos), val, 0, &mdn, data);
3818 if (err)
3819 return 0;
3820 if (mdn.dn.dn_type != DMU_OT_DSL_DIR)
3821 return 0;
3823 fill_fs_info (&info, mdn, data);
3824 return hook (name, &info);
3826 int NESTED_FUNC_ATTR iterate_zap_snap (const char *name, grub_uint64_t val)
3828 struct grub_dirhook_info info;
3829 char *name2;
3830 int ret;
3831 dnode_end_t mdn;
3833 err = dnode_get (&(data->mos), val, 0, &mdn, data);
3834 if (err)
3835 return 0;
3837 if (mdn.dn.dn_type != DMU_OT_DSL_DATASET)
3838 return 0;
3840 fill_fs_info (&info, mdn, data);
3842 name2 = grub_malloc (grub_strlen (name) + 2);
3843 name2[0] = '@';
3844 grub_memcpy (name2 + 1, name, grub_strlen (name) + 1);
3845 ret = hook (name2, &info);
3846 grub_free (name2);
3847 return ret;
3850 data = zfs_mount (device);
3851 if (! data)
3852 return grub_errno;
3853 err = dnode_get_fullpath (path, &(data->subvol), &(data->dnode), &isfs, data);
3854 if (err)
3856 zfs_unmount (data);
3857 return err;
3859 if (isfs)
3861 grub_uint64_t childobj, headobj;
3862 grub_uint64_t snapobj;
3863 dnode_end_t dn;
3864 struct grub_dirhook_info info;
3866 fill_fs_info (&info, data->dnode, data);
3867 hook ("@", &info);
3869 childobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&data->dnode.dn))->dd_child_dir_zapobj, data->dnode.endian);
3870 headobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&data->dnode.dn))->dd_head_dataset_obj, data->dnode.endian);
3871 err = dnode_get (&(data->mos), childobj,
3872 DMU_OT_DSL_DIR_CHILD_MAP, &dn, data);
3873 if (err)
3875 zfs_unmount (data);
3876 return err;
3879 zap_iterate_u64 (&dn, iterate_zap_fs, data);
3881 err = dnode_get (&(data->mos), headobj, DMU_OT_DSL_DATASET, &dn, data);
3882 if (err)
3884 zfs_unmount (data);
3885 return err;
3888 snapobj = grub_zfs_to_cpu64 (((dsl_dataset_phys_t *) DN_BONUS (&dn.dn))->ds_snapnames_zapobj, dn.endian);
3890 err = dnode_get (&(data->mos), snapobj,
3891 DMU_OT_DSL_DS_SNAP_MAP, &dn, data);
3892 if (err)
3894 zfs_unmount (data);
3895 return err;
3898 zap_iterate_u64 (&dn, iterate_zap_snap, data);
3900 else
3902 if (data->dnode.dn.dn_type != DMU_OT_DIRECTORY_CONTENTS)
3904 zfs_unmount (data);
3905 return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory"));
3907 zap_iterate_u64 (&(data->dnode), iterate_zap, data);
3909 zfs_unmount (data);
3910 return grub_errno;
3913 #ifdef GRUB_UTIL
3914 static grub_err_t
3915 grub_zfs_embed (grub_device_t device __attribute__ ((unused)),
3916 unsigned int *nsectors,
3917 unsigned int max_nsectors,
3918 grub_embed_type_t embed_type,
3919 grub_disk_addr_t **sectors)
3921 unsigned i;
3923 if (embed_type != GRUB_EMBED_PCBIOS)
3924 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
3925 "ZFS currently supports only PC-BIOS embedding");
3927 if ((VDEV_BOOT_SIZE >> GRUB_DISK_SECTOR_BITS) < *nsectors)
3928 return grub_error (GRUB_ERR_OUT_OF_RANGE,
3929 N_("your core.img is unusually large. "
3930 "It won't fit in the embedding area"));
3932 *nsectors = (VDEV_BOOT_SIZE >> GRUB_DISK_SECTOR_BITS);
3933 if (*nsectors > max_nsectors)
3934 *nsectors = max_nsectors;
3935 *sectors = grub_malloc (*nsectors * sizeof (**sectors));
3936 if (!*sectors)
3937 return grub_errno;
3938 for (i = 0; i < *nsectors; i++)
3939 (*sectors)[i] = i + (VDEV_BOOT_OFFSET >> GRUB_DISK_SECTOR_BITS);
3941 return GRUB_ERR_NONE;
3943 #endif
3945 static struct grub_fs grub_zfs_fs = {
3946 .name = "zfs",
3947 .dir = grub_zfs_dir,
3948 .open = grub_zfs_open,
3949 .read = grub_zfs_read,
3950 .close = grub_zfs_close,
3951 .label = zfs_label,
3952 .uuid = zfs_uuid,
3953 .mtime = zfs_mtime,
3954 #ifdef GRUB_UTIL
3955 .embed = grub_zfs_embed,
3956 .reserved_first_sector = 1,
3957 .blocklist_install = 0,
3958 #endif
3959 .next = 0
3962 GRUB_MOD_INIT (zfs)
3964 COMPILE_TIME_ASSERT (sizeof (zap_leaf_chunk_t) == ZAP_LEAF_CHUNKSIZE);
3965 grub_fs_register (&grub_zfs_fs);
3966 #ifndef GRUB_UTIL
3967 my_mod = mod;
3968 #endif
3971 GRUB_MOD_FINI (zfs)
3973 grub_fs_unregister (&grub_zfs_fs);