~apw/ubuntu/precise/grub2/precise-lp911225

« back to all changes in this revision

Viewing changes to debian/patches/zfs_update.patch

  • Committer: Colin Watson
  • Date: 2011-11-27 17:19:10 UTC
  • mfrom: (1892.1.591 grub)
  • Revision ID: cjwatson@canonical.com-20111127171910-hgvj7eqgybgp8w4o
merge from Debian 1.99-14

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
Revisions:
 
3
 
 
4
3340: ZFS zlib support
 
5
3474: Fix 2G limit on ZFS
 
6
3486: ZFS fixes
 
7
3488: ZFS multi-device and version 33 support
 
8
3494: Fix memory leak
 
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
 
12
3521: Support raidz3
 
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
 
16
 
 
17
--- a/grub-core/fs/zfs/zfs.c
 
18
+++ b/grub-core/fs/zfs/zfs.c
 
19
@@ -51,6 +51,7 @@
 
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>
 
24
 
 
25
 GRUB_MOD_LICENSE ("GPLv3+");
 
26
 
 
27
@@ -139,6 +140,27 @@
 
28
   grub_zfs_endian_t endian;
 
29
 } dnode_end_t;
 
30
 
 
31
+struct grub_zfs_device_desc
 
32
+{
 
33
+  enum { DEVICE_LEAF, DEVICE_MIRROR, DEVICE_RAIDZ } type;
 
34
+  grub_uint64_t id;
 
35
+  grub_uint64_t guid;
 
36
+
 
37
+  /* Valid only for non-leafs.  */
 
38
+  unsigned n_children;
 
39
+  struct grub_zfs_device_desc *children;
 
40
+
 
41
+  /* Valid only for RAIDZ.  */
 
42
+  unsigned nparity;
 
43
+  unsigned ashift;
 
44
+
 
45
+  /* Valid only for leaf devices.  */
 
46
+  grub_device_t dev;
 
47
+  grub_disk_addr_t vdev_phys_sector;
 
48
+  uberblock_t current_uberblock;
 
49
+  int original;
 
50
+};
 
51
+
 
52
 struct grub_zfs_data
 
53
 {
 
54
   /* cache for a file block of the currently zfs_open()-ed file */
 
55
@@ -153,23 +175,45 @@
 
56
   grub_uint64_t dnode_end;
 
57
   grub_zfs_endian_t dnode_endian;
 
58
 
 
59
-  uberblock_t current_uberblock;
 
60
-  grub_disk_t disk;
 
61
-
 
62
   dnode_end_t mos;
 
63
   dnode_end_t mdn;
 
64
   dnode_end_t dnode;
 
65
 
 
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;
 
71
+
 
72
+  uberblock_t current_uberblock;
 
73
+
 
74
+  int mounted;
 
75
+  grub_uint64_t guid;
 
76
 };
 
77
 
 
78
+static grub_err_t 
 
79
+zlib_decompress (void *s, void *d,
 
80
+                grub_size_t slen, grub_size_t dlen)
 
81
+{
 
82
+  if (grub_zlib_decompress (s, slen, 0, d, dlen) < 0)
 
83
+    return grub_errno;
 
84
+  return GRUB_ERR_NONE;
 
85
+}
 
86
+
 
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 */
 
103
 };
 
104
 
 
105
 static grub_err_t zio_read_data (blkptr_t * bp, grub_zfs_endian_t endian,
 
106
@@ -224,7 +268,7 @@
 
107
  */
 
108
 static grub_err_t
 
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)
 
112
 {
 
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]))
 
118
     {
 
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], 
 
132
@@ -319,7 +363,7 @@
 
133
  *
 
134
  */
 
135
 static grub_err_t
 
136
-uberblock_verify (uberblock_phys_t * ub, int offset)
 
137
+uberblock_verify (uberblock_phys_t * ub, grub_uint64_t offset)
 
138
 {
 
139
   uberblock_t *uber = &ub->ubp_uberblock;
 
140
   grub_err_t err;
 
141
@@ -392,7 +436,7 @@
 
142
 }
 
143
 
 
144
 static grub_uint64_t
 
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)
 
147
 {
 
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;
 
152
 }
 
153
 
 
154
+static grub_err_t
 
155
+zfs_fetch_nvlist (struct grub_zfs_device_desc *diskdesc, char **nvlist)
 
156
+{
 
157
+  grub_err_t err;
 
158
+
 
159
+  *nvlist = grub_malloc (VDEV_PHYS_SIZE);
 
160
+  if (!diskdesc->dev)
 
161
+    return grub_error (GRUB_ERR_BAD_FS, "member drive unknown");
 
162
+
 
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);
 
166
+  if (err)
 
167
+    {
 
168
+      grub_free (*nvlist);
 
169
+      *nvlist = 0;
 
170
+      return err;
 
171
+    }
 
172
+  return GRUB_ERR_NONE;
 
173
+}
 
174
+
 
175
+static grub_err_t
 
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)
 
180
+{
 
181
+  char *type;
 
182
+
 
183
+  type = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_TYPE);
 
184
+
 
185
+  if (!type)
 
186
+    return grub_errno;
 
187
+
 
188
+  if (!grub_zfs_nvlist_lookup_uint64 (nvlist, "id", &(fill->id)))
 
189
+    return grub_error (GRUB_ERR_BAD_FS, "couldn't find vdev id");
 
190
+
 
191
+  if (!grub_zfs_nvlist_lookup_uint64 (nvlist, "guid", &(fill->guid)))
 
192
+    return grub_error (GRUB_ERR_BAD_FS, "couldn't find vdev id");
 
193
+
 
194
+  if (grub_strcmp (type, VDEV_TYPE_DISK) == 0
 
195
+      || grub_strcmp (type, VDEV_TYPE_FILE) == 0)
 
196
+    {
 
197
+      fill->type = DEVICE_LEAF;
 
198
+
 
199
+      if (!fill->dev && fill->guid == insert->guid)
 
200
+       {
 
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;
 
207
+       }
 
208
+
 
209
+      return GRUB_ERR_NONE;
 
210
+    }
 
211
+
 
212
+  if (grub_strcmp (type, VDEV_TYPE_MIRROR) == 0
 
213
+      || grub_strcmp (type, VDEV_TYPE_RAIDZ) == 0)
 
214
+    {
 
215
+      int nelm, i;
 
216
+
 
217
+      if (grub_strcmp (type, VDEV_TYPE_MIRROR) == 0)
 
218
+       fill->type = DEVICE_MIRROR;
 
219
+      else
 
220
+       {
 
221
+         grub_uint64_t par;
 
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;
 
229
+       }
 
230
+
 
231
+      nelm = grub_zfs_nvlist_lookup_nvlist_array_get_nelm (nvlist, ZPOOL_CONFIG_CHILDREN);
 
232
+
 
233
+      if (nelm <= 0)
 
234
+       return grub_error (GRUB_ERR_BAD_FS, "incorrect mirror VDEV");
 
235
+
 
236
+      if (!fill->children)
 
237
+       {
 
238
+         fill->n_children = nelm;
 
239
+         
 
240
+         fill->children = grub_zalloc (fill->n_children
 
241
+                                       * sizeof (fill->children[0]));
 
242
+       }
 
243
+
 
244
+      for (i = 0; i < nelm; i++)
 
245
+       {
 
246
+         char *child;
 
247
+         grub_err_t err;
 
248
+
 
249
+         child = grub_zfs_nvlist_lookup_nvlist_array
 
250
+           (nvlist, ZPOOL_CONFIG_CHILDREN, i);
 
251
+
 
252
+         err = fill_vdev_info_real (data, child, &fill->children[i], insert);
 
253
+
 
254
+         grub_free (child);
 
255
+
 
256
+         if (err)
 
257
+           return err;
 
258
+       }
 
259
+      return GRUB_ERR_NONE;
 
260
+    }
 
261
+
 
262
+  return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "vdev %s isn't supported",
 
263
+                    type);
 
264
+}
 
265
+
 
266
+static grub_err_t
 
267
+fill_vdev_info (struct grub_zfs_data *data,
 
268
+               char *nvlist, struct grub_zfs_device_desc *diskdesc)
 
269
+{
 
270
+  grub_uint64_t id;
 
271
+  unsigned i;
 
272
+
 
273
+  if (!grub_zfs_nvlist_lookup_uint64 (nvlist, "id", &id))
 
274
+    return grub_error (GRUB_ERR_BAD_FS, "couldn't find vdev id");
 
275
+
 
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],
 
279
+                                 diskdesc);
 
280
+
 
281
+  data->n_devices_attached++;
 
282
+  if (data->n_devices_attached > data->n_devices_allocated)
 
283
+    {
 
284
+      void *tmp;
 
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)
 
291
+       {
 
292
+         data->devices_attached = tmp;
 
293
+         return grub_errno;
 
294
+       }
 
295
+    }
 
296
+
 
297
+  grub_memset (&data->devices_attached[data->n_devices_attached - 1],
 
298
+              0, sizeof (data->devices_attached[data->n_devices_attached - 1]));
 
299
+
 
300
+  return fill_vdev_info_real (data, nvlist,
 
301
+                             &data->devices_attached[data->n_devices_attached - 1],
 
302
+                             diskdesc);
 
303
+}
 
304
+
 
305
+/*
 
306
+ * Check the disk label information and retrieve needed vdev name-value pairs.
 
307
+ *
 
308
+ */
 
309
+static grub_err_t
 
310
+check_pool_label (struct grub_zfs_data *data,
 
311
+                 struct grub_zfs_device_desc *diskdesc)
 
312
+{
 
313
+  grub_uint64_t pool_state, txg = 0;
 
314
+  char *nvlist;
 
315
+#if 0
 
316
+  char *nv;
 
317
+#endif
 
318
+  grub_uint64_t poolguid;
 
319
+  grub_uint64_t version;
 
320
+  int found;
 
321
+  grub_err_t err;
 
322
+
 
323
+  err = zfs_fetch_nvlist (diskdesc, &nvlist);
 
324
+  if (err)
 
325
+    return err;
 
326
+
 
327
+  grub_dprintf ("zfs", "check 2 passed\n");
 
328
+
 
329
+  found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_STATE,
 
330
+                                        &pool_state);
 
