2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc.
4 * Copyright 2008 Sun Microsystems, Inc.
5 * Copyright (C) 2009 Vladimir Serbinenko <phcoder@gmail.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 * The zfs plug-in routines for GRUB are:
24 * zfs_mount() - locates a valid uberblock of the root pool and reads
25 * in its MOS at the memory address MOS.
27 * zfs_open() - locates a plain file object by following the MOS
28 * and places its dnode at the memory address DNODE.
30 * zfs_read() - read in the data blocks pointed by the DNODE.
35 #include <grub/file.h>
37 #include <grub/misc.h>
38 #include <grub/disk.h>
39 #include <grub/partition.h>
41 #include <grub/types.h>
42 #include <grub/zfs/zfs.h>
43 #include <grub/zfs/zio.h>
44 #include <grub/zfs/dnode.h>
45 #include <grub/zfs/uberblock_impl.h>
46 #include <grub/zfs/vdev_impl.h>
47 #include <grub/zfs/zio_checksum.h>
48 #include <grub/zfs/zap_impl.h>
49 #include <grub/zfs/zap_leaf.h>
50 #include <grub/zfs/zfs_znode.h>
51 #include <grub/zfs/dmu.h>
52 #include <grub/zfs/dmu_objset.h>
53 #include <grub/zfs/dsl_dir.h>
54 #include <grub/zfs/dsl_dataset.h>
56 #define ZPOOL_PROP_BOOTFS "bootfs"
58 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
61 * For nvlist manipulation. (from nvpair.h)
63 #define NV_ENCODE_NATIVE 0
64 #define NV_ENCODE_XDR 1
65 #define NV_BIG_ENDIAN 0
66 #define NV_LITTLE_ENDIAN 1
67 #define DATA_TYPE_UINT64 8
68 #define DATA_TYPE_STRING 9
69 #define DATA_TYPE_NVLIST 19
70 #define DATA_TYPE_NVLIST_ARRAY 20
73 static grub_dl_t my_mod
;
76 #define P2PHASE(x, align) ((x) & ((align) - 1))
77 #define DVA_OFFSET_TO_PHYS_SECTOR(offset) \
78 ((offset + VDEV_LABEL_START_SIZE) >> SPA_MINBLOCKSHIFT)
81 * FAT ZAP data structures
83 #define ZFS_CRC64_POLY 0xC96C5795D7870F42ULL /* ECMA-182, reflected form */
84 #define ZAP_HASH_IDX(hash, n) (((n) == 0) ? 0 : ((hash) >> (64 - (n))))
85 #define CHAIN_END 0xffff /* end of the chunk chain */
88 * The amount of space within the chunk available for the array is:
89 * chunk size - space for type (1) - space for next pointer (2)
91 #define ZAP_LEAF_ARRAY_BYTES (ZAP_LEAF_CHUNKSIZE - 3)
93 #define ZAP_LEAF_HASH_SHIFT(bs) (bs - 5)
94 #define ZAP_LEAF_HASH_NUMENTRIES(bs) (1 << ZAP_LEAF_HASH_SHIFT(bs))
95 #define LEAF_HASH(bs, h) \
96 ((ZAP_LEAF_HASH_NUMENTRIES(bs)-1) & \
97 ((h) >> (64 - ZAP_LEAF_HASH_SHIFT(bs)-l->l_hdr.lh_prefix_len)))
100 * The amount of space available for chunks is:
101 * block size shift - hash entry size (2) * number of hash
102 * entries - header space (2*chunksize)
104 #define ZAP_LEAF_NUMCHUNKS(bs) \
105 (((1<<bs) - 2*ZAP_LEAF_HASH_NUMENTRIES(bs)) / \
106 ZAP_LEAF_CHUNKSIZE - 2)
109 * The chunks start immediately after the hash table. The end of the
110 * hash table is at l_hash + HASH_NUMENTRIES, which we simply cast to a
113 #define ZAP_LEAF_CHUNK(l, bs, idx) \
114 ((zap_leaf_chunk_t *)(l->l_hash + ZAP_LEAF_HASH_NUMENTRIES(bs)))[idx]
115 #define ZAP_LEAF_ENTRY(l, bs, idx) (&ZAP_LEAF_CHUNK(l, bs, idx).l_entry)
119 * Decompression Entry - lzjb
125 extern grub_err_t
lzjb_decompress (void *, void *, grub_size_t
, grub_size_t
);
127 typedef grub_err_t
zfs_decomp_func_t (void *s_start
, void *d_start
,
128 grub_size_t s_len
, grub_size_t d_len
);
129 typedef struct decomp_entry
132 zfs_decomp_func_t
*decomp_func
;
135 typedef struct dnode_end
138 grub_zfs_endian_t endian
;
143 /* cache for a file block of the currently zfs_open()-ed file */
145 grub_uint64_t file_start
;
146 grub_uint64_t file_end
;
148 /* cache for a dnode block */
149 dnode_phys_t
*dnode_buf
;
150 dnode_phys_t
*dnode_mdn
;
151 grub_uint64_t dnode_start
;
152 grub_uint64_t dnode_end
;
153 grub_zfs_endian_t dnode_endian
;
155 uberblock_t current_uberblock
;
162 grub_disk_addr_t vdev_phys_sector
;
165 decomp_entry_t decomp_table
[ZIO_COMPRESS_FUNCTIONS
] = {
166 {"inherit", 0}, /* ZIO_COMPRESS_INHERIT */
167 {"on", lzjb_decompress
}, /* ZIO_COMPRESS_ON */
168 {"off", 0}, /* ZIO_COMPRESS_OFF */
169 {"lzjb", lzjb_decompress
}, /* ZIO_COMPRESS_LZJB */
170 {"empty", 0} /* ZIO_COMPRESS_EMPTY */
173 static grub_err_t
zio_read_data (blkptr_t
* bp
, grub_zfs_endian_t endian
,
174 void *buf
, struct grub_zfs_data
*data
);
177 * Our own version of log2(). Same thing as highbit()-1.
180 zfs_log2 (grub_uint64_t num
)
193 /* Checksum Functions */
195 zio_checksum_off (const void *buf
__attribute__ ((unused
)),
196 grub_uint64_t size
__attribute__ ((unused
)),
197 grub_zfs_endian_t endian
__attribute__ ((unused
)),
200 ZIO_SET_CHECKSUM (zcp
, 0, 0, 0, 0);
203 /* Checksum Table and Values */
204 zio_checksum_info_t zio_checksum_table
[ZIO_CHECKSUM_FUNCTIONS
] = {
205 {NULL
, 0, 0, "inherit"},
207 {zio_checksum_off
, 0, 0, "off"},
208 {zio_checksum_SHA256
, 1, 1, "label"},
209 {zio_checksum_SHA256
, 1, 1, "gang_header"},
210 {fletcher_2
, 0, 1, "zilog"},
211 {fletcher_2
, 0, 0, "fletcher2"},
212 {fletcher_4
, 1, 0, "fletcher4"},
213 {zio_checksum_SHA256
, 1, 0, "SHA256"},
217 * zio_checksum_verify: Provides support for checksum verification.
219 * Fletcher2, Fletcher4, and SHA256 are supported.
223 zio_checksum_verify (zio_cksum_t zc
, grub_uint32_t checksum
,
224 grub_zfs_endian_t endian
, char *buf
, int size
)
226 zio_block_tail_t
*zbt
= (zio_block_tail_t
*) (buf
+ size
) - 1;
227 zio_checksum_info_t
*ci
= &zio_checksum_table
[checksum
];
228 zio_cksum_t actual_cksum
, expected_cksum
;
230 if (checksum
>= ZIO_CHECKSUM_FUNCTIONS
|| ci
->ci_func
== NULL
)
232 grub_dprintf ("zfs", "unknown checksum function %d\n", checksum
);
233 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
,
234 "unknown checksum function %d", checksum
);
239 expected_cksum
= zbt
->zbt_cksum
;
241 ci
->ci_func (buf
, size
, endian
, &actual_cksum
);
242 zbt
->zbt_cksum
= expected_cksum
;
246 ci
->ci_func (buf
, size
, endian
, &actual_cksum
);
248 if ((actual_cksum
.zc_word
[0] != zc
.zc_word
[0])
249 || (actual_cksum
.zc_word
[1] != zc
.zc_word
[1])
250 || (actual_cksum
.zc_word
[2] != zc
.zc_word
[2])
251 || (actual_cksum
.zc_word
[3] != zc
.zc_word
[3]))
253 grub_dprintf ("zfs", "checksum %d verification failed\n", checksum
);
254 grub_dprintf ("zfs", "actual checksum %16llx %16llx %16llx %16llx\n",
255 (unsigned long long) actual_cksum
.zc_word
[0],
256 (unsigned long long) actual_cksum
.zc_word
[1],
257 (unsigned long long) actual_cksum
.zc_word
[2],
258 (unsigned long long) actual_cksum
.zc_word
[3]);
259 grub_dprintf ("zfs", "expected checksum %16llx %16llx %16llx %16llx\n",
260 (unsigned long long) zc
.zc_word
[0],
261 (unsigned long long) zc
.zc_word
[1],
262 (unsigned long long) zc
.zc_word
[2],
263 (unsigned long long) zc
.zc_word
[3]);
264 return grub_error (GRUB_ERR_BAD_FS
, "checksum verification failed");
267 return GRUB_ERR_NONE
;
271 * vdev_uberblock_compare takes two uberblock structures and returns an integer
272 * indicating the more recent of the two.
273 * Return Value = 1 if ub2 is more recent
274 * Return Value = -1 if ub1 is more recent
275 * The most recent uberblock is determined using its transaction number and
276 * timestamp. The uberblock with the highest transaction number is
277 * considered "newer". If the transaction numbers of the two blocks match, the
278 * timestamps are compared to determine the "newer" of the two.
281 vdev_uberblock_compare (uberblock_t
* ub1
, uberblock_t
* ub2
)
283 grub_zfs_endian_t ub1_endian
, ub2_endian
;
284 if (grub_zfs_to_cpu64 (ub1
->ub_magic
, LITTLE_ENDIAN
) == UBERBLOCK_MAGIC
)
285 ub1_endian
= LITTLE_ENDIAN
;
287 ub1_endian
= BIG_ENDIAN
;
288 if (grub_zfs_to_cpu64 (ub2
->ub_magic
, LITTLE_ENDIAN
) == UBERBLOCK_MAGIC
)
289 ub2_endian
= LITTLE_ENDIAN
;
291 ub2_endian
= BIG_ENDIAN
;
293 if (grub_zfs_to_cpu64 (ub1
->ub_txg
, ub1_endian
)
294 < grub_zfs_to_cpu64 (ub2
->ub_txg
, ub2_endian
))
296 if (grub_zfs_to_cpu64 (ub1
->ub_txg
, ub1_endian
)
297 > grub_zfs_to_cpu64 (ub2
->ub_txg
, ub2_endian
))
300 if (grub_zfs_to_cpu64 (ub1
->ub_timestamp
, ub1_endian
)
301 < grub_zfs_to_cpu64 (ub2
->ub_timestamp
, ub2_endian
))
303 if (grub_zfs_to_cpu64 (ub1
->ub_timestamp
, ub1_endian
)
304 > grub_zfs_to_cpu64 (ub2
->ub_timestamp
, ub2_endian
))
311 * Three pieces of information are needed to verify an uberblock: the magic
312 * number, the version number, and the checksum.
314 * Currently Implemented: version number, magic number
315 * Need to Implement: checksum
319 uberblock_verify (uberblock_phys_t
* ub
, int offset
)
321 uberblock_t
*uber
= &ub
->ubp_uberblock
;
323 grub_zfs_endian_t endian
= UNKNOWN_ENDIAN
;
326 if (grub_zfs_to_cpu64 (uber
->ub_magic
, LITTLE_ENDIAN
) == UBERBLOCK_MAGIC
327 && grub_zfs_to_cpu64 (uber
->ub_version
, LITTLE_ENDIAN
) > 0
328 && grub_zfs_to_cpu64 (uber
->ub_version
, LITTLE_ENDIAN
) <= SPA_VERSION
)
329 endian
= LITTLE_ENDIAN
;
331 if (grub_zfs_to_cpu64 (uber
->ub_magic
, BIG_ENDIAN
) == UBERBLOCK_MAGIC
332 && grub_zfs_to_cpu64 (uber
->ub_version
, BIG_ENDIAN
) > 0
333 && grub_zfs_to_cpu64 (uber
->ub_version
, BIG_ENDIAN
) <= SPA_VERSION
)
336 if (endian
== UNKNOWN_ENDIAN
)
337 return grub_error (GRUB_ERR_BAD_FS
, "invalid uberblock magic");
339 grub_memset (&zc
, 0, sizeof (zc
));
341 zc
.zc_word
[0] = grub_cpu_to_zfs64 (offset
, endian
);
342 err
= zio_checksum_verify (zc
, ZIO_CHECKSUM_LABEL
, endian
,
343 (char *) ub
, UBERBLOCK_SIZE
);
349 * Find the best uberblock.
351 * Success - Pointer to the best uberblock.
354 static uberblock_phys_t
*
355 find_bestub (uberblock_phys_t
* ub_array
, grub_disk_addr_t sector
)
357 uberblock_phys_t
*ubbest
= NULL
;
359 grub_disk_addr_t offset
;
360 grub_err_t err
= GRUB_ERR_NONE
;
362 for (i
= 0; i
< (VDEV_UBERBLOCK_RING
>> VDEV_UBERBLOCK_SHIFT
); i
++)
364 offset
= (sector
<< SPA_MINBLOCKSHIFT
) + VDEV_PHYS_SIZE
365 + (i
<< VDEV_UBERBLOCK_SHIFT
);
367 err
= uberblock_verify (&ub_array
[i
], offset
);
370 grub_errno
= GRUB_ERR_NONE
;
374 || vdev_uberblock_compare (&(ub_array
[i
].ubp_uberblock
),
375 &(ubbest
->ubp_uberblock
)) > 0)
376 ubbest
= &ub_array
[i
];
384 static inline grub_size_t
385 get_psize (blkptr_t
* bp
, grub_zfs_endian_t endian
)
387 return ((((grub_zfs_to_cpu64 ((bp
)->blk_prop
, endian
) >> 16) & 0xffff) + 1)
388 << SPA_MINBLOCKSHIFT
);
392 dva_get_offset (dva_t
* dva
, grub_zfs_endian_t endian
)
394 grub_dprintf ("zfs", "dva=%llx, %llx\n",
395 (unsigned long long) dva
->dva_word
[0],
396 (unsigned long long) dva
->dva_word
[1]);
397 return grub_zfs_to_cpu64 ((dva
)->dva_word
[1],
398 endian
) << SPA_MINBLOCKSHIFT
;
403 * Read a block of data based on the gang block address dva,
404 * and put its data in buf.
408 zio_read_gang (blkptr_t
* bp
, grub_zfs_endian_t endian
, dva_t
* dva
, void *buf
,
409 struct grub_zfs_data
*data
)
411 zio_gbh_phys_t
*zio_gb
;
412 grub_uint64_t offset
, sector
;
417 grub_memset (&zc
, 0, sizeof (zc
));
419 zio_gb
= grub_malloc (SPA_GANGBLOCKSIZE
);
422 grub_dprintf ("zfs", endian
== LITTLE_ENDIAN
? "little-endian gang\n"
423 :"big-endian gang\n");
424 offset
= dva_get_offset (dva
, endian
);
425 sector
= DVA_OFFSET_TO_PHYS_SECTOR (offset
);
426 grub_dprintf ("zfs", "offset=%llx\n", (unsigned long long) offset
);
428 /* read in the gang block header */
429 err
= grub_disk_read (data
->disk
, sector
, 0, SPA_GANGBLOCKSIZE
,
438 /* self checksuming the gang block header */
439 ZIO_SET_CHECKSUM (&zc
, DVA_GET_VDEV (dva
),
440 dva_get_offset (dva
, endian
), bp
->blk_birth
, 0);
441 err
= zio_checksum_verify (zc
, ZIO_CHECKSUM_GANG_HEADER
, endian
,
442 (char *) zio_gb
, SPA_GANGBLOCKSIZE
);
449 endian
= (grub_zfs_to_cpu64 (bp
->blk_prop
, endian
) >> 63) & 1;
451 for (i
= 0; i
< SPA_GBH_NBLKPTRS
; i
++)
453 if (zio_gb
->zg_blkptr
[i
].blk_birth
== 0)
456 err
= zio_read_data (&zio_gb
->zg_blkptr
[i
], endian
, buf
, data
);
462 buf
= (char *) buf
+ get_psize (&zio_gb
->zg_blkptr
[i
], endian
);
465 return GRUB_ERR_NONE
;
469 * Read in a block of raw data to buf.
472 zio_read_data (blkptr_t
* bp
, grub_zfs_endian_t endian
, void *buf
,
473 struct grub_zfs_data
*data
)
476 grub_err_t err
= GRUB_ERR_NONE
;
478 psize
= get_psize (bp
, endian
);
480 /* pick a good dva from the block pointer */
481 for (i
= 0; i
< SPA_DVAS_PER_BP
; i
++)
483 grub_uint64_t offset
, sector
;
485 if (bp
->blk_dva
[i
].dva_word
[0] == 0 && bp
->blk_dva
[i
].dva_word
[1] == 0)
488 if ((grub_zfs_to_cpu64 (bp
->blk_dva
[i
].dva_word
[1], endian
)>>63) & 1)
489 err
= zio_read_gang (bp
, endian
, &bp
->blk_dva
[i
], buf
, data
);
492 /* read in a data block */
493 offset
= dva_get_offset (&bp
->blk_dva
[i
], endian
);
494 sector
= DVA_OFFSET_TO_PHYS_SECTOR (offset
);
495 err
= grub_disk_read (data
->disk
, sector
, 0, psize
, buf
);
498 return GRUB_ERR_NONE
;
499 grub_errno
= GRUB_ERR_NONE
;
503 err
= grub_error (GRUB_ERR_BAD_FS
, "couldn't find a valid DVA");
510 * Read in a block of data, verify its checksum, decompress if needed,
511 * and put the uncompressed data in buf.
514 zio_read (blkptr_t
* bp
, grub_zfs_endian_t endian
, void **buf
,
515 grub_size_t
*size
, struct grub_zfs_data
*data
)
517 grub_size_t lsize
, psize
;
521 zio_cksum_t zc
= bp
->blk_cksum
;
522 grub_uint32_t checksum
;
524 checksum
= (grub_zfs_to_cpu64((bp
)->blk_prop
, endian
) >> 40) & 0xff;
525 comp
= (grub_zfs_to_cpu64((bp
)->blk_prop
, endian
)>>32) & 0xff;
526 lsize
= (BP_IS_HOLE(bp
) ? 0 :
527 (((grub_zfs_to_cpu64 ((bp
)->blk_prop
, endian
) & 0xffff) + 1)
528 << SPA_MINBLOCKSHIFT
));
529 psize
= get_psize (bp
, endian
);
534 if ((unsigned int) comp
>= ZIO_COMPRESS_FUNCTIONS
||
535 (comp
!= ZIO_COMPRESS_OFF
&& decomp_table
[comp
].decomp_func
== NULL
))
537 grub_dprintf ("zfs", "comp=%d\n", comp
);
538 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
,
539 "compression algorithm not supported\n");
542 if (comp
!= ZIO_COMPRESS_OFF
)
544 compbuf
= grub_malloc (psize
);
549 compbuf
= *buf
= grub_malloc (lsize
);
551 grub_dprintf ("zfs", "endian = %d\n", endian
);
552 err
= zio_read_data (bp
, endian
, compbuf
, data
);
559 err
= zio_checksum_verify (zc
, checksum
, endian
, compbuf
, psize
);
562 grub_dprintf ("zfs", "incorrect checksum\n");
567 if (comp
!= ZIO_COMPRESS_OFF
)
569 *buf
= grub_malloc (lsize
);
570 err
= decomp_table
[comp
].decomp_func (compbuf
, *buf
, psize
, lsize
);
576 return GRUB_ERR_NONE
;
580 * Get the block from a block id.
581 * push the block onto the stack.
585 dmu_read (dnode_end_t
* dn
, grub_uint64_t blkid
, void **buf
,
586 grub_zfs_endian_t
*endian_out
, struct grub_zfs_data
*data
)
589 blkptr_t
*bp_array
= dn
->dn
.dn_blkptr
;
590 int epbs
= dn
->dn
.dn_indblkshift
- SPA_BLKPTRSHIFT
;
591 blkptr_t
*bp
, *tmpbuf
= 0;
592 grub_zfs_endian_t endian
;
593 grub_err_t err
= GRUB_ERR_NONE
;
595 bp
= grub_malloc (sizeof (blkptr_t
));
600 for (level
= dn
->dn
.dn_nlevels
- 1; level
>= 0; level
--)
602 grub_dprintf ("zfs", "endian = %d\n", endian
);
603 idx
= (blkid
>> (epbs
* level
)) & ((1 << epbs
) - 1);
605 if (bp_array
!= dn
->dn
.dn_blkptr
)
607 grub_free (bp_array
);
613 grub_size_t size
= grub_zfs_to_cpu16 (dn
->dn
.dn_datablkszsec
,
615 << SPA_MINBLOCKSHIFT
;
616 *buf
= grub_malloc (size
);
622 grub_memset (*buf
, 0, size
);
623 endian
= (grub_zfs_to_cpu64 (bp
->blk_prop
, endian
) >> 63) & 1;
628 grub_dprintf ("zfs", "endian = %d\n", endian
);
629 err
= zio_read (bp
, endian
, buf
, 0, data
);
630 endian
= (grub_zfs_to_cpu64 (bp
->blk_prop
, endian
) >> 63) & 1;
633 grub_dprintf ("zfs", "endian = %d\n", endian
);
634 err
= zio_read (bp
, endian
, (void **) &tmpbuf
, 0, data
);
635 endian
= (grub_zfs_to_cpu64 (bp
->blk_prop
, endian
) >> 63) & 1;
640 if (bp_array
!= dn
->dn
.dn_blkptr
)
641 grub_free (bp_array
);
643 *endian_out
= endian
;
650 * mzap_lookup: Looks up property described by "name" and returns the value
654 mzap_lookup (mzap_phys_t
* zapobj
, grub_zfs_endian_t endian
,
655 int objsize
, char *name
, grub_uint64_t
* value
)
658 mzap_ent_phys_t
*mzap_ent
= zapobj
->mz_chunk
;
660 chunks
= objsize
/ MZAP_ENT_LEN
- 1;
661 for (i
= 0; i
< chunks
; i
++)
663 if (grub_strcmp (mzap_ent
[i
].mze_name
, name
) == 0)
665 *value
= grub_zfs_to_cpu64 (mzap_ent
[i
].mze_value
, endian
);
666 return GRUB_ERR_NONE
;
670 return grub_error (GRUB_ERR_FILE_NOT_FOUND
, "couldn't find %s", name
);
674 mzap_iterate (mzap_phys_t
* zapobj
, grub_zfs_endian_t endian
, int objsize
,
675 int NESTED_FUNC_ATTR (*hook
) (const char *name
,
679 mzap_ent_phys_t
*mzap_ent
= zapobj
->mz_chunk
;
681 chunks
= objsize
/ MZAP_ENT_LEN
- 1;
682 for (i
= 0; i
< chunks
; i
++)
684 grub_dprintf ("zfs", "zap: name = %s, value = %llx, cd = %x\n",
685 mzap_ent
[i
].mze_name
, (long long)mzap_ent
[i
].mze_value
,
686 (int)mzap_ent
[i
].mze_cd
);
687 if (hook (mzap_ent
[i
].mze_name
,
688 grub_zfs_to_cpu64 (mzap_ent
[i
].mze_value
, endian
)))
696 zap_hash (grub_uint64_t salt
, const char *name
)
698 static grub_uint64_t table
[256];
699 const grub_uint8_t
*cp
;
701 grub_uint64_t crc
= salt
;
707 for (i
= 0; i
< 256; i
++)
709 for (ct
= table
+ i
, *ct
= i
, j
= 8; j
> 0; j
--)
710 *ct
= (*ct
>> 1) ^ (-(*ct
& 1) & ZFS_CRC64_POLY
);
714 for (cp
= (const grub_uint8_t
*) name
; (c
= *cp
) != '\0'; cp
++)
715 crc
= (crc
>> 8) ^ table
[(crc
^ c
) & 0xFF];
718 * Only use 28 bits, since we need 4 bits in the cookie for the
719 * collision differentiator. We MUST use the high bits, since
720 * those are the onces that we first pay attention to when
721 * chosing the bucket.
723 crc
&= ~((1ULL << (64 - ZAP_HASHBITS
)) - 1);
729 * Only to be used on 8-bit arrays.
730 * array_len is actual len in bytes (not encoded le_value_length).
731 * buf is null-terminated.
735 zap_leaf_array_equal (zap_leaf_phys_t
* l
, grub_zfs_endian_t endian
,
736 int blksft
, int chunk
, int array_len
, const char *buf
)
740 while (bseen
< array_len
)
742 struct zap_leaf_array
*la
= &ZAP_LEAF_CHUNK (l
, blksft
, chunk
).l_array
;
743 int toread
= MIN (array_len
- bseen
, ZAP_LEAF_ARRAY_BYTES
);
745 if (chunk
>= ZAP_LEAF_NUMCHUNKS (blksft
))
748 if (grub_memcmp (la
->la_array
, buf
+ bseen
, toread
) != 0)
750 chunk
= grub_zfs_to_cpu16 (la
->la_next
, endian
);
753 return (bseen
== array_len
);
758 zap_leaf_array_get (zap_leaf_phys_t
* l
, grub_zfs_endian_t endian
, int blksft
,
759 int chunk
, int array_len
, char *buf
)
763 while (bseen
< array_len
)
765 struct zap_leaf_array
*la
= &ZAP_LEAF_CHUNK (l
, blksft
, chunk
).l_array
;
766 int toread
= MIN (array_len
- bseen
, ZAP_LEAF_ARRAY_BYTES
);
768 if (chunk
>= ZAP_LEAF_NUMCHUNKS (blksft
))
769 /* Don't use grub_error because this error is to be ignored. */
770 return GRUB_ERR_BAD_FS
;
772 grub_memcpy (buf
+ bseen
,la
->la_array
, toread
);
773 chunk
= grub_zfs_to_cpu16 (la
->la_next
, endian
);
776 return GRUB_ERR_NONE
;
781 * Given a zap_leaf_phys_t, walk thru the zap leaf chunks to get the
782 * value for the property "name".
787 zap_leaf_lookup (zap_leaf_phys_t
* l
, grub_zfs_endian_t endian
,
788 int blksft
, grub_uint64_t h
,
789 const char *name
, grub_uint64_t
* value
)
792 struct zap_leaf_entry
*le
;
794 /* Verify if this is a valid leaf block */
795 if (grub_zfs_to_cpu64 (l
->l_hdr
.lh_block_type
, endian
) != ZBT_LEAF
)
796 return grub_error (GRUB_ERR_BAD_FS
, "invalid leaf type");
797 if (grub_zfs_to_cpu32 (l
->l_hdr
.lh_magic
, endian
) != ZAP_LEAF_MAGIC
)
798 return grub_error (GRUB_ERR_BAD_FS
, "invalid leaf magic");
800 for (chunk
= grub_zfs_to_cpu16 (l
->l_hash
[LEAF_HASH (blksft
, h
)], endian
);
801 chunk
!= CHAIN_END
; chunk
= le
->le_next
)
804 if (chunk
>= ZAP_LEAF_NUMCHUNKS (blksft
))
805 return grub_error (GRUB_ERR_BAD_FS
, "invalid chunk number");
807 le
= ZAP_LEAF_ENTRY (l
, blksft
, chunk
);
809 /* Verify the chunk entry */
810 if (le
->le_type
!= ZAP_CHUNK_ENTRY
)
811 return grub_error (GRUB_ERR_BAD_FS
, "invalid chunk entry");
813 if (grub_zfs_to_cpu64 (le
->le_hash
,endian
) != h
)
816 grub_dprintf ("zfs", "fzap: length %d\n", (int) le
->le_name_length
);
818 if (zap_leaf_array_equal (l
, endian
, blksft
,
819 grub_zfs_to_cpu16 (le
->le_name_chunk
,endian
),
820 grub_zfs_to_cpu16 (le
->le_name_length
, endian
),
823 struct zap_leaf_array
*la
;
826 if (le
->le_int_size
!= 8 || le
->le_value_length
!= 1)
827 return grub_error (GRUB_ERR_BAD_FS
, "invalid leaf chunk entry");
829 /* get the uint64_t property value */
830 la
= &ZAP_LEAF_CHUNK (l
, blksft
, le
->le_value_chunk
).l_array
;
833 *value
= grub_be_to_cpu64 (*(grub_uint64_t
*)la
->la_array
);
835 return GRUB_ERR_NONE
;
839 return grub_error (GRUB_ERR_FILE_NOT_FOUND
, "couldn't find %s", name
);
848 fzap_lookup (dnode_end_t
* zap_dnode
, zap_phys_t
* zap
,
849 char *name
, grub_uint64_t
* value
, struct grub_zfs_data
*data
)
852 grub_uint64_t hash
, idx
, blkid
;
853 int blksft
= zfs_log2 (grub_zfs_to_cpu16 (zap_dnode
->dn
.dn_datablkszsec
,
854 zap_dnode
->endian
) << DNODE_SHIFT
);
856 grub_zfs_endian_t leafendian
;
858 /* Verify if this is a fat zap header block */
859 if (zap
->zap_magic
!= (grub_uint64_t
) ZAP_MAGIC
)
860 return grub_error (GRUB_ERR_BAD_FS
, "bad ZAP magic");
862 if (zap
->zap_salt
== 0)
863 return grub_error (GRUB_ERR_BAD_FS
, "bad ZAP salt");
864 hash
= zap_hash (zap
->zap_salt
, name
);
866 /* get block id from index */
867 if (zap
->zap_ptrtbl
.zt_numblks
!= 0)
868 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
,
869 "external pointer tables not supported");
870 idx
= ZAP_HASH_IDX (hash
, zap
->zap_ptrtbl
.zt_shift
);
871 blkid
= ((grub_uint64_t
*) zap
)[idx
+ (1 << (blksft
- 3 - 1))];
873 /* Get the leaf block */
874 if ((1U << blksft
) < sizeof (zap_leaf_phys_t
))
875 return grub_error (GRUB_ERR_BAD_FS
, "ZAP leaf is too small");
876 err
= dmu_read (zap_dnode
, blkid
, (void **) &l
, &leafendian
, data
);
880 err
= zap_leaf_lookup (l
, leafendian
, blksft
, hash
, name
, value
);
887 fzap_iterate (dnode_end_t
* zap_dnode
, zap_phys_t
* zap
,
888 int NESTED_FUNC_ATTR (*hook
) (const char *name
,
890 struct grub_zfs_data
*data
)
893 grub_uint64_t idx
, blkid
;
895 int blksft
= zfs_log2 (grub_zfs_to_cpu16 (zap_dnode
->dn
.dn_datablkszsec
,
896 zap_dnode
->endian
) << DNODE_SHIFT
);
898 grub_zfs_endian_t endian
;
900 /* Verify if this is a fat zap header block */
901 if (zap
->zap_magic
!= (grub_uint64_t
) ZAP_MAGIC
)
903 grub_error (GRUB_ERR_BAD_FS
, "bad ZAP magic");
907 /* get block id from index */
908 if (zap
->zap_ptrtbl
.zt_numblks
!= 0)
910 grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
,
911 "external pointer tables not supported");
914 /* Get the leaf block */
915 if ((1U << blksft
) < sizeof (zap_leaf_phys_t
))
917 grub_error (GRUB_ERR_BAD_FS
, "ZAP leaf is too small");
920 for (idx
= 0; idx
< zap
->zap_ptrtbl
.zt_numblks
; idx
++)
922 blkid
= ((grub_uint64_t
*) zap
)[idx
+ (1 << (blksft
- 3 - 1))];
924 err
= dmu_read (zap_dnode
, blkid
, (void **) &l
, &endian
, data
);
927 grub_errno
= GRUB_ERR_NONE
;
931 /* Verify if this is a valid leaf block */
932 if (grub_zfs_to_cpu64 (l
->l_hdr
.lh_block_type
, endian
) != ZBT_LEAF
)
937 if (grub_zfs_to_cpu32 (l
->l_hdr
.lh_magic
, endian
) != ZAP_LEAF_MAGIC
)
943 for (chunk
= 0; chunk
< ZAP_LEAF_NUMCHUNKS (blksft
); chunk
++)
946 struct zap_leaf_array
*la
;
947 struct zap_leaf_entry
*le
;
949 le
= ZAP_LEAF_ENTRY (l
, blksft
, chunk
);
951 /* Verify the chunk entry */
952 if (le
->le_type
!= ZAP_CHUNK_ENTRY
)
955 buf
= grub_malloc (grub_zfs_to_cpu16 (le
->le_name_length
, endian
)
957 if (zap_leaf_array_get (l
, endian
, blksft
, le
->le_name_chunk
,
958 le
->le_name_length
, buf
))
963 buf
[le
->le_name_length
] = 0;
965 if (le
->le_int_size
!= 8
966 || grub_zfs_to_cpu16 (le
->le_value_length
, endian
) != 1)
969 /* get the uint64_t property value */
970 la
= &ZAP_LEAF_CHUNK (l
, blksft
, le
->le_value_chunk
).l_array
;
971 val
= grub_be_to_cpu64 (*(grub_uint64_t
*)la
->la_array
);
982 * Read in the data of a zap object and find the value for a matching
987 zap_lookup (dnode_end_t
* zap_dnode
, char *name
, grub_uint64_t
* val
,
988 struct grub_zfs_data
*data
)
990 grub_uint64_t block_type
;
994 grub_zfs_endian_t endian
;
996 grub_dprintf ("zfs", "looking for '%s'\n", name
);
998 /* Read in the first block of the zap object data. */
999 size
= grub_zfs_to_cpu16 (zap_dnode
->dn
.dn_datablkszsec
,
1000 zap_dnode
->endian
) << SPA_MINBLOCKSHIFT
;
1001 err
= dmu_read (zap_dnode
, 0, &zapbuf
, &endian
, data
);
1004 block_type
= grub_zfs_to_cpu64 (*((grub_uint64_t
*) zapbuf
), endian
);
1006 grub_dprintf ("zfs", "zap read\n");
1008 if (block_type
== ZBT_MICRO
)
1010 grub_dprintf ("zfs", "micro zap\n");
1011 err
= (mzap_lookup (zapbuf
, endian
, size
, name
, val
));
1012 grub_dprintf ("zfs", "returned %d\n", err
);
1016 else if (block_type
== ZBT_HEADER
)
1018 grub_dprintf ("zfs", "fat zap\n");
1019 /* this is a fat zap */
1020 err
= (fzap_lookup (zap_dnode
, zapbuf
, name
, val
, data
));
1021 grub_dprintf ("zfs", "returned %d\n", err
);
1026 return grub_error (GRUB_ERR_BAD_FS
, "unknown ZAP type");
1030 zap_iterate (dnode_end_t
* zap_dnode
,
1031 int NESTED_FUNC_ATTR (*hook
) (const char *name
, grub_uint64_t val
),
1032 struct grub_zfs_data
*data
)
1034 grub_uint64_t block_type
;
1039 grub_zfs_endian_t endian
;
1041 /* Read in the first block of the zap object data. */
1042 size
= grub_zfs_to_cpu16 (zap_dnode
->dn
.dn_datablkszsec
, zap_dnode
->endian
) << SPA_MINBLOCKSHIFT
;
1043 err
= dmu_read (zap_dnode
, 0, &zapbuf
, &endian
, data
);
1046 block_type
= grub_zfs_to_cpu64 (*((grub_uint64_t
*) zapbuf
), endian
);
1048 grub_dprintf ("zfs", "zap read\n");
1050 if (block_type
== ZBT_MICRO
)
1052 grub_dprintf ("zfs", "micro zap\n");
1053 ret
= mzap_iterate (zapbuf
, endian
, size
, hook
);
1057 else if (block_type
== ZBT_HEADER
)
1059 grub_dprintf ("zfs", "fat zap\n");
1060 /* this is a fat zap */
1061 ret
= fzap_iterate (zap_dnode
, zapbuf
, hook
, data
);
1065 grub_error (GRUB_ERR_BAD_FS
, "unknown ZAP type");
1071 * Get the dnode of an object number from the metadnode of an object set.
1074 * mdn - metadnode to get the object dnode
1075 * objnum - object number for the object dnode
1076 * buf - data buffer that holds the returning dnode
1079 dnode_get (dnode_end_t
* mdn
, grub_uint64_t objnum
, grub_uint8_t type
,
1080 dnode_end_t
* buf
, struct grub_zfs_data
*data
)
1082 grub_uint64_t blkid
, blksz
; /* the block id this object dnode is in */
1083 int epbs
; /* shift of number of dnodes in a block */
1084 int idx
; /* index within a block */
1085 dnode_phys_t
*dnbuf
;
1087 grub_zfs_endian_t endian
;
1089 blksz
= grub_zfs_to_cpu16 (mdn
->dn
.dn_datablkszsec
,
1090 mdn
->endian
) << SPA_MINBLOCKSHIFT
;
1091 epbs
= zfs_log2 (blksz
) - DNODE_SHIFT
;
1092 blkid
= objnum
>> epbs
;
1093 idx
= objnum
& ((1 << epbs
) - 1);
1095 if (data
->dnode_buf
!= NULL
&& grub_memcmp (data
->dnode_mdn
, mdn
,
1097 && objnum
>= data
->dnode_start
&& objnum
< data
->dnode_end
)
1099 grub_memmove (&(buf
->dn
), &(data
->dnode_buf
)[idx
], DNODE_SIZE
);
1100 buf
->endian
= data
->dnode_endian
;
1101 if (type
&& buf
->dn
.dn_type
!= type
)
1102 return grub_error(GRUB_ERR_BAD_FS
, "incorrect dnode type");
1103 return GRUB_ERR_NONE
;
1106 grub_dprintf ("zfs", "endian = %d, blkid=%llx\n", mdn
->endian
,
1107 (unsigned long long) blkid
);
1108 err
= dmu_read (mdn
, blkid
, (void **) &dnbuf
, &endian
, data
);
1111 grub_dprintf ("zfs", "alive\n");
1113 grub_free (data
->dnode_buf
);
1114 grub_free (data
->dnode_mdn
);
1115 data
->dnode_mdn
= grub_malloc (sizeof (*mdn
));
1116 if (! data
->dnode_mdn
)
1118 grub_errno
= GRUB_ERR_NONE
;
1119 data
->dnode_buf
= 0;
1123 grub_memcpy (data
->dnode_mdn
, mdn
, sizeof (*mdn
));
1124 data
->dnode_buf
= dnbuf
;
1125 data
->dnode_start
= blkid
<< epbs
;
1126 data
->dnode_end
= (blkid
+ 1) << epbs
;
1127 data
->dnode_endian
= endian
;
1130 grub_memmove (&(buf
->dn
), &dnbuf
[idx
], DNODE_SIZE
);
1131 buf
->endian
= endian
;
1132 if (type
&& buf
->dn
.dn_type
!= type
)
1133 return grub_error(GRUB_ERR_BAD_FS
, "incorrect dnode type");
1135 return GRUB_ERR_NONE
;
1139 * Get the file dnode for a given file name where mdn is the meta dnode
1140 * for this ZFS object set. When found, place the file dnode in dn.
1141 * The 'path' argument will be mangled.
1145 dnode_get_path (dnode_end_t
* mdn
, const char *path_in
, dnode_end_t
* dn
,
1146 struct grub_zfs_data
*data
)
1148 grub_uint64_t objnum
, version
;
1150 grub_err_t err
= GRUB_ERR_NONE
;
1151 char *path
, *path_buf
;
1154 struct dnode_chain
*next
;
1157 struct dnode_chain
*dnode_path
= 0, *dn_new
, *root
;
1159 dn_new
= grub_malloc (sizeof (*dn_new
));
1163 dnode_path
= root
= dn_new
;
1165 err
= dnode_get (mdn
, MASTER_NODE_OBJ
, DMU_OT_MASTER_NODE
,
1166 &(dnode_path
->dn
), data
);
1173 err
= zap_lookup (&(dnode_path
->dn
), ZPL_VERSION_STR
, &version
, data
);
1179 if (version
> ZPL_VERSION
)
1182 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
, "too new ZPL version");
1185 err
= zap_lookup (&(dnode_path
->dn
), ZFS_ROOT_OBJ
, &objnum
, data
);
1192 err
= dnode_get (mdn
, objnum
, 0, &(dnode_path
->dn
), data
);
1199 path
= path_buf
= grub_strdup (path_in
);
1208 /* skip leading slashes */
1209 while (*path
== '/')
1213 /* get the next component name */
1215 while (*path
&& *path
!= '/')
1218 if (cname
+ 1 == path
&& cname
[0] == '.')
1220 /* Handle double dot. */
1221 if (cname
+ 2 == path
&& cname
[0] == '.' && cname
[1] == '.')
1225 dn_new
= dnode_path
;
1226 dnode_path
= dn_new
->next
;
1231 err
= grub_error (GRUB_ERR_FILE_NOT_FOUND
,
1232 "can't resolve ..");
1239 *path
= 0; /* ensure null termination */
1241 if (dnode_path
->dn
.dn
.dn_type
!= DMU_OT_DIRECTORY_CONTENTS
)
1243 grub_free (path_buf
);
1244 return grub_error (GRUB_ERR_BAD_FILE_TYPE
, "not a directory");
1246 err
= zap_lookup (&(dnode_path
->dn
), cname
, &objnum
, data
);
1250 dn_new
= grub_malloc (sizeof (*dn_new
));
1256 dn_new
->next
= dnode_path
;
1257 dnode_path
= dn_new
;
1259 objnum
= ZFS_DIRENT_OBJ (objnum
);
1260 err
= dnode_get (mdn
, objnum
, 0, &(dnode_path
->dn
), data
);
1265 if (((grub_zfs_to_cpu64(((znode_phys_t
*) &dnode_path
->dn
.dn
.dn_bonus
)->zp_mode
, dnode_path
->dn
.endian
) >> 12) & 0xf) == 0xa && ch
)
1267 char *oldpath
= path
, *oldpathbuf
= path_buf
;
1269 = grub_malloc (sizeof (dnode_path
->dn
.dn
.dn_bonus
)
1270 - sizeof (znode_phys_t
) + grub_strlen (oldpath
) + 1);
1273 grub_free (oldpathbuf
);
1277 (char *) &dnode_path
->dn
.dn
.dn_bonus
[sizeof (znode_phys_t
)],
1278 sizeof (dnode_path
->dn
.dn
.dn_bonus
) - sizeof (znode_phys_t
));
1279 path
[sizeof (dnode_path
->dn
.dn
.dn_bonus
) - sizeof (znode_phys_t
)] = 0;
1280 grub_memcpy (path
+ grub_strlen (path
), oldpath
,
1281 grub_strlen (oldpath
) + 1);
1283 grub_free (oldpathbuf
);
1286 dn_new
= dnode_path
;
1287 dnode_path
= dn_new
->next
;
1290 else while (dnode_path
!= root
)
1292 dn_new
= dnode_path
;
1293 dnode_path
= dn_new
->next
;
1300 grub_memcpy (dn
, &(dnode_path
->dn
), sizeof (*dn
));
1304 dn_new
= dnode_path
->next
;
1305 grub_free (dnode_path
);
1306 dnode_path
= dn_new
;
1308 grub_free (path_buf
);
1314 * Get the default 'bootfs' property value from the rootpool.
1318 get_default_bootfsobj (dnode_phys_t
* mosmdn
, grub_uint64_t
* obj
,
1319 struct grub_zfs_data
*data
)
1321 grub_uint64_t objnum
= 0;
1326 if ((grub_errno
= dnode_get (mosmdn
, DMU_POOL_DIRECTORY_OBJECT
,
1327 DMU_OT_OBJECT_DIRECTORY
, dn
, data
)))
1330 return (grub_errno
);
1334 * find the object number for 'pool_props', and get the dnode
1335 * of the 'pool_props'.
1337 if (zap_lookup (dn
, DMU_POOL_PROPS
, &objnum
, data
))
1340 return (GRUB_ERR_BAD_FS
);
1342 if ((grub_errno
= dnode_get (mosmdn
, objnum
, DMU_OT_POOL_PROPS
, dn
, data
)))
1345 return (grub_errno
);
1347 if (zap_lookup (dn
, ZPOOL_PROP_BOOTFS
, &objnum
, data
))
1350 return (GRUB_ERR_BAD_FS
);
1356 return (GRUB_ERR_BAD_FS
);
1364 * Given a MOS metadnode, get the metadnode of a given filesystem name (fsname),
1365 * e.g. pool/rootfs, or a given object number (obj), e.g. the object number
1368 * If no fsname and no obj are given, return the DSL_DIR metadnode.
1369 * If fsname is given, return its metadnode and its matching object number.
1370 * If only obj is given, return the metadnode for this object number.
1374 get_filesystem_dnode (dnode_end_t
* mosmdn
, char *fsname
,
1375 dnode_end_t
* mdn
, struct grub_zfs_data
*data
)
1377 grub_uint64_t objnum
;
1380 grub_dprintf ("zfs", "endian = %d\n", mosmdn
->endian
);
1382 err
= dnode_get (mosmdn
, DMU_POOL_DIRECTORY_OBJECT
,
1383 DMU_OT_OBJECT_DIRECTORY
, mdn
, data
);
1387 grub_dprintf ("zfs", "alive\n");
1389 err
= zap_lookup (mdn
, DMU_POOL_ROOT_DATASET
, &objnum
, data
);
1393 grub_dprintf ("zfs", "alive\n");
1395 err
= dnode_get (mosmdn
, objnum
, DMU_OT_DSL_DIR
, mdn
, data
);
1399 grub_dprintf ("zfs", "alive\n");
1403 grub_uint64_t childobj
;
1406 while (*fsname
== '/')
1409 if (! *fsname
|| *fsname
== '@')
1413 while (*fsname
&& !grub_isspace (*fsname
) && *fsname
!= '/')
1418 childobj
= grub_zfs_to_cpu64(((dsl_dir_phys_t
*) &(mdn
->dn
.dn_bonus
))->dd_child_dir_zapobj
, mdn
->endian
);
1419 err
= dnode_get (mosmdn
, childobj
,
1420 DMU_OT_DSL_DIR_CHILD_MAP
, mdn
, data
);
1424 err
= zap_lookup (mdn
, cname
, &objnum
, data
);
1428 err
= dnode_get (mosmdn
, objnum
, DMU_OT_DSL_DIR
, mdn
, data
);
1434 return GRUB_ERR_NONE
;
1438 make_mdn (dnode_end_t
* mdn
, struct grub_zfs_data
*data
)
1442 grub_size_t ospsize
;
1445 grub_dprintf ("zfs", "endian = %d\n", mdn
->endian
);
1447 bp
= &((dsl_dataset_phys_t
*) &(mdn
->dn
.dn_bonus
))->ds_bp
;
1448 err
= zio_read (bp
, mdn
->endian
, (void **) &osp
, &ospsize
, data
);
1451 if (ospsize
< sizeof (objset_phys_t
))
1454 return grub_error (GRUB_ERR_BAD_FS
, "too small osp");
1457 mdn
->endian
= (grub_zfs_to_cpu64 (bp
->blk_prop
, mdn
->endian
)>>63) & 1;
1458 grub_memmove ((char *) &(mdn
->dn
), (char *) &osp
->os_meta_dnode
, DNODE_SIZE
);
1460 return GRUB_ERR_NONE
;
1464 dnode_get_fullpath (const char *fullpath
, dnode_end_t
* mdn
,
1465 grub_uint64_t
*mdnobj
, dnode_end_t
* dn
, int *isfs
,
1466 struct grub_zfs_data
*data
)
1468 char *fsname
, *snapname
;
1469 const char *ptr_at
, *filename
;
1470 grub_uint64_t headobj
;
1473 ptr_at
= grub_strchr (fullpath
, '@');
1479 fsname
= grub_strdup (fullpath
);
1483 const char *ptr_slash
= grub_strchr (ptr_at
, '/');
1486 fsname
= grub_malloc (ptr_at
- fullpath
+ 1);
1489 grub_memcpy (fsname
, fullpath
, ptr_at
- fullpath
);
1490 fsname
[ptr_at
- fullpath
] = 0;
1491 if (ptr_at
[1] && ptr_at
[1] != '/')
1493 snapname
= grub_malloc (ptr_slash
- ptr_at
);
1499 grub_memcpy (snapname
, ptr_at
+ 1, ptr_slash
- ptr_at
- 1);
1500 snapname
[ptr_slash
- ptr_at
- 1] = 0;
1505 filename
= ptr_slash
;
1508 grub_dprintf ("zfs", "fsname = '%s' snapname='%s' filename = '%s'\n",
1509 fsname
, snapname
, filename
);
1511 grub_dprintf ("zfs", "alive\n");
1512 err
= get_filesystem_dnode (&(data
->mos
), fsname
, dn
, data
);
1516 grub_free (snapname
);
1520 grub_dprintf ("zfs", "alive\n");
1522 headobj
= grub_zfs_to_cpu64 (((dsl_dir_phys_t
*) &(dn
->dn
.dn_bonus
))->dd_head_dataset_obj
, dn
->endian
);
1524 grub_dprintf ("zfs", "endian = %d\n", mdn
->endian
);
1526 err
= dnode_get (&(data
->mos
), headobj
, DMU_OT_DSL_DATASET
, mdn
, data
);
1530 grub_free (snapname
);
1533 grub_dprintf ("zfs", "endian = %d\n", mdn
->endian
);
1537 grub_uint64_t snapobj
;
1539 snapobj
= grub_zfs_to_cpu64 (((dsl_dataset_phys_t
*) &(mdn
->dn
.dn_bonus
))->ds_snapnames_zapobj
, mdn
->endian
);
1541 err
= dnode_get (&(data
->mos
), snapobj
,
1542 DMU_OT_DSL_DS_SNAP_MAP
, mdn
, data
);
1544 err
= zap_lookup (mdn
, snapname
, &headobj
, data
);
1546 err
= dnode_get (&(data
->mos
), headobj
, DMU_OT_DSL_DATASET
, mdn
, data
);
1550 grub_free (snapname
);
1558 make_mdn (mdn
, data
);
1560 grub_dprintf ("zfs", "endian = %d\n", mdn
->endian
);
1565 grub_free (snapname
);
1566 return GRUB_ERR_NONE
;
1568 err
= dnode_get_path (mdn
, filename
, dn
, data
);
1570 grub_free (snapname
);
1575 * For a given XDR packed nvlist, verify the first 4 bytes and move on.
1577 * An XDR packed nvlist is encoded as (comments from nvs_xdr_create) :
1579 * encoding method/host endian (4 bytes)
1580 * nvl_version (4 bytes)
1581 * nvl_nvflag (4 bytes)
1583 * encoded size of the nvpair (4 bytes)
1584 * decoded size of the nvpair (4 bytes)
1585 * name string size (4 bytes)
1586 * name string data (sizeof(NV_ALIGN4(string))
1587 * data type (4 bytes)
1588 * # of elements in the nvpair (4 bytes)
1590 * 2 zero's for the last nvpair
1591 * (end of the entire list) (8 bytes)
1596 nvlist_find_value (char *nvlist
, char *name
, int valtype
, char **val
,
1597 grub_size_t
*size_out
, grub_size_t
*nelm_out
)
1599 int name_len
, type
, encode_size
;
1600 char *nvpair
, *nvp_name
;
1602 /* Verify if the 1st and 2nd byte in the nvlist are valid. */
1603 /* NOTE: independently of what endianness header announces all
1604 subsequent values are big-endian. */
1605 if (nvlist
[0] != NV_ENCODE_XDR
|| (nvlist
[1] != NV_LITTLE_ENDIAN
1606 && nvlist
[1] != NV_BIG_ENDIAN
))
1608 grub_dprintf ("zfs", "incorrect nvlist header\n");
1609 grub_error (GRUB_ERR_BAD_FS
, "incorrect nvlist");
1613 /* skip the header, nvl_version, and nvl_nvflag */
1614 nvlist
= nvlist
+ 4 * 3;
1616 * Loop thru the nvpair list
1617 * The XDR representation of an integer is in big-endian byte order.
1619 while ((encode_size
= grub_be_to_cpu32 (*(grub_uint32_t
*) nvlist
)))
1623 nvpair
= nvlist
+ 4 * 2; /* skip the encode/decode size */
1625 name_len
= grub_be_to_cpu32 (*(grub_uint32_t
*) nvpair
);
1629 nvpair
= nvpair
+ ((name_len
+ 3) & ~3); /* align */
1631 type
= grub_be_to_cpu32 (*(grub_uint32_t
*) nvpair
);
1634 nelm
= grub_be_to_cpu32 (*(grub_uint32_t
*) nvpair
);
1636 return grub_error (GRUB_ERR_BAD_FS
, "empty nvpair");
1640 if ((grub_strncmp (nvp_name
, name
, name_len
) == 0) && type
== valtype
)
1643 *size_out
= encode_size
;
1649 nvlist
+= encode_size
; /* goto the next nvpair */
1655 grub_zfs_nvlist_lookup_uint64 (char *nvlist
, char *name
, grub_uint64_t
* out
)
1661 found
= nvlist_find_value (nvlist
, name
, DATA_TYPE_UINT64
, &nvpair
, &size
, 0);
1664 if (size
< sizeof (grub_uint64_t
))
1666 grub_error (GRUB_ERR_BAD_FS
, "invalid uint64");
1670 *out
= grub_be_to_cpu64 (*(grub_uint64_t
*) nvpair
);
1675 grub_zfs_nvlist_lookup_string (char *nvlist
, char *name
)
1683 found
= nvlist_find_value (nvlist
, name
, DATA_TYPE_STRING
, &nvpair
, &size
, 0);
1688 grub_error (GRUB_ERR_BAD_FS
, "invalid string");
1691 slen
= grub_be_to_cpu32 (*(grub_uint32_t
*) nvpair
);
1692 if (slen
> size
- 4)
1694 ret
= grub_malloc (slen
+ 1);
1697 grub_memcpy (ret
, nvpair
+ 4, slen
);
1703 grub_zfs_nvlist_lookup_nvlist (char *nvlist
, char *name
)
1710 found
= nvlist_find_value (nvlist
, name
, DATA_TYPE_NVLIST
, &nvpair
,
1714 ret
= grub_zalloc (size
+ 3 * sizeof (grub_uint32_t
));
1717 grub_memcpy (ret
, nvlist
, sizeof (grub_uint32_t
));
1719 grub_memcpy (ret
+ sizeof (grub_uint32_t
), nvpair
, size
);
1724 grub_zfs_nvlist_lookup_nvlist_array_get_nelm (char *nvlist
, char *name
)
1727 grub_size_t nelm
, size
;
1730 found
= nvlist_find_value (nvlist
, name
, DATA_TYPE_NVLIST
, &nvpair
,
1738 grub_zfs_nvlist_lookup_nvlist_array (char *nvlist
, char *name
,
1741 char *nvpair
, *nvpairptr
;
1748 found
= nvlist_find_value (nvlist
, name
, DATA_TYPE_NVLIST
, &nvpair
,
1754 grub_error (GRUB_ERR_OUT_OF_RANGE
, "trying to lookup past nvlist array");
1760 for (i
= 0; i
< index
; i
++)
1762 grub_uint32_t encode_size
;
1764 /* skip the header, nvl_version, and nvl_nvflag */
1765 nvpairptr
= nvpairptr
+ 4 * 2;
1767 while (nvpairptr
< nvpair
+ size
1768 && (encode_size
= grub_be_to_cpu32 (*(grub_uint32_t
*) nvpairptr
)))
1769 nvlist
+= encode_size
; /* goto the next nvpair */
1771 nvlist
= nvlist
+ 4 * 2; /* skip the ending 2 zeros - 8 bytes */
1774 if (nvpairptr
>= nvpair
+ size
1775 || nvpairptr
+ grub_be_to_cpu32 (*(grub_uint32_t
*) (nvpairptr
+ 4 * 2))
1778 grub_error (GRUB_ERR_BAD_FS
, "incorrect nvlist array");
1782 ret
= grub_zalloc (grub_be_to_cpu32 (*(grub_uint32_t
*) (nvpairptr
+ 4 * 2))
1783 + 3 * sizeof (grub_uint32_t
));
1786 grub_memcpy (ret
, nvlist
, sizeof (grub_uint32_t
));
1788 grub_memcpy (ret
+ sizeof (grub_uint32_t
), nvpairptr
, size
);
1793 zfs_fetch_nvlist (struct grub_zfs_data
* data
, char **nvlist
)
1797 *nvlist
= grub_malloc (VDEV_PHYS_SIZE
);
1798 /* Read in the vdev name-value pair list (112K). */
1799 err
= grub_disk_read (data
->disk
, data
->vdev_phys_sector
, 0,
1800 VDEV_PHYS_SIZE
, *nvlist
);
1803 grub_free (*nvlist
);
1807 return GRUB_ERR_NONE
;
1811 * Check the disk label information and retrieve needed vdev name-value pairs.
1815 check_pool_label (struct grub_zfs_data
*data
)
1817 grub_uint64_t pool_state
, txg
= 0;
1822 grub_uint64_t diskguid
;
1823 grub_uint64_t version
;
1827 err
= zfs_fetch_nvlist (data
, &nvlist
);
1831 grub_dprintf ("zfs", "check 2 passed\n");
1833 found
= grub_zfs_nvlist_lookup_uint64 (nvlist
, ZPOOL_CONFIG_POOL_STATE
,
1839 grub_error (GRUB_ERR_BAD_FS
, ZPOOL_CONFIG_POOL_STATE
" not found");
1842 grub_dprintf ("zfs", "check 3 passed\n");
1844 if (pool_state
== POOL_STATE_DESTROYED
)
1847 return grub_error (GRUB_ERR_BAD_FS
, "zpool is marked as destroyed");
1849 grub_dprintf ("zfs", "check 4 passed\n");
1851 found
= grub_zfs_nvlist_lookup_uint64 (nvlist
, ZPOOL_CONFIG_POOL_TXG
, &txg
);
1856 grub_error (GRUB_ERR_BAD_FS
, ZPOOL_CONFIG_POOL_TXG
" not found");
1859 grub_dprintf ("zfs", "check 6 passed\n");
1861 /* not an active device */
1865 return grub_error (GRUB_ERR_BAD_FS
, "zpool isn't active");
1867 grub_dprintf ("zfs", "check 7 passed\n");
1869 found
= grub_zfs_nvlist_lookup_uint64 (nvlist
, ZPOOL_CONFIG_VERSION
,
1875 grub_error (GRUB_ERR_BAD_FS
, ZPOOL_CONFIG_VERSION
" not found");
1878 grub_dprintf ("zfs", "check 8 passed\n");
1880 if (version
> SPA_VERSION
)
1883 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
,
1884 "too new version %llu > %llu",
1885 (unsigned long long) version
,
1886 (unsigned long long) SPA_VERSION
);
1888 grub_dprintf ("zfs", "check 9 passed\n");
1890 if (nvlist_lookup_value (nvlist
, ZPOOL_CONFIG_VDEV_TREE
, &nv
,
1891 DATA_TYPE_NVLIST
, NULL
))
1894 return (GRUB_ERR_BAD_FS
);
1896 grub_dprintf ("zfs", "check 10 passed\n");
1899 found
= grub_zfs_nvlist_lookup_uint64 (nvlist
, ZPOOL_CONFIG_GUID
, &diskguid
);
1904 grub_error (GRUB_ERR_BAD_FS
, ZPOOL_CONFIG_GUID
" not found");
1907 grub_dprintf ("zfs", "check 11 passed\n");
1911 return GRUB_ERR_NONE
;
1915 zfs_unmount (struct grub_zfs_data
*data
)
1917 grub_free (data
->dnode_buf
);
1918 grub_free (data
->dnode_mdn
);
1919 grub_free (data
->file_buf
);
1924 * zfs_mount() locates a valid uberblock of the root pool and read in its MOS
1925 * to the memory address MOS.
1928 static struct grub_zfs_data
*
1929 zfs_mount (grub_device_t dev
)
1931 struct grub_zfs_data
*data
= 0;
1933 uberblock_phys_t
*ub_array
, *ubbest
= NULL
;
1934 vdev_boot_header_t
*bh
;
1935 objset_phys_t
*osp
= 0;
1936 grub_size_t ospsize
;
1942 grub_error (GRUB_ERR_BAD_DEVICE
, "not a disk");
1946 data
= grub_malloc (sizeof (*data
));
1949 grub_memset (data
, 0, sizeof (*data
));
1951 /* if it's our first time here, zero the best uberblock out */
1952 if (data
->best_drive
== 0 && data
->best_part
== 0 && find_best_root
)
1953 grub_memset (¤t_uberblock
, 0, sizeof (uberblock_t
));
1956 data
->disk
= dev
->disk
;
1958 ub_array
= grub_malloc (VDEV_UBERBLOCK_RING
);
1965 bh
= grub_malloc (VDEV_BOOT_HEADER_SIZE
);
1969 grub_free (ub_array
);
1973 vdevnum
= VDEV_LABELS
;
1975 /* Don't check back labels on CDROM. */
1976 if (! data
->disk
->partition
1977 && data
->disk
->dev
->id
== GRUB_DISK_DEVICE_BIOSDISK_ID
1978 && data
->disk
->id
>= 0xc0)
1979 vdevnum
= VDEV_LABELS
/ 2;
1981 for (label
= 0; ubbest
== NULL
&& label
< vdevnum
; label
++)
1983 grub_zfs_endian_t ub_endian
= UNKNOWN_ENDIAN
;
1984 grub_dprintf ("zfs", "label %d\n", label
);
1986 data
->vdev_phys_sector
1987 = label
* (sizeof (vdev_label_t
) >> SPA_MINBLOCKSHIFT
)
1988 + ((VDEV_SKIP_SIZE
+ VDEV_BOOT_HEADER_SIZE
) >> SPA_MINBLOCKSHIFT
)
1989 + (label
< VDEV_LABELS
/ 2 ? 0 : grub_disk_get_size (dev
->disk
)
1990 - VDEV_LABELS
* (sizeof (vdev_label_t
) >> SPA_MINBLOCKSHIFT
));
1992 /* Read in the uberblock ring (128K). */
1993 err
= grub_disk_read (data
->disk
, data
->vdev_phys_sector
1994 + (VDEV_PHYS_SIZE
>> SPA_MINBLOCKSHIFT
),
1995 0, VDEV_UBERBLOCK_RING
, (char *) ub_array
);
1998 grub_errno
= GRUB_ERR_NONE
;
2001 grub_dprintf ("zfs", "label ok %d\n", label
);
2003 ubbest
= find_bestub (ub_array
, data
->vdev_phys_sector
);
2006 grub_dprintf ("zfs", "No uberblock found\n");
2007 grub_errno
= GRUB_ERR_NONE
;
2010 ub_endian
= (grub_zfs_to_cpu64 (ubbest
->ubp_uberblock
.ub_magic
,
2011 LITTLE_ENDIAN
) == UBERBLOCK_MAGIC
2012 ? LITTLE_ENDIAN
: BIG_ENDIAN
);
2013 err
= zio_read (&ubbest
->ubp_uberblock
.ub_rootbp
,
2015 (void **) &osp
, &ospsize
, data
);
2018 grub_dprintf ("zfs", "couldn't zio_read\n");
2019 grub_errno
= GRUB_ERR_NONE
;
2023 if (ospsize
< sizeof (objset_phys_t
))
2025 grub_dprintf ("zfs", "osp too small\n");
2029 grub_dprintf ("zfs", "ubbest %p\n", ubbest
);
2031 err
= check_pool_label (data
);
2034 grub_errno
= GRUB_ERR_NONE
;
2038 if (find_best_root
&&
2039 vdev_uberblock_compare (&ubbest
->ubp_uberblock
,
2040 &(current_uberblock
)) <= 0)
2043 /* Got the MOS. Save it at the memory addr MOS. */
2044 grub_memmove (&(data
->mos
.dn
), &osp
->os_meta_dnode
, DNODE_SIZE
);
2045 data
->mos
.endian
= (grub_zfs_to_cpu64 (ubbest
->ubp_uberblock
.ub_rootbp
.blk_prop
, ub_endian
) >> 63) & 1;
2046 grub_memmove (&(data
->current_uberblock
),
2047 &ubbest
->ubp_uberblock
, sizeof (uberblock_t
));
2048 grub_free (ub_array
);
2053 grub_error (GRUB_ERR_BAD_FS
, "couldn't find a valid label");
2055 grub_free (ub_array
);
2063 grub_zfs_fetch_nvlist (grub_device_t dev
, char **nvlist
)
2065 struct grub_zfs_data
*zfs
;
2068 zfs
= zfs_mount (dev
);
2071 err
= zfs_fetch_nvlist (zfs
, nvlist
);
2077 zfs_label (grub_device_t device
, char **label
)
2081 struct grub_zfs_data
*data
;
2083 data
= zfs_mount (device
);
2087 err
= zfs_fetch_nvlist (data
, &nvlist
);
2094 *label
= grub_zfs_nvlist_lookup_string (nvlist
, ZPOOL_CONFIG_POOL_NAME
);
2101 zfs_uuid (grub_device_t device
, char **uuid
)
2105 struct grub_zfs_data
*data
;
2111 data
= zfs_mount (device
);
2115 err
= zfs_fetch_nvlist (data
, &nvlist
);
2122 found
= grub_zfs_nvlist_lookup_uint64 (nvlist
, ZPOOL_CONFIG_POOL_GUID
, &guid
);
2126 *uuid
= grub_xasprintf ("%016llx", (long long unsigned) guid
);
2130 return GRUB_ERR_NONE
;
2134 * zfs_open() locates a file in the rootpool by following the
2135 * MOS and places the dnode of the file in the memory address DNODE.
2138 grub_zfs_open (struct grub_file
*file
, const char *fsfilename
)
2140 struct grub_zfs_data
*data
;
2144 data
= zfs_mount (file
->device
);
2148 err
= dnode_get_fullpath (fsfilename
, &(data
->mdn
), 0,
2149 &(data
->dnode
), &isfs
, data
);
2159 return grub_error (GRUB_ERR_FILE_NOT_FOUND
, "Missing @ or / separator");
2162 /* We found the dnode for this file. Verify if it is a plain file. */
2163 if (data
->dnode
.dn
.dn_type
!= DMU_OT_PLAIN_FILE_CONTENTS
)
2166 return grub_error (GRUB_ERR_BAD_FILE_TYPE
, "not a file");
2169 /* get the file size and set the file position to 0 */
2172 file
->size
= grub_zfs_to_cpu64 (((znode_phys_t
*) &(data
->dnode
.dn
.dn_bonus
))->zp_size
, data
->dnode
.endian
);
2175 grub_dl_ref (my_mod
);
2178 return GRUB_ERR_NONE
;
2182 grub_zfs_read (grub_file_t file
, char *buf
, grub_size_t len
)
2184 struct grub_zfs_data
*data
= (struct grub_zfs_data
*) file
->data
;
2185 int blksz
, movesize
;
2190 if (data
->file_buf
== NULL
)
2192 data
->file_buf
= grub_malloc (SPA_MAXBLOCKSIZE
);
2193 if (!data
->file_buf
)
2195 data
->file_start
= data
->file_end
= 0;
2199 * If offset is in memory, move it into the buffer provided and return.
2201 if (file
->offset
>= data
->file_start
2202 && file
->offset
+ len
<= data
->file_end
)
2204 grub_memmove (buf
, data
->file_buf
+ file
->offset
- data
->file_start
,
2209 blksz
= grub_zfs_to_cpu16 (data
->dnode
.dn
.dn_datablkszsec
,
2210 data
->dnode
.endian
) << SPA_MINBLOCKSHIFT
;
2213 * Entire Dnode is too big to fit into the space available. We
2214 * will need to read it in chunks. This could be optimized to
2215 * read in as large a chunk as there is space available, but for
2216 * now, this only reads in one data block at a time.
2223 * Find requested blkid and the offset within that block.
2225 grub_uint64_t blkid
= grub_divmod64 (file
->offset
+ read
, blksz
, 0);
2226 grub_free (data
->file_buf
);
2229 err
= dmu_read (&(data
->dnode
), blkid
, (void **) &(data
->file_buf
),
2234 data
->file_start
= blkid
* blksz
;
2235 data
->file_end
= data
->file_start
+ blksz
;
2237 movesize
= MIN (length
, data
->file_end
- (int) file
->offset
- read
);
2239 grub_memmove (buf
, data
->file_buf
+ file
->offset
+ read
2240 - data
->file_start
, movesize
);
2250 grub_zfs_close (grub_file_t file
)
2252 zfs_unmount ((struct grub_zfs_data
*) file
->data
);
2255 grub_dl_unref (my_mod
);
2258 return GRUB_ERR_NONE
;
2262 grub_zfs_getmdnobj (grub_device_t dev
, const char *fsfilename
,
2263 grub_uint64_t
*mdnobj
)
2265 struct grub_zfs_data
*data
;
2269 data
= zfs_mount (dev
);
2273 err
= dnode_get_fullpath (fsfilename
, &(data
->mdn
), mdnobj
,
2274 &(data
->dnode
), &isfs
, data
);
2280 fill_fs_info (struct grub_dirhook_info
*info
,
2281 dnode_end_t mdn
, struct grub_zfs_data
*data
)
2285 grub_uint64_t objnum
;
2286 grub_uint64_t headobj
;
2288 grub_memset (info
, 0, sizeof (*info
));
2292 if (mdn
.dn
.dn_type
== DMU_OT_DSL_DIR
)
2294 headobj
= grub_zfs_to_cpu64 (((dsl_dir_phys_t
*) &(mdn
.dn
.dn_bonus
))->dd_head_dataset_obj
, mdn
.endian
);
2296 err
= dnode_get (&(data
->mos
), headobj
, DMU_OT_DSL_DATASET
, &mdn
, data
);
2299 grub_dprintf ("zfs", "failed here\n");
2303 make_mdn (&mdn
, data
);
2304 err
= dnode_get (&mdn
, MASTER_NODE_OBJ
, DMU_OT_MASTER_NODE
,
2308 grub_dprintf ("zfs", "failed here\n");
2312 err
= zap_lookup (&dn
, ZFS_ROOT_OBJ
, &objnum
, data
);
2315 grub_dprintf ("zfs", "failed here\n");
2319 err
= dnode_get (&mdn
, objnum
, 0, &dn
, data
);
2322 grub_dprintf ("zfs", "failed here\n");
2327 info
->mtime
= grub_zfs_to_cpu64 (((znode_phys_t
*) &dn
.dn
.dn_bonus
)->zp_mtime
[0], dn
.endian
);
2332 grub_zfs_dir (grub_device_t device
, const char *path
,
2333 int (*hook
) (const char *, const struct grub_dirhook_info
*))
2335 struct grub_zfs_data
*data
;
2338 auto int NESTED_FUNC_ATTR
iterate_zap (const char *name
, grub_uint64_t val
);
2339 auto int NESTED_FUNC_ATTR
iterate_zap_fs (const char *name
,
2341 auto int NESTED_FUNC_ATTR
iterate_zap_snap (const char *name
,
2344 int NESTED_FUNC_ATTR
iterate_zap (const char *name
, grub_uint64_t val
)
2346 struct grub_dirhook_info info
;
2348 grub_memset (&info
, 0, sizeof (info
));
2350 dnode_get (&(data
->mdn
), val
, 0, &dn
, data
);
2352 info
.mtime
= grub_zfs_to_cpu64 (((znode_phys_t
*) &dn
.dn
.dn_bonus
)->zp_mtime
[0], dn
.endian
);
2353 info
.dir
= (dn
.dn
.dn_type
== DMU_OT_DIRECTORY_CONTENTS
);
2354 grub_dprintf ("zfs", "type=%d, name=%s\n",
2355 (int)dn
.dn
.dn_type
, (char *)name
);
2356 return hook (name
, &info
);
2359 int NESTED_FUNC_ATTR
iterate_zap_fs (const char *name
, grub_uint64_t val
)
2361 struct grub_dirhook_info info
;
2363 err
= dnode_get (&(data
->mos
), val
, 0, &mdn
, data
);
2366 if (mdn
.dn
.dn_type
!= DMU_OT_DSL_DIR
)
2369 fill_fs_info (&info
, mdn
, data
);
2370 return hook (name
, &info
);
2372 int NESTED_FUNC_ATTR
iterate_zap_snap (const char *name
, grub_uint64_t val
)
2374 struct grub_dirhook_info info
;
2379 err
= dnode_get (&(data
->mos
), val
, 0, &mdn
, data
);
2383 if (mdn
.dn
.dn_type
!= DMU_OT_DSL_DATASET
)
2386 fill_fs_info (&info
, mdn
, data
);
2388 name2
= grub_malloc (grub_strlen (name
) + 2);
2390 grub_memcpy (name2
+ 1, name
, grub_strlen (name
) + 1);
2391 ret
= hook (name2
, &info
);
2396 data
= zfs_mount (device
);
2399 err
= dnode_get_fullpath (path
, &(data
->mdn
), 0, &(data
->dnode
), &isfs
, data
);
2407 grub_uint64_t childobj
, headobj
;
2408 grub_uint64_t snapobj
;
2410 struct grub_dirhook_info info
;
2412 fill_fs_info (&info
, data
->dnode
, data
);
2415 childobj
= grub_zfs_to_cpu64 (((dsl_dir_phys_t
*) &(data
->dnode
.dn
.dn_bonus
))->dd_child_dir_zapobj
, data
->dnode
.endian
);
2416 headobj
= grub_zfs_to_cpu64 (((dsl_dir_phys_t
*) &(data
->dnode
.dn
.dn_bonus
))->dd_head_dataset_obj
, data
->dnode
.endian
);
2417 err
= dnode_get (&(data
->mos
), childobj
,
2418 DMU_OT_DSL_DIR_CHILD_MAP
, &dn
, data
);
2425 zap_iterate (&dn
, iterate_zap_fs
, data
);
2427 err
= dnode_get (&(data
->mos
), headobj
, DMU_OT_DSL_DATASET
, &dn
, data
);
2434 snapobj
= grub_zfs_to_cpu64 (((dsl_dataset_phys_t
*) &dn
.dn
.dn_bonus
)->ds_snapnames_zapobj
, dn
.endian
);
2436 err
= dnode_get (&(data
->mos
), snapobj
,
2437 DMU_OT_DSL_DS_SNAP_MAP
, &dn
, data
);
2444 zap_iterate (&dn
, iterate_zap_snap
, data
);
2448 if (data
->dnode
.dn
.dn_type
!= DMU_OT_DIRECTORY_CONTENTS
)
2451 return grub_error (GRUB_ERR_BAD_FILE_TYPE
, "not a directory");
2453 zap_iterate (&(data
->dnode
), iterate_zap
, data
);
2459 static struct grub_fs grub_zfs_fs
= {
2461 .dir
= grub_zfs_dir
,
2462 .open
= grub_zfs_open
,
2463 .read
= grub_zfs_read
,
2464 .close
= grub_zfs_close
,
2473 grub_fs_register (&grub_zfs_fs
);
2481 grub_fs_unregister (&grub_zfs_fs
);