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.
33 #include <grub/file.h>
35 #include <grub/misc.h>
36 #include <grub/disk.h>
37 #include <grub/partition.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
75 static grub_dl_t my_mod
;
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)
105 ZAP_LEAF_HASH_SHIFT (int bs
)
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)
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
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
166 zfs_decomp_func_t
*decomp_func
;
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
188 grub_zfs_endian_t endian
;
191 struct grub_zfs_device_desc
193 enum { DEVICE_LEAF
, DEVICE_MIRROR
, DEVICE_RAIDZ
} type
;
197 unsigned max_children_ashift
;
199 /* Valid only for non-leafs. */
201 struct grub_zfs_device_desc
*children
;
203 /* Valid only for RAIDZ. */
206 /* Valid only for leaf devices. */
208 grub_disk_addr_t vdev_phys_sector
;
209 uberblock_t current_uberblock
;
217 grub_uint64_t case_insensitive
;
221 grub_crypto_cipher_handle_t cipher
;
229 /* cache for a file block of the currently zfs_open()-ed file */
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
;
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
;
256 grub_err_t (*grub_zfs_decrypt
) (grub_crypto_cipher_handle_t cipher
,
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
,
265 grub_uint64_t algo
) = NULL
;
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)
273 return GRUB_ERR_NONE
;
277 zle_decompress (void *s
, void *d
,
278 grub_size_t slen
, grub_size_t dlen
)
280 grub_uint8_t
*iptr
, *optr
;
282 for (iptr
= s
, optr
= d
; iptr
< (grub_uint8_t
*) s
+ slen
283 && optr
< (grub_uint8_t
*) d
+ dlen
;)
286 clen
= ((*iptr
) & 0x7f) + 0x41;
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
);
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
);
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.
334 zfs_log2 (grub_uint64_t num
)
347 /* Checksum Functions */
349 zio_checksum_off (const void *buf
__attribute__ ((unused
)),
350 grub_uint64_t size
__attribute__ ((unused
)),
351 grub_zfs_endian_t endian
__attribute__ ((unused
)),
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"},
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.
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
);
396 expected_cksum
= zec
->zec_cksum
;
398 ci
->ci_func (buf
, size
, endian
, &actual_cksum
);
399 zec
->zec_cksum
= expected_cksum
;
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.
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
)
441 ub1_endian
= GRUB_ZFS_LITTLE_ENDIAN
;
443 ub1_endian
= GRUB_ZFS_BIG_ENDIAN
;
444 if (grub_zfs_to_cpu64 (ub2
->ub_magic
, GRUB_ZFS_LITTLE_ENDIAN
)
446 ub2_endian
= GRUB_ZFS_LITTLE_ENDIAN
;
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
))
453 if (grub_zfs_to_cpu64 (ub1
->ub_txg
, ub1_endian
)
454 > grub_zfs_to_cpu64 (ub2
->ub_txg
, ub2_endian
))
457 if (grub_zfs_to_cpu64 (ub1
->ub_timestamp
, ub1_endian
)
458 < grub_zfs_to_cpu64 (ub2
->ub_timestamp
, ub2_endian
))
460 if (grub_zfs_to_cpu64 (ub1
->ub_timestamp
, ub1_endian
)
461 > grub_zfs_to_cpu64 (ub2
->ub_timestamp
, ub2_endian
))
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
475 uberblock_verify (uberblock_phys_t
* ub
, grub_uint64_t offset
,
478 uberblock_t
*uber
= &ub
->ubp_uberblock
;
480 grub_zfs_endian_t endian
= GRUB_ZFS_UNKNOWN_ENDIAN
;
483 if (grub_zfs_to_cpu64 (uber
->ub_magic
, GRUB_ZFS_LITTLE_ENDIAN
)
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
)
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
)
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
,
509 * Find the best uberblock.
511 * Success - Pointer to the best uberblock.
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
;
520 grub_disk_addr_t offset
;
521 grub_err_t err
= GRUB_ERR_NONE
;
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
533 ubptr
= (uberblock_phys_t
*) ((grub_properly_aligned_t
*) ub_array
535 / sizeof (grub_properly_aligned_t
)));
536 err
= uberblock_verify (ubptr
, offset
, 1 << ub_shift
);
539 grub_errno
= GRUB_ERR_NONE
;
543 || vdev_uberblock_compare (&(ubptr
->ubp_uberblock
),
544 &(ubbest
->ubp_uberblock
)) > 0)
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
);
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
;
571 zfs_fetch_nvlist (struct grub_zfs_device_desc
*diskdesc
, char **nvlist
)
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
);
591 return GRUB_ERR_NONE
;
595 fill_vdev_info_real (struct grub_zfs_data
*data
,
597 struct grub_zfs_device_desc
*fill
,
598 struct grub_zfs_device_desc
*insert
,
604 type
= grub_zfs_nvlist_lookup_string (nvlist
, ZPOOL_CONFIG_TYPE
);
609 if (!grub_zfs_nvlist_lookup_uint64 (nvlist
, "id", &(fill
->id
)))
612 return grub_error (GRUB_ERR_BAD_FS
, "couldn't find vdev id");
615 if (!grub_zfs_nvlist_lookup_uint64 (nvlist
, "guid", &(fill
->guid
)))
618 return grub_error (GRUB_ERR_BAD_FS
, "couldn't find vdev id");
623 if (grub_zfs_nvlist_lookup_uint64 (nvlist
, "ashift", &par
))
625 else if (ashift
!= 0xffffffff)
626 fill
->ashift
= ashift
;
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
;
655 return GRUB_ERR_NONE
;
658 if (grub_strcmp (type
, VDEV_TYPE_MIRROR
) == 0
659 || grub_strcmp (type
, VDEV_TYPE_RAIDZ
) == 0)
663 if (grub_strcmp (type
, VDEV_TYPE_MIRROR
) == 0)
664 fill
->type
= DEVICE_MIRROR
;
668 fill
->type
= DEVICE_RAIDZ
;
669 if (!grub_zfs_nvlist_lookup_uint64 (nvlist
, "nparity", &par
))
672 return grub_error (GRUB_ERR_BAD_FS
, "couldn't find raidz parity");
677 nelm
= grub_zfs_nvlist_lookup_nvlist_array_get_nelm (nvlist
,
678 ZPOOL_CONFIG_CHILDREN
);
683 return grub_error (GRUB_ERR_BAD_FS
, "incorrect mirror VDEV");
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
++)
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
);
712 if (fill
->children
[i
].ashift
> fill
->max_children_ashift
)
713 fill
->max_children_ashift
= fill
->children
[i
].ashift
;
716 return GRUB_ERR_NONE
;
719 grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
, "vdev %s isn't supported", type
);
725 fill_vdev_info (struct grub_zfs_data
*data
,
726 char *nvlist
, struct grub_zfs_device_desc
*diskdesc
,
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
)
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
;
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.
771 check_pool_label (struct grub_zfs_data
*data
,
772 struct grub_zfs_device_desc
*diskdesc
,
775 grub_uint64_t pool_state
, txg
= 0;
780 grub_uint64_t poolguid
;
781 grub_uint64_t version
;
787 err
= zfs_fetch_nvlist (diskdesc
, &nvlist
);
791 grub_dprintf ("zfs", "check 2 passed\n");
793 found
= grub_zfs_nvlist_lookup_uint64 (nvlist
, ZPOOL_CONFIG_POOL_STATE
,
799 grub_error (GRUB_ERR_BAD_FS
, ZPOOL_CONFIG_POOL_STATE
" not found");
802 grub_dprintf ("zfs", "check 3 passed\n");
804 if (pool_state
== POOL_STATE_DESTROYED
)
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
);
816 grub_error (GRUB_ERR_BAD_FS
, ZPOOL_CONFIG_POOL_TXG
" not found");
819 grub_dprintf ("zfs", "check 6 passed\n");
821 /* not an active device */
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
,
835 grub_error (GRUB_ERR_BAD_FS
, ZPOOL_CONFIG_VERSION
" not found");
838 grub_dprintf ("zfs", "check 8 passed\n");
840 if (version
> SPA_VERSION
)
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
,
856 grub_error (GRUB_ERR_BAD_FS
, ZPOOL_CONFIG_GUID
" not found");
860 found
= grub_zfs_nvlist_lookup_uint64 (nvlist
, ZPOOL_CONFIG_POOL_GUID
,
866 grub_error (GRUB_ERR_BAD_FS
, ZPOOL_CONFIG_POOL_GUID
" not found");
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");
875 data
->guid
= poolguid
;
879 nv
= grub_zfs_nvlist_lookup_nvlist (nvlist
, ZPOOL_CONFIG_VDEV_TREE
);
884 return grub_error (GRUB_ERR_BAD_FS
, "couldn't find vdev tree");
886 err
= fill_vdev_info (data
, nv
, diskdesc
, inserted
);
895 grub_dprintf ("zfs", "check 10 passed\n");
899 return GRUB_ERR_NONE
;
903 scan_disk (grub_device_t dev
, struct grub_zfs_data
*data
,
904 int original
, int *inserted
)
907 uberblock_phys_t
*ub_array
, *ubbest
= NULL
;
908 vdev_boot_header_t
*bh
;
911 struct grub_zfs_device_desc desc
;
913 ub_array
= grub_malloc (VDEV_UBERBLOCK_RING
);
917 bh
= grub_malloc (VDEV_BOOT_HEADER_SIZE
);
920 grub_free (ub_array
);
924 vdevnum
= VDEV_LABELS
;
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
);
948 grub_errno
= GRUB_ERR_NONE
;
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
;
960 ubbest
= find_bestub (ub_array
, &desc
);
963 grub_dprintf ("zfs", "No uberblock found\n");
964 grub_errno
= GRUB_ERR_NONE
;
968 grub_memmove (&(desc
.current_uberblock
),
969 &ubbest
->ubp_uberblock
, sizeof (uberblock_t
));
971 grub_memmove (&(data
->current_uberblock
),
972 &ubbest
->ubp_uberblock
, sizeof (uberblock_t
));
975 if (find_best_root
&&
976 vdev_uberblock_compare (&ubbest
->ubp_uberblock
,
977 &(current_uberblock
)) <= 0)
980 grub_free (ub_array
);
982 return GRUB_ERR_NONE
;
985 grub_free (ub_array
);
988 return grub_error (GRUB_ERR_BAD_FS
, "couldn't find a valid label");
992 scan_devices (struct grub_zfs_data
*data
)
994 auto int hook (const char *name
);
995 int hook (const char *name
)
1000 dev
= grub_device_open (name
);
1005 grub_device_close (dev
);
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
;
1017 grub_device_close (dev
);
1018 grub_print_error ();
1023 grub_device_close (dev
);
1027 grub_device_iterate (hook
);
1028 return GRUB_ERR_NONE
;
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) ) */
1039 xor_out (grub_uint8_t
*a
, const grub_uint8_t
*b
, grub_size_t s
,
1040 int known_idx
, int recovery_pow
)
1045 if (known_idx
== 0 || recovery_pow
== 0)
1047 grub_crypto_xor (a
, a
, b
, s
);
1050 add
= (known_idx
* recovery_pow
) % 255;
1051 for (;s
--; b
++, a
++)
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)
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
,
1069 grub_dprintf ("zfs", "recovering %u buffers\n", nbufs
);
1071 /* b_i = sum (r_j* (x ** (powers[i] * idx[j])))*/
1072 /* Let's invert the matrix in question. */
1075 /* Easy: r_0 = bufs[0] / (x << (powers[i] * idx[j])). */
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
++)
1085 *a
= powx
[powx_inv
[*a
] + add
];
1086 return GRUB_ERR_NONE
;
1088 /* Case 2x2: Let's use the determinant formula. */
1091 grub_uint8_t det
, det_inv
;
1092 grub_uint8_t matrixinv
[2][2];
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]);
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
;
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. */
1120 grub_uint8_t matrix1
[nbufs
][nbufs
], matrix2
[nbufs
][nbufs
];
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
++)
1129 for (i
= 0; i
< nbufs
; i
++)
1132 for (i
= 0; i
< nbufs
; i
++)
1135 for (j
= i
; j
< nbufs
; j
++)
1139 return grub_error (GRUB_ERR_BAD_FS
, "singular recovery matrix");
1144 for (j
= 0; j
< nbufs
; j
++)
1147 t
= matrix1
[xchng
][j
];
1148 matrix1
[xchng
][j
] = matrix1
[i
][j
];
1151 for (j
= 0; j
< nbufs
; j
++)
1154 t
= matrix2
[xchng
][j
];
1155 matrix2
[xchng
][j
] = matrix2
[i
][j
];
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
++)
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
++)
1191 for (j
= 0; j
< nbufs
; j
++)
1194 for (k
= 0; k
< nbufs
; k
++)
1195 bufs
[j
][i
] ^= gf_mul (matrix2
[j
][k
], b
[k
]);
1198 return GRUB_ERR_NONE
;
1204 read_device (grub_uint64_t offset
, struct grub_zfs_device_desc
*desc
,
1205 grub_size_t len
, void *buf
)
1211 grub_uint64_t sector
;
1212 sector
= DVA_OFFSET_TO_PHYS_SECTOR (offset
);
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
);
1224 grub_err_t err
= GRUB_ERR_NONE
;
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
],
1235 grub_errno
= GRUB_ERR_NONE
;
1237 return (grub_errno
= err
);
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;
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);
1262 high
= grub_divmod64 ((offset
>> desc
->ashift
),
1263 desc
->n_children
, &m
);
1264 if (desc
->nparity
== 2)
1266 if (desc
->nparity
== 3)
1268 if (((len
+ (1 << desc
->ashift
) - 1) >> desc
->ashift
)
1269 >= (desc
->n_children
- desc
->nparity
))
1270 idx
= (desc
->n_children
- desc
->nparity
- 1);
1272 idx
= ((len
+ (1 << desc
->ashift
) - 1) >> desc
->ashift
) - 1;
1277 grub_uint32_t bsize
;
1279 bsize
= s
/ (desc
->n_children
- desc
->nparity
);
1281 if (desc
->nparity
== 1
1282 && ((offset
>> (desc
->ashift
+ 20 - desc
->max_children_ashift
))
1286 high
= grub_divmod64 ((offset
>> desc
->ashift
) + c
,
1287 desc
->n_children
, &devn
);
1288 csize
= bsize
<< desc
->ashift
;
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
,
1298 err
= read_device ((high
<< desc
->ashift
)
1299 | (offset
& ((1 << desc
->ashift
) - 1)),
1300 &desc
->children
[devn
],
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
;
1308 grub_errno
= err
= 0;
1316 buf
= (char *) buf
+ csize
;
1321 unsigned redundancy_pow
[4];
1322 unsigned cur_redundancy_pow
= 0;
1323 unsigned n_redundancy
= 0;
1327 /* Compute mul. x**s has a period of 255. */
1330 grub_uint8_t cur
= 1;
1331 for (i
= 0; i
< 255; i
++)
1334 powx
[i
+ 255] = cur
;
1337 cur
= (cur
<< 1) ^ poly
;
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
))
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
1364 grub_errno
= GRUB_ERR_NONE
;
1369 redundancy_pow
[n_redundancy
] = cur_redundancy_pow
;
1372 /* Now xor-our the parts we already know. */
1381 csize
= ((s
/ (desc
->n_children
- desc
->nparity
))
1386 for (j
= 0; j
< failed_devices
; j
++)
1387 if (buf
== recovery_buf
[j
])
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
]);
1397 buf
= (char *) buf
+ csize
;
1401 for (i
= 0; i
< failed_devices
1402 && recovery_len
[i
] == recovery_len
[0];
1404 /* Since the chunks have variable length handle the last block
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
,
1416 err
= recovery (recovery_buf
, recovery_len
[failed_devices
- 1],
1417 failed_devices
, redundancy_pow
, recovery_idx
);
1421 return GRUB_ERR_NONE
;
1424 return grub_error (GRUB_ERR_BAD_FS
, "unsupported device type");
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
;
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
);
1445 return GRUB_ERR_NONE
;
1450 err
= scan_devices (data
);
1455 return grub_error (GRUB_ERR_BAD_FS
, "unknown device %d",
1456 (int) DVA_GET_VDEV (dva
));
1461 * Read a block of data based on the gang block address dva,
1462 * and put its data in buf.
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
;
1474 grub_memset (&zc
, 0, sizeof (zc
));
1476 zio_gb
= grub_malloc (SPA_GANGBLOCKSIZE
);
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
);
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
);
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)
1508 err
= zio_read_data (&zio_gb
->zg_blkptr
[i
], endian
, buf
, data
);
1514 buf
= (char *) buf
+ get_psize (&zio_gb
->zg_blkptr
[i
], endian
);
1517 return GRUB_ERR_NONE
;
1521 * Read in a block of raw data to buf.
1524 zio_read_data (blkptr_t
* bp
, grub_zfs_endian_t endian
, void *buf
,
1525 struct grub_zfs_data
*data
)
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)
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
);
1541 err
= read_dva (&bp
->blk_dva
[i
], endian
, data
, buf
, psize
);
1543 return GRUB_ERR_NONE
;
1544 grub_errno
= GRUB_ERR_NONE
;
1548 err
= grub_error (GRUB_ERR_BAD_FS
, "couldn't find a valid DVA");
1555 * Read in a block of data, verify its checksum, decompress if needed,
1556 * and put the uncompressed data in buf.
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
;
1566 zio_cksum_t zc
= bp
->blk_cksum
;
1567 grub_uint32_t checksum
;
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
);
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));
1598 compbuf
= *buf
= grub_malloc (lsize
);
1600 grub_dprintf ("zfs", "endian = %d\n", endian
);
1601 err
= zio_read_data (bp
, endian
, compbuf
, data
);
1604 grub_free (compbuf
);
1608 grub_memset (compbuf
, 0, ALIGN_UP (psize
, 16) - psize
);
1610 err
= zio_checksum_verify (zc
, checksum
, endian
,
1614 grub_dprintf ("zfs", "incorrect checksum\n");
1615 grub_free (compbuf
);
1622 if (!grub_zfs_decrypt
)
1623 err
= grub_error (GRUB_ERR_BAD_FS
,
1624 N_("module `%s' isn't loaded"),
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
,
1633 && data
->subvol
.keyring
[i
].txg
> bestval
)
1636 bestval
= data
->subvol
.keyring
[i
].txg
;
1640 grub_free (compbuf
);
1642 grub_dprintf ("zfs", "no key for txg %" PRIxGRUB_UINT64_T
"\n",
1643 grub_zfs_to_cpu64 (bp
->blk_birth
,
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
,
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),
1661 grub_free (compbuf
);
1667 if (comp
!= ZIO_COMPRESS_OFF
)
1669 *buf
= grub_malloc (lsize
);
1672 grub_free (compbuf
);
1676 err
= decomp_table
[comp
].decomp_func (compbuf
, *buf
, psize
, lsize
);
1677 grub_free (compbuf
);
1686 return GRUB_ERR_NONE
;
1690 * Get the block from a block id.
1691 * push the block onto the stack.
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
)
1700 blkptr_t
*bp_array
= dn
->dn
.dn_blkptr
;
1701 int epbs
= dn
->dn
.dn_indblkshift
- SPA_BLKPTRSHIFT
;
1704 grub_zfs_endian_t endian
;
1705 grub_err_t err
= GRUB_ERR_NONE
;
1707 bp
= grub_malloc (sizeof (blkptr_t
));
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
);
1723 if (BP_IS_HOLE (bp
))
1725 grub_size_t size
= grub_zfs_to_cpu16 (dn
->dn
.dn_datablkszsec
,
1727 << SPA_MINBLOCKSHIFT
;
1728 *buf
= grub_malloc (size
);
1734 grub_memset (*buf
, 0, size
);
1735 endian
= (grub_zfs_to_cpu64 (bp
->blk_prop
, endian
) >> 63) & 1;
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;
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;
1752 if (bp_array
!= dn
->dn
.dn_blkptr
)
1753 grub_free (bp_array
);
1755 *endian_out
= endian
;
1762 * mzap_lookup: Looks up property described by "name" and returns the value
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
)
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
);
1788 mzap_iterate (mzap_phys_t
* zapobj
, grub_zfs_endian_t endian
, int objsize
,
1789 int NESTED_FUNC_ATTR (*hook
) (const char *name
,
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
)))
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
;
1816 grub_uint64_t crc
= salt
;
1818 if (table
[128] == 0)
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];
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);
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.
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
);
1865 if (grub_toupper (*t1
) != grub_toupper (*t2
))
1866 return (int) grub_toupper (*t1
) - (int) grub_toupper (*t2
);
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
))
1894 if (name_cmp ((char *) la
->la_array
, buf
+ bseen
, toread
,
1895 case_insensitive
) != 0)
1897 chunk
= grub_zfs_to_cpu16 (la
->la_next
, endian
);
1900 return (bseen
== array_len
);
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
);
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".
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
)
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
,
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 */
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
;
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
)
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
);
2021 grub_zfs_endian_t leafendian
;
2023 err
= zap_verify (zap
, zap_dnode
->endian
);
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
);
2043 err
= zap_leaf_lookup (l
, leafendian
, blksft
, hash
, name
, value
,
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
,
2057 grub_size_t elemsize
),
2058 struct grub_zfs_data
*data
)
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
);
2067 grub_zfs_endian_t endian
;
2069 if (zap_verify (zap
, zap_dnode
->endian
))
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");
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");
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))],
2090 for (idx2
= 0; idx2
< idx
; idx2
++)
2091 if (blkid
== grub_zfs_to_cpu64 (((grub_uint64_t
*) zap
)[idx2
+ (1 << (blksft
- 3 - 1))],
2097 err
= dmu_read (zap_dnode
, blkid
, &l_in
, &endian
, data
);
2101 grub_errno
= GRUB_ERR_NONE
;
2105 /* Verify if this is a valid leaf block */
2106 if (grub_zfs_to_cpu64 (l
->l_hdr
.lh_block_type
, endian
) != ZBT_LEAF
)
2111 if (grub_zfs_to_cpu32 (l
->l_hdr
.lh_magic
, endian
) != ZAP_LEAF_MAGIC
)
2117 for (chunk
= 0; chunk
< ZAP_LEAF_NUMCHUNKS (blksft
); chunk
++)
2120 struct zap_leaf_entry
*le
;
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
)
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
,
2134 grub_zfs_to_cpu16 (le
->le_name_length
,
2136 * name_elem_length
, buf
))
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
,
2156 if (hook (buf
, le
->le_name_length
,
2157 val
, le
->le_value_length
, le
->le_int_size
))
2171 * Read in the data of a zap object and find the value for a matching
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
;
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
);
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
,
2202 grub_dprintf ("zfs", "returned %d\n", 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
,
2212 grub_dprintf ("zfs", "returned %d\n", err
);
2217 return grub_error (GRUB_ERR_BAD_FS
, "unknown ZAP type");
2221 zap_iterate_u64 (dnode_end_t
* zap_dnode
,
2222 int NESTED_FUNC_ATTR (*hook
) (const char *name
,
2224 struct grub_zfs_data
*data
)
2226 grub_uint64_t block_type
;
2231 grub_zfs_endian_t endian
;
2233 auto int NESTED_FUNC_ATTR
transform (const void *name
,
2234 grub_size_t namelen
,
2237 grub_size_t elemsize
);
2239 int NESTED_FUNC_ATTR
transform (const void *name
,
2240 grub_size_t namelen
__attribute__ ((unused
)),
2243 grub_size_t elemsize
)
2245 if (elemsize
!= sizeof (grub_uint64_t
) || nelem
!= 1)
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
);
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
);
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
);
2274 grub_error (GRUB_ERR_BAD_FS
, "unknown ZAP type");
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
,
2285 grub_size_t elemsize
),
2286 struct grub_zfs_data
*data
)
2288 grub_uint64_t block_type
;
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
);
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");
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
);
2315 grub_error (GRUB_ERR_BAD_FS
, "unknown ZAP type");
2321 * Get the dnode of an object number from the metadnode of an object set.
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
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 */
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
,
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
);
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;
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.
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
;
2402 grub_err_t err
= GRUB_ERR_NONE
;
2403 char *path
, *path_buf
;
2406 struct dnode_chain
*next
;
2409 struct dnode_chain
*dnode_path
= 0, *dn_new
, *root
;
2411 dn_new
= grub_malloc (sizeof (*dn_new
));
2415 dnode_path
= root
= dn_new
;
2417 err
= dnode_get (&subvol
->mdn
, MASTER_NODE_OBJ
, DMU_OT_MASTER_NODE
,
2418 &(dnode_path
->dn
), data
);
2425 err
= zap_lookup (&(dnode_path
->dn
), ZPL_VERSION_STR
, &version
,
2433 if (version
> ZPL_VERSION
)
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
,
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);
2455 err
= dnode_get (&subvol
->mdn
, objnum
, 0, &(dnode_path
->dn
), data
);
2462 path
= path_buf
= grub_strdup (path_in
);
2471 /* skip leading slashes */
2472 while (*path
== '/')
2476 /* get the next component name */
2478 while (*path
&& *path
!= '/')
2481 if (cname
+ 1 == path
&& cname
[0] == '.')
2483 /* Handle double dot. */
2484 if (cname
+ 2 == path
&& cname
[0] == '.' && cname
[1] == '.')
2488 dn_new
= dnode_path
;
2489 dnode_path
= dn_new
->next
;
2494 err
= grub_error (GRUB_ERR_FILE_NOT_FOUND
,
2495 "can't resolve ..");
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
);
2514 dn_new
= grub_malloc (sizeof (*dn_new
));
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
);
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)
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)
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
);
2551 for (block
= 0; block
< (sym_sz
+ blksz
- 1) / blksz
; block
++)
2554 grub_size_t movesize
;
2556 err
= dmu_read (&(dnode_path
->dn
), block
, &t
, 0, data
);
2560 movesize
= sym_sz
- block
* blksz
;
2561 if (movesize
> blksz
)
2564 grub_memcpy (sym_value
+ block
* blksz
, t
, movesize
);
2569 path
= path_buf
= grub_malloc (sym_sz
+ grub_strlen (oldpath
) + 1);
2572 grub_free (oldpathbuf
);
2575 grub_memcpy (path
, sym_value
, sym_sz
);
2577 grub_free (sym_value
);
2579 grub_memcpy (path
+ grub_strlen (path
), oldpath
,
2580 grub_strlen (oldpath
) + 1);
2582 grub_free (oldpathbuf
);
2585 dn_new
= dnode_path
;
2586 dnode_path
= dn_new
->next
;
2589 else while (dnode_path
!= root
)
2591 dn_new
= dnode_path
;
2592 dnode_path
= dn_new
->next
;
2596 if (dnode_path
->dn
.dn
.dn_bonustype
== DMU_OT_SA
)
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
);
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
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
2630 dnode_path
->dn
.endian
);
2631 char *oldpath
= path
, *oldpathbuf
= path_buf
;
2632 path
= path_buf
= grub_malloc (sym_sz
+ grub_strlen (oldpath
) + 1);
2635 grub_free (oldpathbuf
);
2638 grub_memcpy (path
, sym_value
, sym_sz
);
2640 grub_memcpy (path
+ grub_strlen (path
), oldpath
,
2641 grub_strlen (oldpath
) + 1);
2643 grub_free (oldpathbuf
);
2646 dn_new
= dnode_path
;
2647 dnode_path
= dn_new
->next
;
2650 else while (dnode_path
!= root
)
2652 dn_new
= dnode_path
;
2653 dnode_path
= dn_new
->next
;
2661 grub_memcpy (dn
, &(dnode_path
->dn
), sizeof (*dn
));
2665 dn_new
= dnode_path
->next
;
2666 grub_free (dnode_path
);
2667 dnode_path
= dn_new
;
2669 grub_free (path_buf
);
2675 * Get the default 'bootfs' property value from the rootpool.
2679 get_default_bootfsobj (dnode_phys_t
* mosmdn
, grub_uint64_t
* obj
,
2680 struct grub_zfs_data
*data
)
2682 grub_uint64_t objnum
= 0;
2687 if ((grub_errno
= dnode_get (mosmdn
, DMU_POOL_DIRECTORY_OBJECT
,
2688 DMU_OT_OBJECT_DIRECTORY
, dn
, data
)))
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
))
2701 return (GRUB_ERR_BAD_FS
);
2703 if ((grub_errno
= dnode_get (mosmdn
, objnum
, DMU_OT_POOL_PROPS
, dn
, data
)))
2706 return (grub_errno
);
2708 if (zap_lookup (dn
, ZPOOL_PROP_BOOTFS
, &objnum
, data
))
2711 return (GRUB_ERR_BAD_FS
);
2717 return (GRUB_ERR_BAD_FS
);
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
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.
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
;
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
);
2748 grub_dprintf ("zfs", "alive\n");
2750 err
= zap_lookup (mdn
, DMU_POOL_ROOT_DATASET
, &objnum
, data
, 0);
2754 grub_dprintf ("zfs", "alive\n");
2756 err
= dnode_get (mosmdn
, objnum
, DMU_OT_DSL_DIR
, mdn
, data
);
2760 grub_dprintf ("zfs", "alive\n");
2764 grub_uint64_t childobj
;
2767 while (*fsname
== '/')
2770 if (! *fsname
|| *fsname
== '@')
2774 while (*fsname
&& *fsname
!= '/')
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
);
2785 err
= zap_lookup (mdn
, cname
, &objnum
, data
, 0);
2789 err
= dnode_get (mosmdn
, objnum
, DMU_OT_DSL_DIR
, mdn
, data
);
2795 return GRUB_ERR_NONE
;
2799 make_mdn (dnode_end_t
* mdn
, struct grub_zfs_data
*data
)
2803 grub_size_t ospsize
;
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
);
2812 if (ospsize
< OBJSET_PHYS_SIZE_V14
)
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
);
2822 return GRUB_ERR_NONE
;
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
;
2838 auto int NESTED_FUNC_ATTR
count_zap_keys (const void *name
,
2839 grub_size_t namelen
,
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
)))
2853 auto int NESTED_FUNC_ATTR
load_zap_key (const void *name
,
2854 grub_size_t namelen
,
2857 grub_size_t elemsize
);
2858 int NESTED_FUNC_ATTR
load_zap_key (const void *name
,
2859 grub_size_t namelen
,
2862 grub_size_t elemsize
)
2866 grub_dprintf ("zfs", "Unexpected key index size %" PRIuGRUB_SIZE
"\n",
2873 grub_dprintf ("zfs", "Unexpected key element size %" PRIuGRUB_SIZE
"\n",
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
);
2886 ptr_at
= grub_strchr (fullpath
, '@');
2892 fsname
= grub_strdup (fullpath
);
2896 const char *ptr_slash
= grub_strchr (ptr_at
, '/');
2899 fsname
= grub_malloc (ptr_at
- fullpath
+ 1);
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
);
2912 grub_memcpy (snapname
, ptr_at
+ 1, ptr_slash
- ptr_at
- 1);
2913 snapname
[ptr_slash
- ptr_at
- 1] = 0;
2918 filename
= ptr_slash
;
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
);
2929 grub_free (snapname
);
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
,
2944 grub_free (snapname
);
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
,
2961 grub_free (snapname
);
2965 err
= zap_lookup (&props_dn
, "salt", &salt
, data
, 0);
2966 if (err
== GRUB_ERR_FILE_NOT_FOUND
)
2974 grub_dprintf ("zfs", "failed here\n");
2978 err
= dnode_get (&(data
->mos
), keychainobj
, DMU_OT_DSL_KEYCHAIN
,
2979 &keychain_dn
, data
);
2983 grub_free (snapname
);
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
)
2992 grub_free (snapname
);
2995 zap_iterate (&keychain_dn
, 8, load_zap_key
, data
);
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
);
3007 err
= zap_lookup (&subvol
->mdn
, snapname
, &headobj
, data
, 0);
3009 err
= dnode_get (&(data
->mos
), headobj
, DMU_OT_DSL_DATASET
,
3010 &subvol
->mdn
, data
);
3014 grub_free (snapname
);
3019 subvol
->obj
= headobj
;
3021 make_mdn (&subvol
->mdn
, data
);
3023 grub_dprintf ("zfs", "endian = %d\n", subvol
->mdn
.endian
);
3028 grub_free (snapname
);
3029 return GRUB_ERR_NONE
;
3031 err
= dnode_get_path (subvol
, filename
, dn
, data
);
3033 grub_free (snapname
);
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)
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)
3053 * 2 zero's for the last nvpair
3054 * (end of the entire list) (8 bytes)
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");
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
))))
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");
3094 nvpair
= nvlist
+ 4 * 2; /* skip the encode/decode size */
3096 name_len
= grub_be_to_cpu32 (grub_get_unaligned32 (nvpair
));
3100 nvpair
= nvpair
+ ((name_len
+ 3) & ~3); /* align */
3102 if (nvpair
+ 8 >= nvlist_in
+ VDEV_PHYS_SIZE
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");
3111 type
= grub_be_to_cpu32 (grub_get_unaligned32 (nvpair
));
3114 nelm
= grub_be_to_cpu32 (grub_get_unaligned32 (nvpair
));
3117 grub_error (GRUB_ERR_BAD_FS
, "empty nvpair");
3123 if ((grub_strncmp (nvp_name
, name
, name_len
) == 0) && type
== valtype
)
3125 *val
= (char *) nvpair
;
3126 *size_out
= encode_size
;
3132 nvlist
+= encode_size
; /* goto the next nvpair */
3138 grub_zfs_nvlist_lookup_uint64 (const char *nvlist
, const char *name
,
3139 grub_uint64_t
* out
)
3145 found
= nvlist_find_value (nvlist
, name
, DATA_TYPE_UINT64
, &nvpair
, &size
, 0);
3148 if (size
< sizeof (grub_uint64_t
))
3150 grub_error (GRUB_ERR_BAD_FS
, "invalid uint64");
3154 *out
= grub_be_to_cpu64 (grub_get_unaligned64 (nvpair
));
3159 grub_zfs_nvlist_lookup_string (const char *nvlist
, const char *name
)
3167 found
= nvlist_find_value (nvlist
, name
, DATA_TYPE_STRING
, &nvpair
, &size
, 0);
3172 grub_error (GRUB_ERR_BAD_FS
, "invalid string");
3175 slen
= grub_be_to_cpu32 (grub_get_unaligned32 (nvpair
));
3176 if (slen
> size
- 4)
3178 ret
= grub_malloc (slen
+ 1);
3181 grub_memcpy (ret
, nvpair
+ 4, slen
);
3187 grub_zfs_nvlist_lookup_nvlist (const char *nvlist
, const char *name
)
3194 found
= nvlist_find_value (nvlist
, name
, DATA_TYPE_NVLIST
, &nvpair
,
3198 ret
= grub_zalloc (size
+ 3 * sizeof (grub_uint32_t
));
3201 grub_memcpy (ret
, nvlist
, sizeof (grub_uint32_t
));
3203 grub_memcpy (ret
+ sizeof (grub_uint32_t
), nvpair
, size
);
3208 grub_zfs_nvlist_lookup_nvlist_array_get_nelm (const char *nvlist
,
3212 grub_size_t nelm
, size
;
3215 found
= nvlist_find_value (nvlist
, name
, DATA_TYPE_NVLIST_ARRAY
, &nvpair
,
3223 get_nvlist_size (const char *beg
, const char *limit
)
3226 grub_uint32_t encode_size
;
3231 && (encode_size
= grub_be_to_cpu32 (grub_get_unaligned32 (ptr
))))
3232 ptr
+= encode_size
; /* goto the next nvpair */
3234 return (ptr
> limit
) ? -1 : (ptr
- beg
);
3238 grub_zfs_nvlist_lookup_nvlist_array (const char *nvlist
, const char *name
,
3241 char *nvpair
, *nvpairptr
;
3249 found
= nvlist_find_value (nvlist
, name
, DATA_TYPE_NVLIST_ARRAY
, &nvpair
,
3255 grub_error (GRUB_ERR_OUT_OF_RANGE
, "trying to lookup past nvlist array");
3261 for (i
= 0; i
< index
; i
++)
3264 r
= get_nvlist_size (nvpairptr
, nvpair
+ size
);
3268 grub_error (GRUB_ERR_BAD_FS
, "incorrect nvlist array");
3274 elemsize
= get_nvlist_size (nvpairptr
, nvpair
+ size
);
3278 grub_error (GRUB_ERR_BAD_FS
, "incorrect nvlist array");
3282 ret
= grub_zalloc (elemsize
+ sizeof (grub_uint32_t
));
3285 grub_memcpy (ret
, nvlist
, sizeof (grub_uint32_t
));
3287 grub_memcpy (ret
+ sizeof (grub_uint32_t
), nvpairptr
, elemsize
);
3292 unmount_device (struct grub_zfs_device_desc
*desc
)
3298 if (!desc
->original
&& desc
->dev
)
3299 grub_device_close (desc
->dev
);
3303 for (i
= 0; i
< desc
->n_children
; i
++)
3304 unmount_device (&desc
->children
[i
]);
3305 grub_free (desc
->children
);
3311 zfs_unmount (struct grub_zfs_data
*data
)
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
);
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;
3337 grub_size_t ospsize
;
3338 grub_zfs_endian_t ub_endian
= GRUB_ZFS_UNKNOWN_ENDIAN
;
3344 grub_error (GRUB_ERR_BAD_DEVICE
, "not a disk");
3348 data
= grub_zalloc (sizeof (*data
));
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 (¤t_uberblock
, 0, sizeof (uberblock_t
));
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
);
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
);
3381 if (ospsize
< OBJSET_PHYS_SIZE_V14
)
3383 grub_error (GRUB_ERR_BAD_FS
, "OSP too small");
3389 /* Got the MOS. Save it at the memory addr MOS. */
3390 grub_memmove (&(data
->mos
.dn
), &((objset_phys_t
*) osp
)->os_meta_dnode
,
3392 data
->mos
.endian
= (grub_zfs_to_cpu64 (ub
->ub_rootbp
.blk_prop
,
3393 ub_endian
) >> 63) & 1;
3402 grub_zfs_fetch_nvlist (grub_device_t dev
, char **nvlist
)
3404 struct grub_zfs_data
*zfs
;
3407 zfs
= zfs_mount (dev
);
3410 err
= zfs_fetch_nvlist (zfs
->device_original
, nvlist
);
3416 zfs_label (grub_device_t device
, char **label
)
3420 struct grub_zfs_data
*data
;
3422 data
= zfs_mount (device
);
3426 err
= zfs_fetch_nvlist (data
->device_original
, &nvlist
);
3433 *label
= grub_zfs_nvlist_lookup_string (nvlist
, ZPOOL_CONFIG_POOL_NAME
);
3440 zfs_uuid (grub_device_t device
, char **uuid
)
3442 struct grub_zfs_data
*data
;
3446 data
= zfs_mount (device
);
3450 *uuid
= grub_xasprintf ("%016llx", (long long unsigned) data
->guid
);
3454 return GRUB_ERR_NONE
;
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
;
3466 data
= zfs_mount (device
);
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
);
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.
3485 grub_zfs_open (struct grub_file
*file
, const char *fsfilename
)
3487 struct grub_zfs_data
*data
;
3491 data
= zfs_mount (file
->device
);
3495 err
= dnode_get_fullpath (fsfilename
, &(data
->subvol
),
3496 &(data
->dnode
), &isfs
, 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
)
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
)
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
);
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
);
3553 return grub_error (GRUB_ERR_BAD_FS
, "bad bonus type");
3559 grub_dl_ref (my_mod
);
3562 return GRUB_ERR_NONE
;
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
;
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
,
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.
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
);
3606 err
= dmu_read (&(data
->dnode
), blkid
, &t
,
3611 data
->file_buf
= NULL
;
3612 data
->file_start
= data
->file_end
= 0;
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
)
3623 grub_memmove (buf
, data
->file_buf
+ file
->offset
+ read
3624 - data
->file_start
, movesize
);
3634 grub_zfs_close (grub_file_t file
)
3636 zfs_unmount ((struct grub_zfs_data
*) file
->data
);
3639 grub_dl_unref (my_mod
);
3642 return GRUB_ERR_NONE
;
3646 grub_zfs_getmdnobj (grub_device_t dev
, const char *fsfilename
,
3647 grub_uint64_t
*mdnobj
)
3649 struct grub_zfs_data
*data
;
3653 data
= zfs_mount (dev
);
3657 err
= dnode_get_fullpath (fsfilename
, &(data
->subvol
),
3658 &(data
->dnode
), &isfs
, data
);
3659 *mdnobj
= data
->subvol
.obj
;
3665 fill_fs_info (struct grub_dirhook_info
*info
,
3666 dnode_end_t mdn
, struct grub_zfs_data
*data
)
3670 grub_uint64_t objnum
;
3671 grub_uint64_t headobj
;
3673 grub_memset (info
, 0, sizeof (*info
));
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
);
3684 grub_dprintf ("zfs", "failed here\n");
3688 make_mdn (&mdn
, data
);
3689 err
= dnode_get (&mdn
, MASTER_NODE_OBJ
, DMU_OT_MASTER_NODE
,
3693 grub_dprintf ("zfs", "failed here\n");
3697 err
= zap_lookup (&dn
, ZFS_ROOT_OBJ
, &objnum
, data
, 0);
3700 grub_dprintf ("zfs", "failed here\n");
3704 err
= dnode_get (&mdn
, objnum
, 0, &dn
, data
);
3707 grub_dprintf ("zfs", "failed here\n");
3711 if (dn
.dn
.dn_bonustype
== DMU_OT_SA
)
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
);
3730 grub_error (GRUB_ERR_BAD_FS
, "filesystem is corrupt");
3734 hdrsize
= SA_HDR_SIZE (((sa_hdr_phys_t
*) sahdrp
));
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
)
3742 info
->mtime
= grub_zfs_to_cpu64 (((znode_phys_t
*) DN_BONUS (&dn
.dn
))->zp_mtime
[0], dn
.endian
);
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
;
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
,
3757 auto int NESTED_FUNC_ATTR
iterate_zap_snap (const char *name
,
3760 int NESTED_FUNC_ATTR
iterate_zap (const char *name
, grub_uint64_t val
)
3762 struct grub_dirhook_info info
;
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
)
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
);
3784 grub_print_error ();
3790 grub_error (GRUB_ERR_BAD_FS
, "filesystem is corrupt");
3791 grub_print_error ();
3795 hdrsize
= SA_HDR_SIZE (((sa_hdr_phys_t
*) sahdrp
));
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
)
3804 info
.mtime
= grub_zfs_to_cpu64 (((znode_phys_t
*) DN_BONUS (&dn
.dn
))->zp_mtime
[0],
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
;
3817 err
= dnode_get (&(data
->mos
), val
, 0, &mdn
, data
);
3820 if (mdn
.dn
.dn_type
!= DMU_OT_DSL_DIR
)
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
;
3833 err
= dnode_get (&(data
->mos
), val
, 0, &mdn
, data
);
3837 if (mdn
.dn
.dn_type
!= DMU_OT_DSL_DATASET
)
3840 fill_fs_info (&info
, mdn
, data
);
3842 name2
= grub_malloc (grub_strlen (name
) + 2);
3844 grub_memcpy (name2
+ 1, name
, grub_strlen (name
) + 1);
3845 ret
= hook (name2
, &info
);
3850 data
= zfs_mount (device
);
3853 err
= dnode_get_fullpath (path
, &(data
->subvol
), &(data
->dnode
), &isfs
, data
);
3861 grub_uint64_t childobj
, headobj
;
3862 grub_uint64_t snapobj
;
3864 struct grub_dirhook_info info
;
3866 fill_fs_info (&info
, data
->dnode
, data
);
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
);
3879 zap_iterate_u64 (&dn
, iterate_zap_fs
, data
);
3881 err
= dnode_get (&(data
->mos
), headobj
, DMU_OT_DSL_DATASET
, &dn
, data
);
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
);
3898 zap_iterate_u64 (&dn
, iterate_zap_snap
, data
);
3902 if (data
->dnode
.dn
.dn_type
!= DMU_OT_DIRECTORY_CONTENTS
)
3905 return grub_error (GRUB_ERR_BAD_FILE_TYPE
, N_("not a directory"));
3907 zap_iterate_u64 (&(data
->dnode
), iterate_zap
, data
);
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
)
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
));
3938 for (i
= 0; i
< *nsectors
; i
++)
3939 (*sectors
)[i
] = i
+ (VDEV_BOOT_OFFSET
>> GRUB_DISK_SECTOR_BITS
);
3941 return GRUB_ERR_NONE
;
3945 static struct grub_fs grub_zfs_fs
= {
3947 .dir
= grub_zfs_dir
,
3948 .open
= grub_zfs_open
,
3949 .read
= grub_zfs_read
,
3950 .close
= grub_zfs_close
,
3955 .embed
= grub_zfs_embed
,
3956 .reserved_first_sector
= 1,
3957 .blocklist_install
= 0,
3964 COMPILE_TIME_ASSERT (sizeof (zap_leaf_chunk_t
) == ZAP_LEAF_CHUNKSIZE
);
3965 grub_fs_register (&grub_zfs_fs
);
3973 grub_fs_unregister (&grub_zfs_fs
);