331
+  if (! found)
 
332
+    {
 
333
+      grub_free (nvlist);
 
334
+      if (! grub_errno)
 
335
+       grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_POOL_STATE " not found");
 
336
+      return grub_errno;
 
337
+    }
 
338
+  grub_dprintf ("zfs", "check 3 passed\n");
 
339
+
 
340
+  if (pool_state == POOL_STATE_DESTROYED)
 
341
+    {
 
342
+      grub_free (nvlist);
 
343
+      return grub_error (GRUB_ERR_BAD_FS, "zpool is marked as destroyed");
 
344
+    }
 
345
+  grub_dprintf ("zfs", "check 4 passed\n");
 
346
+
 
347
+  found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_TXG, &txg);
 
348
+  if (!found)
 
349
+    {
 
350
+      grub_free (nvlist);
 
351
+      if (! grub_errno)
 
352
+       grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_POOL_TXG " not found");
 
353
+      return grub_errno;
 
354
+    }
 
355
+  grub_dprintf ("zfs", "check 6 passed\n");
 
356
+
 
357
+  /* not an active device */
 
358
+  if (txg == 0)
 
359
+    {
 
360
+      grub_free (nvlist);
 
361
+      return grub_error (GRUB_ERR_BAD_FS, "zpool isn't active");
 
362
+    }
 
363
+  grub_dprintf ("zfs", "check 7 passed\n");
 
364
+
 
365
+  found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_VERSION,
 
366
+                                        &version);
 
367
+  if (! found)
 
368
+    {
 
369
+      grub_free (nvlist);
 
370
+      if (! grub_errno)
 
371
+       grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_VERSION " not found");
 
372
+      return grub_errno;
 
373
+    }
 
374
+  grub_dprintf ("zfs", "check 8 passed\n");
 
375
+
 
376
+  if (version > SPA_VERSION)
 
377
+    {
 
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);
 
383
+    }
 
384
+  grub_dprintf ("zfs", "check 9 passed\n");
 
385
+
 
386
+  found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_GUID,
 
387
+                                        &(diskdesc->guid));
 
388
+  if (! found)
 
389
+    {
 
390
+      grub_free (nvlist);
 
391
+      if (! grub_errno)
 
392
+       grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_GUID " not found");
 
393
+      return grub_errno;
 
394
+    }
 
395
+
 
396
+  found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_GUID,
 
397
+                                        &poolguid);
 
398
+  if (! found)
 
399
+    {
 
400
+      grub_free (nvlist);
 
401
+      if (! grub_errno)
 
402
+       grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_POOL_GUID " not found");
 
403
+      return grub_errno;
 
404
+    }
 
405
+
 
406
+  grub_dprintf ("zfs", "check 11 passed\n");
 
407
+
 
408
+  if (data->mounted && data->guid != poolguid)
 
409
+    return grub_error (GRUB_ERR_BAD_FS, "another zpool");
 
410
+  else
 
411
+    data->guid = poolguid;
 
412
+
 
413
+  {
 
414
+    char *nv;
 
415
+    nv = grub_zfs_nvlist_lookup_nvlist (nvlist, ZPOOL_CONFIG_VDEV_TREE);
 
416
+
 
417
+    if (!nv)
 
418
+      {
 
419
+       grub_free (nvlist);
 
420
+       return grub_error (GRUB_ERR_BAD_FS, "couldn't find vdev tree");
 
421
+      }
 
422
+    err = fill_vdev_info (data, nv, diskdesc);
 
423
+    if (err)
 
424
+      {
 
425
+       grub_free (nvlist);
 
426
+       return err;
 
427
+      }
 
428
+  }
 
429
+  grub_dprintf ("zfs", "check 10 passed\n");
 
430
+
 
431
+  grub_free (nvlist);
 
432
+
 
433
+  return GRUB_ERR_NONE;
 
434
+}
 
435
+
 
436
+static grub_err_t
 
437
+scan_disk (grub_device_t dev, struct grub_zfs_data *data,
 
438
+          int original)
 
439
+{
 
440
+  int label = 0;
 
441
+  uberblock_phys_t *ub_array, *ubbest = NULL;
 
442
+  vdev_boot_header_t *bh;
 
443
+  grub_err_t err;
 
444
+  int vdevnum;
 
445
+  struct grub_zfs_device_desc desc;
 
446
+
 
447
+  ub_array = grub_malloc (VDEV_UBERBLOCK_RING);
 
448
+  if (!ub_array)
 
449
+    return grub_errno;
 
450
+
 
451
+  bh = grub_malloc (VDEV_BOOT_HEADER_SIZE);
 
452
+  if (!bh)
 
453
+    {
 
454
+      grub_free (ub_array);
 
455
+      return grub_errno;
 
456
+    }
 
457
+
 
458
+  vdevnum = VDEV_LABELS;
 
459
+
 
460
+  desc.dev = dev;
 
461
+  desc.original = original;
 
462
+
 
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;
 
466
+
 
467
+  for (label = 0; ubbest == NULL && label < vdevnum; label++)
 
468
+    {
 
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));
 
474
+
 
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);
 
479
+      if (err)
 
480
+       {
 
481
+         grub_errno = GRUB_ERR_NONE;
 
482
+         continue;
 
483
+       }
 
484
+      grub_dprintf ("zfs", "label ok %d\n", label);
 
485
+
 
486
+      ubbest = find_bestub (ub_array, desc.vdev_phys_sector);
 
487
+      if (!ubbest)
 
488
+       {
 
489
+         grub_dprintf ("zfs", "No uberblock found\n");
 
490
+         grub_errno = GRUB_ERR_NONE;
 
491
+         continue;
 
492
+       }
 
493
+
 
494
+      grub_memmove (&(desc.current_uberblock),
 
495
+                   &ubbest->ubp_uberblock, sizeof (uberblock_t));
 
496
+      if (original)
 
497
+       grub_memmove (&(data->current_uberblock),
 
498
+                     &ubbest->ubp_uberblock, sizeof (uberblock_t));
 
499
+
 
500
+      err = check_pool_label (data, &desc);
 
501
+      if (err)
 
502
+       {
 
503
+         grub_errno = GRUB_ERR_NONE;
 
504
+         continue;
 
505
+       }
 
506
+#if 0
 
507
+      if (find_best_root &&
 
508
+         vdev_uberblock_compare (&ubbest->ubp_uberblock,
 
509
+                                 &(current_uberblock)) <= 0)
 
510
+       continue;
 
511
+#endif
 
512
+      grub_free (ub_array);
 
513
+      grub_free (bh);
 
514
+      return GRUB_ERR_NONE;
 
515
+    }
 
516
+  
 
517
+  grub_free (ub_array);
 
518
+  grub_free (bh);
 
519
+
 
520
+  return grub_error (GRUB_ERR_BAD_FS, "couldn't find a valid label");
 
521
+}
 
522
+
 
523
+static grub_err_t
 
524
+scan_devices (struct grub_zfs_data *data)
 
525
+{
 
526
+  auto int hook (const char *name);
 
527
+  int hook (const char *name)
 
528
+  {
 
529
+    grub_device_t dev;
 
530
+    grub_err_t err;
 
531
+    dev = grub_device_open (name);
 
532
+    if (!dev)
 
533
+      return 0;
 
534
+    if (!dev->disk)
 
535
+      {
 
536
+       grub_device_close (dev);
 
537
+       return 0;
 
538
+      }
 
539
+    err = scan_disk (dev, data, 0);
 
540
+    if (err == GRUB_ERR_BAD_FS)
 
541
+      {
 
542
+       grub_device_close (dev);
 
543
+       grub_errno = GRUB_ERR_NONE;
 
544
+       return 0;
 
545
+      }
 
546
+    if (err)
 
547
+      {
 
548
+       grub_device_close (dev);
 
549
+       grub_print_error ();
 
550
+       return 0;
 
551
+      }
 
552
+    
 
553
+    return 0;
 
554
+  }
 
555
+  grub_device_iterate (hook);
 
556
+  return GRUB_ERR_NONE;
 
557
+}
 
558
+
 
559
+static inline void
 
560
+xor (grub_uint64_t *a, const grub_uint64_t *b, grub_size_t s)
 
561
+{
 
562
+  s /= sizeof (grub_uint64_t);
 
563
+  while (s--)
 
564
+    *a++ ^= *b++;
 
565
+}
 
566
+
 
567
+/* x**y.  */
 
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;
 
572
+
 
573
+/* perform the operation a ^= b * (x ** (known_idx * recovery_pow) ) */
 
574
+static inline void
 
575
+xor_out (void *a_in, const void *b_in, grub_size_t s,
 
576
+        int known_idx, int recovery_pow)
 
577
+{
 
578
+  int add;
 
579
+  grub_uint8_t *a = a_in;
 
580
+  const grub_uint8_t *b = b_in;
 
581
+
 
582
+  /* Simple xor.  */
 
583
+  if (known_idx == 0 || recovery_pow == 0)
 
584
+    {
 
585
+      xor (a_in, b_in, s);
 
586
+      return;
 
587
+    }
 
588
+  add = (known_idx * recovery_pow) % 255;
 
589
+  for (;s--; b++, a++)
 
590
+    if (*b)
 
591
+      *a ^= powx[powx_inv[*b] + add];
 
592
+}
 
593
+
 
594
+static inline grub_uint8_t
 
595
+gf_mul (grub_uint8_t a, grub_uint8_t b)
 
596
+{
 
597
+  if (a == 0 || b == 0)
 
598
+    return 0;
 
599
+  return powx[powx_inv[a] + powx_inv[b]];
 
600
+}
 
601
+
 
602
+static inline grub_err_t
 
603
+recovery (grub_uint8_t *bufs[4], grub_size_t s, const int nbufs,
 
604
+         const unsigned *powers,
 
605
+         const int *idx)
 
