Lines 1-894
Link Here
|
1 |
From |
|
|
2 |
|
3 |
http://sources.gentoo.org/cgi-bin/viewvc.cgi/gentoo-x86/sys-boot/grub/files/grub-2.00-zfs-feature-flag-support-r1.patch |
4 |
|
5 |
ZFS Feature Flag Support |
6 |
|
7 |
This is a monolithic version of the following commits: |
8 |
|
9 |
https://github.com/maxximino/grub2/commit/31a32560fd7948ae5ff5c63105d7c068de7890c8 |
10 |
https://github.com/maxximino/grub2/commit/595d76e8ca0690a963f5533689de8db54ef07e75 |
11 |
https://github.com/maxximino/grub2/commit/58344034e40218b20500fa2936eb4d7d019e1e88 |
12 |
https://github.com/maxximino/grub2/commit/f98cb078abab2c14bb0766b5a0ceb055683dab81 |
13 |
https://github.com/maxximino/grub2/commit/f12806f43a969a654dee7bb89b2e8fd5c42f0e2e |
14 |
|
15 |
A change was made to account for d8a0feb6 from upstream. This change prevents a |
16 |
compile time failure that is caused by a change in the callback interface used |
17 |
by mzap_interate(). Modifications to nvlist_find_value() were reverted to |
18 |
resolve Gentoo bug #462740. This eliminated the need for the new nvpair_type() |
19 |
and nvpair_value() functions. They have been removed to silence a compiler |
20 |
warning and reduce the size of the patch. Further adjustments were made to |
21 |
silence the following warnings: |
22 |
|
23 |
/var/tmp/portage/sys-boot/grub-2.00-r2/work/grub-2.00/grub-core/fs/zfs/zfs_lz4.c:77:5: |
24 |
warning: "__STDC_VERSION__" is not defined [-Wundef] |
25 |
/var/tmp/portage/sys-boot/grub-2.00-r2/work/grub-2.00/grub-core/fs/zfs/zfs.c:4079:3: |
26 |
warning: passing argument 4 of 'mzap_iterate' from incompatible pointer type |
27 |
[enabled by default] |
28 |
|
29 |
The initial feature flag support patches were written by Delphix while the LZ4 |
30 |
support was written by Saso Kiselkov. The work porting this to GRUB2 was done |
31 |
by Massimo Maggi, while the adaption to Gentoo's GRUB2 package was done by |
32 |
Richard Yao. |
33 |
|
34 |
diff --git a/Makefile.util.def b/Makefile.util.def |
35 |
index b80187c..1bf3038 100644 |
36 |
--- Makefile.util.def |
37 |
+++ Makefile.util.def |
38 |
@@ -95,6 +95,7 @@ library = { |
39 |
common = grub-core/fs/zfs/zfs.c; |
40 |
common = grub-core/fs/zfs/zfsinfo.c; |
41 |
common = grub-core/fs/zfs/zfs_lzjb.c; |
42 |
+ common = grub-core/fs/zfs/zfs_lz4.c; |
43 |
common = grub-core/fs/zfs/zfs_sha256.c; |
44 |
common = grub-core/fs/zfs/zfs_fletcher.c; |
45 |
common = grub-core/lib/envblk.c; |
46 |
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def |
47 |
index 39e77a4..1550b90 100644 |
48 |
--- grub-core/Makefile.core.def |
49 |
+++ grub-core/Makefile.core.def |
50 |
@@ -1186,6 +1186,7 @@ module = { |
51 |
name = zfs; |
52 |
common = fs/zfs/zfs.c; |
53 |
common = fs/zfs/zfs_lzjb.c; |
54 |
+ common = fs/zfs/zfs_lz4.c; |
55 |
common = fs/zfs/zfs_sha256.c; |
56 |
common = fs/zfs/zfs_fletcher.c; |
57 |
}; |
58 |
diff --git a/grub-core/fs/zfs/zfs.c b/grub-core/fs/zfs/zfs.c |
59 |
index ba0554a..811e3df 100644 |
60 |
--- grub-core/fs/zfs/zfs.c |
61 |
+++ grub-core/fs/zfs/zfs.c |
62 |
@@ -2,6 +2,7 @@ |
63 |
* GRUB -- GRand Unified Bootloader |
64 |
* Copyright (C) 1999,2000,2001,2002,2003,2004,2009,2010,2011 Free Software Foundation, Inc. |
65 |
* Copyright 2010 Sun Microsystems, Inc. |
66 |
+ * Copyright (c) 2012 by Delphix. All rights reserved. |
67 |
* |
68 |
* GRUB is free software; you can redistribute it and/or modify |
69 |
* it under the terms of the GNU General Public License as published by |
70 |
@@ -153,11 +154,13 @@ ZAP_LEAF_ENTRY(zap_leaf_phys_t *l, int bs, int idx) |
71 |
|
72 |
|
73 |
/* |
74 |
- * Decompression Entry - lzjb |
75 |
+ * Decompression Entry - lzjb & lz4 |
76 |
*/ |
77 |
|
78 |
extern grub_err_t lzjb_decompress (void *, void *, grub_size_t, grub_size_t); |
79 |
|
80 |
+extern grub_err_t lz4_decompress (void *, void *, grub_size_t, grub_size_t); |
81 |
+ |
82 |
typedef grub_err_t zfs_decomp_func_t (void *s_start, void *d_start, |
83 |
grub_size_t s_len, grub_size_t d_len); |
84 |
typedef struct decomp_entry |
85 |
@@ -263,6 +266,19 @@ grub_crypto_cipher_handle_t (*grub_zfs_load_key) (const struct grub_zfs_key *key |
86 |
grub_size_t keysize, |
87 |
grub_uint64_t salt, |
88 |
grub_uint64_t algo) = NULL; |
89 |
+/* |
90 |
+ * List of pool features that the grub implementation of ZFS supports for |
91 |
+ * read. Note that features that are only required for write do not need |
92 |
+ * to be listed here since grub opens pools in read-only mode. |
93 |
+ */ |
94 |
+static const char *spa_feature_names[] = { |
95 |
+ "org.illumos:lz4_compress","com.delphix:hole_birth",NULL |
96 |
+}; |
97 |
+ |
98 |
+static int NESTED_FUNC_ATTR |
99 |
+check_feature(const char *name, grub_uint64_t val); |
100 |
+static int |
101 |
+check_mos_features(dnode_phys_t *mosmdn_phys,grub_zfs_endian_t endian,struct grub_zfs_data* data ); |
102 |
|
103 |
static grub_err_t |
104 |
zlib_decompress (void *s, void *d, |
105 |
@@ -322,6 +338,7 @@ static decomp_entry_t decomp_table[ZIO_COMPRESS_FUNCTIONS] = { |
106 |
{"gzip-8", zlib_decompress}, /* ZIO_COMPRESS_GZIP8 */ |
107 |
{"gzip-9", zlib_decompress}, /* ZIO_COMPRESS_GZIP9 */ |
108 |
{"zle", zle_decompress}, /* ZIO_COMPRESS_ZLE */ |
109 |
+ {"lz4", lz4_decompress}, /* ZIO_COMPRESS_LZ4 */ |
110 |
}; |
111 |
|
112 |
static grub_err_t zio_read_data (blkptr_t * bp, grub_zfs_endian_t endian, |
113 |
@@ -482,15 +499,11 @@ uberblock_verify (uberblock_phys_t * ub, grub_uint64_t offset, |
114 |
|
115 |
if (grub_zfs_to_cpu64 (uber->ub_magic, GRUB_ZFS_LITTLE_ENDIAN) |
116 |
== UBERBLOCK_MAGIC |
117 |
- && grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_LITTLE_ENDIAN) > 0 |
118 |
- && grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_LITTLE_ENDIAN) |
119 |
- <= SPA_VERSION) |
120 |
- endian = GRUB_ZFS_LITTLE_ENDIAN; |
121 |
+ && SPA_VERSION_IS_SUPPORTED(grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_LITTLE_ENDIAN))) |
122 |
+ endian = GRUB_ZFS_LITTLE_ENDIAN; |
123 |
|
124 |
if (grub_zfs_to_cpu64 (uber->ub_magic, GRUB_ZFS_BIG_ENDIAN) == UBERBLOCK_MAGIC |
125 |
- && grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_BIG_ENDIAN) > 0 |
126 |
- && grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_BIG_ENDIAN) |
127 |
- <= SPA_VERSION) |
128 |
+ && SPA_VERSION_IS_SUPPORTED(grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_BIG_ENDIAN))) |
129 |
endian = GRUB_ZFS_BIG_ENDIAN; |
130 |
|
131 |
if (endian == GRUB_ZFS_UNKNOWN_ENDIAN) |
132 |
@@ -764,6 +777,99 @@ fill_vdev_info (struct grub_zfs_data *data, |
133 |
} |
134 |
|
135 |
/* |
136 |
+ * For a given XDR packed nvlist, verify the first 4 bytes and move on. |
137 |
+ * |
138 |
+ * An XDR packed nvlist is encoded as (comments from nvs_xdr_create) : |
139 |
+ * |
140 |
+ * encoding method/host endian (4 bytes) |
141 |
+ * nvl_version (4 bytes) |
142 |
+ * nvl_nvflag (4 bytes) |
143 |
+ * encoded nvpairs: |
144 |
+ * encoded size of the nvpair (4 bytes) |
145 |
+ * decoded size of the nvpair (4 bytes) |
146 |
+ * name string size (4 bytes) |
147 |
+ * name string data (sizeof(NV_ALIGN4(string)) |
148 |
+ * data type (4 bytes) |
149 |
+ * # of elements in the nvpair (4 bytes) |
150 |
+ * data |
151 |
+ * 2 zero's for the last nvpair |
152 |
+ * (end of the entire list) (8 bytes) |
153 |
+ * |
154 |
+ */ |
155 |
+ |
156 |
+/* |
157 |
+ * The nvlist_next_nvpair() function returns a handle to the next nvpair in the |
158 |
+ * list following nvpair. If nvpair is NULL, the first pair is returned. If |
159 |
+ * nvpair is the last pair in the nvlist, NULL is returned. |
160 |
+ */ |
161 |
+static const char * |
162 |
+nvlist_next_nvpair(const char *nvl, const char *nvpair) |
163 |
+{ |
164 |
+ const char *nvp; |
165 |
+ int encode_size; |
166 |
+ int name_len; |
167 |
+ if (nvl == NULL) |
168 |
+ return (NULL); |
169 |
+ |
170 |
+ if (nvpair == NULL) { |
171 |
+ /* skip over header, nvl_version and nvl_nvflag */ |
172 |
+ nvpair = nvl + 4 * 3; |
173 |
+ } else { |
174 |
+ /* skip to the next nvpair */ |
175 |
+ encode_size = grub_be_to_cpu32 (grub_get_unaligned32(nvpair)); |
176 |
+ nvpair += encode_size; |
177 |
+ } |
178 |
+ /* 8 bytes of 0 marks the end of the list */ |
179 |
+ if (*(grub_uint64_t*)nvpair == 0) |
180 |
+ return (NULL); |
181 |
+ /*consistency checks*/ |
182 |
+ if (nvpair + 4 * 3 >= nvl + VDEV_PHYS_SIZE) |
183 |
+ { |
184 |
+ grub_dprintf ("zfs", "nvlist overflow\n"); |
185 |
+ grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist"); |
186 |
+ return (NULL); |
187 |
+ } |
188 |
+ encode_size = grub_be_to_cpu32 (grub_get_unaligned32(nvpair)); |
189 |
+ |
190 |
+ nvp = nvpair + 4*2; |
191 |
+ name_len = grub_be_to_cpu32 (grub_get_unaligned32 (nvp)); |
192 |
+ nvp += 4; |
193 |
+ |
194 |
+ nvp = nvp + ((name_len + 3) & ~3); // align |
195 |
+ if (nvp + 4 >= nvl + VDEV_PHYS_SIZE |
196 |
+ || encode_size < 0 |
197 |
+ || nvp + 4 + encode_size > nvl + VDEV_PHYS_SIZE) |
198 |
+ { |
199 |
+ grub_dprintf ("zfs", "nvlist overflow\n"); |
200 |
+ grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist"); |
201 |
+ return (NULL); |
202 |
+ } |
203 |
+ /* end consistency checks */ |
204 |
+ |
205 |
+ return (nvpair); |
206 |
+} |
207 |
+/* |
208 |
+ * This function returns 0 on success and 1 on failure. On success, a string |
209 |
+ * containing the name of nvpair is saved in buf. |
210 |
+ */ |
211 |
+static int |
212 |
+nvpair_name(const char *nvp, char **buf, int* buflen) |
213 |
+{ |
214 |
+ int len; |
215 |
+ |
216 |
+ /* skip over encode/decode size */ |
217 |
+ nvp += 4 * 2; |
218 |
+ |
219 |
+ len = grub_be_to_cpu32 (grub_get_unaligned32 (nvp)); |
220 |
+ nvp=nvp+4; |
221 |
+ |
222 |
+ *buf=(char*)nvp; |
223 |
+ *buflen=len; |
224 |
+ |
225 |
+ return (0); |
226 |
+} |
227 |
+ |
228 |
+/* |
229 |
* Check the disk label information and retrieve needed vdev name-value pairs. |
230 |
* |
231 |
*/ |
232 |
@@ -773,7 +879,7 @@ check_pool_label (struct grub_zfs_data *data, |
233 |
int *inserted) |
234 |
{ |
235 |
grub_uint64_t pool_state, txg = 0; |
236 |
- char *nvlist; |
237 |
+ char *nvlist,*features; |
238 |
#if 0 |
239 |
char *nv; |
240 |
#endif |
241 |
@@ -837,13 +943,13 @@ check_pool_label (struct grub_zfs_data *data, |
242 |
} |
243 |
grub_dprintf ("zfs", "check 8 passed\n"); |
244 |
|
245 |
- if (version > SPA_VERSION) |
246 |
+ if (!SPA_VERSION_IS_SUPPORTED(version)) |
247 |
{ |
248 |
grub_free (nvlist); |
249 |
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, |
250 |
"too new version %llu > %llu", |
251 |
(unsigned long long) version, |
252 |
- (unsigned long long) SPA_VERSION); |
253 |
+ (unsigned long long) SPA_VERSION_BEFORE_FEATURES); |
254 |
} |
255 |
grub_dprintf ("zfs", "check 9 passed\n"); |
256 |
|
257 |
@@ -893,7 +999,30 @@ check_pool_label (struct grub_zfs_data *data, |
258 |
grub_free (nv); |
259 |
} |
260 |
grub_dprintf ("zfs", "check 10 passed\n"); |
261 |
- |
262 |
+ if ((features=grub_zfs_nvlist_lookup_nvlist(nvlist, ZPOOL_CONFIG_FEATURES_FOR_READ))) |
263 |
+ { |
264 |
+ const char *nvp=NULL; |
265 |
+ char *name = grub_zalloc(51); |
266 |
+ char *nameptr; |
267 |
+ int namelen; |
268 |
+ while ((nvp = nvlist_next_nvpair(features, nvp)) != NULL) |
269 |
+ { |
270 |
+ nvpair_name(nvp, &nameptr,&namelen); |
271 |
+ if(namelen > 50){namelen=50;} |
272 |
+ grub_strncpy(name,nameptr,namelen); |
273 |
+ name[namelen]=0; |
274 |
+ grub_dprintf("zfs","namelen=%u str=%s\n",namelen,name); |
275 |
+ if (check_feature(name,1) != 0) |
276 |
+ { |
277 |
+ grub_dprintf("zfs","feature missing in check_pool_label:%s\n",name); |
278 |
+ err= grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET," check_pool_label missing feature '%s' for read",name); |
279 |
+ grub_free(name); |
280 |
+ return err; |
281 |
+ } |
282 |
+ } |
283 |
+ grub_free(name); |
284 |
+ } |
285 |
+ grub_dprintf ("zfs", "check 12 passed (feature flags)\n"); |
286 |
grub_free (nvlist); |
287 |
|
288 |
return GRUB_ERR_NONE; |
289 |
@@ -3034,27 +3163,6 @@ dnode_get_fullpath (const char *fullpath, struct subvolume *subvol, |
290 |
return err; |
291 |
} |
292 |
|
293 |
-/* |
294 |
- * For a given XDR packed nvlist, verify the first 4 bytes and move on. |
295 |
- * |
296 |
- * An XDR packed nvlist is encoded as (comments from nvs_xdr_create) : |
297 |
- * |
298 |
- * encoding method/host endian (4 bytes) |
299 |
- * nvl_version (4 bytes) |
300 |
- * nvl_nvflag (4 bytes) |
301 |
- * encoded nvpairs: |
302 |
- * encoded size of the nvpair (4 bytes) |
303 |
- * decoded size of the nvpair (4 bytes) |
304 |
- * name string size (4 bytes) |
305 |
- * name string data (sizeof(NV_ALIGN4(string)) |
306 |
- * data type (4 bytes) |
307 |
- * # of elements in the nvpair (4 bytes) |
308 |
- * data |
309 |
- * 2 zero's for the last nvpair |
310 |
- * (end of the entire list) (8 bytes) |
311 |
- * |
312 |
- */ |
313 |
- |
314 |
static int |
315 |
nvlist_find_value (const char *nvlist_in, const char *name, |
316 |
int valtype, char **val, |
317 |
@@ -3386,6 +3494,10 @@ zfs_mount (grub_device_t dev) |
318 |
return NULL; |
319 |
} |
320 |
|
321 |
+ if (ub->ub_version >= SPA_VERSION_FEATURES && |
322 |
+ check_mos_features(&((objset_phys_t *) osp)->os_meta_dnode,ub_endian, data) != 0) |
323 |
+ return NULL; |
324 |
+ |
325 |
/* Got the MOS. Save it at the memory addr MOS. */ |
326 |
grub_memmove (&(data->mos.dn), &((objset_phys_t *) osp)->os_meta_dnode, |
327 |
DNODE_SIZE); |
328 |
@@ -3910,6 +4022,64 @@ grub_zfs_dir (grub_device_t device, const char *path, |
329 |
return grub_errno; |
330 |
} |
331 |
|
332 |
+static int NESTED_FUNC_ATTR |
333 |
+check_feature(const char *name, grub_uint64_t val) |
334 |
+{ |
335 |
+ int i; |
336 |
+ if(val ==0) return 0; |
337 |
+ if(*name==0) return 0; |
338 |
+ for (i = 0; spa_feature_names[i] != NULL; i++) |
339 |
+ { |
340 |
+ if (grub_strcmp(name, spa_feature_names[i]) == 0) |
341 |
+ return 0; |
342 |
+ } |
343 |
+ grub_printf("missing feature for read '%s'\n",name); |
344 |
+ return 1; |
345 |
+} |
346 |
+ |
347 |
+/* |
348 |
+ * Checks whether the MOS features that are active are supported by this |
349 |
+ * (GRUB's) implementation of ZFS. |
350 |
+ * |
351 |
+ * Return: |
352 |
+ * 0: Success. |
353 |
+ * errnum: Failure. |
354 |
+ */ |
355 |
+ |
356 |
+static int |
357 |
+check_mos_features(dnode_phys_t *mosmdn_phys,grub_zfs_endian_t endian,struct grub_zfs_data* data ) |
358 |
+{ |
359 |
+ grub_uint64_t objnum; |
360 |
+ grub_uint8_t errnum = 0; |
361 |
+ dnode_end_t dn,mosmdn; |
362 |
+ mzap_phys_t* mzp; |
363 |
+ grub_zfs_endian_t endianzap; |
364 |
+ int size; |
365 |
+ grub_memmove(&(mosmdn.dn),mosmdn_phys,sizeof(dnode_phys_t)); |
366 |
+ mosmdn.endian=endian; |
367 |
+ if ((errnum = dnode_get(&mosmdn, DMU_POOL_DIRECTORY_OBJECT, |
368 |
+ DMU_OT_OBJECT_DIRECTORY, &dn,data)) != 0) |
369 |
+ return (errnum); |
370 |
+ |
371 |
+ /* |
372 |
+ * Find the object number for 'features_for_read' and retrieve its |
373 |
+ * corresponding dnode. Note that we don't check features_for_write |
374 |
+ * because GRUB is not opening the pool for write. |
375 |
+ */ |
376 |
+ if ((errnum = zap_lookup(&dn, DMU_POOL_FEATURES_FOR_READ, &objnum, data,0)) != 0) |
377 |
+ return (errnum); |
378 |
+ |
379 |
+ if ((errnum = dnode_get(&mosmdn, objnum, DMU_OTN_ZAP_METADATA, &dn, data)) != 0) |
380 |
+ return (errnum); |
381 |
+ |
382 |
+ if ((errnum = dmu_read(&dn, 0, (void**)&mzp, &endianzap,data)) != 0) |
383 |
+ return (errnum); |
384 |
+ |
385 |
+ size = grub_zfs_to_cpu16 (dn.dn.dn_datablkszsec, dn.endian) << SPA_MINBLOCKSHIFT; |
386 |
+ return (mzap_iterate(mzp,endianzap, size, check_feature)); |
387 |
+} |
388 |
+ |
389 |
+ |
390 |
#ifdef GRUB_UTIL |
391 |
static grub_err_t |
392 |
grub_zfs_embed (grub_device_t device __attribute__ ((unused)), |
393 |
diff --git a/grub-core/fs/zfs/zfs_lz4.c b/grub-core/fs/zfs/zfs_lz4.c |
394 |
new file mode 100644 |
395 |
index 0000000..ff85a77 |
396 |
--- /dev/null |
397 |
+++ grub-core/fs/zfs/zfs_lz4.c |
398 |
@@ -0,0 +1,318 @@ |
399 |
+/* |
400 |
+ * LZ4 - Fast LZ compression algorithm |
401 |
+ * Header File |
402 |
+ * Copyright (C) 2011-2013, Yann Collet. |
403 |
+ * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) |
404 |
+ * |
405 |
+ * Redistribution and use in source and binary forms, with or without |
406 |
+ * modification, are permitted provided that the following conditions are |
407 |
+ * met: |
408 |
+ * |
409 |
+ * * Redistributions of source code must retain the above copyright |
410 |
+ * notice, this list of conditions and the following disclaimer. |
411 |
+ * * Redistributions in binary form must reproduce the above |
412 |
+ * copyright notice, this list of conditions and the following disclaimer |
413 |
+ * in the documentation and/or other materials provided with the |
414 |
+ * distribution. |
415 |
+ * |
416 |
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
417 |
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
418 |
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
419 |
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
420 |
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
421 |
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
422 |
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
423 |
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
424 |
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
425 |
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
426 |
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
427 |
+ * |
428 |
+ * You can contact the author at : |
429 |
+ * - LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html |
430 |
+ * - LZ4 source repository : http://code.google.com/p/lz4/ |
431 |
+ */ |
432 |
+ |
433 |
+#include <sys/endian.h> |
434 |
+#include <grub/err.h> |
435 |
+#include <grub/mm.h> |
436 |
+#include <grub/misc.h> |
437 |
+#include <grub/types.h> |
438 |
+ |
439 |
+static int LZ4_uncompress_unknownOutputSize(const char *source, char *dest, |
440 |
+ int isize, int maxOutputSize); |
441 |
+ |
442 |
+/* |
443 |
+ * CPU Feature Detection |
444 |
+ */ |
445 |
+ |
446 |
+/* 32 or 64 bits ? */ |
447 |
+#if (defined(__x86_64__) || defined(__x86_64) || defined(__amd64__) || \ |
448 |
+ defined(__amd64) || defined(__ppc64__) || defined(_WIN64) || \ |
449 |
+ defined(__LP64__) || defined(_LP64)) |
450 |
+#define LZ4_ARCH64 1 |
451 |
+#else |
452 |
+#define LZ4_ARCH64 0 |
453 |
+#endif |
454 |
+ |
455 |
+/* |
456 |
+ * Little Endian or Big Endian? |
457 |
+ * Note: overwrite the below #define if you know your architecture endianess. |
458 |
+ */ |
459 |
+#if BYTE_ORDER == BIG_ENDIAN |
460 |
+#define LZ4_BIG_ENDIAN 1 |
461 |
+#else |
462 |
+ /* |
463 |
+ * Little Endian assumed. PDP Endian and other very rare endian format |
464 |
+ * are unsupported. |
465 |
+ */ |
466 |
+#endif |
467 |
+ |
468 |
+/* |
469 |
+ * Compiler Options |
470 |
+ */ |
471 |
+ |
472 |
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ |
473 |
+/* "restrict" is a known keyword */ |
474 |
+#else |
475 |
+/* Disable restrict */ |
476 |
+#ifndef restrict |
477 |
+#define restrict /* Only if somebody already didn't take care of that.*/ |
478 |
+#endif |
479 |
+#endif |
480 |
+ |
481 |
+#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) |
482 |
+ |
483 |
+#define lz4_bswap16(x) ((unsigned short int) ((((x) >> 8) & 0xffu) \ |
484 |
+ | (((x) & 0xffu) << 8))) |
485 |
+ |
486 |
+#if (GCC_VERSION >= 302) || (__INTEL_COMPILER >= 800) || defined(__clang__) |
487 |
+#define expect(expr, value) (__builtin_expect((expr), (value))) |
488 |
+#else |
489 |
+#define expect(expr, value) (expr) |
490 |
+#endif |
491 |
+ |
492 |
+#define likely(expr) expect((expr) != 0, 1) |
493 |
+#define unlikely(expr) expect((expr) != 0, 0) |
494 |
+ |
495 |
+/* Basic types */ |
496 |
+#define BYTE grub_uint8_t |
497 |
+#define U16 grub_uint16_t |
498 |
+#define U32 grub_uint32_t |
499 |
+#define S32 grub_int32_t |
500 |
+#define U64 grub_uint64_t |
501 |
+typedef grub_size_t size_t; |
502 |
+ |
503 |
+typedef struct _U16_S { |
504 |
+ U16 v; |
505 |
+} U16_S; |
506 |
+typedef struct _U32_S { |
507 |
+ U32 v; |
508 |
+} U32_S; |
509 |
+typedef struct _U64_S { |
510 |
+ U64 v; |
511 |
+} U64_S; |
512 |
+ |
513 |
+#define A64(x) (((U64_S *)(x))->v) |
514 |
+#define A32(x) (((U32_S *)(x))->v) |
515 |
+#define A16(x) (((U16_S *)(x))->v) |
516 |
+ |
517 |
+/* |
518 |
+ * Constants |
519 |
+ */ |
520 |
+#define MINMATCH 4 |
521 |
+ |
522 |
+#define COPYLENGTH 8 |
523 |
+#define LASTLITERALS 5 |
524 |
+ |
525 |
+#define ML_BITS 4 |
526 |
+#define ML_MASK ((1U<<ML_BITS)-1) |
527 |
+#define RUN_BITS (8-ML_BITS) |
528 |
+#define RUN_MASK ((1U<<RUN_BITS)-1) |
529 |
+ |
530 |
+/* |
531 |
+ * Architecture-specific macros |
532 |
+ */ |
533 |
+#if LZ4_ARCH64 |
534 |
+#define STEPSIZE 8 |
535 |
+#define UARCH U64 |
536 |
+#define AARCH A64 |
537 |
+#define LZ4_COPYSTEP(s, d) A64(d) = A64(s); d += 8; s += 8; |
538 |
+#define LZ4_COPYPACKET(s, d) LZ4_COPYSTEP(s, d) |
539 |
+#define LZ4_SECURECOPY(s, d, e) if (d < e) LZ4_WILDCOPY(s, d, e) |
540 |
+#define HTYPE U32 |
541 |
+#define INITBASE(base) const BYTE* const base = ip |
542 |
+#else |
543 |
+#define STEPSIZE 4 |
544 |
+#define UARCH U32 |
545 |
+#define AARCH A32 |
546 |
+#define LZ4_COPYSTEP(s, d) A32(d) = A32(s); d += 4; s += 4; |
547 |
+#define LZ4_COPYPACKET(s, d) LZ4_COPYSTEP(s, d); LZ4_COPYSTEP(s, d); |
548 |
+#define LZ4_SECURECOPY LZ4_WILDCOPY |
549 |
+#define HTYPE const BYTE* |
550 |
+#define INITBASE(base) const int base = 0 |
551 |
+#endif |
552 |
+ |
553 |
+#if (defined(LZ4_BIG_ENDIAN) && !defined(BIG_ENDIAN_NATIVE_BUT_INCOMPATIBLE)) |
554 |
+#define LZ4_READ_LITTLEENDIAN_16(d, s, p) \ |
555 |
+ { U16 v = A16(p); v = lz4_bswap16(v); d = (s) - v; } |
556 |
+#define LZ4_WRITE_LITTLEENDIAN_16(p, i) \ |
557 |
+ { U16 v = (U16)(i); v = lz4_bswap16(v); A16(p) = v; p += 2; } |
558 |
+#else |
559 |
+#define LZ4_READ_LITTLEENDIAN_16(d, s, p) { d = (s) - A16(p); } |
560 |
+#define LZ4_WRITE_LITTLEENDIAN_16(p, v) { A16(p) = v; p += 2; } |
561 |
+#endif |
562 |
+ |
563 |
+/* Macros */ |
564 |
+#define LZ4_WILDCOPY(s, d, e) do { LZ4_COPYPACKET(s, d) } while (d < e); |
565 |
+ |
566 |
+/* Decompression functions */ |
567 |
+grub_err_t |
568 |
+lz4_decompress(void *s_start, void *d_start, size_t s_len, size_t d_len); |
569 |
+ |
570 |
+grub_err_t |
571 |
+lz4_decompress(void *s_start, void *d_start, size_t s_len, size_t d_len) |
572 |
+{ |
573 |
+ const BYTE *src = s_start; |
574 |
+ U32 bufsiz = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | |
575 |
+ src[3]; |
576 |
+ |
577 |
+ /* invalid compressed buffer size encoded at start */ |
578 |
+ if (bufsiz + 4 > s_len) |
579 |
+ return grub_error(GRUB_ERR_BAD_FS,"lz4 decompression failed."); |
580 |
+ |
581 |
+ /* |
582 |
+ * Returns 0 on success (decompression function returned non-negative) |
583 |
+ * and appropriate error on failure (decompression function returned negative). |
584 |
+ */ |
585 |
+ return (LZ4_uncompress_unknownOutputSize((char*)s_start + 4, d_start, bufsiz, |
586 |
+ d_len) < 0)?grub_error(GRUB_ERR_BAD_FS,"lz4 decompression failed."):0; |
587 |
+} |
588 |
+ |
589 |
+static int |
590 |
+LZ4_uncompress_unknownOutputSize(const char *source, |
591 |
+ char *dest, int isize, int maxOutputSize) |
592 |
+{ |
593 |
+ /* Local Variables */ |
594 |
+ const BYTE *restrict ip = (const BYTE *) source; |
595 |
+ const BYTE *const iend = ip + isize; |
596 |
+ const BYTE *restrict ref; |
597 |
+ |
598 |
+ BYTE *restrict op = (BYTE *) dest; |
599 |
+ BYTE *const oend = op + maxOutputSize; |
600 |
+ BYTE *cpy; |
601 |
+ |
602 |
+ size_t dec[] = { 0, 3, 2, 3, 0, 0, 0, 0 }; |
603 |
+ |
604 |
+ /* Main Loop */ |
605 |
+ while (ip < iend) { |
606 |
+ BYTE token; |
607 |
+ int length; |
608 |
+ |
609 |
+ /* get runlength */ |
610 |
+ token = *ip++; |
611 |
+ if ((length = (token >> ML_BITS)) == RUN_MASK) { |
612 |
+ int s = 255; |
613 |
+ while ((ip < iend) && (s == 255)) { |
614 |
+ s = *ip++; |
615 |
+ length += s; |
616 |
+ } |
617 |
+ } |
618 |
+ /* copy literals */ |
619 |
+ cpy = op + length; |
620 |
+ if ((cpy > oend - COPYLENGTH) || |
621 |
+ (ip + length > iend - COPYLENGTH)) { |
622 |
+ if (cpy > oend) |
623 |
+ /* |
624 |
+ * Error: request to write beyond destination |
625 |
+ * buffer. |
626 |
+ */ |
627 |
+ goto _output_error; |
628 |
+ if (ip + length > iend) |
629 |
+ /* |
630 |
+ * Error : request to read beyond source |
631 |
+ * buffer. |
632 |
+ */ |
633 |
+ goto _output_error; |
634 |
+ grub_memcpy(op, ip, length); |
635 |
+ op += length; |
636 |
+ ip += length; |
637 |
+ if (ip < iend) |
638 |
+ /* Error : LZ4 format violation */ |
639 |
+ goto _output_error; |
640 |
+ /* Necessarily EOF, due to parsing restrictions. */ |
641 |
+ break; |
642 |
+ } |
643 |
+ LZ4_WILDCOPY(ip, op, cpy); |
644 |
+ ip -= (op - cpy); |
645 |
+ op = cpy; |
646 |
+ |
647 |
+ /* get offset */ |
648 |
+ LZ4_READ_LITTLEENDIAN_16(ref, cpy, ip); |
649 |
+ ip += 2; |
650 |
+ if (ref < (BYTE * const) dest) |
651 |
+ /* |
652 |
+ * Error: offset creates reference outside of |
653 |
+ * destination buffer. |
654 |
+ */ |
655 |
+ goto _output_error; |
656 |
+ |
657 |
+ /* get matchlength */ |
658 |
+ if ((length = (token & ML_MASK)) == ML_MASK) { |
659 |
+ while (ip < iend) { |
660 |
+ int s = *ip++; |
661 |
+ length += s; |
662 |
+ if (s == 255) |
663 |
+ continue; |
664 |
+ break; |
665 |
+ } |
666 |
+ } |
667 |
+ /* copy repeated sequence */ |
668 |
+ if unlikely(op - ref < STEPSIZE) { |
669 |
+#if LZ4_ARCH64 |
670 |
+ size_t dec2table[] = { 0, 0, 0, -1, 0, 1, 2, 3 }; |
671 |
+ size_t dec2 = dec2table[op - ref]; |
672 |
+#else |
673 |
+ const int dec2 = 0; |
674 |
+#endif |
675 |
+ *op++ = *ref++; |
676 |
+ *op++ = *ref++; |
677 |
+ *op++ = *ref++; |
678 |
+ *op++ = *ref++; |
679 |
+ ref -= dec[op - ref]; |
680 |
+ A32(op) = A32(ref); |
681 |
+ op += STEPSIZE - 4; |
682 |
+ ref -= dec2; |
683 |
+ } else { |
684 |
+ LZ4_COPYSTEP(ref, op); |
685 |
+ } |
686 |
+ cpy = op + length - (STEPSIZE - 4); |
687 |
+ if (cpy > oend - COPYLENGTH) { |
688 |
+ if (cpy > oend) |
689 |
+ /* |
690 |
+ * Error: request to write outside of |
691 |
+ * destination buffer. |
692 |
+ */ |
693 |
+ goto _output_error; |
694 |
+ LZ4_SECURECOPY(ref, op, (oend - COPYLENGTH)); |
695 |
+ while (op < cpy) |
696 |
+ *op++ = *ref++; |
697 |
+ op = cpy; |
698 |
+ if (op == oend) |
699 |
+ /* |
700 |
+ * Check EOF (should never happen, since last |
701 |
+ * 5 bytes are supposed to be literals). |
702 |
+ */ |
703 |
+ break; |
704 |
+ continue; |
705 |
+ } |
706 |
+ LZ4_SECURECOPY(ref, op, cpy); |
707 |
+ op = cpy; /* correction */ |
708 |
+ } |
709 |
+ |
710 |
+ /* end of decoding */ |
711 |
+ return (int)(((char *)op) - dest); |
712 |
+ |
713 |
+ /* write overflow error detected */ |
714 |
+ _output_error: |
715 |
+ return (int)(-(((char *)ip) - source)); |
716 |
+} |
717 |
diff --git a/grub-core/fs/zfs/zfsinfo.c b/grub-core/fs/zfs/zfsinfo.c |
718 |
index fdb587a..c96bf21 100644 |
719 |
--- grub-core/fs/zfs/zfsinfo.c |
720 |
+++ grub-core/fs/zfs/zfsinfo.c |
721 |
@@ -132,21 +132,31 @@ print_vdev_info (char *nvlist, int tab) |
722 |
grub_free (path); |
723 |
return GRUB_ERR_NONE; |
724 |
} |
725 |
+ char is_mirror=(grub_strcmp(type,VDEV_TYPE_MIRROR) == 0); |
726 |
+ char is_raidz=(grub_strcmp(type,VDEV_TYPE_RAIDZ) == 0); |
727 |
|
728 |
- if (grub_strcmp (type, VDEV_TYPE_MIRROR) == 0) |
729 |
+ if (is_mirror || is_raidz) |
730 |
{ |
731 |
int nelm, i; |
732 |
|
733 |
nelm = grub_zfs_nvlist_lookup_nvlist_array_get_nelm |
734 |
(nvlist, ZPOOL_CONFIG_CHILDREN); |
735 |
|
736 |
+ if(is_mirror){ |
737 |
+ grub_puts_ (N_("This VDEV is a mirror")); |
738 |
+ } |
739 |
+ else if(is_raidz){ |
740 |
+ grub_uint64_t parity; |
741 |
+ grub_zfs_nvlist_lookup_uint64(nvlist,"nparity",&parity); |
742 |
+ grub_printf_ (N_("This VDEV is a RAIDZ%llu\n"),(unsigned long long)parity); |
743 |
+ } |
744 |
print_tabs (tab); |
745 |
if (nelm <= 0) |
746 |
{ |
747 |
- grub_puts_ (N_("Incorrect mirror")); |
748 |
+ grub_puts_ (N_("Incorrect VDEV")); |
749 |
return GRUB_ERR_NONE; |
750 |
} |
751 |
- grub_printf_ (N_("Mirror with %d children\n"), nelm); |
752 |
+ grub_printf_ (N_("VDEV with %d children\n"), nelm); |
753 |
print_state (nvlist, tab); |
754 |
for (i = 0; i < nelm; i++) |
755 |
{ |
756 |
@@ -162,14 +172,14 @@ print_vdev_info (char *nvlist, int tab) |
757 |
total element number. And the number itself is fine, |
758 |
only the element isn't. |
759 |
*/ |
760 |
- grub_printf_ (N_("Mirror element number %d isn't correct\n"), i); |
761 |
+ grub_printf_ (N_("VDEV element number %d isn't correct\n"), i); |
762 |
continue; |
763 |
} |
764 |
|
765 |
/* TRANSLATORS: it's the element carying the number %d, not |
766 |
total element number. This is used in enumeration |
767 |
"Element number 1", "Element number 2", ... */ |
768 |
- grub_printf_ (N_("Mirror element number %d:\n"), i); |
769 |
+ grub_printf_ (N_("VDEV element number %d:\n"), i); |
770 |
print_vdev_info (child, tab + 1); |
771 |
|
772 |
grub_free (child); |
773 |
diff --git a/include/grub/zfs/dmu.h b/include/grub/zfs/dmu.h |
774 |
index 8fc6dc5..4ad616c 100644 |
775 |
--- include/grub/zfs/dmu.h |
776 |
+++ include/grub/zfs/dmu.h |
777 |
@@ -22,6 +22,39 @@ |
778 |
|
779 |
#ifndef _SYS_DMU_H |
780 |
#define _SYS_DMU_H |
781 |
+#define B_FALSE 0 |
782 |
+#define B_TRUE 1 |
783 |
+ |
784 |
+#define DMU_OT_NEWTYPE 0x80 |
785 |
+#define DMU_OT_METADATA 0x40 |
786 |
+#define DMU_OT_BYTESWAP_MASK 0x3f |
787 |
+ |
788 |
+#define DMU_OT(byteswap, metadata) \ |
789 |
+ (DMU_OT_NEWTYPE | \ |
790 |
+ ((metadata) ? DMU_OT_METADATA : 0) | \ |
791 |
+ ((byteswap) & DMU_OT_BYTESWAP_MASK)) |
792 |
+ |
793 |
+#define DMU_OT_IS_VALID(ot) (((ot) & DMU_OT_NEWTYPE) ? \ |
794 |
+ ((ot) & DMU_OT_BYTESWAP_MASK) < DMU_BSWAP_NUMFUNCS : \ |
795 |
+ (ot) < DMU_OT_NUMTYPES) |
796 |
+ |
797 |
+#define DMU_OT_IS_METADATA(ot) (((ot) & DMU_OT_NEWTYPE) ? \ |
798 |
+ ((ot) & DMU_OT_METADATA) : \ |
799 |
+ dmu_ot[(ot)].ot_metadata) |
800 |
+ |
801 |
+typedef enum dmu_object_byteswap { |
802 |
+ DMU_BSWAP_UINT8, |
803 |
+ DMU_BSWAP_UINT16, |
804 |
+ DMU_BSWAP_UINT32, |
805 |
+ DMU_BSWAP_UINT64, |
806 |
+ DMU_BSWAP_ZAP, |
807 |
+ DMU_BSWAP_DNODE, |
808 |
+ DMU_BSWAP_OBJSET, |
809 |
+ DMU_BSWAP_ZNODE, |
810 |
+ DMU_BSWAP_OLDACL, |
811 |
+ DMU_BSWAP_ACL, |
812 |
+ DMU_BSWAP_NUMFUNCS |
813 |
+} dmu_object_byteswap_t; |
814 |
|
815 |
/* |
816 |
* This file describes the interface that the DMU provides for its |
817 |
@@ -89,7 +122,17 @@ typedef enum dmu_object_type { |
818 |
DMU_OT_SA_ATTR_REGISTRATION, /* ZAP */ |
819 |
DMU_OT_SA_ATTR_LAYOUTS, /* ZAP */ |
820 |
DMU_OT_DSL_KEYCHAIN = 54, |
821 |
- DMU_OT_NUMTYPES |
822 |
+ DMU_OT_NUMTYPES, |
823 |
+ DMU_OTN_UINT8_DATA = DMU_OT(DMU_BSWAP_UINT8, B_FALSE), |
824 |
+ DMU_OTN_UINT8_METADATA = DMU_OT(DMU_BSWAP_UINT8, B_TRUE), |
825 |
+ DMU_OTN_UINT16_DATA = DMU_OT(DMU_BSWAP_UINT16, B_FALSE), |
826 |
+ DMU_OTN_UINT16_METADATA = DMU_OT(DMU_BSWAP_UINT16, B_TRUE), |
827 |
+ DMU_OTN_UINT32_DATA = DMU_OT(DMU_BSWAP_UINT32, B_FALSE), |
828 |
+ DMU_OTN_UINT32_METADATA = DMU_OT(DMU_BSWAP_UINT32, B_TRUE), |
829 |
+ DMU_OTN_UINT64_DATA = DMU_OT(DMU_BSWAP_UINT64, B_FALSE), |
830 |
+ DMU_OTN_UINT64_METADATA = DMU_OT(DMU_BSWAP_UINT64, B_TRUE), |
831 |
+ DMU_OTN_ZAP_DATA = DMU_OT(DMU_BSWAP_ZAP, B_FALSE), |
832 |
+ DMU_OTN_ZAP_METADATA = DMU_OT(DMU_BSWAP_ZAP, B_TRUE), |
833 |
} dmu_object_type_t; |
834 |
|
835 |
typedef enum dmu_objset_type { |
836 |
@@ -116,5 +159,6 @@ typedef enum dmu_objset_type { |
837 |
#define DMU_POOL_HISTORY "history" |
838 |
#define DMU_POOL_PROPS "pool_props" |
839 |
#define DMU_POOL_L2CACHE "l2cache" |
840 |
+#define DMU_POOL_FEATURES_FOR_READ "features_for_read" |
841 |
|
842 |
#endif /* _SYS_DMU_H */ |
843 |
diff --git a/include/grub/zfs/zfs.h b/include/grub/zfs/zfs.h |
844 |
index e326c8b..761ade7 100644 |
845 |
--- include/grub/zfs/zfs.h |
846 |
+++ include/grub/zfs/zfs.h |
847 |
@@ -36,8 +36,13 @@ typedef enum grub_zfs_endian |
848 |
/* |
849 |
* On-disk version number. |
850 |
*/ |
851 |
-#define SPA_VERSION 33ULL |
852 |
- |
853 |
+#define SPA_VERSION_INITIAL 1ULL |
854 |
+#define SPA_VERSION_BEFORE_FEATURES 33ULL |
855 |
+#define SPA_VERSION 5000ULL |
856 |
+#define SPA_VERSION_FEATURES 5000ULL |
857 |
+#define SPA_VERSION_IS_SUPPORTED(v) \ |
858 |
+ (((v) >= SPA_VERSION_INITIAL && (v) <= SPA_VERSION_BEFORE_FEATURES) || \ |
859 |
+ ((v) >= SPA_VERSION_FEATURES && (v) <= SPA_VERSION)) |
860 |
/* |
861 |
* The following are configuration names used in the nvlist describing a pool's |
862 |
* configuration. |
863 |
@@ -76,6 +81,7 @@ typedef enum grub_zfs_endian |
864 |
#define ZPOOL_CONFIG_DDT_HISTOGRAM "ddt_histogram" |
865 |
#define ZPOOL_CONFIG_DDT_OBJ_STATS "ddt_object_stats" |
866 |
#define ZPOOL_CONFIG_DDT_STATS "ddt_stats" |
867 |
+#define ZPOOL_CONFIG_FEATURES_FOR_READ "features_for_read" |
868 |
/* |
869 |
* The persistent vdev state is stored as separate values rather than a single |
870 |
* 'vdev_state' entry. This is because a device can be in multiple states, such |
871 |
diff --git a/include/grub/zfs/zio.h b/include/grub/zfs/zio.h |
872 |
index b1c46da..8fad2cc 100644 |
873 |
--- include/grub/zfs/zio.h |
874 |
+++ include/grub/zfs/zio.h |
875 |
@@ -88,6 +88,7 @@ enum zio_compress { |
876 |
ZIO_COMPRESS_GZIP8, |
877 |
ZIO_COMPRESS_GZIP9, |
878 |
ZIO_COMPRESS_ZLE, |
879 |
+ ZIO_COMPRESS_LZ4, |
880 |
ZIO_COMPRESS_FUNCTIONS |
881 |
}; |
882 |
|
883 |
diff --git a/po/POTFILES.in b/po/POTFILES.in |
884 |
index 987b37a..c55d9e3 100644 |
885 |
--- po/POTFILES.in |
886 |
+++ po/POTFILES.in |
887 |
@@ -173,6 +173,7 @@ |
888 |
./grub-core/fs/zfs/zfs_fletcher.c |
889 |
./grub-core/fs/zfs/zfsinfo.c |
890 |
./grub-core/fs/zfs/zfs_lzjb.c |
891 |
+./grub-core/fs/zfs/zfs_lz4.c |
892 |
./grub-core/fs/zfs/zfs_sha256.c |
893 |
./grub-core/gdb/cstub.c |
894 |
./grub-core/gdb/gdb.c |