1 /*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 1999,2000,2001,2002,2003,2004,2009,2010,2011 Free Software Foundation, Inc.
4 * Copyright 2010 Sun Microsystems, Inc.
5 *
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.
10 *
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.
15 *
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/>.
18 */
19 /*
20 * The zfs plug-in routines for GRUB are:
21 *
22 * zfs_mount() - locates a valid uberblock of the root pool and reads
23 * in its MOS at the memory address MOS.
24 *
207 grub_device_t dev;
208 grub_disk_addr_t vdev_phys_sector;
209 uberblock_t current_uberblock;
210 int original;
211 };
212
213 struct subvolume
214 {
215 dnode_end_t mdn;
216 grub_uint64_t obj;
217 grub_uint64_t case_insensitive;
218 grub_size_t nkeys;
219 struct
220 {
221 grub_crypto_cipher_handle_t cipher;
222 grub_uint64_t txg;
223 grub_uint64_t algo;
224 } *keyring;
225 };
226
227 struct grub_zfs_data
228 {
229 /* cache for a file block of the currently zfs_open()-ed file */
230 char *file_buf;
231 grub_uint64_t file_start;
232 grub_uint64_t file_end;
233
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;
240
241 dnode_end_t mos;
242 dnode_end_t dnode;
243 struct subvolume subvol;
244
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;
249
250 uberblock_t current_uberblock;
251
252 int mounted;
253 grub_uint64_t guid;
254 };
255
256 grub_err_t (*grub_zfs_decrypt) (grub_crypto_cipher_handle_t cipher,
257 grub_uint64_t algo,
258 void *nonce,
259 char *buf, grub_size_t size,
260 const grub_uint32_t *expected_mac,
261 grub_zfs_endian_t endian) = NULL;
262 grub_crypto_cipher_handle_t (*grub_zfs_load_key) (const struct grub_zfs_key *key,
263 grub_size_t keysize,
264 grub_uint64_t salt,
265 grub_uint64_t algo) = NULL;
266
267 static grub_err_t
268 zlib_decompress (void *s, void *d,
269 grub_size_t slen, grub_size_t dlen)
270 {
271 if (grub_zlib_decompress (s, slen, 0, d, dlen) < 0)
465 }
466
467 /*
468 * Three pieces of information are needed to verify an uberblock: the magic
469 * number, the version number, and the checksum.
470 *
471 * Currently Implemented: version number, magic number, checksum
472 *
473 */
474 static grub_err_t
475 uberblock_verify (uberblock_phys_t * ub, grub_uint64_t offset,
476 grub_size_t s)
477 {
478 uberblock_t *uber = &ub->ubp_uberblock;
479 grub_err_t err;
480 grub_zfs_endian_t endian = GRUB_ZFS_UNKNOWN_ENDIAN;
481 zio_cksum_t zc;
482
483 if (grub_zfs_to_cpu64 (uber->ub_magic, GRUB_ZFS_LITTLE_ENDIAN)
484 == UBERBLOCK_MAGIC
485 && grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_LITTLE_ENDIAN) > 0
486 && grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_LITTLE_ENDIAN)
487 <= SPA_VERSION)
488 endian = GRUB_ZFS_LITTLE_ENDIAN;
489
490 if (grub_zfs_to_cpu64 (uber->ub_magic, GRUB_ZFS_BIG_ENDIAN) == UBERBLOCK_MAGIC
491 && grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_BIG_ENDIAN) > 0
492 && grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_BIG_ENDIAN)
493 <= SPA_VERSION)
494 endian = GRUB_ZFS_BIG_ENDIAN;
495
496 if (endian == GRUB_ZFS_UNKNOWN_ENDIAN)
497 return grub_error (GRUB_ERR_BAD_FS, "invalid uberblock magic");
498
499 grub_memset (&zc, 0, sizeof (zc));
500
501 zc.zc_word[0] = grub_cpu_to_zfs64 (offset, endian);
502 err = zio_checksum_verify (zc, ZIO_CHECKSUM_LABEL, endian,
503 (char *) ub, s);
504
505 return err;
506 }
507
508 /*
509 * Find the best uberblock.
510 * Return:
511 * Success - Pointer to the best uberblock.
512 * Failure - NULL
513 */
819 grub_dprintf ("zfs", "check 6 passed\n");
820
821 /* not an active device */
822 if (txg == 0)
823 {
824 grub_free (nvlist);
825 return grub_error (GRUB_ERR_BAD_FS, "zpool isn't active");
826 }
827 grub_dprintf ("zfs", "check 7 passed\n");
828
829 found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_VERSION,
830 &version);
831 if (! found)
832 {
833 grub_free (nvlist);
834 if (! grub_errno)
835 grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_VERSION " not found");
836 return grub_errno;
837 }
838 grub_dprintf ("zfs", "check 8 passed\n");
839
840 if (version > SPA_VERSION)
841 {
842 grub_free (nvlist);
843 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
844 "too new version %llu > %llu",
845 (unsigned long long) version,
846 (unsigned long long) SPA_VERSION);
847 }
848 grub_dprintf ("zfs", "check 9 passed\n");
849
850 found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_GUID,
851 &(diskdesc->guid));
852 if (! found)
853 {
854 grub_free (nvlist);
855 if (! grub_errno)
856 grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_GUID " not found");
857 return grub_errno;
858 }
859
860 found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_GUID,
861 &poolguid);
862 if (! found)
863 {
864 grub_free (nvlist);
865 if (! grub_errno)
866 grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_POOL_GUID " not found");
867 return grub_errno;
2653 dnode_path = dn_new->next;
2654 grub_free (dn_new);
2655 }
2656 }
2657 }
2658 }
2659
2660 if (!err)
2661 grub_memcpy (dn, &(dnode_path->dn), sizeof (*dn));
2662
2663 while (dnode_path)
2664 {
2665 dn_new = dnode_path->next;
2666 grub_free (dnode_path);
2667 dnode_path = dn_new;
2668 }
2669 grub_free (path_buf);
2670 return err;
2671 }
2672
2673 #if 0
2674 /*
2675 * Get the default 'bootfs' property value from the rootpool.
2676 *
2677 */
2678 static grub_err_t
2679 get_default_bootfsobj (dnode_phys_t * mosmdn, grub_uint64_t * obj,
2680 struct grub_zfs_data *data)
2681 {
2682 grub_uint64_t objnum = 0;
2683 dnode_phys_t *dn;
2684 if (!dn)
2685 return grub_errno;
2686
2687 if ((grub_errno = dnode_get (mosmdn, DMU_POOL_DIRECTORY_OBJECT,
2688 DMU_OT_OBJECT_DIRECTORY, dn, data)))
2689 {
2690 grub_free (dn);
2691 return (grub_errno);
2692 }
2693
2694 /*
2695 * find the object number for 'pool_props', and get the dnode
2696 * of the 'pool_props'.
2697 */
2698 if (zap_lookup (dn, DMU_POOL_PROPS, &objnum, data))
2699 {
2700 grub_free (dn);
2701 return (GRUB_ERR_BAD_FS);
2702 }
2703 if ((grub_errno = dnode_get (mosmdn, objnum, DMU_OT_POOL_PROPS, dn, data)))
2704 {
2705 grub_free (dn);
2706 return (grub_errno);
2707 }
2708 if (zap_lookup (dn, ZPOOL_PROP_BOOTFS, &objnum, data))
2709 {
2710 grub_free (dn);
2711 return (GRUB_ERR_BAD_FS);
2712 }
2713
2714 if (!objnum)
2715 {
2716 grub_free (dn);
2717 return (GRUB_ERR_BAD_FS);
2718 }
2719
2720 *obj = objnum;
2721 return (0);
2722 }
2723 #endif
2724 /*
2725 * Given a MOS metadnode, get the metadnode of a given filesystem name (fsname),
2726 * e.g. pool/rootfs, or a given object number (obj), e.g. the object number
2727 * of pool/rootfs.
2728 *
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.
2732 *
2733 */
2734 static grub_err_t
2735 get_filesystem_dnode (dnode_end_t * mosmdn, char *fsname,
2736 dnode_end_t * mdn, struct grub_zfs_data *data)
2737 {
2738 grub_uint64_t objnum;
2739 grub_err_t err;
2740
2741 grub_dprintf ("zfs", "endian = %d\n", mosmdn->endian);
2742
3303 for (i = 0; i < desc->n_children; i++)
3304 unmount_device (&desc->children[i]);
3305 grub_free (desc->children);
3306 return;
3307 }
3308 }
3309
3310 static void
3311 zfs_unmount (struct grub_zfs_data *data)
3312 {
3313 unsigned i;
3314 for (i = 0; i < data->n_devices_attached; i++)
3315 unmount_device (&data->devices_attached[i]);
3316 grub_free (data->devices_attached);
3317 grub_free (data->dnode_buf);
3318 grub_free (data->dnode_mdn);
3319 grub_free (data->file_buf);
3320 for (i = 0; i < data->subvol.nkeys; i++)
3321 grub_crypto_cipher_close (data->subvol.keyring[i].cipher);
3322 grub_free (data->subvol.keyring);
3323 grub_free (data);
3324 }
3325
3326 /*
3327 * zfs_mount() locates a valid uberblock of the root pool and read in its MOS
3328 * to the memory address MOS.
3329 *
3330 */
3331 static struct grub_zfs_data *
3332 zfs_mount (grub_device_t dev)
3333 {
3334 struct grub_zfs_data *data = 0;
3335 grub_err_t err;
3336 void *osp = 0;
3337 grub_size_t ospsize;
3338 grub_zfs_endian_t ub_endian = GRUB_ZFS_UNKNOWN_ENDIAN;
3339 uberblock_t *ub;
3340 int inserted;
3341
3342 if (! dev->disk)
3343 {
3344 grub_error (GRUB_ERR_BAD_DEVICE, "not a disk");
3345 return 0;
3346 }
3347
3348 data = grub_zalloc (sizeof (*data));
3349 if (!data)
3350 return 0;
3351 #if 0
3352 /* if it's our first time here, zero the best uberblock out */
3353 if (data->best_drive == 0 && data->best_part == 0 && find_best_root)
3354 grub_memset (¤t_uberblock, 0, sizeof (uberblock_t));
3355 #endif
3356
3357 data->n_devices_allocated = 16;
3358 data->devices_attached = grub_malloc (sizeof (data->devices_attached[0])
3359 * data->n_devices_allocated);
3360 data->n_devices_attached = 0;
3361 err = scan_disk (dev, data, 1, &inserted);
3362 if (err)
3363 {
3364 zfs_unmount (data);
3365 return NULL;
3366 }
3367
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);
3372
3373 err = zio_read (&ub->ub_rootbp, ub_endian,
3374 &osp, &ospsize, data);
3375 if (err)
3376 {
3378 return NULL;
3379 }
3380
3381 if (ospsize < OBJSET_PHYS_SIZE_V14)
3382 {
3383 grub_error (GRUB_ERR_BAD_FS, "OSP too small");
3384 grub_free (osp);
3385 zfs_unmount (data);
3386 return NULL;
3387 }
3388
3389 /* Got the MOS. Save it at the memory addr MOS. */
3390 grub_memmove (&(data->mos.dn), &((objset_phys_t *) osp)->os_meta_dnode,
3391 DNODE_SIZE);
3392 data->mos.endian = (grub_zfs_to_cpu64 (ub->ub_rootbp.blk_prop,
3393 ub_endian) >> 63) & 1;
3394 grub_free (osp);
3395
3396 data->mounted = 1;
3397
3398 return data;
3399 }
3400
3401 grub_err_t
3402 grub_zfs_fetch_nvlist (grub_device_t dev, char **nvlist)
3403 {
3404 struct grub_zfs_data *zfs;
3405 grub_err_t err;
3406
3407 zfs = zfs_mount (dev);
3408 if (!zfs)
3409 return grub_errno;
3410 err = zfs_fetch_nvlist (zfs->device_original, nvlist);
3411 zfs_unmount (zfs);
3412 return err;
3413 }
3414
3415 static grub_err_t
3416 zfs_label (grub_device_t device, char **label)
3417 {
3418 char *nvlist;
3419 grub_err_t err;
3420 struct grub_zfs_data *data;
|
1 /*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 1999,2000,2001,2002,2003,2004,2009,2010,2011 Free Software Foundation, Inc.
4 * Copyright 2010 Sun Microsystems, Inc.
5 * Copyright 2012 Daniil Lunev
6 *
7 * GRUB is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * GRUB is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
19 */
20 /*
21 * The zfs plug-in routines for GRUB are:
22 *
23 * zfs_mount() - locates a valid uberblock of the root pool and reads
24 * in its MOS at the memory address MOS.
25 *
208 grub_device_t dev;
209 grub_disk_addr_t vdev_phys_sector;
210 uberblock_t current_uberblock;
211 int original;
212 };
213
214 struct subvolume
215 {
216 dnode_end_t mdn;
217 grub_uint64_t obj;
218 grub_uint64_t case_insensitive;
219 grub_size_t nkeys;
220 struct
221 {
222 grub_crypto_cipher_handle_t cipher;
223 grub_uint64_t txg;
224 grub_uint64_t algo;
225 } *keyring;
226 };
227
228 static const char * feature_list[] = {
229 "localhost:unknown_feature",
230 NULL,
231 };
232
233 typedef enum zfs_feature_id {
234 ZFS_FEATURE_UNKNOWN,
235 } zfs_feature_id_t;
236
237 struct enabled_feature_list {
238 struct enabled_feature_list * next;
239 zfs_feature_id_t id;
240 };
241
242 struct grub_zfs_data
243 {
244 /* cache for a file block of the currently zfs_open()-ed file */
245 char *file_buf;
246 grub_uint64_t file_start;
247 grub_uint64_t file_end;
248
249 /* cache for a dnode block */
250 dnode_phys_t *dnode_buf;
251 dnode_phys_t *dnode_mdn;
252 grub_uint64_t dnode_start;
253 grub_uint64_t dnode_end;
254 grub_zfs_endian_t dnode_endian;
255
256 dnode_end_t mos;
257 dnode_end_t dnode;
258 struct subvolume subvol;
259
260 struct grub_zfs_device_desc *devices_attached;
261 unsigned n_devices_attached;
262 unsigned n_devices_allocated;
263 struct grub_zfs_device_desc *device_original;
264
265 uberblock_t current_uberblock;
266
267 struct enabled_feature_list * feature_list;
268
269 int mounted;
270 grub_uint64_t guid;
271 };
272
273 grub_err_t (*grub_zfs_decrypt) (grub_crypto_cipher_handle_t cipher,
274 grub_uint64_t algo,
275 void *nonce,
276 char *buf, grub_size_t size,
277 const grub_uint32_t *expected_mac,
278 grub_zfs_endian_t endian) = NULL;
279 grub_crypto_cipher_handle_t (*grub_zfs_load_key) (const struct grub_zfs_key *key,
280 grub_size_t keysize,
281 grub_uint64_t salt,
282 grub_uint64_t algo) = NULL;
283
284 static grub_err_t
285 zlib_decompress (void *s, void *d,
286 grub_size_t slen, grub_size_t dlen)
287 {
288 if (grub_zlib_decompress (s, slen, 0, d, dlen) < 0)
482 }
483
484 /*
485 * Three pieces of information are needed to verify an uberblock: the magic
486 * number, the version number, and the checksum.
487 *
488 * Currently Implemented: version number, magic number, checksum
489 *
490 */
491 static grub_err_t
492 uberblock_verify (uberblock_phys_t * ub, grub_uint64_t offset,
493 grub_size_t s)
494 {
495 uberblock_t *uber = &ub->ubp_uberblock;
496 grub_err_t err;
497 grub_zfs_endian_t endian = GRUB_ZFS_UNKNOWN_ENDIAN;
498 zio_cksum_t zc;
499
500 if (grub_zfs_to_cpu64 (uber->ub_magic, GRUB_ZFS_LITTLE_ENDIAN)
501 == UBERBLOCK_MAGIC
502 && grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_LITTLE_ENDIAN) > 0)
503 endian = GRUB_ZFS_LITTLE_ENDIAN;
504
505 if (grub_zfs_to_cpu64 (uber->ub_magic, GRUB_ZFS_BIG_ENDIAN) == UBERBLOCK_MAGIC
506 && grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_BIG_ENDIAN) > 0)
507 endian = GRUB_ZFS_BIG_ENDIAN;
508
509 if (endian == GRUB_ZFS_UNKNOWN_ENDIAN)
510 return grub_error (GRUB_ERR_BAD_FS, "invalid uberblock magic");
511
512 grub_memset (&zc, 0, sizeof (zc));
513
514 zc.zc_word[0] = grub_cpu_to_zfs64 (offset, endian);
515 err = zio_checksum_verify (zc, ZIO_CHECKSUM_LABEL, endian,
516 (char *) ub, s);
517
518 return err;
519 }
520
521 /*
522 * Find the best uberblock.
523 * Return:
524 * Success - Pointer to the best uberblock.
525 * Failure - NULL
526 */
832 grub_dprintf ("zfs", "check 6 passed\n");
833
834 /* not an active device */
835 if (txg == 0)
836 {
837 grub_free (nvlist);
838 return grub_error (GRUB_ERR_BAD_FS, "zpool isn't active");
839 }
840 grub_dprintf ("zfs", "check 7 passed\n");
841
842 found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_VERSION,
843 &version);
844 if (! found)
845 {
846 grub_free (nvlist);
847 if (! grub_errno)
848 grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_VERSION " not found");
849 return grub_errno;
850 }
851 grub_dprintf ("zfs", "check 8 passed\n");
852 grub_dprintf ("zfs", "check 9 passed\n");
853
854 found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_GUID,
855 &(diskdesc->guid));
856 if (! found)
857 {
858 grub_free (nvlist);
859 if (! grub_errno)
860 grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_GUID " not found");
861 return grub_errno;
862 }
863
864 found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_GUID,
865 &poolguid);
866 if (! found)
867 {
868 grub_free (nvlist);
869 if (! grub_errno)
870 grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_POOL_GUID " not found");
871 return grub_errno;
2657 dnode_path = dn_new->next;
2658 grub_free (dn_new);
2659 }
2660 }
2661 }
2662 }
2663
2664 if (!err)
2665 grub_memcpy (dn, &(dnode_path->dn), sizeof (*dn));
2666
2667 while (dnode_path)
2668 {
2669 dn_new = dnode_path->next;
2670 grub_free (dnode_path);
2671 dnode_path = dn_new;
2672 }
2673 grub_free (path_buf);
2674 return err;
2675 }
2676
2677 #if 1
2678 /*
2679 * Get the default 'bootfs' property value from the rootpool.
2680 *
2681 */
2682 static grub_err_t
2683 get_default_bootfsobj (dnode_end_t * mosmdn, grub_uint64_t * obj,
2684 struct grub_zfs_data *data)
2685 {
2686 grub_uint64_t objnum = 0;
2687 dnode_end_t dn;
2688
2689 if ((grub_errno = dnode_get (mosmdn, DMU_POOL_DIRECTORY_OBJECT,
2690 DMU_OT_OBJECT_DIRECTORY, &dn, data)))
2691 {
2692 return (grub_errno);
2693 }
2694 /*
2695 * find the object number for 'pool_props', and get the dnode
2696 * of the 'pool_props'.
2697 */
2698 if (zap_lookup (&dn, DMU_POOL_PROPS, &objnum, data, 0))
2699 {
2700 return (GRUB_ERR_BAD_FS);
2701 }
2702 if ((grub_errno = dnode_get (mosmdn, objnum, DMU_OT_POOL_PROPS, &dn, data)))
2703 {
2704 return (grub_errno);
2705 }
2706 if (zap_lookup (&dn, ZPOOL_PROP_BOOTFS, &objnum, data,0))
2707 {
2708 return (GRUB_ERR_BAD_FS);
2709 }
2710
2711 if (!objnum)
2712 {
2713 return (GRUB_ERR_BAD_FS);
2714 }
2715
2716 *obj = objnum;
2717 return (0);
2718 }
2719
2720 #endif
2721 /*
2722 * Given a MOS metadnode, get the metadnode of a given filesystem name (fsname),
2723 * e.g. pool/rootfs, or a given object number (obj), e.g. the object number
2724 * of pool/rootfs.
2725 *
2726 * If no fsname and no obj are given, return the DSL_DIR metadnode.
2727 * If fsname is given, return its metadnode and its matching object number.
2728 * If only obj is given, return the metadnode for this object number.
2729 *
2730 */
2731 static grub_err_t
2732 get_filesystem_dnode (dnode_end_t * mosmdn, char *fsname,
2733 dnode_end_t * mdn, struct grub_zfs_data *data)
2734 {
2735 grub_uint64_t objnum;
2736 grub_err_t err;
2737
2738 grub_dprintf ("zfs", "endian = %d\n", mosmdn->endian);
2739
3300 for (i = 0; i < desc->n_children; i++)
3301 unmount_device (&desc->children[i]);
3302 grub_free (desc->children);
3303 return;
3304 }
3305 }
3306
3307 static void
3308 zfs_unmount (struct grub_zfs_data *data)
3309 {
3310 unsigned i;
3311 for (i = 0; i < data->n_devices_attached; i++)
3312 unmount_device (&data->devices_attached[i]);
3313 grub_free (data->devices_attached);
3314 grub_free (data->dnode_buf);
3315 grub_free (data->dnode_mdn);
3316 grub_free (data->file_buf);
3317 for (i = 0; i < data->subvol.nkeys; i++)
3318 grub_crypto_cipher_close (data->subvol.keyring[i].cipher);
3319 grub_free (data->subvol.keyring);
3320 while (data->feature_list) {
3321 struct enabled_feature_list * tmp = data->feature_list;
3322 data->feature_list = data->feature_list->next;
3323 grub_free(tmp);
3324 }
3325 grub_free (data);
3326 }
3327
3328 static int
3329 add_feature (struct grub_zfs_data * data, zfs_feature_id_t id)
3330 {
3331 struct enabled_feature_list * list = data->feature_list;
3332
3333 while (list->next) {
3334 if (list->next->id == id)
3335 return id;
3336 list = list->next;
3337 }
3338
3339 list->next = (struct enabled_feature_list *) grub_zalloc (sizeof (struct enabled_feature_list));
3340
3341 if (! list->next)
3342 return (-1);
3343
3344 list->next->id = id;
3345 list->next->next = NULL;
3346
3347 return 0;
3348 }
3349
3350 static zfs_feature_id_t
3351 check_feature (const char * feature)
3352 {
3353 int i = 0;
3354 for ( ; i < ZFS_FEATURE_UNKNOWN; ++i)
3355 if (! grub_strcmp (feature, feature_list[i]))
3356 return i;
3357
3358 return ZFS_FEATURE_UNKNOWN;
3359 }
3360
3361 /*
3362 * zfs_get_features_list() get feature list and check compatability
3363 */
3364 static grub_err_t
3365 zfs_get_features_list (struct grub_zfs_data * data)
3366 {
3367 dnode_end_t dn;
3368 dnode_end_t * mos = &(data->mos);
3369 grub_err_t err;
3370 grub_uint64_t objnum;
3371 int ret;
3372
3373 int NESTED_FUNC_ATTR feature_hook (const char * cname, grub_uint64_t val)
3374 {
3375 grub_err_t iret = 0;
3376
3377 zfs_feature_id_t id;
3378
3379 if (! (*cname))
3380 goto out;
3381
3382 // retrieve feature number
3383 id = check_feature (cname);
3384
3385 // if grub doesn't support such feature, return error
3386 if (id == ZFS_FEATURE_UNKNOWN) {
3387 if (val == 0) {
3388 grub_error(GRUB_ERR_BAD_FS,
3389 "Unsupported feature %s was enabled,"
3390 " but haven't been activated yet. You will not be able to boot"
3391 " if this feature are activated.", cname);
3392 } else {
3393 grub_error(GRUB_ERR_BAD_FS,
3394 "Unsupported feature %s is activated. Booting failed",cname);
3395 iret = 1;
3396 }
3397 goto out;
3398 }
3399
3400 // add feature to list
3401 iret = add_feature(data, id);
3402
3403 out:
3404 return iret;
3405 }
3406
3407 // get object directory
3408 err = dnode_get (mos, DMU_POOL_DIRECTORY_OBJECT,
3409 DMU_OT_OBJECT_DIRECTORY, &dn, data);
3410 if (err)
3411 return err;
3412
3413 // retrieve pool properties object numer
3414 err = zap_lookup (&dn, DMU_POOL_FEATURES_FOR_READ, &objnum, data, 0);
3415 if (err)
3416 return err;
3417
3418 // get "features for read" zap dnode
3419 err = dnode_get (mos, objnum, DMU_OTN_ZAP_METADATA, &dn, data);
3420 if (err)
3421 return err;
3422
3423 // itterate zap to fetch feature list
3424 ret = zap_iterate_u64 (&dn, feature_hook, data);
3425 if (ret)
3426 return grub_error(GRUB_ERR_BAD_FS, "There are enabled unsupported features");
3427
3428 return GRUB_ERR_NONE;
3429 }
3430
3431 /*
3432 * zfs_mount() locates a valid uberblock of the root pool and read in its MOS
3433 * to the memory address MOS.
3434 *
3435 */
3436 static struct grub_zfs_data *
3437 zfs_mount (grub_device_t dev)
3438 {
3439 struct grub_zfs_data *data = 0;
3440 grub_err_t err;
3441 void *osp = 0;
3442 grub_size_t ospsize;
3443 grub_zfs_endian_t ub_endian = GRUB_ZFS_UNKNOWN_ENDIAN;
3444 uberblock_t *ub;
3445 int inserted;
3446
3447 if (! dev->disk)
3448 {
3449 grub_error (GRUB_ERR_BAD_DEVICE, "not a disk");
3450 return 0;
3451 }
3452
3453 data = grub_zalloc (sizeof (*data));
3454 if (!data)
3455 return 0;
3456 #if 0
3457 /* if it's our first time here, zero the best uberblock out */
3458 if (data->best_drive == 0 && data->best_part == 0 && find_best_root)
3459 grub_memset (¤t_uberblock, 0, sizeof (uberblock_t));
3460 #endif
3461
3462 data->feature_list = NULL;
3463 data->n_devices_allocated = 16;
3464 data->devices_attached = grub_malloc (sizeof (data->devices_attached[0])
3465 * data->n_devices_allocated);
3466 data->n_devices_attached = 0;
3467 err = scan_disk (dev, data, 1, &inserted);
3468 if (err)
3469 {
3470 zfs_unmount (data);
3471 return NULL;
3472 }
3473
3474 ub = &(data->current_uberblock);
3475 ub_endian = (grub_zfs_to_cpu64 (ub->ub_magic,
3476 GRUB_ZFS_LITTLE_ENDIAN) == UBERBLOCK_MAGIC
3477 ? GRUB_ZFS_LITTLE_ENDIAN : GRUB_ZFS_BIG_ENDIAN);
3478
3479 err = zio_read (&ub->ub_rootbp, ub_endian,
3480 &osp, &ospsize, data);
3481 if (err)
3482 {
3484 return NULL;
3485 }
3486
3487 if (ospsize < OBJSET_PHYS_SIZE_V14)
3488 {
3489 grub_error (GRUB_ERR_BAD_FS, "OSP too small");
3490 grub_free (osp);
3491 zfs_unmount (data);
3492 return NULL;
3493 }
3494
3495 /* Got the MOS. Save it at the memory addr MOS. */
3496 grub_memmove (&(data->mos.dn), &((objset_phys_t *) osp)->os_meta_dnode,
3497 DNODE_SIZE);
3498 data->mos.endian = (grub_zfs_to_cpu64 (ub->ub_rootbp.blk_prop,
3499 ub_endian) >> 63) & 1;
3500 grub_free (osp);
3501
3502 data->mounted = 1;
3503
3504 if (grub_zfs_to_cpu64(ub->ub_version, ub_endian) == SPA_FEATURE_VERSION) {
3505 data->feature_list = (struct enabled_feature_list*) grub_zalloc (
3506 sizeof (struct enabled_feature_list));
3507 data->feature_list->next = NULL;
3508 err = zfs_get_features_list(data);
3509
3510 if (err) {
3511 data->mounted = 0;
3512 zfs_unmount (data);
3513 return NULL;
3514 }
3515 }
3516
3517 return data;
3518 }
3519
3520 static grub_err_t
3521 find_default_dataset_path(char * path, grub_uint64_t * mdnobj, struct grub_zfs_data *data)
3522 {
3523 grub_uint64_t obj, pobj, zobj;
3524 grub_err_t err;
3525 dnode_end_t mdn, *mosmdn;
3526 char buf[512];
3527
3528 int NESTED_FUNC_ATTR hook (const char * name, grub_uint64_t val) {
3529 if (val == obj) {
3530 grub_strcpy(buf, name);
3531 return 1;
3532 }
3533 return 0;
3534 }
3535
3536 obj = *mdnobj;
3537 mosmdn = &(data->mos);
3538 buf[0] = '\0';
3539 path[0] = '\0';
3540
3541 // get object's data dir
3542 err = dnode_get(mosmdn, obj, DMU_OT_DSL_DATASET, &mdn, data);
3543 if (err)
3544 return err;
3545 obj = grub_zfs_to_cpu64((((dsl_dataset_phys_t*)DN_BONUS (&mdn.dn)))->ds_dir_obj, mdn.endian);
3546
3547 for (;;) {
3548 // get object dnode
3549 err = dnode_get(mosmdn, obj, DMU_OT_DSL_DIR, &mdn, data);
3550 if (err)
3551 return err;
3552
3553 // find out its parent's objnum
3554 pobj = grub_zfs_to_cpu64((((dsl_dir_phys_t*)DN_BONUS (&mdn.dn)))->dd_parent_obj, mdn.endian);
3555 if (obj == pobj)
3556 break;
3557
3558 // if pobj is 0 then we have reached top dataset
3559 if (! pobj)
3560 break;
3561
3562 // get object's parent dnode
3563 err = dnode_get(mosmdn, pobj, DMU_OT_DSL_DIR, &mdn, data);
3564 if (err)
3565 return err;
3566
3567 // find out parent's zap objnum
3568 zobj = grub_zfs_to_cpu64((((dsl_dir_phys_t*)DN_BONUS (&mdn.dn)))->dd_child_dir_zapobj, mdn.endian);
3569
3570 // get zap's dnode
3571 err = dnode_get(mosmdn, zobj, DMU_OT_DSL_DIR_CHILD_MAP, &mdn, data);
3572 if (err)
3573 return err;
3574
3575 // lookup zap to get name
3576 err = zap_iterate_u64(&mdn, hook, data);
3577 if (err == 0)
3578 return err;
3579
3580 // pobj becomes obj now
3581 obj = pobj;
3582
3583 // append new intermediate dnode to path
3584 grub_strcat(buf, path);
3585 grub_strcpy(path, "/");
3586 grub_strcat(path, buf);
3587 }
3588
3589 return GRUB_ERR_NONE;
3590 }
3591
3592 grub_err_t
3593 get_default_bootfs_obj(grub_device_t dev, char * path, grub_uint64_t * mdnobj)
3594 {
3595 struct grub_zfs_data * data;
3596 grub_err_t err = 0;
3597 data = zfs_mount(dev);
3598 if (data) {
3599 err = get_default_bootfsobj(&(data->mos), mdnobj, data);
3600 if (err)
3601 return err;
3602 err = find_default_dataset_path(path, mdnobj, data);
3603 zfs_unmount(data);
3604 return err;
3605 } else {
3606 return grub_errno;
3607 }
3608 return 0;
3609 }
3610
3611 grub_err_t
3612 grub_zfs_fetch_nvlist (grub_device_t dev, char **nvlist)
3613 {
3614 struct grub_zfs_data *zfs;
3615 grub_err_t err;
3616
3617 zfs = zfs_mount (dev);
3618 if (!zfs)
3619 return grub_errno;
3620 err = zfs_fetch_nvlist (zfs->device_original, nvlist);
3621 zfs_unmount (zfs);
3622 return err;
3623 }
3624
3625 static grub_err_t
3626 zfs_label (grub_device_t device, char **label)
3627 {
3628 char *nvlist;
3629 grub_err_t err;
3630 struct grub_zfs_data *data;
|