606
+{
 
607
+  grub_dprintf ("zfs", "recovering %u bufers\n", nbufs);
 
608
+  /* Now we have */
 
609
+  /* b_i = sum (r_j* (x ** (powers[i] * idx[j])))*/
 
610
+  /* Let's invert the matrix in question. */
 
611
+  switch (nbufs)
 
612
+    {
 
613
+      /* Easy: r_0 = bufs[0] / (x << (powers[i] * idx[j])).  */
 
614
+    case 1:
 
615
+      {
 
616
+       int add;
 
617
+       grub_uint8_t *a;
 
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++)
 
622
+         if (*a)
 
623
+           *a = powx[powx_inv[*a] + add];
 
624
+       return GRUB_ERR_NONE;
 
625
+      }
 
626
+      /* Case 2x2: Let's use the determinant formula.  */
 
627
+    case 2:
 
628
+      {
 
629
+       grub_uint8_t det, det_inv;
 
630
+       grub_uint8_t matrixinv[2][2];
 
631
+       unsigned i;
 
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]);
 
635
+       if (det == 0)
 
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++)
 
643
+         {
 
644
+           grub_uint8_t b0, b1;
 
645
+           b0 = bufs[0][i];
 
646
+           b1 = bufs[1][i];
 
647
+
 
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]));
 
652
+         }
 
653
+       return GRUB_ERR_NONE;
 
654
+      }
 
655
+      /* Otherwise use Gauss.  */
 
656
+    default:
 
657
+      {
 
658
+       grub_uint8_t matrix1[nbufs][nbufs], matrix2[nbufs][nbufs];
 
659
+       int i, j, k;
 
660
+
 
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++)
 
666
+           matrix2[i][j] = 0;
 
667
+       for (i = 0; i < nbufs; i++)
 
668
+           matrix2[i][i] = 1;
 
669
+
 
670
+       for (i = 0; i < nbufs; i++)
 
671
+         {
 
672
+           grub_uint8_t mul;
 
673
+           for (j = i; j < nbufs; j++)     
 
674
+             if (matrix1[i][j])
 
675
+               break;
 
676
+           if (j == nbufs)
 
677
+             return grub_error (GRUB_ERR_BAD_FS, "singular recovery matrix");
 
678
+           if (j != i)
 
679
+             {
 
680
+               int xchng;
 
681
+               xchng = j;
 
682
+               for (j = 0; j < nbufs; j++)
 
683
+                 {
 
684
+                   grub_uint8_t t;
 
685
+                   t = matrix1[xchng][j];
 
686
+                   matrix1[xchng][j] = matrix1[i][j];
 
687
+                   matrix1[i][j] = t;
 
688
+                 }
 
689
+               for (j = 0; j < nbufs; j++)
 
690
+                 {
 
691
+                   grub_uint8_t t;
 
692
+                   t = matrix2[xchng][j];
 
693
+                   matrix2[xchng][j] = matrix2[i][j];
 
694
+                   matrix2[i][j] = t;
 
695
+                 }
 
696
+             }
 
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++)
 
703
+             {
 
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);
 
709
+             }
 
710
+         }
 
711
+       for (i = nbufs - 1; i >= 0; i--)
 
712
+         {
 
713
+           for (j = 0; j < i; j++)
 
714
+             {
 
715
+               grub_uint8_t mul;
 
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);
 
721
+             }
 
722
+         }
 
723
+
 
724
+       for (i = 0; i < (int) s; i++)
 
725
+         {
 
726
+           grub_uint8_t b[nbufs];
 
727
+           for (j = 0; j < nbufs; j++)
 
728
+             b[j] = bufs[j][i];
 
729
+           for (j = 0; j < nbufs; j++)
 
730
+             {
 
731
+               bufs[j][i] = 0;
 
732
+               for (k = 0; k < nbufs; k++)
 
733
+                 bufs[j][i] ^= gf_mul (matrix2[j][k], b[k]);
 
734
+             }
 
735
+         }
 
736
+       return GRUB_ERR_NONE;
 
737
+      }
 
738
+    }      
 
739
+}
 
740
+
 
741
+static grub_err_t
 
742
+read_device (grub_uint64_t offset, struct grub_zfs_device_desc *desc,
 
743
+            grub_size_t len, void *buf)
 
744
+{
 
745
+  switch (desc->type)
 
746
+    {
 
747
+    case DEVICE_LEAF:
 
748
+      {
 
749
+       grub_uint64_t sector;
 
750
+       sector = DVA_OFFSET_TO_PHYS_SECTOR (offset);
 
751
+       if (!desc->dev)
 
752
+         {
 
753
+           return grub_error (GRUB_ERR_BAD_FS, "member drive unknown");
 
754
+         }
 
755
+       /* read in a data block */
 
756
+       return grub_disk_read (desc->dev->disk, sector, 0, len, buf);
 
757
+      }
 
758
+    case DEVICE_MIRROR:
 
759
+      {
 
760
+       grub_err_t err = GRUB_ERR_NONE;
 
761
+       unsigned i;
 
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++)
 
766
+         {
 
767
+           err = read_device (offset, &desc->children[i],
 
768
+                              len, buf);
 
769
+           if (!err)
 
770
+             break;
 
771
+           grub_errno = GRUB_ERR_NONE;
 
772
+         }
 
773
+       return (grub_errno = err);
 
774
+      }
 
775
+    case DEVICE_RAIDZ:
 
776
+      {
 
777
+       unsigned c = 0;
 
778
+       grub_uint64_t high;
 
779
+       grub_uint64_t devn;
 
780
+       grub_uint64_t m;
 
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;
 
788
+       int idx, orig_idx;
 
789
+
 
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);
 
793
+
 
794
+       orig_s = (((len + (1 << desc->ashift) - 1) >> desc->ashift)
 
795
+                 + (desc->n_children - desc->nparity) - 1);
 
796
+       s = orig_s;
 
797
+
 
798
+       high = grub_divmod64_full ((offset >> desc->ashift),
 
799
+                                  desc->n_children, &m);
 
800
+       if (desc->nparity == 2)
 
801
+         c = 2;
 
802
+       if (desc->nparity == 3)
 
803
+         c = 3;
 
804
+       if (((len + (1 << desc->ashift) - 1) >> desc->ashift)
 
805
+           >= (desc->n_children - desc->nparity))
 
806
+         idx = (desc->n_children - desc->nparity - 1);
 
807
+       else
 
808
+         idx = ((len + (1 << desc->ashift) - 1) >> desc->ashift) - 1;
 
809
+       orig_idx = idx;
 
810
+       while (len > 0)
 
811
+         {
 
812
+           grub_size_t csize;
 
813
+           grub_uint32_t bsize;
 
814
+           grub_err_t err;
 
815
+           bsize = s / (desc->n_children - desc->nparity);
 
816
+
 
817
+           if (desc->nparity == 1
 
818
+               && ((offset >> (desc->ashift + 11)) & 1) == c)
 
819
+             c++;
 
820
+
 
821
+           high = grub_divmod64_full ((offset >> desc->ashift) + c,
 
822
+                                      desc->n_children, &devn);
 
823
+           csize = bsize << desc->ashift;
 
824
+           if (csize > len)
 
825
+             csize = len;
 
826
+
 
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,
 
832
+                         devn);
 
833
+           err = read_device ((high << desc->ashift)
 
834
+                              | (offset & ((1 << desc->ashift) - 1)),
 
835
+                              &desc->children[devn],
 
836
+                              csize, buf);
 
837
+           if (err && failed_devices < desc->nparity)
 
838
+             {
 
839
+               recovery_buf[failed_devices] = buf;
 
840
+               recovery_len[failed_devices] = csize;
 
841
+               recovery_idx[failed_devices] = idx;
 
842
+               failed_devices++;
 
843
+               grub_errno = err = 0;
 
844
+             }
 
845
+           if (err)
 
846
+             return err;
 
847
+
 
848
+           c++;
 
849
+           idx--;
 
850
+           s--;
 
851
+           buf = (char *) buf + csize;
 
852
+           len -= csize;
 
853
+         }
 
854
+       if (failed_devices)
 
855
+         {
 
856
+           unsigned redundancy_pow[4];
 
857
+           unsigned cur_redundancy_pow = 0;
 
858
+           unsigned n_redundancy = 0;
 
859
+           unsigned i, j;
 
860
+           grub_err_t err;
 
861
+           
 
862
+           /* Compute mul. x**s has a period of 255.  */
 
863
+           if (powx[0] == 0)
 
864
+             {
 
865
+               grub_uint8_t cur = 1;
 
866
+               for (i = 0; i < 255; i++)
 
867
+                 {
 
868
+                   powx[i] = cur;
 
869
+                   powx[i + 255] = cur;
 
870
+                   powx_inv[cur] = i;
 
871
+                   if (cur & 0x80)
 
872
+                     cur = (cur << 1) ^ poly;
 
873
+                   else
 
874
+                     cur <<= 1;
 
875
+                 }
 
876
+             }
 
877
+           
 
878
+           /* Read redundancy data.  */
 
879
+           for (n_redundancy = 0, cur_redundancy_pow = 0;
 
880
+                n_redundancy < failed_devices;
 
881
+                cur_redundancy_pow++)
 
882
+             {
 
883
+               high = grub_divmod64_full ((offset >> desc->ashift)
 
884
+                                          + cur_redundancy_pow
 
885
+                                          + ((desc->nparity == 1)
 
886
+                                             && ((offset >> (desc->ashift + 11))
 
887
+                                                 & 1)),
 
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
 
896
+                   >= failed_devices)
 
897
+                 {
 
898
+                   grub_errno = GRUB_ERR_NONE;
 
899
+                   continue;
 
900
+                 }
 
901
+               if (err)
 
902
+                 return err;
 
903
+               redundancy_pow[n_redundancy] = cur_redundancy_pow;
 
904
+               n_redundancy++;
 
905
+             }
 
906
+           /* Now xor-our the parts we already know.  */
 
907
+           buf = orig_buf;
 
908
+           len = orig_len;
 
909
+           s = orig_s;
 
910
+           idx = orig_idx;
 
911
+
 
912
+           while (len > 0)
 
913
+             {
 
914
+               grub_size_t csize;
 
915
+               csize = ((s / (desc->n_children - desc->nparity))
 
916
+                        << desc->ashift);
 
917
+               if (csize > len)
 
918
+                 csize = len;
 
919
+
 
920
+               for (j = 0; j < failed_devices; j++)
 
921
+                 if (buf == recovery_buf[j])
 
922
+                   break;
 
923
+
 
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]);
 
929
+
 
930
+               s--;
 
