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