5
3474: Fix 2G limit on ZFS
7
3488: ZFS multi-device and version 33 support
9
3518: Rewrite RAIDZ part based on reverse engineering
10
3519: Fix RAIDZ(2) for >= 5 devices
11
3520: Add ability to sustain a single drive failure on both raidz and raidz2
13
3533: Support second redundancy strip on raidz(2,3)
14
3534: Support case-insensitive ZFS subvolumes
15
3535: Support third redundancy strip on raidz3
17
--- a/grub-core/fs/zfs/zfs.c
18
+++ b/grub-core/fs/zfs/zfs.c
20
#include <grub/zfs/sa_impl.h>
21
#include <grub/zfs/dsl_dir.h>
22
#include <grub/zfs/dsl_dataset.h>
23
+#include <grub/deflate.h>
25
GRUB_MOD_LICENSE ("GPLv3+");
28
grub_zfs_endian_t endian;
31
+struct grub_zfs_device_desc
33
+ enum { DEVICE_LEAF, DEVICE_MIRROR, DEVICE_RAIDZ } type;
37
+ /* Valid only for non-leafs. */
38
+ unsigned n_children;
39
+ struct grub_zfs_device_desc *children;
41
+ /* Valid only for RAIDZ. */
45
+ /* Valid only for leaf devices. */
47
+ grub_disk_addr_t vdev_phys_sector;
48
+ uberblock_t current_uberblock;
54
/* cache for a file block of the currently zfs_open()-ed file */
56
grub_uint64_t dnode_end;
57
grub_zfs_endian_t dnode_endian;
59
- uberblock_t current_uberblock;
66
- grub_disk_addr_t vdev_phys_sector;
67
+ struct grub_zfs_device_desc *devices_attached;
68
+ unsigned n_devices_attached;
69
+ unsigned n_devices_allocated;
70
+ struct grub_zfs_device_desc *device_original;
72
+ uberblock_t current_uberblock;
79
+zlib_decompress (void *s, void *d,
80
+ grub_size_t slen, grub_size_t dlen)
82
+ if (grub_zlib_decompress (s, slen, 0, d, dlen) < 0)
84
+ return GRUB_ERR_NONE;
87
static decomp_entry_t decomp_table[ZIO_COMPRESS_FUNCTIONS] = {
88
{"inherit", NULL}, /* ZIO_COMPRESS_INHERIT */
89
{"on", lzjb_decompress}, /* ZIO_COMPRESS_ON */
90
{"off", NULL}, /* ZIO_COMPRESS_OFF */
91
{"lzjb", lzjb_decompress}, /* ZIO_COMPRESS_LZJB */
92
{"empty", NULL}, /* ZIO_COMPRESS_EMPTY */
93
- {"gzip", NULL}, /* ZIO_COMPRESS_GZIP */
94
+ {"gzip-1", zlib_decompress}, /* ZIO_COMPRESS_GZIP1 */
95
+ {"gzip-2", zlib_decompress}, /* ZIO_COMPRESS_GZIP2 */
96
+ {"gzip-3", zlib_decompress}, /* ZIO_COMPRESS_GZIP3 */
97
+ {"gzip-4", zlib_decompress}, /* ZIO_COMPRESS_GZIP4 */
98
+ {"gzip-5", zlib_decompress}, /* ZIO_COMPRESS_GZIP5 */
99
+ {"gzip-6", zlib_decompress}, /* ZIO_COMPRESS_GZIP6 */
100
+ {"gzip-7", zlib_decompress}, /* ZIO_COMPRESS_GZIP7 */
101
+ {"gzip-8", zlib_decompress}, /* ZIO_COMPRESS_GZIP8 */
102
+ {"gzip-9", zlib_decompress}, /* ZIO_COMPRESS_GZIP9 */
105
static grub_err_t zio_read_data (blkptr_t * bp, grub_zfs_endian_t endian,
109
zio_checksum_verify (zio_cksum_t zc, grub_uint32_t checksum,
110
- grub_zfs_endian_t endian, char *buf, int size)
111
+ grub_zfs_endian_t endian, char *buf, grub_size_t size)
113
zio_eck_t *zec = (zio_eck_t *) (buf + size) - 1;
114
zio_checksum_info_t *ci = &zio_checksum_table[checksum];
115
@@ -253,13 +297,13 @@
116
|| (actual_cksum.zc_word[2] != zc.zc_word[2])
117
|| (actual_cksum.zc_word[3] != zc.zc_word[3]))
119
- grub_dprintf ("zfs", "checksum %d verification failed\n", checksum);
120
- grub_dprintf ("zfs", "actual checksum %16llx %16llx %16llx %16llx\n",
121
+ grub_dprintf ("zfs", "checksum %s verification failed\n", ci->ci_name);
122
+ grub_dprintf ("zfs", "actual checksum %016llx %016llx %016llx %016llx\n",
123
(unsigned long long) actual_cksum.zc_word[0],
124
(unsigned long long) actual_cksum.zc_word[1],
125
(unsigned long long) actual_cksum.zc_word[2],
126
(unsigned long long) actual_cksum.zc_word[3]);
127
- grub_dprintf ("zfs", "expected checksum %16llx %16llx %16llx %16llx\n",
128
+ grub_dprintf ("zfs", "expected checksum %016llx %016llx %016llx %016llx\n",
129
(unsigned long long) zc.zc_word[0],
130
(unsigned long long) zc.zc_word[1],
131
(unsigned long long) zc.zc_word[2],
136
-uberblock_verify (uberblock_phys_t * ub, int offset)
137
+uberblock_verify (uberblock_phys_t * ub, grub_uint64_t offset)
139
uberblock_t *uber = &ub->ubp_uberblock;
145
-dva_get_offset (dva_t * dva, grub_zfs_endian_t endian)
146
+dva_get_offset (const dva_t *dva, grub_zfs_endian_t endian)
148
grub_dprintf ("zfs", "dva=%llx, %llx\n",
149
(unsigned long long) dva->dva_word[0],
150
@@ -401,6 +445,842 @@
151
endian) << SPA_MINBLOCKSHIFT;
155
+zfs_fetch_nvlist (struct grub_zfs_device_desc *diskdesc, char **nvlist)
159
+ *nvlist = grub_malloc (VDEV_PHYS_SIZE);
160
+ if (!diskdesc->dev)
161
+ return grub_error (GRUB_ERR_BAD_FS, "member drive unknown");
163
+ /* Read in the vdev name-value pair list (112K). */
164
+ err = grub_disk_read (diskdesc->dev->disk, diskdesc->vdev_phys_sector, 0,
165
+ VDEV_PHYS_SIZE, *nvlist);
168
+ grub_free (*nvlist);
172
+ return GRUB_ERR_NONE;
176
+fill_vdev_info_real (struct grub_zfs_data *data,
177
+ const char *nvlist,
178
+ struct grub_zfs_device_desc *fill,
179
+ struct grub_zfs_device_desc *insert)
183
+ type = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_TYPE);
188
+ if (!grub_zfs_nvlist_lookup_uint64 (nvlist, "id", &(fill->id)))
189
+ return grub_error (GRUB_ERR_BAD_FS, "couldn't find vdev id");
191
+ if (!grub_zfs_nvlist_lookup_uint64 (nvlist, "guid", &(fill->guid)))
192
+ return grub_error (GRUB_ERR_BAD_FS, "couldn't find vdev id");
194
+ if (grub_strcmp (type, VDEV_TYPE_DISK) == 0
195
+ || grub_strcmp (type, VDEV_TYPE_FILE) == 0)
197
+ fill->type = DEVICE_LEAF;
199
+ if (!fill->dev && fill->guid == insert->guid)
201
+ fill->dev = insert->dev;
202
+ fill->vdev_phys_sector = insert->vdev_phys_sector;
203
+ fill->current_uberblock = insert->current_uberblock;
204
+ fill->original = insert->original;
205
+ if (!data->device_original)
206
+ data->device_original = fill;
209
+ return GRUB_ERR_NONE;
212
+ if (grub_strcmp (type, VDEV_TYPE_MIRROR) == 0
213
+ || grub_strcmp (type, VDEV_TYPE_RAIDZ) == 0)
217
+ if (grub_strcmp (type, VDEV_TYPE_MIRROR) == 0)
218
+ fill->type = DEVICE_MIRROR;
222
+ fill->type = DEVICE_RAIDZ;
223
+ if (!grub_zfs_nvlist_lookup_uint64 (nvlist, "nparity", &par))
224
+ return grub_error (GRUB_ERR_BAD_FS, "couldn't find raidz parity");
225
+ fill->nparity = par;
226
+ if (!grub_zfs_nvlist_lookup_uint64 (nvlist, "ashift", &par))
227
+ return grub_error (GRUB_ERR_BAD_FS, "couldn't find raidz ashift");
228
+ fill->ashift = par;
231
+ nelm = grub_zfs_nvlist_lookup_nvlist_array_get_nelm (nvlist, ZPOOL_CONFIG_CHILDREN);
234
+ return grub_error (GRUB_ERR_BAD_FS, "incorrect mirror VDEV");
236
+ if (!fill->children)
238
+ fill->n_children = nelm;
240
+ fill->children = grub_zalloc (fill->n_children
241
+ * sizeof (fill->children[0]));
244
+ for (i = 0; i < nelm; i++)
249
+ child = grub_zfs_nvlist_lookup_nvlist_array
250
+ (nvlist, ZPOOL_CONFIG_CHILDREN, i);
252
+ err = fill_vdev_info_real (data, child, &fill->children[i], insert);
259
+ return GRUB_ERR_NONE;
262
+ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "vdev %s isn't supported",
267
+fill_vdev_info (struct grub_zfs_data *data,
268
+ char *nvlist, struct grub_zfs_device_desc *diskdesc)
273
+ if (!grub_zfs_nvlist_lookup_uint64 (nvlist, "id", &id))
274
+ return grub_error (GRUB_ERR_BAD_FS, "couldn't find vdev id");
276
+ for (i = 0; i < data->n_devices_attached; i++)
277
+ if (data->devices_attached[i].id == id)
278
+ return fill_vdev_info_real (data, nvlist, &data->devices_attached[i],
281
+ data->n_devices_attached++;
282
+ if (data->n_devices_attached > data->n_devices_allocated)
285
+ data->n_devices_allocated = 2 * data->n_devices_attached + 1;
286
+ data->devices_attached
287
+ = grub_realloc (tmp = data->devices_attached,
288
+ data->n_devices_allocated
289
+ * sizeof (data->devices_attached[0]));
290
+ if (!data->devices_attached)
292
+ data->devices_attached = tmp;
297
+ grub_memset (&data->devices_attached[data->n_devices_attached - 1],
298
+ 0, sizeof (data->devices_attached[data->n_devices_attached - 1]));
300
+ return fill_vdev_info_real (data, nvlist,
301
+ &data->devices_attached[data->n_devices_attached - 1],
306
+ * Check the disk label information and retrieve needed vdev name-value pairs.
310
+check_pool_label (struct grub_zfs_data *data,
311
+ struct grub_zfs_device_desc *diskdesc)
313
+ grub_uint64_t pool_state, txg = 0;
318
+ grub_uint64_t poolguid;
319
+ grub_uint64_t version;
323
+ err = zfs_fetch_nvlist (diskdesc, &nvlist);
327
+ grub_dprintf ("zfs", "check 2 passed\n");
329
+ found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_STATE,
333
+ grub_free (nvlist);
335
+ grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_POOL_STATE " not found");
338
+ grub_dprintf ("zfs", "check 3 passed\n");
340
+ if (pool_state == POOL_STATE_DESTROYED)
342
+ grub_free (nvlist);
343
+ return grub_error (GRUB_ERR_BAD_FS, "zpool is marked as destroyed");
345
+ grub_dprintf ("zfs", "check 4 passed\n");
347
+ found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_TXG, &txg);
350
+ grub_free (nvlist);
352
+ grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_POOL_TXG " not found");
355
+ grub_dprintf ("zfs", "check 6 passed\n");
357
+ /* not an active device */
360
+ grub_free (nvlist);
361
+ return grub_error (GRUB_ERR_BAD_FS, "zpool isn't active");
363
+ grub_dprintf ("zfs", "check 7 passed\n");
365
+ found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_VERSION,
369
+ grub_free (nvlist);
371
+ grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_VERSION " not found");
374
+ grub_dprintf ("zfs", "check 8 passed\n");
376
+ if (version > SPA_VERSION)
378
+ grub_free (nvlist);
379
+ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
380
+ "too new version %llu > %llu",
381
+ (unsigned long long) version,
382
+ (unsigned long long) SPA_VERSION);
384
+ grub_dprintf ("zfs", "check 9 passed\n");
386
+ found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_GUID,
387
+ &(diskdesc->guid));
390
+ grub_free (nvlist);
392
+ grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_GUID " not found");
396
+ found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_GUID,
400
+ grub_free (nvlist);
402
+ grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_POOL_GUID " not found");
406
+ grub_dprintf ("zfs", "check 11 passed\n");
408
+ if (data->mounted && data->guid != poolguid)
409
+ return grub_error (GRUB_ERR_BAD_FS, "another zpool");
411
+ data->guid = poolguid;
415
+ nv = grub_zfs_nvlist_lookup_nvlist (nvlist, ZPOOL_CONFIG_VDEV_TREE);
419
+ grub_free (nvlist);
420
+ return grub_error (GRUB_ERR_BAD_FS, "couldn't find vdev tree");
422
+ err = fill_vdev_info (data, nv, diskdesc);
425
+ grub_free (nvlist);
429
+ grub_dprintf ("zfs", "check 10 passed\n");
431
+ grub_free (nvlist);
433
+ return GRUB_ERR_NONE;
437
+scan_disk (grub_device_t dev, struct grub_zfs_data *data,
441
+ uberblock_phys_t *ub_array, *ubbest = NULL;
442
+ vdev_boot_header_t *bh;
445
+ struct grub_zfs_device_desc desc;
447
+ ub_array = grub_malloc (VDEV_UBERBLOCK_RING);
451
+ bh = grub_malloc (VDEV_BOOT_HEADER_SIZE);
454
+ grub_free (ub_array);
458
+ vdevnum = VDEV_LABELS;
461
+ desc.original = original;
463
+ /* Don't check back labels on CDROM. */
464
+ if (grub_disk_get_size (dev->disk) == GRUB_DISK_SIZE_UNKNOWN)
465
+ vdevnum = VDEV_LABELS / 2;
467
+ for (label = 0; ubbest == NULL && label < vdevnum; label++)
469
+ desc.vdev_phys_sector
470
+ = label * (sizeof (vdev_label_t) >> SPA_MINBLOCKSHIFT)
471
+ + ((VDEV_SKIP_SIZE + VDEV_BOOT_HEADER_SIZE) >> SPA_MINBLOCKSHIFT)
472
+ + (label < VDEV_LABELS / 2 ? 0 : grub_disk_get_size (dev->disk)
473
+ - VDEV_LABELS * (sizeof (vdev_label_t) >> SPA_MINBLOCKSHIFT));
475
+ /* Read in the uberblock ring (128K). */
476
+ err = grub_disk_read (dev->disk, desc.vdev_phys_sector
477
+ + (VDEV_PHYS_SIZE >> SPA_MINBLOCKSHIFT),
478
+ 0, VDEV_UBERBLOCK_RING, (char *) ub_array);
481
+ grub_errno = GRUB_ERR_NONE;
484
+ grub_dprintf ("zfs", "label ok %d\n", label);
486
+ ubbest = find_bestub (ub_array, desc.vdev_phys_sector);
489
+ grub_dprintf ("zfs", "No uberblock found\n");
490
+ grub_errno = GRUB_ERR_NONE;
494
+ grub_memmove (&(desc.current_uberblock),
495
+ &ubbest->ubp_uberblock, sizeof (uberblock_t));
497
+ grub_memmove (&(data->current_uberblock),
498
+ &ubbest->ubp_uberblock, sizeof (uberblock_t));
500
+ err = check_pool_label (data, &desc);
503
+ grub_errno = GRUB_ERR_NONE;
507
+ if (find_best_root &&
508
+ vdev_uberblock_compare (&ubbest->ubp_uberblock,
509
+ &(current_uberblock)) <= 0)
512
+ grub_free (ub_array);
514
+ return GRUB_ERR_NONE;
517
+ grub_free (ub_array);
520
+ return grub_error (GRUB_ERR_BAD_FS, "couldn't find a valid label");
524
+scan_devices (struct grub_zfs_data *data)
526
+ auto int hook (const char *name);
527
+ int hook (const char *name)
531
+ dev = grub_device_open (name);
536
+ grub_device_close (dev);
539
+ err = scan_disk (dev, data, 0);
540
+ if (err == GRUB_ERR_BAD_FS)
542
+ grub_device_close (dev);
543
+ grub_errno = GRUB_ERR_NONE;
548
+ grub_device_close (dev);
549
+ grub_print_error ();
555
+ grub_device_iterate (hook);
556
+ return GRUB_ERR_NONE;
560
+xor (grub_uint64_t *a, const grub_uint64_t *b, grub_size_t s)
562
+ s /= sizeof (grub_uint64_t);
568
+static grub_uint8_t powx[255 * 2];
569
+/* Such an s that x**s = y */
570
+static int powx_inv[256];
571
+static const grub_uint8_t poly = 0x1d;
573
+/* perform the operation a ^= b * (x ** (known_idx * recovery_pow) ) */
575
+xor_out (void *a_in, const void *b_in, grub_size_t s,
576
+ int known_idx, int recovery_pow)
579
+ grub_uint8_t *a = a_in;
580
+ const grub_uint8_t *b = b_in;
583
+ if (known_idx == 0 || recovery_pow == 0)
585
+ xor (a_in, b_in, s);
588
+ add = (known_idx * recovery_pow) % 255;
589
+ for (;s--; b++, a++)
591
+ *a ^= powx[powx_inv[*b] + add];
594
+static inline grub_uint8_t
595
+gf_mul (grub_uint8_t a, grub_uint8_t b)
597
+ if (a == 0 || b == 0)
599
+ return powx[powx_inv[a] + powx_inv[b]];
602
+static inline grub_err_t
603
+recovery (grub_uint8_t *bufs[4], grub_size_t s, const int nbufs,
604
+ const unsigned *powers,
607
+ grub_dprintf ("zfs", "recovering %u bufers\n", nbufs);
609
+ /* b_i = sum (r_j* (x ** (powers[i] * idx[j])))*/
610
+ /* Let's invert the matrix in question. */
613
+ /* Easy: r_0 = bufs[0] / (x << (powers[i] * idx[j])). */
618
+ if (powers[0] == 0 || idx[0] == 0)
619
+ return GRUB_ERR_NONE;
620
+ add = 255 - ((powers[0] * idx[0]) % 255);
621
+ for (a = bufs[0]; s--; a++)
623
+ *a = powx[powx_inv[*a] + add];
624
+ return GRUB_ERR_NONE;
626
+ /* Case 2x2: Let's use the determinant formula. */
629
+ grub_uint8_t det, det_inv;
630
+ grub_uint8_t matrixinv[2][2];
632
+ /* The determinant is: */
633
+ det = (powx[(powers[0] * idx[0] + powers[1] * idx[1]) % 255]
634
+ ^ powx[(powers[0] * idx[1] + powers[1] * idx[0]) % 255]);
636
+ return grub_error (GRUB_ERR_BAD_FS, "singular recovery matrix");
637
+ det_inv = powx[255 - powx_inv[det]];
638
+ matrixinv[0][0] = gf_mul (powx[(powers[1] * idx[1]) % 255], det_inv);
639
+ matrixinv[1][1] = gf_mul (powx[(powers[0] * idx[0]) % 255], det_inv);
640
+ matrixinv[0][1] = gf_mul (powx[(powers[0] * idx[1]) % 255], det_inv);
641
+ matrixinv[1][0] = gf_mul (powx[(powers[1] * idx[0]) % 255], det_inv);
642
+ for (i = 0; i < s; i++)
644
+ grub_uint8_t b0, b1;
648
+ bufs[0][i] = (gf_mul (b0, matrixinv[0][0])
649
+ ^ gf_mul (b1, matrixinv[0][1]));
650
+ bufs[1][i] = (gf_mul (b0, matrixinv[1][0])
651
+ ^ gf_mul (b1, matrixinv[1][1]));
653
+ return GRUB_ERR_NONE;
655
+ /* Otherwise use Gauss. */
658
+ grub_uint8_t matrix1[nbufs][nbufs], matrix2[nbufs][nbufs];
661
+ for (i = 0; i < nbufs; i++)
662
+ for (j = 0; j < nbufs; j++)
663
+ matrix1[i][j] = powx[(powers[i] * idx[j]) % 255];
664
+ for (i = 0; i < nbufs; i++)
665
+ for (j = 0; j < nbufs; j++)
667
+ for (i = 0; i < nbufs; i++)
670
+ for (i = 0; i < nbufs; i++)
673
+ for (j = i; j < nbufs; j++)
677
+ return grub_error (GRUB_ERR_BAD_FS, "singular recovery matrix");
682
+ for (j = 0; j < nbufs; j++)
685
+ t = matrix1[xchng][j];
686
+ matrix1[xchng][j] = matrix1[i][j];
689
+ for (j = 0; j < nbufs; j++)
692
+ t = matrix2[xchng][j];
693
+ matrix2[xchng][j] = matrix2[i][j];
697
+ mul = powx[255 - powx_inv[matrix1[i][i]]];
698
+ for (j = 0; j < nbufs; j++)
699
+ matrix1[i][j] = gf_mul (matrix1[i][j], mul);
700
+ for (j = 0; j < nbufs; j++)
701
+ matrix2[i][j] = gf_mul (matrix2[i][j], mul);
702
+ for (j = i + 1; j < nbufs; j++)
704
+ mul = matrix1[j][i];
705
+ for (k = 0; k < nbufs; k++)
706
+ matrix1[j][k] ^= gf_mul (matrix1[i][k], mul);
707
+ for (k = 0; k < nbufs; k++)
708
+ matrix2[j][k] ^= gf_mul (matrix2[i][k], mul);
711
+ for (i = nbufs - 1; i >= 0; i--)
713
+ for (j = 0; j < i; j++)
716
+ mul = matrix1[j][i];
717
+ for (k = 0; k < nbufs; k++)
718
+ matrix1[j][k] ^= gf_mul (matrix1[i][k], mul);
719
+ for (k = 0; k < nbufs; k++)
720
+ matrix2[j][k] ^= gf_mul (matrix2[i][k], mul);
724
+ for (i = 0; i < (int) s; i++)
726
+ grub_uint8_t b[nbufs];
727
+ for (j = 0; j < nbufs; j++)
729
+ for (j = 0; j < nbufs; j++)
732
+ for (k = 0; k < nbufs; k++)
733
+ bufs[j][i] ^= gf_mul (matrix2[j][k], b[k]);
736
+ return GRUB_ERR_NONE;
742
+read_device (grub_uint64_t offset, struct grub_zfs_device_desc *desc,
743
+ grub_size_t len, void *buf)
745
+ switch (desc->type)
749
+ grub_uint64_t sector;
750
+ sector = DVA_OFFSET_TO_PHYS_SECTOR (offset);
753
+ return grub_error (GRUB_ERR_BAD_FS, "member drive unknown");
755
+ /* read in a data block */
756
+ return grub_disk_read (desc->dev->disk, sector, 0, len, buf);
758
+ case DEVICE_MIRROR:
760
+ grub_err_t err = GRUB_ERR_NONE;
762
+ if (desc->n_children <= 0)
763
+ return grub_error (GRUB_ERR_BAD_FS,
764
+ "non-positive number of mirror children");
765
+ for (i = 0; i < desc->n_children; i++)
767
+ err = read_device (offset, &desc->children[i],
771
+ grub_errno = GRUB_ERR_NONE;
773
+ return (grub_errno = err);
778
+ grub_uint64_t high;
779
+ grub_uint64_t devn;
781
+ grub_uint32_t s, orig_s;
782
+ void *orig_buf = buf;
783
+ grub_size_t orig_len = len;
784
+ grub_uint8_t *recovery_buf[4];
785
+ grub_size_t recovery_len[4];
786
+ int recovery_idx[4];
787
+ unsigned failed_devices = 0;
790
+ if (desc->nparity < 1 || desc->nparity > 3)
791
+ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
792
+ "raidz%d is not supported", desc->nparity);
794
+ orig_s = (((len + (1 << desc->ashift) - 1) >> desc->ashift)
795
+ + (desc->n_children - desc->nparity) - 1);
798
+ high = grub_divmod64_full ((offset >> desc->ashift),
799
+ desc->n_children, &m);
800
+ if (desc->nparity == 2)
802
+ if (desc->nparity == 3)
804
+ if (((len + (1 << desc->ashift) - 1) >> desc->ashift)
805
+ >= (desc->n_children - desc->nparity))
806
+ idx = (desc->n_children - desc->nparity - 1);
808
+ idx = ((len + (1 << desc->ashift) - 1) >> desc->ashift) - 1;
813
+ grub_uint32_t bsize;
815
+ bsize = s / (desc->n_children - desc->nparity);
817
+ if (desc->nparity == 1
818
+ && ((offset >> (desc->ashift + 11)) & 1) == c)
821
+ high = grub_divmod64_full ((offset >> desc->ashift) + c,
822
+ desc->n_children, &devn);
823
+ csize = bsize << desc->ashift;
827
+ grub_dprintf ("zfs", "RAIDZ mapping 0x%" PRIxGRUB_UINT64_T
828
+ "+%u (%" PRIxGRUB_SIZE ", %" PRIxGRUB_UINT32_T
829
+ ") -> (0x%" PRIxGRUB_UINT64_T ", 0x%"
830
+ PRIxGRUB_UINT64_T ")\n",
831
+ offset >> desc->ashift, c, len, bsize, high,
833
+ err = read_device ((high << desc->ashift)
834
+ | (offset & ((1 << desc->ashift) - 1)),
835
+ &desc->children[devn],
837
+ if (err && failed_devices < desc->nparity)
839
+ recovery_buf[failed_devices] = buf;
840
+ recovery_len[failed_devices] = csize;
841
+ recovery_idx[failed_devices] = idx;
843
+ grub_errno = err = 0;
851
+ buf = (char *) buf + csize;
854
+ if (failed_devices)
856
+ unsigned redundancy_pow[4];
857
+ unsigned cur_redundancy_pow = 0;
858
+ unsigned n_redundancy = 0;
862
+ /* Compute mul. x**s has a period of 255. */
865
+ grub_uint8_t cur = 1;
866
+ for (i = 0; i < 255; i++)
869
+ powx[i + 255] = cur;
872
+ cur = (cur << 1) ^ poly;
878
+ /* Read redundancy data. */
879
+ for (n_redundancy = 0, cur_redundancy_pow = 0;
880
+ n_redundancy < failed_devices;
881
+ cur_redundancy_pow++)
883
+ high = grub_divmod64_full ((offset >> desc->ashift)
884
+ + cur_redundancy_pow
885
+ + ((desc->nparity == 1)
886
+ && ((offset >> (desc->ashift + 11))
888
+ desc->n_children, &devn);
889
+ err = read_device ((high << desc->ashift)
890
+ | (offset & ((1 << desc->ashift) - 1)),
891
+ &desc->children[devn],
892
+ recovery_len[n_redundancy],
893
+ recovery_buf[n_redundancy]);
894
+ /* Ignore error if we may still have enough devices. */
895
+ if (err && n_redundancy + desc->nparity - cur_redundancy_pow - 1
898
+ grub_errno = GRUB_ERR_NONE;
903
+ redundancy_pow[n_redundancy] = cur_redundancy_pow;
906
+ /* Now xor-our the parts we already know. */
915
+ csize = ((s / (desc->n_children - desc->nparity))
920
+ for (j = 0; j < failed_devices; j++)
921
+ if (buf == recovery_buf[j])
924
+ if (j == failed_devices)
925
+ for (j = 0; j < failed_devices; j++)
926
+ xor_out (recovery_buf[j], buf,
927
+ csize < recovery_len[j] ? csize : recovery_len[j],
928
+ idx, redundancy_pow[j]);
931
+ buf = (char *) buf + csize;
935
+ for (i = 0; i < failed_devices
936
+ && recovery_len[i] == recovery_len[0];
938
+ /* Since the chunks have variable length handle the last block
940
+ if (i != failed_devices)
942
+ grub_uint8_t *tmp_recovery_buf[4];
943
+ for (j = 0; j < i; j++)
944
+ tmp_recovery_buf[j] = recovery_buf[j] + recovery_len[j] - 1;
945
+ err = recovery (tmp_recovery_buf, 1, i, redundancy_pow,
950
+ err = recovery (recovery_buf, recovery_len[failed_devices - 1],
951
+ failed_devices, redundancy_pow, recovery_idx);
955
+ return GRUB_ERR_NONE;
958
+ return grub_error (GRUB_ERR_BAD_FS, "unsupported device type");
962
+read_dva (const dva_t *dva,
963
+ grub_zfs_endian_t endian, struct grub_zfs_data *data,
964
+ void *buf, grub_size_t len)
966
+ grub_uint64_t offset;
970
+ offset = dva_get_offset (dva, endian);
972
+ for (try = 0; try < 2; try++)
974
+ for (i = 0; i < data->n_devices_attached; i++)
975
+ if (data->devices_attached[i].id == DVA_GET_VDEV (dva))
977
+ err = read_device (offset, &data->devices_attached[i], len, buf);
979
+ return GRUB_ERR_NONE;
984
+ err = scan_devices (data);
992
* Read a block of data based on the gang block address dva,
994
struct grub_zfs_data *data)
996
zio_gbh_phys_t *zio_gb;
997
- grub_uint64_t offset, sector;
1001
@@ -424,13 +1303,8 @@
1003
grub_dprintf ("zfs", endian == LITTLE_ENDIAN ? "little-endian gang\n"
1004
:"big-endian gang\n");
1005
- offset = dva_get_offset (dva, endian);
1006
- sector = DVA_OFFSET_TO_PHYS_SECTOR (offset);
1007
- grub_dprintf ("zfs", "offset=%llx\n", (unsigned long long) offset);
1009
- /* read in the gang block header */
1010
- err = grub_disk_read (data->disk, sector, 0, SPA_GANGBLOCKSIZE,
1012
+ err = read_dva (dva, endian, data, zio_gb, SPA_GANGBLOCKSIZE);
1016
@@ -483,20 +1357,13 @@
1017
/* pick a good dva from the block pointer */
1018
for (i = 0; i < SPA_DVAS_PER_BP; i++)
1020
- grub_uint64_t offset, sector;
1022
if (bp->blk_dva[i].dva_word[0] == 0 && bp->blk_dva[i].dva_word[1] == 0)
1025
if ((grub_zfs_to_cpu64 (bp->blk_dva[i].dva_word[1], endian)>>63) & 1)
1026
err = zio_read_gang (bp, endian, &bp->blk_dva[i], buf, data);
1029
- /* read in a data block */
1030
- offset = dva_get_offset (&bp->blk_dva[i], endian);
1031
- sector = DVA_OFFSET_TO_PHYS_SECTOR (offset);
1032
- err = grub_disk_read (data->disk, sector, 0, psize, buf);
1034
+ err = read_dva (&bp->blk_dva[i], endian, data, buf, psize);
1036
return GRUB_ERR_NONE;
1037
grub_errno = GRUB_ERR_NONE;
1038
@@ -527,7 +1394,7 @@
1041
checksum = (grub_zfs_to_cpu64((bp)->blk_prop, endian) >> 40) & 0xff;
1042
- comp = (grub_zfs_to_cpu64((bp)->blk_prop, endian)>>32) & 0x7;
1043
+ comp = (grub_zfs_to_cpu64((bp)->blk_prop, endian)>>32) & 0xff;
1044
lsize = (BP_IS_HOLE(bp) ? 0 :
1045
(((grub_zfs_to_cpu64 ((bp)->blk_prop, endian) & 0xffff) + 1)
1046
<< SPA_MINBLOCKSHIFT));
1047
@@ -602,7 +1469,8 @@
1048
dmu_read (dnode_end_t * dn, grub_uint64_t blkid, void **buf,
1049
grub_zfs_endian_t *endian_out, struct grub_zfs_data *data)
1054
blkptr_t *bp_array = dn->dn.dn_blkptr;
1055
int epbs = dn->dn.dn_indblkshift - SPA_BLKPTRSHIFT;
1057
@@ -670,7 +1538,8 @@
1060
mzap_lookup (mzap_phys_t * zapobj, grub_zfs_endian_t endian,
1061
- int objsize, char *name, grub_uint64_t * value)
1062
+ int objsize, char *name, grub_uint64_t * value,
1063
+ int case_insensitive)
1066
mzap_ent_phys_t *mzap_ent = zapobj->mz_chunk;
1067
@@ -678,7 +1547,8 @@
1068
chunks = objsize / MZAP_ENT_LEN - 1;
1069
for (i = 0; i < chunks; i++)
1071
- if (grub_strcmp (mzap_ent[i].mze_name, name) == 0)
1072
+ if (case_insensitive ? (grub_strcasecmp (mzap_ent[i].mze_name, name) == 0)
1073
+ : (grub_strcmp (mzap_ent[i].mze_name, name) == 0))
1075
*value = grub_zfs_to_cpu64 (mzap_ent[i].mze_value, endian);
1076
return GRUB_ERR_NONE;
1077
@@ -711,7 +1581,8 @@
1080
static grub_uint64_t
1081
-zap_hash (grub_uint64_t salt, const char *name)
1082
+zap_hash (grub_uint64_t salt, const char *name,
1083
+ int case_insensitive)
1085
static grub_uint64_t table[256];
1086
const grub_uint8_t *cp;
1087
@@ -729,8 +1600,12 @@
1091
- for (cp = (const grub_uint8_t *) name; (c = *cp) != '\0'; cp++)
1092
- crc = (crc >> 8) ^ table[(crc ^ c) & 0xFF];
1093
+ if (case_insensitive)
1094
+ for (cp = (const grub_uint8_t *) name; (c = *cp) != '\0'; cp++)
1095
+ crc = (crc >> 8) ^ table[(crc ^ grub_toupper (c)) & 0xFF];
1097
+ for (cp = (const grub_uint8_t *) name; (c = *cp) != '\0'; cp++)
1098
+ crc = (crc >> 8) ^ table[(crc ^ c) & 0xFF];
1101
* Only use 28 bits, since we need 4 bits in the cookie for the
1102
@@ -748,10 +1623,34 @@
1103
* array_len is actual len in bytes (not encoded le_value_length).
1104
* buf is null-terminated.
1108
+name_cmp (const char *s1, const char *s2, grub_size_t n,
1109
+ int case_insensitive)
1111
+ const char *t1 = (const char *) s1;
1112
+ const char *t2 = (const char *) s2;
1114
+ if (!case_insensitive)
1115
+ return grub_memcmp (t1, t2, n);
1119
+ if (grub_toupper (*t1) != grub_toupper (*t2))
1120
+ return (int) grub_toupper (*t1) - (int) grub_toupper (*t2);
1131
zap_leaf_array_equal (zap_leaf_phys_t * l, grub_zfs_endian_t endian,
1132
- int blksft, int chunk, int array_len, const char *buf)
1133
+ int blksft, int chunk, int array_len, const char *buf,
1134
+ int case_insensitive)
1138
@@ -763,7 +1662,8 @@
1139
if (chunk >= ZAP_LEAF_NUMCHUNKS (blksft))
1142
- if (grub_memcmp (la->la_array, buf + bseen, toread) != 0)
1143
+ if (name_cmp ((char *) la->la_array, buf + bseen, toread,
1144
+ case_insensitive) != 0)
1146
chunk = grub_zfs_to_cpu16 (la->la_next, endian);
1148
@@ -804,7 +1704,8 @@
1150
zap_leaf_lookup (zap_leaf_phys_t * l, grub_zfs_endian_t endian,
1151
int blksft, grub_uint64_t h,
1152
- const char *name, grub_uint64_t * value)
1153
+ const char *name, grub_uint64_t * value,
1154
+ int case_insensitive)
1156
grub_uint16_t chunk;
1157
struct zap_leaf_entry *le;
1158
@@ -816,7 +1717,7 @@
1159
return grub_error (GRUB_ERR_BAD_FS, "invalid leaf magic");
1161
for (chunk = grub_zfs_to_cpu16 (l->l_hash[LEAF_HASH (blksft, h)], endian);
1162
- chunk != CHAIN_END; chunk = le->le_next)
1163
+ chunk != CHAIN_END; chunk = grub_zfs_to_cpu16 (le->le_next, endian))
1166
if (chunk >= ZAP_LEAF_NUMCHUNKS (blksft))
1167
@@ -836,11 +1737,12 @@
1168
if (zap_leaf_array_equal (l, endian, blksft,
1169
grub_zfs_to_cpu16 (le->le_name_chunk,endian),
1170
grub_zfs_to_cpu16 (le->le_name_length, endian),
1172
+ name, case_insensitive))
1174
struct zap_leaf_array *la;
1176
- if (le->le_int_size != 8 || le->le_value_length != 1)
1177
+ if (le->le_int_size != 8 || grub_zfs_to_cpu16 (le->le_value_length,
1179
return grub_error (GRUB_ERR_BAD_FS, "invalid leaf chunk entry");
1181
/* get the uint64_t property value */
1182
@@ -858,9 +1760,9 @@
1184
/* Verify if this is a fat zap header block */
1186
-zap_verify (zap_phys_t *zap)
1187
+zap_verify (zap_phys_t *zap, grub_zfs_endian_t endian)
1189
- if (zap->zap_magic != (grub_uint64_t) ZAP_MAGIC)
1190
+ if (grub_zfs_to_cpu64 (zap->zap_magic, endian) != (grub_uint64_t) ZAP_MAGIC)
1191
return grub_error (GRUB_ERR_BAD_FS, "bad ZAP magic");
1193
if (zap->zap_flags != 0)
1194
@@ -879,7 +1781,8 @@
1197
fzap_lookup (dnode_end_t * zap_dnode, zap_phys_t * zap,
1198
- char *name, grub_uint64_t * value, struct grub_zfs_data *data)
1199
+ char *name, grub_uint64_t * value, struct grub_zfs_data *data,
1200
+ int case_insensitive)
1203
grub_uint64_t hash, idx, blkid;
1204
@@ -888,18 +1791,18 @@
1206
grub_zfs_endian_t leafendian;
1208
- err = zap_verify (zap);
1209
+ err = zap_verify (zap, zap_dnode->endian);
1213
- hash = zap_hash (zap->zap_salt, name);
1214
+ hash = zap_hash (zap->zap_salt, name, case_insensitive);
1216
/* get block id from index */
1217
if (zap->zap_ptrtbl.zt_numblks != 0)
1218
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
1219
"external pointer tables not supported");
1220
idx = ZAP_HASH_IDX (hash, zap->zap_ptrtbl.zt_shift);
1221
- blkid = ((grub_uint64_t *) zap)[idx + (1 << (blksft - 3 - 1))];
1222
+ blkid = grub_zfs_to_cpu64 (((grub_uint64_t *) zap)[idx + (1 << (blksft - 3 - 1))], zap_dnode->endian);
1224
/* Get the leaf block */
1225
if ((1U << blksft) < sizeof (zap_leaf_phys_t))
1226
@@ -908,7 +1811,8 @@
1230
- err = zap_leaf_lookup (l, leafendian, blksft, hash, name, value);
1231
+ err = zap_leaf_lookup (l, leafendian, blksft, hash, name, value,
1232
+ case_insensitive);
1236
@@ -922,14 +1826,14 @@
1240
- grub_uint64_t idx, blkid;
1241
+ grub_uint64_t idx, idx2, blkid;
1242
grub_uint16_t chunk;
1243
int blksft = zfs_log2 (grub_zfs_to_cpu16 (zap_dnode->dn.dn_datablkszsec,
1244
zap_dnode->endian) << DNODE_SHIFT);
1246
grub_zfs_endian_t endian;
1248
- if (zap_verify (zap))
1249
+ if (zap_verify (zap, zap_dnode->endian))
1252
/* get block id from index */
1253
@@ -945,9 +1849,17 @@
1254
grub_error (GRUB_ERR_BAD_FS, "ZAP leaf is too small");
1257
- for (idx = 0; idx < zap->zap_ptrtbl.zt_numblks; idx++)
1258
+ for (idx = 0; idx < (1ULL << zap->zap_ptrtbl.zt_shift); idx++)
1260
- blkid = ((grub_uint64_t *) zap)[idx + (1 << (blksft - 3 - 1))];
1261
+ blkid = grub_zfs_to_cpu64 (((grub_uint64_t *) zap)[idx + (1 << (blksft - 3 - 1))],
1262
+ zap_dnode->endian);
1264
+ for (idx2 = 0; idx2 < idx; idx2++)
1265
+ if (blkid == grub_zfs_to_cpu64 (((grub_uint64_t *) zap)[idx2 + (1 << (blksft - 3 - 1))],
1266
+ zap_dnode->endian))
1271
err = dmu_read (zap_dnode, blkid, &l_in, &endian, data);
1273
@@ -983,8 +1895,11 @@
1275
buf = grub_malloc (grub_zfs_to_cpu16 (le->le_name_length, endian)
1277
- if (zap_leaf_array_get (l, endian, blksft, le->le_name_chunk,
1278
- le->le_name_length, buf))
1279
+ if (zap_leaf_array_get (l, endian, blksft,
1280
+ grub_zfs_to_cpu16 (le->le_name_chunk,
1282
+ grub_zfs_to_cpu16 (le->le_name_length,
1287
@@ -996,7 +1911,9 @@
1290
/* get the uint64_t property value */
1291
- la = &ZAP_LEAF_CHUNK (l, blksft, le->le_value_chunk).l_array;
1292
+ la = &ZAP_LEAF_CHUNK (l, blksft,
1293
+ grub_zfs_to_cpu16 (le->le_value_chunk,
1295
val = grub_be_to_cpu64 (la->la_array64);
1296
if (hook (buf, val))
1298
@@ -1014,7 +1931,7 @@
1301
zap_lookup (dnode_end_t * zap_dnode, char *name, grub_uint64_t * val,
1302
- struct grub_zfs_data *data)
1303
+ struct grub_zfs_data *data, int case_insensitive)
1305
grub_uint64_t block_type;
1307
@@ -1037,7 +1954,8 @@
1308
if (block_type == ZBT_MICRO)
1310
grub_dprintf ("zfs", "micro zap\n");
1311
- err = (mzap_lookup (zapbuf, endian, size, name, val));
1312
+ err = mzap_lookup (zapbuf, endian, size, name, val,
1313
+ case_insensitive);
1314
grub_dprintf ("zfs", "returned %d\n", err);
1317
@@ -1046,7 +1964,8 @@
1319
grub_dprintf ("zfs", "fat zap\n");
1320
/* this is a fat zap */
1321
- err = (fzap_lookup (zap_dnode, zapbuf, name, val, data));
1322
+ err = fzap_lookup (zap_dnode, zapbuf, name, val, data,
1323
+ case_insensitive);
1324
grub_dprintf ("zfs", "returned %d\n", err);
1327
@@ -1074,7 +1993,7 @@
1329
block_type = grub_zfs_to_cpu64 (*((grub_uint64_t *) zapbuf), endian);
1331
- grub_dprintf ("zfs", "zap read\n");
1332
+ grub_dprintf ("zfs", "zap iterate\n");
1334
if (block_type == ZBT_MICRO)
1336
@@ -1172,9 +2091,9 @@
1339
dnode_get_path (dnode_end_t * mdn, const char *path_in, dnode_end_t * dn,
1340
- struct grub_zfs_data *data)
1341
+ struct grub_zfs_data *data, int *case_insensitive)
1343
- grub_uint64_t objnum, version;
1344
+ grub_uint64_t objnum, version, insensitivity;
1346
grub_err_t err = GRUB_ERR_NONE;
1347
char *path, *path_buf;
1348
@@ -1199,19 +2118,31 @@
1352
- err = zap_lookup (&(dnode_path->dn), ZPL_VERSION_STR, &version, data);
1353
+ err = zap_lookup (&(dnode_path->dn), ZPL_VERSION_STR, &version,
1361
if (version > ZPL_VERSION)
1364
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "too new ZPL version");
1367
- err = zap_lookup (&(dnode_path->dn), ZFS_ROOT_OBJ, &objnum, data);
1369
+ err = zap_lookup (&(dnode_path->dn), "casesensitivity", &insensitivity,
1371
+ if (err == GRUB_ERR_FILE_NOT_FOUND)
1373
+ grub_errno = GRUB_ERR_NONE;
1374
+ insensitivity = 0;
1376
+ if (case_insensitive)
1377
+ *case_insensitive = insensitivity;
1379
+ err = zap_lookup (&(dnode_path->dn), ZFS_ROOT_OBJ, &objnum, data, 0);
1383
@@ -1272,7 +2203,7 @@
1384
grub_free (path_buf);
1385
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
1387
- err = zap_lookup (&(dnode_path->dn), cname, &objnum, data);
1388
+ err = zap_lookup (&(dnode_path->dn), cname, &objnum, data, insensitivity);
1392
@@ -1291,22 +2222,54 @@
1397
- if (((grub_zfs_to_cpu64(((znode_phys_t *) DN_BONUS (&dnode_path->dn.dn))->zp_mode, dnode_path->dn.endian) >> 12) & 0xf) == 0xa && ch)
1398
+ if (dnode_path->dn.dn.dn_bonustype == DMU_OT_ZNODE
1399
+ && ((grub_zfs_to_cpu64(((znode_phys_t *) DN_BONUS (&dnode_path->dn.dn))->zp_mode, dnode_path->dn.endian) >> 12) & 0xf) == 0xa)
1402
+ grub_size_t sym_sz;
1403
+ int free_symval = 0;
1404
char *oldpath = path, *oldpathbuf = path_buf;
1406
- = grub_malloc (sizeof (dnode_path->dn.dn.dn_bonus)
1407
- - sizeof (znode_phys_t) + grub_strlen (oldpath) + 1);
1408
+ sym_value = ((char *) DN_BONUS (&dnode_path->dn.dn) + sizeof (struct znode_phys));
1410
+ sym_sz = grub_zfs_to_cpu64 (((znode_phys_t *) DN_BONUS (&dnode_path->dn.dn))->zp_size, dnode_path->dn.endian);
1412
+ if (dnode_path->dn.dn.dn_flags & 1)
1414
+ grub_size_t block;
1415
+ grub_size_t blksz;
1416
+ blksz = (grub_zfs_to_cpu16 (dnode_path->dn.dn.dn_datablkszsec,
1417
+ dnode_path->dn.endian)
1418
+ << SPA_MINBLOCKSHIFT);
1420
+ sym_value = grub_malloc (sym_sz);
1422
+ return grub_errno;
1423
+ for (block = 0; block < (sym_sz + blksz - 1) / blksz; block++)
1426
+ grub_size_t movesize;
1428
+ err = dmu_read (&(dnode_path->dn), block, &t, 0, data);
1432
+ movesize = MIN (sym_sz - block * blksz, blksz);
1434
+ grub_memcpy (sym_value + block * blksz, t, movesize);
1439
+ path = path_buf = grub_malloc (sym_sz + grub_strlen (oldpath) + 1);
1442
grub_free (oldpathbuf);
1445
- grub_memcpy (path,
1446
- (char *) DN_BONUS(&dnode_path->dn.dn) + sizeof (znode_phys_t),
1447
- sizeof (dnode_path->dn.dn.dn_bonus) - sizeof (znode_phys_t));
1448
- path [sizeof (dnode_path->dn.dn.dn_bonus) - sizeof (znode_phys_t)] = 0;
1449
+ grub_memcpy (path, sym_value, sym_sz);
1451
+ grub_free (sym_value);
1452
+ path [sym_sz] = 0;
1453
grub_memcpy (path + grub_strlen (path), oldpath,
1454
grub_strlen (oldpath) + 1);
1456
@@ -1324,7 +2287,62 @@
1461
+ if (dnode_path->dn.dn.dn_bonustype == DMU_OT_SA)
1466
+ if (dnode_path->dn.dn.dn_bonuslen != 0)
1468
+ sahdrp = DN_BONUS (&dnode_path->dn.dn);
1470
+ else if (dnode_path->dn.dn.dn_flags & DNODE_FLAG_SPILL_BLKPTR)
1472
+ blkptr_t *bp = &dnode_path->dn.dn.dn_spill;
1474
+ err = zio_read (bp, dnode_path->dn.endian, &sahdrp, NULL, data);
1480
+ return grub_error (GRUB_ERR_BAD_FS, "filesystem is corrupt");
1483
+ hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp));
1485
+ if (((grub_zfs_to_cpu64 (*(grub_uint64_t *) ((char *) sahdrp + hdrsize + SA_TYPE_OFFSET), dnode_path->dn.endian) >> 12) & 0xf) == 0xa)
1487
+ char *sym_value = (char *) sahdrp + hdrsize + SA_SYMLINK_OFFSET;
1488
+ grub_size_t sym_sz =
1489
+ grub_zfs_to_cpu64 (*(grub_uint64_t *) ((char *) sahdrp + hdrsize + SA_SIZE_OFFSET), dnode_path->dn.endian);
1490
+ char *oldpath = path, *oldpathbuf = path_buf;
1491
+ path = path_buf = grub_malloc (sym_sz + grub_strlen (oldpath) + 1);
1494
+ grub_free (oldpathbuf);
1495
+ return grub_errno;
1497
+ grub_memcpy (path, sym_value, sym_sz);
1498
+ path [sym_sz] = 0;
1499
+ grub_memcpy (path + grub_strlen (path), oldpath,
1500
+ grub_strlen (oldpath) + 1);
1502
+ grub_free (oldpathbuf);
1503
+ if (path[0] != '/')
1505
+ dn_new = dnode_path;
1506
+ dnode_path = dn_new->next;
1507
+ grub_free (dn_new);
1509
+ else while (dnode_path != root)
1511
+ dn_new = dnode_path;
1512
+ dnode_path = dn_new->next;
1513
+ grub_free (dn_new);
1520
@@ -1417,7 +2435,7 @@
1522
grub_dprintf ("zfs", "alive\n");
1524
- err = zap_lookup (mdn, DMU_POOL_ROOT_DATASET, &objnum, data);
1525
+ err = zap_lookup (mdn, DMU_POOL_ROOT_DATASET, &objnum, data, 0);
1529
@@ -1452,7 +2470,7 @@
1533
- err = zap_lookup (mdn, cname, &objnum, data);
1534
+ err = zap_lookup (mdn, cname, &objnum, data, 0);
1538
@@ -1495,7 +2513,7 @@
1540
dnode_get_fullpath (const char *fullpath, dnode_end_t * mdn,
1541
grub_uint64_t *mdnobj, dnode_end_t * dn, int *isfs,
1542
- struct grub_zfs_data *data)
1543
+ struct grub_zfs_data *data, int *case_insensitive)
1545
char *fsname, *snapname;
1546
const char *ptr_at, *filename;
1547
@@ -1573,7 +2591,7 @@
1548
err = dnode_get (&(data->mos), snapobj,
1549
DMU_OT_DSL_DS_SNAP_MAP, mdn, data);
1551
- err = zap_lookup (mdn, snapname, &headobj, data);
1552
+ err = zap_lookup (mdn, snapname, &headobj, data, 0);
1554
err = dnode_get (&(data->mos), headobj, DMU_OT_DSL_DATASET, mdn, data);
1556
@@ -1597,7 +2615,7 @@
1557
grub_free (snapname);
1558
return GRUB_ERR_NONE;
1560
- err = dnode_get_path (mdn, filename, dn, data);
1561
+ err = dnode_get_path (mdn, filename, dn, data, case_insensitive);
1563
grub_free (snapname);
1565
@@ -1625,11 +2643,12 @@
1569
-nvlist_find_value (char *nvlist, char *name, int valtype, char **val,
1570
+nvlist_find_value (const char *nvlist, const char *name,
1571
+ int valtype, char **val,
1572
grub_size_t *size_out, grub_size_t *nelm_out)
1574
int name_len, type, encode_size;
1575
- char *nvpair, *nvp_name;
1576
+ const char *nvpair, *nvp_name;
1578
/* Verify if the 1st and 2nd byte in the nvlist are valid. */
1579
/* NOTE: independently of what endianness header announces all
1580
@@ -1671,7 +2690,7 @@
1582
if ((grub_strncmp (nvp_name, name, name_len) == 0) && type == valtype)
1585
+ *val = (char *) nvpair;
1586
*size_out = encode_size;
1589
@@ -1684,7 +2703,8 @@
1593
-grub_zfs_nvlist_lookup_uint64 (char *nvlist, char *name, grub_uint64_t * out)
1594
+grub_zfs_nvlist_lookup_uint64 (const char *nvlist, const char *name,
1595
+ grub_uint64_t * out)
1599
@@ -1704,7 +2724,7 @@
1603
-grub_zfs_nvlist_lookup_string (char *nvlist, char *name)
1604
+grub_zfs_nvlist_lookup_string (const char *nvlist, const char *name)
1608
@@ -1732,7 +2752,7 @@
1612
-grub_zfs_nvlist_lookup_nvlist (char *nvlist, char *name)
1613
+grub_zfs_nvlist_lookup_nvlist (const char *nvlist, const char *name)
1617
@@ -1753,199 +2773,114 @@
1621
-grub_zfs_nvlist_lookup_nvlist_array_get_nelm (char *nvlist, char *name)
1624
- grub_size_t nelm, size;
1627
- found = nvlist_find_value (nvlist, name, DATA_TYPE_NVLIST, &nvpair,
1635
-grub_zfs_nvlist_lookup_nvlist_array (char *nvlist, char *name,
1636
- grub_size_t index)
1638
- char *nvpair, *nvpairptr;
1645
- found = nvlist_find_value (nvlist, name, DATA_TYPE_NVLIST, &nvpair,
1649
- if (index >= nelm)
1651
- grub_error (GRUB_ERR_OUT_OF_RANGE, "trying to lookup past nvlist array");
1655
- nvpairptr = nvpair;
1657
- for (i = 0; i < index; i++)
1659
- grub_uint32_t encode_size;
1661
- /* skip the header, nvl_version, and nvl_nvflag */
1662
- nvpairptr = nvpairptr + 4 * 2;
1664
- while (nvpairptr < nvpair + size
1665
- && (encode_size = grub_be_to_cpu32 (*(grub_uint32_t *) nvpairptr)))
1666
- nvlist += encode_size; /* goto the next nvpair */
1668
- nvlist = nvlist + 4 * 2; /* skip the ending 2 zeros - 8 bytes */
1671
- if (nvpairptr >= nvpair + size
1672
- || nvpairptr + grub_be_to_cpu32 (*(grub_uint32_t *) (nvpairptr + 4 * 2))
1675
- grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist array");
1679
- ret = grub_zalloc (grub_be_to_cpu32 (*(grub_uint32_t *) (nvpairptr + 4 * 2))
1680
- + 3 * sizeof (grub_uint32_t));
1683
- grub_memcpy (ret, nvlist, sizeof (grub_uint32_t));
1685
- grub_memcpy (ret + sizeof (grub_uint32_t), nvpairptr, size);
1690
-zfs_fetch_nvlist (struct grub_zfs_data * data, char **nvlist)
1694
- *nvlist = grub_malloc (VDEV_PHYS_SIZE);
1695
- /* Read in the vdev name-value pair list (112K). */
1696
- err = grub_disk_read (data->disk, data->vdev_phys_sector, 0,
1697
- VDEV_PHYS_SIZE, *nvlist);
1700
- grub_free (*nvlist);
1704
- return GRUB_ERR_NONE;
1708
- * Check the disk label information and retrieve needed vdev name-value pairs.
1712
-check_pool_label (struct grub_zfs_data *data)
1713
+grub_zfs_nvlist_lookup_nvlist_array_get_nelm (const char *nvlist,
1716
- grub_uint64_t pool_state, txg = 0;
1721
- grub_uint64_t diskguid;
1722
- grub_uint64_t version;
1724
+ grub_size_t nelm, size;
1728
- err = zfs_fetch_nvlist (data, &nvlist);
1731
+ found = nvlist_find_value (nvlist, name, DATA_TYPE_NVLIST_ARRAY, &nvpair,
1738
- grub_dprintf ("zfs", "check 2 passed\n");
1740
+get_nvlist_size (const char *beg, const char *limit)
1743
+ grub_uint32_t encode_size;
1747
- found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_STATE,
1751
- grub_free (nvlist);
1753
- grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_POOL_STATE " not found");
1754
- return grub_errno;
1756
- grub_dprintf ("zfs", "check 3 passed\n");
1757
+ while (ptr < limit
1758
+ && (encode_size = grub_be_to_cpu32 (*(grub_uint32_t *) ptr)))
1759
+ ptr += encode_size; /* goto the next nvpair */
1761
+ return (ptr > limit) ? -1 : (ptr - beg);
1764
- if (pool_state == POOL_STATE_DESTROYED)
1766
- grub_free (nvlist);
1767
- return grub_error (GRUB_ERR_BAD_FS, "zpool is marked as destroyed");
1769
- grub_dprintf ("zfs", "check 4 passed\n");
1771
+grub_zfs_nvlist_lookup_nvlist_array (const char *nvlist, const char *name,
1772
+ grub_size_t index)
1774
+ char *nvpair, *nvpairptr;
1782
- found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_TXG, &txg);
1783
+ found = nvlist_find_value (nvlist, name, DATA_TYPE_NVLIST_ARRAY, &nvpair,
1787
+ if (index >= nelm)
1789
- grub_free (nvlist);
1791
- grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_POOL_TXG " not found");
1792
- return grub_errno;
1793
+ grub_error (GRUB_ERR_OUT_OF_RANGE, "trying to lookup past nvlist array");
1796
- grub_dprintf ("zfs", "check 6 passed\n");
1798
- /* not an active device */
1801
- grub_free (nvlist);
1802
- return grub_error (GRUB_ERR_BAD_FS, "zpool isn't active");
1804
- grub_dprintf ("zfs", "check 7 passed\n");
1805
+ nvpairptr = nvpair;
1807
- found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_VERSION,
1810
+ for (i = 0; i < index; i++)
1812
- grub_free (nvlist);
1814
- grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_VERSION " not found");
1815
- return grub_errno;
1817
- grub_dprintf ("zfs", "check 8 passed\n");
1819
+ r = get_nvlist_size (nvpairptr, nvpair + size);
1821
- if (version > SPA_VERSION)
1823
- grub_free (nvlist);
1824
- return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
1825
- "too new version %llu > %llu",
1826
- (unsigned long long) version,
1827
- (unsigned long long) SPA_VERSION);
1829
- grub_dprintf ("zfs", "check 9 passed\n");
1831
- if (nvlist_lookup_value (nvlist, ZPOOL_CONFIG_VDEV_TREE, &nv,
1832
- DATA_TYPE_NVLIST, NULL))
1835
- return (GRUB_ERR_BAD_FS);
1838
+ grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist array");
1843
- grub_dprintf ("zfs", "check 10 passed\n");
1846
- found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_GUID, &diskguid);
1848
+ elemsize = get_nvlist_size (nvpairptr, nvpair + size);
1852
- grub_free (nvlist);
1854
- grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_GUID " not found");
1855
- return grub_errno;
1856
+ grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist array");
1859
- grub_dprintf ("zfs", "check 11 passed\n");
1861
- grub_free (nvlist);
1862
+ ret = grub_zalloc (elemsize + sizeof (grub_uint32_t));
1865
+ grub_memcpy (ret, nvlist, sizeof (grub_uint32_t));
1867
- return GRUB_ERR_NONE;
1868
+ grub_memcpy (ret + sizeof (grub_uint32_t), nvpairptr, elemsize);
1873
+unmount_device (struct grub_zfs_device_desc *desc)
1876
+ switch (desc->type)
1879
+ if (!desc->original && desc->dev)
1880
+ grub_device_close (desc->dev);
1882
+ case DEVICE_RAIDZ:
1883
+ case DEVICE_MIRROR:
1884
+ for (i = 0; i < desc->n_children; i++)
1885
+ unmount_device (&desc->children[i]);
1891
zfs_unmount (struct grub_zfs_data *data)
1894
+ for (i = 0; i < data->n_devices_attached; i++)
1895
+ unmount_device (&data->devices_attached[i]);
1896
+ grub_free (data->devices_attached);
1897
grub_free (data->dnode_buf);
1898
grub_free (data->dnode_mdn);
1899
grub_free (data->file_buf);
1900
@@ -1961,13 +2896,11 @@
1901
zfs_mount (grub_device_t dev)
1903
struct grub_zfs_data *data = 0;
1905
- uberblock_phys_t *ub_array, *ubbest = NULL;
1906
- vdev_boot_header_t *bh;
1908
- grub_size_t ospsize;
1911
+ objset_phys_t *osp = 0;
1912
+ grub_size_t ospsize;
1913
+ grub_zfs_endian_t ub_endian = UNKNOWN_ENDIAN;
1918
@@ -1975,119 +2908,56 @@
1922
- data = grub_malloc (sizeof (*data));
1923
+ data = grub_zalloc (sizeof (*data));
1926
- grub_memset (data, 0, sizeof (*data));
1928
/* if it's our first time here, zero the best uberblock out */
1929
if (data->best_drive == 0 && data->best_part == 0 && find_best_root)
1930
grub_memset (¤t_uberblock, 0, sizeof (uberblock_t));
1933
- data->disk = dev->disk;
1935
- ub_array = grub_malloc (VDEV_UBERBLOCK_RING);
1937
+ data->n_devices_allocated = 16;
1938
+ data->devices_attached = grub_malloc (sizeof (data->devices_attached[0])
1939
+ * data->n_devices_allocated);
1940
+ data->n_devices_attached = 0;
1941
+ err = scan_disk (dev, data, 1);
1949
- bh = grub_malloc (VDEV_BOOT_HEADER_SIZE);
1951
+ ub = &(data->current_uberblock);
1952
+ ub_endian = (grub_zfs_to_cpu64 (ub->ub_magic,
1953
+ LITTLE_ENDIAN) == UBERBLOCK_MAGIC
1954
+ ? LITTLE_ENDIAN : BIG_ENDIAN);
1956
+ err = zio_read (&ub->ub_rootbp, ub_endian,
1957
+ (void **) &osp, &ospsize, data);
1961
- grub_free (ub_array);
1966
- vdevnum = VDEV_LABELS;
1968
- /* Don't check back labels on CDROM. */
1969
- if (grub_disk_get_size (dev->disk) == GRUB_DISK_SIZE_UNKNOWN)
1970
- vdevnum = VDEV_LABELS / 2;
1972
- for (label = 0; ubbest == NULL && label < vdevnum; label++)
1973
+ if (ospsize < OBJSET_PHYS_SIZE_V14)
1975
- grub_zfs_endian_t ub_endian = UNKNOWN_ENDIAN;
1976
- grub_dprintf ("zfs", "label %d\n", label);
1978
- data->vdev_phys_sector
1979
- = label * (sizeof (vdev_label_t) >> SPA_MINBLOCKSHIFT)
1980
- + ((VDEV_SKIP_SIZE + VDEV_BOOT_HEADER_SIZE) >> SPA_MINBLOCKSHIFT)
1981
- + (label < VDEV_LABELS / 2 ? 0 : grub_disk_get_size (dev->disk)
1982
- - VDEV_LABELS * (sizeof (vdev_label_t) >> SPA_MINBLOCKSHIFT));
1984
- /* Read in the uberblock ring (128K). */
1985
- err = grub_disk_read (data->disk, data->vdev_phys_sector
1986
- + (VDEV_PHYS_SIZE >> SPA_MINBLOCKSHIFT),
1987
- 0, VDEV_UBERBLOCK_RING, (char *) ub_array);
1990
- grub_errno = GRUB_ERR_NONE;
1993
- grub_dprintf ("zfs", "label ok %d\n", label);
1995
- ubbest = find_bestub (ub_array, data->vdev_phys_sector);
1998
- grub_dprintf ("zfs", "No uberblock found\n");
1999
- grub_errno = GRUB_ERR_NONE;
2002
- ub_endian = (grub_zfs_to_cpu64 (ubbest->ubp_uberblock.ub_magic,
2003
- LITTLE_ENDIAN) == UBERBLOCK_MAGIC
2004
- ? LITTLE_ENDIAN : BIG_ENDIAN);
2005
- err = zio_read (&ubbest->ubp_uberblock.ub_rootbp,
2007
- &osp, &ospsize, data);
2010
- grub_dprintf ("zfs", "couldn't zio_read\n");
2011
- grub_errno = GRUB_ERR_NONE;
2015
- if (ospsize < OBJSET_PHYS_SIZE_V14)
2017
- grub_dprintf ("zfs", "osp too small\n");
2021
- grub_dprintf ("zfs", "ubbest %p\n", ubbest);
2023
- err = check_pool_label (data);
2026
- grub_errno = GRUB_ERR_NONE;
2030
- if (find_best_root &&
2031
- vdev_uberblock_compare (&ubbest->ubp_uberblock,
2032
- &(current_uberblock)) <= 0)
2035
- /* Got the MOS. Save it at the memory addr MOS. */
2036
- grub_memmove (&(data->mos.dn), &((objset_phys_t *) osp)->os_meta_dnode,
2038
- data->mos.endian = (grub_zfs_to_cpu64 (ubbest->ubp_uberblock.ub_rootbp.blk_prop, ub_endian) >> 63) & 1;
2039
- grub_memmove (&(data->current_uberblock),
2040
- &ubbest->ubp_uberblock, sizeof (uberblock_t));
2041
- grub_free (ub_array);
2043
+ grub_error (GRUB_ERR_BAD_FS, "OSP too small");
2046
+ zfs_unmount (data);
2049
- grub_error (GRUB_ERR_BAD_FS, "couldn't find a valid label");
2050
- zfs_unmount (data);
2051
- grub_free (ub_array);
2054
+ /* Got the MOS. Save it at the memory addr MOS. */
2055
+ grub_memmove (&(data->mos.dn), &osp->os_meta_dnode, DNODE_SIZE);
2056
+ data->mos.endian = (grub_zfs_to_cpu64 (ub->ub_rootbp.blk_prop,
2057
+ ub_endian) >> 63) & 1;
2061
+ data->mounted = 1;
2067
@@ -2099,7 +2969,7 @@
2068
zfs = zfs_mount (dev);
2071
- err = zfs_fetch_nvlist (zfs, nvlist);
2072
+ err = zfs_fetch_nvlist (zfs->device_original, nvlist);
2076
@@ -2115,7 +2985,7 @@
2080
- err = zfs_fetch_nvlist (data, &nvlist);
2081
+ err = zfs_fetch_nvlist (data->device_original, &nvlist);
2085
@@ -2131,11 +3001,7 @@
2087
zfs_uuid (grub_device_t device, char **uuid)
2091
struct grub_zfs_data *data;
2092
- grub_uint64_t guid;
2097
@@ -2143,24 +3009,36 @@
2101
- err = zfs_fetch_nvlist (data, &nvlist);
2104
- zfs_unmount (data);
2108
- found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_GUID, &guid);
2110
- return grub_errno;
2111
- grub_free (nvlist);
2112
- *uuid = grub_xasprintf ("%016llx", (long long unsigned) guid);
2113
+ *uuid = grub_xasprintf ("%016llx", (long long unsigned) data->guid);
2117
return GRUB_ERR_NONE;
2121
+zfs_mtime (grub_device_t device, grub_int32_t *mt)
2123
+ struct grub_zfs_data *data;
2124
+ grub_zfs_endian_t ub_endian = UNKNOWN_ENDIAN;
2129
+ data = zfs_mount (device);
2131
+ return grub_errno;
2133
+ ub = &(data->current_uberblock);
2134
+ ub_endian = (grub_zfs_to_cpu64 (ub->ub_magic,
2135
+ LITTLE_ENDIAN) == UBERBLOCK_MAGIC
2136
+ ? LITTLE_ENDIAN : BIG_ENDIAN);
2138
+ *mt = grub_zfs_to_cpu64 (ub->ub_timestamp, ub_endian);
2139
+ zfs_unmount (data);
2140
+ return GRUB_ERR_NONE;
2144
* zfs_open() locates a file in the rootpool by following the
2145
* MOS and places the dnode of the file in the memory address DNODE.
2146
@@ -2177,7 +3055,7 @@
2149
err = dnode_get_fullpath (fsfilename, &(data->mdn), 0,
2150
- &(data->dnode), &isfs, data);
2151
+ &(data->dnode), &isfs, data, NULL);
2155
@@ -2227,12 +3105,14 @@
2158
hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp));
2159
- file->size = *(grub_uint64_t *) ((char *) sahdrp + hdrsize + SA_SIZE_OFFSET);
2160
+ file->size = grub_zfs_to_cpu64 (*(grub_uint64_t *) ((char *) sahdrp + hdrsize + SA_SIZE_OFFSET), data->dnode.endian);
2163
+ else if (data->dnode.dn.dn_bonustype == DMU_OT_ZNODE)
2165
file->size = grub_zfs_to_cpu64 (((znode_phys_t *) DN_BONUS (&data->dnode.dn))->zp_size, data->dnode.endian);
2168
+ return grub_error (GRUB_ERR_BAD_FS, "bad bonus type");
2172
@@ -2248,7 +3128,7 @@
2173
grub_zfs_read (grub_file_t file, char *buf, grub_size_t len)
2175
struct grub_zfs_data *data = (struct grub_zfs_data *) file->data;
2176
- int blksz, movesize;
2177
+ grub_size_t blksz, movesize;
2181
@@ -2302,7 +3182,7 @@
2182
data->file_start = blkid * blksz;
2183
data->file_end = data->file_start + blksz;
2185
- movesize = MIN (length, data->file_end - (int) file->offset - read);
2186
+ movesize = MIN (length, data->file_end - file->offset - read);
2188
grub_memmove (buf, data->file_buf + file->offset + read
2189
- data->file_start, movesize);
2190
@@ -2339,7 +3219,7 @@
2193
err = dnode_get_fullpath (fsfilename, &(data->mdn), mdnobj,
2194
- &(data->dnode), &isfs, data);
2195
+ &(data->dnode), &isfs, data, NULL);
2199
@@ -2377,7 +3257,7 @@
2203
- err = zap_lookup (&dn, ZFS_ROOT_OBJ, &objnum, data);
2204
+ err = zap_lookup (&dn, ZFS_ROOT_OBJ, &objnum, data, 0);
2207
grub_dprintf ("zfs", "failed here\n");
2208
@@ -2391,8 +3271,39 @@
2212
- info->mtimeset = 1;
2213
- info->mtime = grub_zfs_to_cpu64 (((znode_phys_t *) DN_BONUS (&dn.dn))->zp_mtime[0], dn.endian);
2214
+ if (dn.dn.dn_bonustype == DMU_OT_SA)
2219
+ if (dn.dn.dn_bonuslen != 0)
2221
+ sahdrp = (sa_hdr_phys_t *) DN_BONUS (&dn.dn);
2223
+ else if (dn.dn.dn_flags & DNODE_FLAG_SPILL_BLKPTR)
2225
+ blkptr_t *bp = &dn.dn.dn_spill;
2227
+ err = zio_read (bp, dn.endian, &sahdrp, NULL, data);
2233
+ grub_error (GRUB_ERR_BAD_FS, "filesystem is corrupt");
2237
+ hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp));
2238
+ info->mtimeset = 1;
2239
+ info->mtime = grub_zfs_to_cpu64 (*(grub_uint64_t *) ((char *) sahdrp + hdrsize + SA_MTIME_OFFSET), dn.endian);
2242
+ if (dn.dn.dn_bonustype == DMU_OT_ZNODE)
2244
+ info->mtimeset = 1;
2245
+ info->mtime = grub_zfs_to_cpu64 (((znode_phys_t *) DN_BONUS (&dn.dn))->zp_mtime[0], dn.endian);
2250
@@ -2403,6 +3314,7 @@
2251
struct grub_zfs_data *data;
2254
+ int case_insensitive = 0;
2255
auto int NESTED_FUNC_ATTR iterate_zap (const char *name, grub_uint64_t val);
2256
auto int NESTED_FUNC_ATTR iterate_zap_fs (const char *name,
2258
@@ -2416,10 +3328,48 @@
2259
grub_memset (&info, 0, sizeof (info));
2261
dnode_get (&(data->mdn), val, 0, &dn, data);
2262
- info.mtimeset = 1;
2263
- info.mtime = grub_zfs_to_cpu64 (((znode_phys_t *) DN_BONUS (&dn.dn))->zp_mtime[0], dn.endian);
2264
- info.dir = (dn.dn.dn_type == DMU_OT_DIRECTORY_CONTENTS);
2265
- grub_dprintf ("zfs", "type=%d, name=%s\n",
2267
+ if (dn.dn.dn_bonustype == DMU_OT_SA)
2272
+ if (dn.dn.dn_bonuslen != 0)
2274
+ sahdrp = (sa_hdr_phys_t *) DN_BONUS (&data->dnode.dn);
2276
+ else if (dn.dn.dn_flags & DNODE_FLAG_SPILL_BLKPTR)
2278
+ blkptr_t *bp = &dn.dn.dn_spill;
2280
+ err = zio_read (bp, dn.endian, &sahdrp, NULL, data);
2283
+ grub_print_error ();
2289
+ grub_error (GRUB_ERR_BAD_FS, "filesystem is corrupt");
2290
+ grub_print_error ();
2294
+ hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp));
2295
+ info.mtimeset = 1;
2296
+ info.mtime = grub_zfs_to_cpu64 (*(grub_uint64_t *) ((char *) sahdrp + hdrsize + SA_MTIME_OFFSET), dn.endian);
2297
+ info.case_insensitive = case_insensitive;
2300
+ if (dn.dn.dn_bonustype == DMU_OT_ZNODE)
2302
+ info.mtimeset = 1;
2303
+ info.mtime = grub_zfs_to_cpu64 (((znode_phys_t *) DN_BONUS (&dn.dn))->zp_mtime[0],
2306
+ info.dir = (dn.dn.dn_type == DMU_OT_DIRECTORY_CONTENTS);
2307
+ grub_dprintf ("zfs", "type=%d, name=%s\n",
2308
(int)dn.dn.dn_type, (char *)name);
2309
return hook (name, &info);
2311
@@ -2464,7 +3414,8 @@
2312
data = zfs_mount (device);
2315
- err = dnode_get_fullpath (path, &(data->mdn), 0, &(data->dnode), &isfs, data);
2316
+ err = dnode_get_fullpath (path, &(data->mdn), 0, &(data->dnode), &isfs, data,
2317
+ &case_insensitive);
2321
@@ -2532,12 +3483,13 @@
2322
.close = grub_zfs_close,
2326
+ .mtime = zfs_mtime,
2332
+ COMPILE_TIME_ASSERT (sizeof (zap_leaf_chunk_t) == ZAP_LEAF_CHUNKSIZE);
2333
grub_fs_register (&grub_zfs_fs);
2336
--- a/include/grub/zfs/zio.h
2337
+++ b/include/grub/zfs/zio.h
2342
- ZIO_COMPRESS_GZIP,
2343
+ ZIO_COMPRESS_GZIP1,
2344
+ ZIO_COMPRESS_GZIP2,
2345
+ ZIO_COMPRESS_GZIP3,
2346
+ ZIO_COMPRESS_GZIP4,
2347
+ ZIO_COMPRESS_GZIP5,
2348
+ ZIO_COMPRESS_GZIP6,
2349
+ ZIO_COMPRESS_GZIP7,
2350
+ ZIO_COMPRESS_GZIP8,
2351
+ ZIO_COMPRESS_GZIP9,
2352
ZIO_COMPRESS_FUNCTIONS
2355
--- a/grub-core/fs/zfs/zfsinfo.c
2356
+++ b/grub-core/fs/zfs/zfsinfo.c
2359
grub_printf ("Mirror VDEV with %d children\n", nelm);
2360
print_state (nvlist, tab);
2362
for (i = 0; i < nelm; i++)
2369
+ return GRUB_ERR_NONE;
2373
--- a/include/grub/zfs/sa_impl.h
2374
+++ b/include/grub/zfs/sa_impl.h
2378
#define SA_HDR_SIZE(hdr) BF32_GET_SB(hdr->sa_layout_info, 10, 16, 3, 0)
2379
+#define SA_TYPE_OFFSET 0x0
2380
#define SA_SIZE_OFFSET 0x8
2381
+#define SA_MTIME_OFFSET 0x38
2382
+#define SA_SYMLINK_OFFSET 0xa0
2384
#endif /* _SYS_SA_IMPL_H */
2385
--- a/include/grub/zfs/zfs.h
2386
+++ b/include/grub/zfs/zfs.h
2389
* On-disk version number.
2391
-#define SPA_VERSION 28ULL
2392
+#define SPA_VERSION 33ULL
2395
* The following are configuration names used in the nvlist describing a pool's
2396
@@ -112,12 +112,14 @@
2397
grub_err_t grub_zfs_getmdnobj (grub_device_t dev, const char *fsfilename,
2398
grub_uint64_t *mdnobj);
2400
-char *grub_zfs_nvlist_lookup_string (char *nvlist, char *name);
2401
-char *grub_zfs_nvlist_lookup_nvlist (char *nvlist, char *name);
2402
-int grub_zfs_nvlist_lookup_uint64 (char *nvlist, char *name,
2403
+char *grub_zfs_nvlist_lookup_string (const char *nvlist, const char *name);
2404
+char *grub_zfs_nvlist_lookup_nvlist (const char *nvlist, const char *name);
2405
+int grub_zfs_nvlist_lookup_uint64 (const char *nvlist, const char *name,
2406
grub_uint64_t *out);
2407
-char *grub_zfs_nvlist_lookup_nvlist_array (char *nvlist, char *name,
2408
+char *grub_zfs_nvlist_lookup_nvlist_array (const char *nvlist,
2411
-int grub_zfs_nvlist_lookup_nvlist_array_get_nelm (char *nvlist, char *name);
2412
+int grub_zfs_nvlist_lookup_nvlist_array_get_nelm (const char *nvlist,
2413
+ const char *name);
2415
#endif /* ! GRUB_ZFS_HEADER */