931
+               buf = (char *) buf + csize;
 
932
+               len -= csize;
 
933
+               idx--;
 
934
+             }
 
935
+           for (i = 0; i < failed_devices 
 
936
+                  && recovery_len[i] == recovery_len[0];
 
937
+                i++);
 
938
+           /* Since the chunks have variable length handle the last block
 
939
+              separately.  */
 
940
+           if (i != failed_devices)
 
941
+             {
 
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,
 
946
+                               recovery_idx);
 
947
+               if (err)
 
948
+                 return err;
 
949
+             }
 
950
+           err = recovery (recovery_buf, recovery_len[failed_devices - 1],
 
951
+                           failed_devices, redundancy_pow, recovery_idx);
 
952
+           if (err)
 
953
+             return err;
 
954
+         }
 
955
+       return GRUB_ERR_NONE;
 
956
+      }
 
957
+    }
 
958
+  return grub_error (GRUB_ERR_BAD_FS, "unsupported device type");
 
959
+}
 
960
+
 
961
+static grub_err_t
 
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)
 
965
+{
 
966
+  grub_uint64_t offset;
 
967
+  unsigned i;
 
968
+  grub_err_t err;
 
969
+  int try = 0;
 
970
+  offset = dva_get_offset (dva, endian);
 
971
+
 
972
+  for (try = 0; try < 2; try++)
 
973
+    {
 
974
+      for (i = 0; i < data->n_devices_attached; i++)
 
975
+       if (data->devices_attached[i].id == DVA_GET_VDEV (dva))
 
976
+         {
 
977
+           err = read_device (offset, &data->devices_attached[i], len, buf);
 
978
+           if (!err)
 
979
+             return GRUB_ERR_NONE;
 
980
+           break;
 
981
+         }
 
982
+      if (try == 1)
 
983
+       break;
 
984
+      err = scan_devices (data);
 
985
+      if (err)
 
986
+       return err;
 
987
+    }
 
988
+  return err;
 
989
+}
 
990
 
 
991
 /*
 
992
  * Read a block of data based on the gang block address dva,
 
993
@@ -412,7 +1292,6 @@
 
994
               struct grub_zfs_data *data)
 
995
 {
 
996
   zio_gbh_phys_t *zio_gb;
 
997
-  grub_uint64_t offset, sector;
 
998
   unsigned i;
 
999
   grub_err_t err;
 
1000
   zio_cksum_t zc;
 
1001
@@ -424,13 +1303,8 @@
 
1002
     return grub_errno;
 
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);
 
1008
 
 
1009
-  /* read in the gang block header */
 
1010
-  err = grub_disk_read (data->disk, sector, 0, SPA_GANGBLOCKSIZE,
 
1011
-                       (char *) zio_gb);
 
1012
+  err = read_dva (dva, endian, data, zio_gb, SPA_GANGBLOCKSIZE);
 
1013
   if (err)
 
1014
     {
 
1015
       grub_free (zio_gb);
 
1016
@@ -483,20 +1357,13 @@
 
1017
   /* pick a good dva from the block pointer */
 
1018
   for (i = 0; i < SPA_DVAS_PER_BP; i++)
 
1019
     {
 
1020
-      grub_uint64_t offset, sector;
 
1021
-
 
1022
       if (bp->blk_dva[i].dva_word[0] == 0 && bp->blk_dva[i].dva_word[1] == 0)
 
1023
        continue;
 
1024
 
 
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);
 
1027
       else
 
1028
-       {
 
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); 
 
1033
-       }
 
1034
+       err = read_dva (&bp->blk_dva[i], endian, data, buf, psize);
 
1035
       if (!err)
 
1036
        return GRUB_ERR_NONE;
 
1037
       grub_errno = GRUB_ERR_NONE;
 
1038
@@ -527,7 +1394,7 @@
 
1039
   *buf = NULL;
 
1040
 
 
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)
 
1050
 {
 
1051
-  int idx, level;
 
1052
+  int level;
 
1053
+  grub_off_t idx;
 
1054
   blkptr_t *bp_array = dn->dn.dn_blkptr;
 
1055
   int epbs = dn->dn.dn_indblkshift - SPA_BLKPTRSHIFT;
 
1056
   blkptr_t *bp;
 
1057
@@ -670,7 +1538,8 @@
 
1058
  */
 
1059
 static grub_err_t
 
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)
 
1064
 {
 
1065
   int i, chunks;
 
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++)
 
1070
     {
 
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))
 
1074
        {
 
1075
          *value = grub_zfs_to_cpu64 (mzap_ent[i].mze_value, endian);
 
1076
          return GRUB_ERR_NONE;
 
1077
@@ -711,7 +1581,8 @@
 
1078
 }
 
1079
 
 
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)
 
1084
 {
 
1085
   static grub_uint64_t table[256];
 
1086
   const grub_uint8_t *cp;
 
1087
@@ -729,8 +1600,12 @@
 
1088
        }
 
1089
     }
 
1090
 
 
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];
 
1096
+  else
 
1097
+    for (cp = (const grub_uint8_t *) name; (c = *cp) != '\0'; cp++)
 
1098
+      crc = (crc >> 8) ^ table[(crc ^ c) & 0xFF];
 
1099
 
 
1100
   /*
 
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.
 
1105
  */
 
1106
+
 
1107
+static inline int
 
1108
+name_cmp (const char *s1, const char *s2, grub_size_t n,
 
1109
+         int case_insensitive)
 
1110
+{
 
1111
+  const char *t1 = (const char *) s1;
 
1112
+  const char *t2 = (const char *) s2;
 
1113
+
 
1114
+  if (!case_insensitive)
 
1115
+    return grub_memcmp (t1, t2, n);
 
1116
+      
 
1117
+  while (n--)
 
1118
+    {
 
1119
+      if (grub_toupper (*t1) != grub_toupper (*t2))
 
1120
+         return (int) grub_toupper (*t1) - (int) grub_toupper (*t2);
 
1121
+         
 
1122
+      t1++;
 
1123
+      t2++;
 
1124
+    }
 
1125
+
 
1126
+  return 0;
 
1127
+}
 
1128
+
 
1129
 /* XXX */
 
1130
 static int
 
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)
 
1135
 {
 
1136
   int bseen = 0;
 
1137
 
 
1138
@@ -763,7 +1662,8 @@
 
1139
       if (chunk >= ZAP_LEAF_NUMCHUNKS (blksft))
 
1140
        return (0);
 
1141
 
 
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)
 
1145
        break;
 
1146
       chunk = grub_zfs_to_cpu16 (la->la_next, endian);
 
1147
       bseen += toread;
 
1148
@@ -804,7 +1704,8 @@
 
1149
 static grub_err_t
 
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)
 
1155
 {
 
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");
 
1160
 
 
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))
 
1164
     {
 
1165
 
 
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),
 
1171
-                               name))
 
1172
+                               name, case_insensitive))
 
1173
        {
 
1174
          struct zap_leaf_array *la;
 
1175
 
 
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,
 
1178
+                                                        endian) != 1)
 
1179
            return grub_error (GRUB_ERR_BAD_FS, "invalid leaf chunk entry");
 
1180
 
 
1181
          /* get the uint64_t property value */
 
1182
@@ -858,9 +1760,9 @@
 
1183
 
 
1184
 /* Verify if this is a fat zap header block */
 
1185
 static grub_err_t
 
1186
-zap_verify (zap_phys_t *zap)
 
1187
+zap_verify (zap_phys_t *zap, grub_zfs_endian_t endian)
 
1188
 {
 
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");
 
1192
 
 
1193
   if (zap->zap_flags != 0)
 
1194
@@ -879,7 +1781,8 @@
 
1195
 /* XXX */
 
1196
 static grub_err_t
 
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)
 
1201
 {
 
1202
   void *l;
 
1203
   grub_uint64_t hash, idx, blkid;
 
1204
@@ -888,18 +1791,18 @@
 
1205
   grub_err_t err;
 
1206
   grub_zfs_endian_t leafendian;
 
1207
 
 
1208
-  err = zap_verify (zap);
 
1209
+  err = zap_verify (zap, zap_dnode->endian);
 
1210
   if (err)
 
1211
     return err;
 
1212
 
 
1213
-  hash = zap_hash (zap->zap_salt, name);
 
1214
+  hash = zap_hash (zap->zap_salt, name, case_insensitive);
 
1215
 
 
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);
 
1223
 
 
1224
   /* Get the leaf block */
 
1225
   if ((1U << blksft) < sizeof (zap_leaf_phys_t))
 
1226
@@ -908,7 +1811,8 @@
 
1227
   if (err)
 
1228
     return err;
 
1229
 
 
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);
 
1233
   grub_free (l);
 
1234
   return err;
 
1235
 }
 
1236
@@ -922,14 +1826,14 @@
 
1237
 {
 
1238
   zap_leaf_phys_t *l;
 
1239
   void *l_in;
 
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);
 
1245
   grub_err_t err;
 
1246
   grub_zfs_endian_t endian;
 
1247
 
 
1248
-  if (zap_verify (zap))
 
1249
+  if (zap_verify (zap, zap_dnode->endian))
 
1250
     return 0;
 
1251
 
 
1252
   /* get block id from index */
 
1253
@@ -945,9 +1849,17 @@
 
1254
       grub_error (GRUB_ERR_BAD_FS, "ZAP leaf is too small");
 
1255
       return 0;
 
1256
     }
 
1257
-  for (idx = 0; idx < zap->zap_ptrtbl.zt_numblks; idx++)
 
1258
+  for (idx = 0; idx < (1ULL << zap->zap_ptrtbl.zt_shift); idx++)
 
1259
     {
 
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);
 
1263
+
 
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))
 
1267
+         break;
 
1268
+      if (idx2 != idx)
 
1269
+       continue;
 
1270
 
 
1271
       err = dmu_read (zap_dnode, blkid, &l_in, &endian, data);
 
1272
       l = l_in;
 
1273
@@ -983,8 +1895,11 @@
 
1274
 
 
1275
            buf = grub_malloc (grub_zfs_to_cpu16 (le->le_name_length, endian) 
 
1276
                               + 1);
 
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,
 
1281
+                                                      endian),
 
