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