1282
+                                   grub_zfs_to_cpu16 (le->le_name_length,
 
1283
+                                                      endian), buf))
 
1284
              {
 
1285
                grub_free (buf);
 
1286
                continue;
 
1287
@@ -996,7 +1911,9 @@
 
1288
              continue;
 
1289
 
 
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,
 
1294
+                                                    endian)).l_array;
 
1295
            val = grub_be_to_cpu64 (la->la_array64);
 
1296
            if (hook (buf, val))
 
1297
              return 1;
 
1298
@@ -1014,7 +1931,7 @@
 
1299
  */
 
1300
 static grub_err_t
 
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)
 
1304
 {
 
1305
   grub_uint64_t block_type;
 
1306
   int size;
 
1307
@@ -1037,7 +1954,8 @@
 
1308
   if (block_type == ZBT_MICRO)
 
1309
     {
 
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);      
 
1315
       grub_free (zapbuf);
 
1316
       return err;
 
1317
@@ -1046,7 +1964,8 @@
 
1318
     {
 
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);      
 
1325
       grub_free (zapbuf);
 
1326
       return err;
 
1327
@@ -1074,7 +1993,7 @@
 
1328
     return 0;
 
1329
   block_type = grub_zfs_to_cpu64 (*((grub_uint64_t *) zapbuf), endian);
 
1330
 
 
1331
-  grub_dprintf ("zfs", "zap read\n");
 
1332
+  grub_dprintf ("zfs", "zap iterate\n");
 
1333
 
 
1334
   if (block_type == ZBT_MICRO)
 
1335
     {
 
1336
@@ -1172,9 +2091,9 @@
 
1337
  */
 
1338
 static grub_err_t
 
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)
 
1342
 {
 
1343
-  grub_uint64_t objnum, version;
 
1344
+  grub_uint64_t objnum, version, insensitivity;
 
1345
   char *cname, ch;
 
1346
   grub_err_t err = GRUB_ERR_NONE;
 
1347
   char *path, *path_buf;
 
1348
@@ -1199,19 +2118,31 @@
 
1349
       return err;
 
1350
     }
 
1351
 
 
1352
-  err = zap_lookup (&(dnode_path->dn), ZPL_VERSION_STR, &version, data);
 
1353
+  err = zap_lookup (&(dnode_path->dn), ZPL_VERSION_STR, &version,
 
1354
+                   data, 0);
 
1355
   if (err)
 
1356
     {
 
1357
       grub_free (dn_new);
 
1358
       return err;
 
1359
     }
 
1360
+
 
1361
   if (version > ZPL_VERSION)
 
1362
     {
 
1363
       grub_free (dn_new);
 
1364
       return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "too new ZPL version");
 
1365
     }
 
1366
-  
 
1367
-  err = zap_lookup (&(dnode_path->dn), ZFS_ROOT_OBJ, &objnum, data);
 
1368
+
 
1369
+  err = zap_lookup (&(dnode_path->dn), "casesensitivity", &insensitivity,
 
1370
+                   data, 0);
 
1371
+  if (err == GRUB_ERR_FILE_NOT_FOUND)
 
1372
+    {
 
1373
+      grub_errno = GRUB_ERR_NONE;
 
1374
+      insensitivity = 0;
 
1375
+    }
 
1376
+  if (case_insensitive)
 
1377
+    *case_insensitive = insensitivity;
 
1378
+
 
1379
+  err = zap_lookup (&(dnode_path->dn), ZFS_ROOT_OBJ, &objnum, data, 0);
 
1380
   if (err)
 
1381
     {
 
1382
       grub_free (dn_new);
 
1383
@@ -1272,7 +2203,7 @@
 
1384
          grub_free (path_buf);
 
1385
          return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
 
1386
        }
 
1387
-      err = zap_lookup (&(dnode_path->dn), cname, &objnum, data);
 
1388
+      err = zap_lookup (&(dnode_path->dn), cname, &objnum, data, insensitivity);
 
1389
       if (err)
 
1390
        break;
 
1391
 
 
1392
@@ -1291,22 +2222,54 @@
 
1393
        break;
 
1394
 
 
1395
       *path = ch;
 
1396
-#if 0
 
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)
 
1400
        {
 
1401
+         char *sym_value;
 
1402
+         grub_size_t sym_sz;
 
1403
+         int free_symval = 0;
 
1404
          char *oldpath = path, *oldpathbuf = path_buf;
 
1405
-         path = 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));
 
1409
+
 
1410
+         sym_sz = grub_zfs_to_cpu64 (((znode_phys_t *) DN_BONUS (&dnode_path->dn.dn))->zp_size, dnode_path->dn.endian);
 
1411
+
 
1412
+         if (dnode_path->dn.dn.dn_flags & 1)
 
1413
+           {
 
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);
 
1419
+
 
1420
+             sym_value = grub_malloc (sym_sz);
 
1421
+             if (!sym_value)
 
1422
+               return grub_errno;
 
1423
+             for (block = 0; block < (sym_sz + blksz - 1) / blksz; block++)
 
1424
+               {
 
1425
+                 void *t;
 
1426
+                 grub_size_t movesize;
 
1427
+
 
1428
+                 err = dmu_read (&(dnode_path->dn), block, &t, 0, data);
 
1429
+                 if (err)
 
1430
+                   return err;
 
1431
+
 
1432
+                 movesize = MIN (sym_sz - block * blksz, blksz);
 
1433
+
 
1434
+                 grub_memcpy (sym_value + block * blksz, t, movesize);
 
1435
+                 grub_free (t);
 
1436
+               }
 
1437
+             free_symval = 1;
 
1438
+           }       
 
1439
+         path = path_buf = grub_malloc (sym_sz + grub_strlen (oldpath) + 1);
 
1440
          if (!path_buf)
 
1441
            {
 
1442
              grub_free (oldpathbuf);
 
1443
              return grub_errno;
 
1444
            }
 
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);
 
1450
+         if (free_symval)
 
1451
+           grub_free (sym_value);
 
1452
+         path [sym_sz] = 0;
 
1453
          grub_memcpy (path + grub_strlen (path), oldpath, 
 
1454
                       grub_strlen (oldpath) + 1);
 
1455
          
 
1456
@@ -1324,7 +2287,62 @@
 
1457
              grub_free (dn_new);
 
1458
            }
 
1459
        }
 
1460
-#endif
 
1461
+      if (dnode_path->dn.dn.dn_bonustype == DMU_OT_SA)
 
1462
+       {
 
1463
+         void *sahdrp;
 
1464
+         int hdrsize;
 
1465
+         
 
1466
+         if (dnode_path->dn.dn.dn_bonuslen != 0)
 
1467
+           {
 
1468
+             sahdrp = DN_BONUS (&dnode_path->dn.dn);
 
1469
+           }
 
1470
+         else if (dnode_path->dn.dn.dn_flags & DNODE_FLAG_SPILL_BLKPTR)
 
1471
+           {
 
1472
+             blkptr_t *bp = &dnode_path->dn.dn.dn_spill;
 
1473
+             
 
1474
+             err = zio_read (bp, dnode_path->dn.endian, &sahdrp, NULL, data);
 
1475
+             if (err)
 
1476
+               return err;
 
1477
+           }
 
1478
+         else
 
1479
+           {
 
1480
+             return grub_error (GRUB_ERR_BAD_FS, "filesystem is corrupt");
 
1481
+           }
 
1482
+
 
1483
+         hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp));
 
1484
+
 
1485
+         if (((grub_zfs_to_cpu64 (*(grub_uint64_t *) ((char *) sahdrp + hdrsize + SA_TYPE_OFFSET), dnode_path->dn.endian) >> 12) & 0xf) == 0xa)
 
1486
+           {
 
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);
 
1492
+             if (!path_buf)
 
1493
+               {
 
1494
+                 grub_free (oldpathbuf);
 
1495
+                 return grub_errno;
 
1496
+               }
 
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);
 
1501
+             
 
1502
+             grub_free (oldpathbuf);
 
1503
+             if (path[0] != '/')
 
1504
+               {
 
1505
+                 dn_new = dnode_path;
 
1506
+                 dnode_path = dn_new->next;
 
1507
+                 grub_free (dn_new);
 
1508
+               }
 
1509
+             else while (dnode_path != root)
 
1510
+               {
 
1511
+                 dn_new = dnode_path;
 
1512
+                 dnode_path = dn_new->next;
 
1513
+                 grub_free (dn_new);
 
1514
+               }
 
1515
+           }
 
1516
+       }
 
1517
     }
 
1518
 
 
1519
   if (!err)
 
1520
@@ -1417,7 +2435,7 @@
 
1521
 
 
1522
   grub_dprintf ("zfs", "alive\n");
 
1523
 
 
1524
-  err = zap_lookup (mdn, DMU_POOL_ROOT_DATASET, &objnum, data);
 
1525
+  err = zap_lookup (mdn, DMU_POOL_ROOT_DATASET, &objnum, data, 0);
 
1526
   if (err)
 
1527
     return err;
 
1528
 
 
1529
@@ -1452,7 +2470,7 @@
 
1530
       if (err)
 
1531
        return err;
 
1532
 
 
1533
-      err = zap_lookup (mdn, cname, &objnum, data);
 
1534
+      err = zap_lookup (mdn, cname, &objnum, data, 0);
 
1535
       if (err)
 
1536
        return err;
 
1537
 
 
1538
@@ -1495,7 +2513,7 @@
 
1539
 static grub_err_t
 
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)
 
1544
 {
 
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);
 
1550
       if (!err)
 
1551
-       err = zap_lookup (mdn, snapname, &headobj, data);
 
1552
+       err = zap_lookup (mdn, snapname, &headobj, data, 0);
 
1553
       if (!err)
 
1554
        err = dnode_get (&(data->mos), headobj, DMU_OT_DSL_DATASET, mdn, data);
 
1555
       if (err)
 
1556
@@ -1597,7 +2615,7 @@
 
1557
       grub_free (snapname);      
 
1558
       return GRUB_ERR_NONE;
 
1559
     }
 
1560
-  err = dnode_get_path (mdn, filename, dn, data);
 
1561
+  err = dnode_get_path (mdn, filename, dn, data, case_insensitive);
 
1562
   grub_free (fsname);
 
1563
   grub_free (snapname);
 
1564
   return err;
 
1565
@@ -1625,11 +2643,12 @@
 
1566
  */
 
1567
 
 
1568
 static int
 
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)
 
1573
 {
 
1574
   int name_len, type, encode_size;
 
1575
-  char *nvpair, *nvp_name;
 
1576
+  const char *nvpair, *nvp_name;
 
1577
 
 
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 @@
 
1581
 
 
1582
       if ((grub_strncmp (nvp_name, name, name_len) == 0) && type == valtype)
 
1583
        {
 
1584
-         *val = nvpair;
 
1585
+         *val = (char *) nvpair;
 
1586
          *size_out = encode_size;
 
1587
          if (nelm_out)
 
1588
            *nelm_out = nelm;
 
1589
@@ -1684,7 +2703,8 @@
 
1590
 }
 
1591
 
 
1592
 int
 
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)
 
1596
 {
 
1597
   char *nvpair;
 
1598
   grub_size_t size;
 
1599
@@ -1704,7 +2724,7 @@
 
1600
 }
 
1601
 
 
1602
 char *
 
1603
-grub_zfs_nvlist_lookup_string (char *nvlist, char *name)
 
1604
+grub_zfs_nvlist_lookup_string (const char *nvlist, const char *name)
 
1605
 {
 
1606
   char *nvpair;
 
1607
   char *ret;
 
1608
@@ -1732,7 +2752,7 @@
 
1609
 }
 
1610
 
 
1611
 char *
 
1612
-grub_zfs_nvlist_lookup_nvlist (char *nvlist, char *name)
 
1613
+grub_zfs_nvlist_lookup_nvlist (const char *nvlist, const char *name)
 
1614
 {
 
1615
   char *nvpair;
 
1616
   char *ret;
 
1617
@@ -1753,199 +2773,114 @@
 
1618
 }
 
1619
 
 
1620
 int
 
1621
-grub_zfs_nvlist_lookup_nvlist_array_get_nelm (char *nvlist, char *name)
 
1622
-{
 
1623
-  char *nvpair;
 
1624
-  grub_size_t nelm, size;
 
1625
-  int found;
 
1626
-
 
1627
-  found = nvlist_find_value (nvlist, name, DATA_TYPE_NVLIST, &nvpair,
 
1628
-                            &size, &nelm);
 
1629
-  if (! found)
 
1630
-    return -1;
 
1631
-  return nelm;
 
1632
-}
 
1633
-
 
1634
-char *
 
1635
-grub_zfs_nvlist_lookup_nvlist_array (char *nvlist, char *name,
 
1636
-                                    grub_size_t index)
 
1637
-{
 
1638
-  char *nvpair, *nvpairptr;
 
1639
-  int found;
 
1640
-  char *ret;
 
1641
-  grub_size_t size;
 
1642
-  unsigned i;
 
1643
-  grub_size_t nelm;
 
1644
-
 
1645
-  found = nvlist_find_value (nvlist, name, DATA_TYPE_NVLIST, &nvpair,
 
1646
-                            &size, &nelm);
 
1647
-  if (!found)
 
1648
-    return 0;
 
1649
-  if (index >= nelm)
 
1650
-    {
 
1651
-      grub_error (GRUB_ERR_OUT_OF_RANGE, "trying to lookup past nvlist array");
 
1652
-      return 0;
 
1653
-    }
 
1654
-
 
1655
-  nvpairptr = nvpair;
 
1656
-
 
1657
-  for (i = 0; i < index; i++)
 
1658
-    {
 
1659
-      grub_uint32_t encode_size;
 
1660
-
 
1661
-      /* skip the header, nvl_version, and nvl_nvflag */
 
1662
-      nvpairptr = nvpairptr + 4 * 2;
 
1663
-
 
1664
-      while (nvpairptr < nvpair + size
 
1665
-            && (encode_size = grub_be_to_cpu32 (*(grub_uint32_t *) nvpairptr)))
 
1666
-       nvlist += encode_size;  /* goto the next nvpair */
 
1667
-
 
1668
-      nvlist = nvlist + 4 * 2; /* skip the ending 2 zeros - 8 bytes */
 
1669
-    }
 
1670
-
 
1671
-  if (nvpairptr >= nvpair + size
 
1672
-      || nvpairptr + grub_be_to_cpu32 (*(grub_uint32_t *) (nvpairptr + 4 * 2))
 
1673
-      >= nvpair + size)
 
1674
-    {
 
1675
-      grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist array");
 
1676
-      return 0;
 
1677
-    }
 
1678
-
 
1679
-  ret = grub_zalloc (grub_be_to_cpu32 (*(grub_uint32_t *) (nvpairptr + 4 * 2))
 
1680
-                    + 3 * sizeof (grub_uint32_t));
 
1681
-  if (!ret)
 
1682
-    return 0;
 
1683
-  grub_memcpy (ret, nvlist, sizeof (grub_uint32_t));
 
1684
-
 
1685
-  grub_memcpy (ret + sizeof (grub_uint32_t), nvpairptr, size);
 
1686
-  return ret;
 
1687
-}
 
1688
-
 
1689
-static grub_err_t
 
1690
-zfs_fetch_nvlist (struct grub_zfs_data * data, char **nvlist)
 
1691
-{
 
1692
-  grub_err_t err;
 
1693
-
 
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);
 
1698
-  if (err)
 
1699
-    {
 
1700
-      grub_free (*nvlist);
 
1701
-      *nvlist = 0;
 
1702
-      return err;
 
1703
-    }
 
1704
-  return GRUB_ERR_NONE;
 
1705
-}
 
1706
-
 
1707
-/*
 
1708
- * Check the disk label information and retrieve needed vdev name-value pairs.
 
1709
- *
 
1710
- */
 
1711
-static grub_err_t
 
1712
-check_pool_label (struct grub_zfs_data *data)
 
1713
+grub_zfs_nvlist_lookup_nvlist_array_get_nelm (const char *nvlist,
 
1714
+                                             const char *name)
 
1715
 {
 
1716
-  grub_uint64_t pool_state, txg = 0;
 
1717
-  char *nvlist;
 
1718
-#if 0
 
1719
-  char *nv;
 
1720
-#endif
 
1721
-  grub_uint64_t diskguid;
 
1722
-  grub_uint64_t version;
 
1723
+  char *nvpair;
 
1724
+  grub_size_t nelm, size;
 
1725
   int found;
 
1726
-  grub_err_t err;
 
1727
 
 
1728
-  err = zfs_fetch_nvlist (data, &nvlist);
 
1729
-  if (err)
 
1730
-    return err;
 
1731
+  found = nvlist_find_value (nvlist, name, DATA_TYPE_NVLIST_ARRAY, &nvpair,
 
1732
+                            &size, &nelm);
 
1733
+  if (! found)
 
1734
+    return -1;
 
1735
+  return nelm;
 
1736
+}
 
1737
 
 
1738
-  grub_dprintf ("zfs", "check 2 passed\n");
 
1739
+static int
 
1740
+get_nvlist_size (const char *beg, const char *limit)
 
1741
+{
 
1742
+  const char *ptr;
 
1743
+  grub_uint32_t encode_size;
 
1744
+  
 
1745
+  ptr = beg + 8;
 
1746
 
 
1747
-  found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_STATE,
 
1748
-                                        &pool_state);
 
1749
-  if (! found)
 
1750
-    {
 
1751
-      grub_free (nvlist);
 
1752
-      if (! grub_errno)
 
1753
-       grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_POOL_STATE " not found");
 
1754
-      return grub_errno;
 
1755
-    }
 
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 */
 
1760
+  ptr += 8;      
 
1761
+  return (ptr > limit) ? -1 : (ptr - beg);
 
1762
+}
 
1763
 
 
1764
-  if (pool_state == POOL_STATE_DESTROYED)
 
1765
-    {
 
1766
-      grub_free (nvlist);
 
1767
-      return grub_error (GRUB_ERR_BAD_FS, "zpool is marked as destroyed");
 
1768
-    }
 
1769
-  grub_dprintf ("zfs", "check 4 passed\n");
 
1770
+char *
 
1771
+grub_zfs_nvlist_lookup_nvlist_array (const char *nvlist, const char *name,
 
1772
+                                    grub_size_t index)
 
1773
+{
 
1774
+  char *nvpair, *nvpairptr;
 
1775
+  int found;
 
1776
+  char *ret;
 
1777
+  grub_size_t size;
 
1778
+  unsigned i;
 
1779
+  grub_size_t nelm;
 
1780
+  int elemsize = 0;
 
1781
 
 
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,
 
1784
+                            &size, &nelm);
 
1785
   if (!found)
 
1786
+    return 0;
 
1787
+  if (index >= nelm)
 
1788
     {
 
1789
-      grub_free (nvlist);
 
1790
-      if (! grub_errno)
 
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");
 
1794
+      return 0;
 
1795
     }
 
1796
-  grub_dprintf ("zfs", "check 6 passed\n");
 
1797
 
 
1798
-  /* not an active device */
 
1799
-  if (txg == 0)
 
1800
-    {
 
1801
-      grub_free (nvlist);
 
1802
-      return grub_error (GRUB_ERR_BAD_FS, "zpool isn't active");
 
1803
-    }
 
1804
-  grub_dprintf ("zfs", "check 7 passed\n");
 
1805
+  nvpairptr = nvpair;
 
1806
 
 
1807
-  found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_VERSION,
 
1808
-                                        &version);
 
1809
-  if (! found)
 
1810
+  for (i = 0; i < index; i++)
 
1811
     {
 
1812
-      grub_free (nvlist);
 
1813
-      if (! grub_errno)
 
1814
-       grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_VERSION " not found");
 
1815
-      return grub_errno;
 
1816
-    }
 
1817
-  grub_dprintf ("zfs", "check 8 passed\n");
 
1818
+      int r;
 
1819
+      r = get_nvlist_size (nvpairptr, nvpair + size);
 
1820
 
 
1821
-  if (version > SPA_VERSION)
 
1822
-    {
 
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);
 
1828
-    }
 
1829
-  grub_dprintf ("zfs", "check 9 passed\n");
 
1830
-#if 0
 
1831
-  if (nvlist_lookup_value (nvlist, ZPOOL_CONFIG_VDEV_TREE, &nv,
 
1832
-                          DATA_TYPE_NVLIST, NULL))
 
1833
-    {
 
1834
-      grub_free (vdev);
 
1835
-      return (GRUB_ERR_BAD_FS);
 
1836
+      if (r < 0)
 
1837
+       {
 
1838
+         grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist array");
 
1839
+         return NULL;
 
1840
+       }
 
1841
+      nvpairptr += r;
 
1842
     }
 
1843
-  grub_dprintf ("zfs", "check 10 passed\n");
 
1844
-#endif
 
1845
 
 
1846
-  found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_GUID, &diskguid);
 
1847
-  if (! found)
 
1848
+  elemsize = get_nvlist_size (nvpairptr, nvpair + size);
 
1849
+
 
1850
+  if (elemsize < 0)
 
1851
     {
 
1852
-      grub_free (nvlist);
 
1853
-      if (! grub_errno)
 
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");
 
1857
+      return 0;
 
1858
     }
 
1859
-  grub_dprintf ("zfs", "check 11 passed\n");
 
1860
 
 
1861
-  grub_free (nvlist);
 
1862
+  ret = grub_zalloc (elemsize + sizeof (grub_uint32_t));
 
1863
+  if (!ret)
 
1864
+    return 0;
 
1865
+  grub_memcpy (ret, nvlist, sizeof (grub_uint32_t));
 
1866
 
 
1867
-  return GRUB_ERR_NONE;
 
1868
+  grub_memcpy (ret + sizeof (grub_uint32_t), nvpairptr, elemsize);
 
1869
+  return ret;
 
1870
+}
 
1871
+
 
1872
+static void
 
1873
+unmount_device (struct grub_zfs_device_desc *desc)
 
1874
+{
 
1875
+  unsigned i;
 
1876
+  switch (desc->type)
 
1877
+    {
 
1878
+    case DEVICE_LEAF:
 
1879
+      if (!desc->original && desc->dev)
 
1880
+       grub_device_close (desc->dev);
 
1881
+      return;
 
1882
+    case DEVICE_RAIDZ:
 
1883
+    case DEVICE_MIRROR:
 
1884
+      for (i = 0; i < desc->n_children; i++)
 
1885
+       unmount_device (&desc->children[i]);
 
1886
+      return;
 
1887
+    }
 
1888
 }
 
1889
 
 
1890
 static void
 
1891
 zfs_unmount (struct grub_zfs_data *data)
 
1892
 {
 
1893
+  unsigned i;
 
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)
 
1902
 {
 
1903
   struct grub_zfs_data *data = 0;
 
1904
-  int label = 0;
 
1905
-  uberblock_phys_t *ub_array, *ubbest = NULL;
 
1906
-  vdev_boot_header_t *bh;
 
1907
-  void *osp = 0;
 
1908
-  grub_size_t ospsize;
 
1909
   grub_err_t err;
 
1910
-  int vdevnum;
 
1911
+  objset_phys_t *osp = 0;
 
1912
+  grub_size_t ospsize;
 
1913
+  grub_zfs_endian_t ub_endian = UNKNOWN_ENDIAN;
 
1914
+  uberblock_t *ub;
 
1915
 
 
1916
   if (! dev->disk)
 
1917
     {
 
1918
@@ -1975,119 +2908,56 @@
 
1919
       return 0;
 
1920
     }
 
1921
 
 
1922
-  data = grub_malloc (sizeof (*data));
 
1923
+  data = grub_zalloc (sizeof (*data));
 
1924
   if (!data)
 
1925
     return 0;
 
1926
-  grub_memset (data, 0, sizeof (*data));
 
1927
 #if 0
 
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 (&current_uberblock, 0, sizeof (uberblock_t));
 
1931
 #endif
 
1932
 
 
1933
-  data->disk = dev->disk;
 
1934
-
 
1935
-  ub_array = grub_malloc (VDEV_UBERBLOCK_RING);
 
1936
-  if (!ub_array)
 
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);
 
1942
+  if (err)
 
1943
     {
 
1944
       zfs_unmount (data);
 
1945
-      return 0;
 
1946
+      return NULL;
 
1947
     }
 
1948
 
 
1949
-  bh = grub_malloc (VDEV_BOOT_HEADER_SIZE);
 
1950
-  if (!bh)
 
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);
 
1955
+
 
1956
+  err = zio_read (&ub->ub_rootbp, ub_endian,
 
1957
+                 (void **) &osp, &ospsize, data);
 
1958
+  if (err)
 
1959
     {
 
1960
       zfs_unmount (data);
 
1961
-      grub_free (ub_array);
 
1962
-      return 0;
 
1963
+      return NULL;
 
1964
     }
 
1965
 
 
1966
-  vdevnum = VDEV_LABELS;
 
1967
-
 
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;
 
1971
-
 
1972
-  for (label = 0; ubbest == NULL && label < vdevnum; label++)
 
1973
+  if (ospsize < OBJSET_PHYS_SIZE_V14)
 
1974
     {
 
1975
-      grub_zfs_endian_t ub_endian = UNKNOWN_ENDIAN;
 
1976
-      grub_dprintf ("zfs", "label %d\n", label);
 
1977
-
 
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));
 
1983
-
 
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);
 
1988
-      if (err)
 
1989
-       {
 
1990
-         grub_errno = GRUB_ERR_NONE;
 
1991
-         continue;
 
1992
-       }
 
1993
-      grub_dprintf ("zfs", "label ok %d\n", label);
 
1994
-
 
1995
-      ubbest = find_bestub (ub_array, data->vdev_phys_sector);
 
1996
-      if (!ubbest)
 
1997
-       {
 
1998
-         grub_dprintf ("zfs", "No uberblock found\n");
 
1999
-         grub_errno = GRUB_ERR_NONE;
 
2000
-         continue;
 
2001
-       }
 
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, 
 
2006
-                     ub_endian,
 
2007
-                     &osp, &ospsize, data);
 
2008
-      if (err)
 
2009
-       {
 
2010
-         grub_dprintf ("zfs", "couldn't zio_read\n"); 
 
2011
-         grub_errno = GRUB_ERR_NONE;
 
2012
-         continue;
 
2013
-       }
 
2014
-
 
2015
-      if (ospsize < OBJSET_PHYS_SIZE_V14)
 
2016
-       {
 
2017
-         grub_dprintf ("zfs", "osp too small\n"); 
 
2018
-         grub_free (osp);
 
2019
-         continue;
 
2020
-       }
 
2021
-      grub_dprintf ("zfs", "ubbest %p\n", ubbest);
 
2022
-
 
2023
-      err = check_pool_label (data);
 
2024
-      if (err)
 
2025
-       {
 
2026
-         grub_errno = GRUB_ERR_NONE;
 
2027
-         continue;
 
2028
-       }
 
2029
-#if 0
 
2030
-      if (find_best_root &&
 
2031
-         vdev_uberblock_compare (&ubbest->ubp_uberblock,
 
2032
-                                 &(current_uberblock)) <= 0)
 
2033
-       continue;
 
2034
-#endif
 
2035
-      /* Got the MOS. Save it at the memory addr MOS. */
 
2036
-      grub_memmove (&(data->mos.dn), &((objset_phys_t *) osp)->os_meta_dnode,
 
2037
-                   DNODE_SIZE);
 
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);
 
2042
-      grub_free (bh);
 
2043
+      grub_error (GRUB_ERR_BAD_FS, "OSP too small");
 
2044
       grub_free (osp);
 
2045
-      return data;  
 
2046
+      zfs_unmount (data);
 
2047
+      return NULL;
 
2048
     }
 
2049
-  grub_error (GRUB_ERR_BAD_FS, "couldn't find a valid label");
 
2050
-  zfs_unmount (data);
 
2051
-  grub_free (ub_array);
 
2052
-  grub_free (bh);
 
2053
+
 
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;
 
2058
   grub_free (osp);
 
2059
 
 
2060
-  return 0;
 
2061
+  data->mounted = 1;
 
2062
+
 
2063
+  return data;
 
2064
 }
 
2065
 
 
2066
 grub_err_t
 
2067
@@ -2099,7 +2969,7 @@
 
2068
   zfs = zfs_mount (dev);
 
2069
   if (!zfs)
 
2070
     return grub_errno;
 
2071
-  err = zfs_fetch_nvlist (zfs, nvlist);
 
2072
+  err = zfs_fetch_nvlist (zfs->device_original, nvlist);
 
2073
   zfs_unmount (zfs);
 
2074
   return err;
 
2075
 }
 
2076
@@ -2115,7 +2985,7 @@
 
2077
   if (! data)
 
2078
     return grub_errno;
 
2079
 
 
2080
-  err = zfs_fetch_nvlist (data, &nvlist);
 
2081
+  err = zfs_fetch_nvlist (data->device_original, &nvlist);
 
2082
   if (err)      
 
2083
     {
 
2084
       zfs_unmount (data);
 
2085
@@ -2131,11 +3001,7 @@
 
2086
 static grub_err_t 
 
2087
 zfs_uuid (grub_device_t device, char **uuid)
 
2088
 {
 
2089
-  char *nvlist;
 
2090
-  int found;
 
2091
   struct grub_zfs_data *data;
 
2092
-  grub_uint64_t guid;
 
2093
-  grub_err_t err;
 
2094
 
 
2095
   *uuid = 0;
 
2096
 
 
2097
@@ -2143,24 +3009,36 @@
 
2098
   if (! data)
 
2099
     return grub_errno;
 
2100
 
 
2101
-  err = zfs_fetch_nvlist (data, &nvlist);
 
2102
-  if (err)
 
2103
-    {
 
2104
-      zfs_unmount (data);
 
2105
-      return err;
 
2106
-    }
 
2107
-
 
2108
-  found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_GUID, &guid);
 
2109
-  if (! found)
 
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);
 
2114
   zfs_unmount (data);
 
2115
   if (! *uuid)
 
2116
     return grub_errno;
 
2117
   return GRUB_ERR_NONE;
 
2118
 }
 
2119
 
 
2120
+static grub_err_t 
 
2121
+zfs_mtime (grub_device_t device, grub_int32_t *mt)
 
2122
+{
 
2123
+  struct grub_zfs_data *data;
 
2124
+  grub_zfs_endian_t ub_endian = UNKNOWN_ENDIAN;
 
2125
+  uberblock_t *ub;
 
2126
+
 
2127
+  *mt = 0;
 
2128
+
 
2129
+  data = zfs_mount (device);
 
2130
+  if (! data)
 
2131
+    return grub_errno;
 
2132
+
 
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);
 
2137
+
 
2138
+  *mt = grub_zfs_to_cpu64 (ub->ub_timestamp, ub_endian);
 
2139
+  zfs_unmount (data);
 
2140
+  return GRUB_ERR_NONE;
 
2141
+}
 
2142
+
 
2143
 /*
 
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 @@
 
2147
     return grub_errno;
 
2148
 
 
2149
   err = dnode_get_fullpath (fsfilename, &(data->mdn), 0,
 
2150
-                           &(data->dnode), &isfs, data);
 
2151
+                           &(data->dnode), &isfs, data, NULL);
 
2152
   if (err)
 
2153
     {
 
2154
       zfs_unmount (data);
 
2155
@@ -2227,12 +3105,14 @@
 
2156
        }
 
2157
 
 
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);
 
2161
     }
 
2162
-  else
 
2163
+  else if (data->dnode.dn.dn_bonustype == DMU_OT_ZNODE)
 
2164
     {
 
2165
       file->size = grub_zfs_to_cpu64 (((znode_phys_t *) DN_BONUS (&data->dnode.dn))->zp_size, data->dnode.endian);
 
2166
     }
 
2167
+  else
 
2168
+    return grub_error (GRUB_ERR_BAD_FS, "bad bonus type");
 
2169
 
 
2170
   file->data = data;
 
2171
   file->offset = 0;
 
2172
@@ -2248,7 +3128,7 @@
 
2173
 grub_zfs_read (grub_file_t file, char *buf, grub_size_t len)
 
2174
 {
 
2175
   struct grub_zfs_data *data = (struct grub_zfs_data *) file->data;
 
2176
-  int blksz, movesize;
 
2177
+  grub_size_t blksz, movesize;
 
2178
   grub_size_t length;
 
2179
   grub_size_t read;
 
2180
   grub_err_t err;
 
2181
@@ -2302,7 +3182,7 @@
 
2182
       data->file_start = blkid * blksz;
 
2183
       data->file_end = data->file_start + blksz;
 
2184
 
 
2185
-      movesize = MIN (length, data->file_end - (int) file->offset - read);
 
2186
+      movesize = MIN (length, data->file_end - file->offset - read);
 
2187
 
 
2188
       grub_memmove (buf, data->file_buf + file->offset + read
 
2189
                    - data->file_start, movesize);
 
2190
@@ -2339,7 +3219,7 @@
 
2191
     return grub_errno;
 
2192
 
 
2193
   err = dnode_get_fullpath (fsfilename, &(data->mdn), mdnobj,
 
2194
-                           &(data->dnode), &isfs, data);
 
2195
+                           &(data->dnode), &isfs, data, NULL);
 
2196
   zfs_unmount (data);
 
2197
   return err;
 
2198
 }
 
2199
@@ -2377,7 +3257,7 @@
 
2200
       return;
 
2201
     }
 
2202
   
 
2203
-  err = zap_lookup (&dn, ZFS_ROOT_OBJ, &objnum, data);
 
2204
+  err = zap_lookup (&dn, ZFS_ROOT_OBJ, &objnum, data, 0);
 
2205
   if (err)
 
2206
     {
 
2207
       grub_dprintf ("zfs", "failed here\n");
 
2208
@@ -2391,8 +3271,39 @@
 
2209
       return;
 
2210
     }
 
2211
   
 
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)
 
2215
+    {
 
2216
+      void *sahdrp;
 
2217
+      int hdrsize;
 
2218
+
 
2219
+      if (dn.dn.dn_bonuslen != 0)
 
2220
+       {
 
2221
+         sahdrp = (sa_hdr_phys_t *) DN_BONUS (&dn.dn);
 
2222
+       }
 
2223
+      else if (dn.dn.dn_flags & DNODE_FLAG_SPILL_BLKPTR)
 
2224
+       {
 
2225
+         blkptr_t *bp = &dn.dn.dn_spill;
 
2226
+
 
2227
+         err = zio_read (bp, dn.endian, &sahdrp, NULL, data);
 
2228
+         if (err)
 
2229
+           return;
 
2230
+       }
 
2231
+      else
 
2232
+       {
 
2233
+         grub_error (GRUB_ERR_BAD_FS, "filesystem is corrupt");
 
2234
+         return;
 
2235
+       }
 
2236
+
 
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);
 
2240
+    }
 
2241
+
 
2242
+  if (dn.dn.dn_bonustype == DMU_OT_ZNODE)
 
2243
+    {
 
2244
+      info->mtimeset = 1;
 
2245
+      info->mtime = grub_zfs_to_cpu64 (((znode_phys_t *) DN_BONUS (&dn.dn))->zp_mtime[0], dn.endian);
 
2246
+    }
 
2247
   return;
 
2248
 }
 
2249
 
 
2250
@@ -2403,6 +3314,7 @@
 
2251
   struct grub_zfs_data *data;
 
2252
   grub_err_t err;
 
2253
   int isfs;
 
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, 
 
2257
                                            grub_uint64_t val);
 
2258
@@ -2416,10 +3328,48 @@
 
2259
     grub_memset (&info, 0, sizeof (info));
 
2260
 
 
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", 
 
2266
+
 
2267
+    if (dn.dn.dn_bonustype == DMU_OT_SA)
 
2268
+      {
 
2269
+       void *sahdrp;
 
2270
+       int hdrsize;
 
2271
+
 
2272
+       if (dn.dn.dn_bonuslen != 0)
 
2273
+         {
 
2274
+           sahdrp = (sa_hdr_phys_t *) DN_BONUS (&data->dnode.dn);
 
2275
+         }
 
2276
+       else if (dn.dn.dn_flags & DNODE_FLAG_SPILL_BLKPTR)
 
2277
+         {
 
2278
+           blkptr_t *bp = &dn.dn.dn_spill;
 
2279
+
 
2280
+           err = zio_read (bp, dn.endian, &sahdrp, NULL, data);
 
2281
+           if (err)
 
2282
+             {
 
2283
+               grub_print_error ();
 
2284
+               return 0;
 
2285
+             }
 
2286
+         }
 
2287
+       else
 
2288
+         {
 
2289
+           grub_error (GRUB_ERR_BAD_FS, "filesystem is corrupt");
 
2290
+           grub_print_error ();
 
2291
+           return 0;
 
2292
+         }
 
2293
+
 
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;
 
2298
+      }
 
2299
+    
 
2300
+    if (dn.dn.dn_bonustype == DMU_OT_ZNODE)
 
2301
+      {        
 
2302
+       info.mtimeset = 1;
 
2303
+       info.mtime = grub_zfs_to_cpu64 (((znode_phys_t *) DN_BONUS (&dn.dn))->zp_mtime[0],
 
2304
+                                       dn.endian);
 
2305
+      }
 
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);
 
2310
   }
 
2311
@@ -2464,7 +3414,8 @@
 
2312
   data = zfs_mount (device);
 
2313
   if (! data)
 
2314
     return grub_errno;
 
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);
 
2318
   if (err)
 
2319
     {
 
2320
       zfs_unmount (data);
 
2321
@@ -2532,12 +3483,13 @@
 
2322
   .close = grub_zfs_close,
 
2323
   .label = zfs_label,
 
2324
   .uuid = zfs_uuid,
 
2325
-  .mtime = 0,
 
2326
+  .mtime = zfs_mtime,
 
2327
   .next = 0
 
2328
 };
 
2329
 
 
2330
 GRUB_MOD_INIT (zfs)
 
2331
 {
 
2332
+  COMPILE_TIME_ASSERT (sizeof (zap_leaf_chunk_t) == ZAP_LEAF_CHUNKSIZE);
 
2333
   grub_fs_register (&grub_zfs_fs);
 
2334
 #ifndef GRUB_UTIL
 
2335
   my_mod = mod;
 
2336
--- a/include/grub/zfs/zio.h
 
2337
+++ b/include/grub/zfs/zio.h
 
2338
@@ -77,7 +77,15 @@
 
2339
        ZIO_COMPRESS_OFF,
 
2340
        ZIO_COMPRESS_LZJB,
 
2341
        ZIO_COMPRESS_EMPTY,
 
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
 
2353
 };
 
2354
 
 
2355
--- a/grub-core/fs/zfs/zfsinfo.c
 
2356
+++ b/grub-core/fs/zfs/zfsinfo.c
 
2357
@@ -141,7 +141,6 @@
 
2358
        }
 
2359
       grub_printf ("Mirror VDEV with %d children\n", nelm);
 
2360
       print_state (nvlist, tab);
 
2361
-
 
2362
       for (i = 0; i < nelm; i++)
 
2363
        {
 
2364
          char *child;
 
2365
@@ -161,6 +160,7 @@
 
2366
 
 
2367
          grub_free (child);
 
2368
        }
 
2369
+      return GRUB_ERR_NONE;
 
2370
     }
 
2371
 
 
2372
   print_tabs (tab);
 
2373
--- a/include/grub/zfs/sa_impl.h
 
2374
+++ b/include/grub/zfs/sa_impl.h
 
2375
@@ -29,6 +29,9 @@
 
2376
 } sa_hdr_phys_t;
 
2377
 
 
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
 
2383
 
 
2384
 #endif /* _SYS_SA_IMPL_H */
 
2385
--- a/include/grub/zfs/zfs.h
 
2386
+++ b/include/grub/zfs/zfs.h
 
2387
@@ -28,7 +28,7 @@
 
2388
 /*
 
2389
  * On-disk version number.
 
2390
  */
 
2391
-#define        SPA_VERSION                     28ULL
 
2392
+#define        SPA_VERSION                     33ULL
 
2393
 
 
2394
 /*
 
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);
 
2399
 
 
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,
 
2409
+                                          const char *name,
 
2410
                                           grub_size_t index);
 
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);
 
2414
 
 
2415
 #endif /* ! GRUB_ZFS_HEADER */