Lines 1-8
Link Here
|
1 |
/* |
1 |
/* |
2 |
* GRUB -- GRand Unified Bootloader |
2 |
* GRUB -- GRand Unified Bootloader |
3 |
* Copyright (C) 1999,2000,2001,2002,2003,2004,2009,2010,2011 Free Software Foundation, Inc. |
3 |
* Copyright (C) 1999,2000,2001,2002,2003,2004,2009,2010,2011 Free Software Foundation, Inc. |
4 |
* Copyright 2010 Sun Microsystems, Inc. |
4 |
* Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. |
5 |
* Copyright (c) 2012 by Delphix. All rights reserved. |
5 |
* Copyright (c) 2012 by Delphix. All rights reserved. |
|
|
6 |
* Copyright (c) 2013 by Saso Kiselkov. All rights reserved. |
7 |
* Copyright (c) 2015 by Toomas Soome. |
6 |
* |
8 |
* |
7 |
* GRUB is free software; you can redistribute it and/or modify |
9 |
* GRUB is free software; you can redistribute it and/or modify |
8 |
* it under the terms of the GNU General Public License as published by |
10 |
* it under the terms of the GNU General Public License as published by |
Lines 18-33
Link Here
|
18 |
* along with GRUB. If not, see <http://www.gnu.org/licenses/>. |
20 |
* along with GRUB. If not, see <http://www.gnu.org/licenses/>. |
19 |
*/ |
21 |
*/ |
20 |
/* |
22 |
/* |
21 |
* The zfs plug-in routines for GRUB are: |
23 |
* This file and its contents are supplied under the terms of the |
22 |
* |
24 |
* Common Development and Distribution License ("CDDL"), version 1.0. |
23 |
* zfs_mount() - locates a valid uberblock of the root pool and reads |
25 |
* You may only use this file in accordance with the terms of version |
24 |
* in its MOS at the memory address MOS. |
26 |
* 1.0 of the CDDL. |
25 |
* |
|
|
26 |
* zfs_open() - locates a plain file object by following the MOS |
27 |
* and places its dnode at the memory address DNODE. |
28 |
* |
29 |
* zfs_read() - read in the data blocks pointed by the DNODE. |
30 |
* |
27 |
* |
|
|
28 |
* A full copy of the text of the CDDL should have accompanied this |
29 |
* source. A copy of the CDDL is also available via the Internet at |
30 |
* http://www.illumos.org/license/CDDL. |
31 |
*/ |
31 |
*/ |
32 |
|
32 |
|
33 |
#include <grub/err.h> |
33 |
#include <grub/err.h> |
Lines 59-64
Link Here
|
59 |
GRUB_MOD_LICENSE ("GPLv3+"); |
59 |
GRUB_MOD_LICENSE ("GPLv3+"); |
60 |
|
60 |
|
61 |
#define ZPOOL_PROP_BOOTFS "bootfs" |
61 |
#define ZPOOL_PROP_BOOTFS "bootfs" |
|
|
62 |
#define BOOTFSNAME_SIZE 256 |
62 |
|
63 |
|
63 |
/* |
64 |
/* |
64 |
* For nvlist manipulation. (from nvpair.h) |
65 |
* For nvlist manipulation. (from nvpair.h) |
Lines 76-82
Link Here
|
76 |
static grub_dl_t my_mod; |
77 |
static grub_dl_t my_mod; |
77 |
#endif |
78 |
#endif |
78 |
|
79 |
|
|
|
80 |
#define P2ALIGN_TYPED(x, align, type) ((type)(x) & -(type)(align)) |
79 |
#define P2PHASE(x, align) ((x) & ((align) - 1)) |
81 |
#define P2PHASE(x, align) ((x) & ((align) - 1)) |
|
|
82 |
#define P2ROUNDUP(x, align) (-(-(x) & -(align))) |
83 |
#ifndef NBBY |
84 |
#define NBBY 8 |
85 |
#endif |
86 |
|
87 |
static grub_err_t vdev_disk_read_rootlabel(grub_device_t, char **); |
88 |
static grub_err_t vdev_attach(struct grub_zfs_data *, grub_device_t, char *, |
89 |
char *, int); |
80 |
|
90 |
|
81 |
static inline grub_disk_addr_t |
91 |
static inline grub_disk_addr_t |
82 |
DVA_OFFSET_TO_PHYS_SECTOR (grub_disk_addr_t offset) |
92 |
DVA_OFFSET_TO_PHYS_SECTOR (grub_disk_addr_t offset) |
Lines 158-164
Link Here
|
158 |
*/ |
168 |
*/ |
159 |
|
169 |
|
160 |
extern grub_err_t lzjb_decompress (void *, void *, grub_size_t, grub_size_t); |
170 |
extern grub_err_t lzjb_decompress (void *, void *, grub_size_t, grub_size_t); |
161 |
|
|
|
162 |
extern grub_err_t lz4_decompress (void *, void *, grub_size_t, grub_size_t); |
171 |
extern grub_err_t lz4_decompress (void *, void *, grub_size_t, grub_size_t); |
163 |
|
172 |
|
164 |
typedef grub_err_t zfs_decomp_func_t (void *s_start, void *d_start, |
173 |
typedef grub_err_t zfs_decomp_func_t (void *s_start, void *d_start, |
Lines 179-188
Link Here
|
179 |
* Information about each checksum function. |
188 |
* Information about each checksum function. |
180 |
*/ |
189 |
*/ |
181 |
typedef struct zio_checksum_info { |
190 |
typedef struct zio_checksum_info { |
182 |
zio_checksum_t *ci_func; /* checksum function for each byteorder */ |
191 |
zio_checksum_t *ci_func; /* checksum function for each byteorder */ |
183 |
int ci_correctable; /* number of correctable bits */ |
192 |
int ci_correctable; /* number of correctable bits */ |
184 |
int ci_eck; /* uses zio embedded checksum? */ |
193 |
int ci_eck; /* uses zio embedded checksum? */ |
185 |
const char *ci_name; /* descriptive name */ |
194 |
const char *ci_name; /* descriptive name */ |
186 |
} zio_checksum_info_t; |
195 |
} zio_checksum_info_t; |
187 |
|
196 |
|
188 |
typedef struct dnode_end |
197 |
typedef struct dnode_end |
Lines 194-203
Link Here
|
194 |
struct grub_zfs_device_desc |
203 |
struct grub_zfs_device_desc |
195 |
{ |
204 |
{ |
196 |
enum { DEVICE_LEAF, DEVICE_MIRROR, DEVICE_RAIDZ } type; |
205 |
enum { DEVICE_LEAF, DEVICE_MIRROR, DEVICE_RAIDZ } type; |
|
|
206 |
enum { DEVICE_OK, DEVICE_ERROR } dev_state; |
197 |
grub_uint64_t id; |
207 |
grub_uint64_t id; |
198 |
grub_uint64_t guid; |
208 |
grub_uint64_t guid; |
199 |
unsigned ashift; |
209 |
grub_uint64_t txg; /* label transaction group */ |
200 |
unsigned max_children_ashift; |
210 |
char *config; /* nvlist from label */ |
201 |
|
211 |
|
202 |
/* Valid only for non-leafs. */ |
212 |
/* Valid only for non-leafs. */ |
203 |
unsigned n_children; |
213 |
unsigned n_children; |
Lines 206-216
Link Here
|
206 |
/* Valid only for RAIDZ. */ |
216 |
/* Valid only for RAIDZ. */ |
207 |
unsigned nparity; |
217 |
unsigned nparity; |
208 |
|
218 |
|
|
|
219 |
/* Valid for all */ |
220 |
unsigned ashift; |
221 |
|
209 |
/* Valid only for leaf devices. */ |
222 |
/* Valid only for leaf devices. */ |
|
|
223 |
struct grub_zfs_device_desc *top_vdev; |
210 |
grub_device_t dev; |
224 |
grub_device_t dev; |
211 |
grub_disk_addr_t vdev_phys_sector; |
225 |
char *dev_name; |
|
|
226 |
int original; /* we dont close original */ |
212 |
uberblock_t current_uberblock; |
227 |
uberblock_t current_uberblock; |
213 |
int original; |
|
|
214 |
}; |
228 |
}; |
215 |
|
229 |
|
216 |
struct subvolume |
230 |
struct subvolume |
Lines 229-234
Link Here
|
229 |
|
243 |
|
230 |
struct grub_zfs_data |
244 |
struct grub_zfs_data |
231 |
{ |
245 |
{ |
|
|
246 |
int zcached; /* the value should be zero if no cache available */ |
247 |
|
232 |
/* cache for a file block of the currently zfs_open()-ed file */ |
248 |
/* cache for a file block of the currently zfs_open()-ed file */ |
233 |
char *file_buf; |
249 |
char *file_buf; |
234 |
grub_uint64_t file_start; |
250 |
grub_uint64_t file_start; |
Lines 248-261
Link Here
|
248 |
struct grub_zfs_device_desc *devices_attached; |
264 |
struct grub_zfs_device_desc *devices_attached; |
249 |
unsigned n_devices_attached; |
265 |
unsigned n_devices_attached; |
250 |
unsigned n_devices_allocated; |
266 |
unsigned n_devices_allocated; |
251 |
struct grub_zfs_device_desc *device_original; |
|
|
252 |
|
267 |
|
253 |
uberblock_t current_uberblock; |
268 |
uberblock_t current_uberblock; |
254 |
|
269 |
|
255 |
int mounted; |
270 |
int mounted; |
256 |
grub_uint64_t guid; |
271 |
|
|
|
272 |
grub_uint64_t guid; /* pool guid */ |
273 |
grub_uint64_t state; /* pool state */ |
274 |
char *label; /* pool label name */ |
257 |
}; |
275 |
}; |
258 |
|
276 |
|
|
|
277 |
typedef struct mirror_child |
278 |
{ |
279 |
struct grub_zfs_device_desc *mc_vd; |
280 |
grub_uint64_t mc_offset; |
281 |
int mc_error; |
282 |
grub_uint8_t mc_tried; |
283 |
grub_uint8_t mc_skipped; |
284 |
grub_uint8_t mc_speculative; |
285 |
} mirror_child_t; |
286 |
|
287 |
typedef struct mirror_map |
288 |
{ |
289 |
void *mm_buf; |
290 |
grub_size_t mm_size; |
291 |
grub_uint64_t mm_offset; |
292 |
int mm_children; |
293 |
int mm_replacing; |
294 |
int mm_preferred; |
295 |
int mm_root; |
296 |
mirror_child_t mm_child[1]; |
297 |
} mirror_map_t; |
298 |
|
299 |
/* |
300 |
* The following are taken straight from usr/src/uts/common/fs/zfs/vdev_raidz.c |
301 |
* If they change there, they need to be changed here. |
302 |
* |
303 |
* a map of columns returned for a given offset and size |
304 |
*/ |
305 |
typedef struct raidz_col |
306 |
{ |
307 |
grub_uint64_t rc_devidx; /* child device index for I/O */ |
308 |
grub_uint64_t rc_offset; /* device offset */ |
309 |
grub_uint64_t rc_size; /* I/O size */ |
310 |
void *rc_data; /* I/O data */ |
311 |
void *rc_gdata; /* used to store the "good" version */ |
312 |
int rc_error; /* I/O error for this device */ |
313 |
grub_uint8_t rc_tried; /* Did we attempt this I/O column? */ |
314 |
grub_uint8_t rc_skipped; /* Did we skip this I/O column? */ |
315 |
} raidz_col_t; |
316 |
|
317 |
typedef struct raidz_map |
318 |
{ |
319 |
grub_uint64_t rm_cols; /* Regular column count */ |
320 |
grub_uint64_t rm_scols; /* Count including skipped columns */ |
321 |
grub_uint64_t rm_bigcols; /* Number of oversized columns */ |
322 |
grub_uint64_t rm_asize; /* Actual total I/O size */ |
323 |
grub_uint64_t rm_missingdata; /* Count of missing data devices */ |
324 |
grub_uint64_t rm_missingparity; /* Count of missing parity devices */ |
325 |
grub_uint64_t rm_firstdatacol; /* First data column/parity count */ |
326 |
grub_uint64_t rm_nskip; /* Skipped sectors for padding */ |
327 |
grub_uint64_t rm_skipstart; /* Column index of padding start */ |
328 |
void *rm_datacopy; /* rm_asize-buffer of copied data */ |
329 |
grub_addr_t rm_reports; /* # of referencing checksum reports */ |
330 |
grub_uint8_t rm_freed; /* map no longer has referencing ZIO */ |
331 |
grub_uint8_t rm_ecksuminjected; /* checksum error was injected */ |
332 |
raidz_col_t rm_col[1]; /* Flexible array of I/O columns */ |
333 |
} raidz_map_t; |
334 |
|
335 |
#define VDEV_RAIDZ_P 0 |
336 |
#define VDEV_RAIDZ_Q 1 |
337 |
#define VDEV_RAIDZ_R 2 |
338 |
/* |
339 |
#define VDEV_RAIDZ_MUL_2(x) (((x) << 1) ^ (((x) & 0x80) ? 0x1d : 0)) |
340 |
#define VDEV_RAIDZ_MUL_4(x) (VDEV_RAIDZ_MUL_2(VDEV_RAIDZ_MUL_2(x))) |
341 |
*/ |
342 |
#define VDEV_RAIDZ_64MUL_2(x, mask) \ |
343 |
{ \ |
344 |
(mask) = (x) & 0x8080808080808080ULL; \ |
345 |
(mask) = ((mask) << 1) - ((mask) >> 7); \ |
346 |
(x) = (((x) << 1) & 0xfefefefefefefefeULL) ^ \ |
347 |
((mask) & 0x1d1d1d1d1d1d1d1dULL); \ |
348 |
} |
349 |
|
350 |
#define VDEV_RAIDZ_64MUL_4(x, mask) \ |
351 |
{ \ |
352 |
VDEV_RAIDZ_64MUL_2((x), mask); \ |
353 |
VDEV_RAIDZ_64MUL_2((x), mask); \ |
354 |
} |
355 |
|
356 |
/* cache list for ZFS mount */ |
357 |
struct zfs_mount_cache |
358 |
{ |
359 |
char *zcache_pool_name; |
360 |
grub_uint64_t zcache_pool_guid; |
361 |
struct grub_zfs_data *zcache_zfs_data; |
362 |
struct zfs_mount_cache *next; |
363 |
} *zfs_mount_cache_list; |
364 |
|
365 |
/* cache list for non-zfs disk dev */ |
366 |
struct zfs_dev_notzfs |
367 |
{ |
368 |
char *dev_name; |
369 |
unsigned long dev_id; |
370 |
struct zfs_dev_notzfs *next; |
371 |
} *zfs_dev_notzfs_list; |
372 |
|
259 |
/* Context for grub_zfs_dir. */ |
373 |
/* Context for grub_zfs_dir. */ |
260 |
struct grub_zfs_dir_ctx |
374 |
struct grub_zfs_dir_ctx |
261 |
{ |
375 |
{ |
Lines 279-305
Link Here
|
279 |
* read. Note that features that are only required for write do not need |
393 |
* read. Note that features that are only required for write do not need |
280 |
* to be listed here since grub opens pools in read-only mode. |
394 |
* to be listed here since grub opens pools in read-only mode. |
281 |
*/ |
395 |
*/ |
282 |
#define MAX_SUPPORTED_FEATURE_STRLEN 50 |
|
|
283 |
static const char *spa_feature_names[] = { |
396 |
static const char *spa_feature_names[] = { |
284 |
"org.illumos:lz4_compress",NULL |
397 |
"org.illumos:lz4_compress", |
|
|
398 |
"com.delphix:hole_birth", |
399 |
"com.delphix:extensible_dataset", |
400 |
"com.delphix:embedded_data", |
401 |
"org.open-zfs:large_blocks", |
402 |
NULL |
285 |
}; |
403 |
}; |
286 |
|
404 |
|
287 |
static int |
|
|
288 |
check_feature(const char *name, grub_uint64_t val, struct grub_zfs_dir_ctx *ctx); |
289 |
static int |
290 |
check_mos_features(dnode_phys_t *mosmdn_phys,grub_zfs_endian_t endian,struct grub_zfs_data* data ); |
291 |
|
292 |
static grub_err_t |
405 |
static grub_err_t |
293 |
zlib_decompress (void *s, void *d, |
406 |
zlib_decompress (void *s, void *d, |
294 |
grub_size_t slen, grub_size_t dlen) |
407 |
grub_size_t slen, grub_size_t dlen) |
295 |
{ |
408 |
{ |
296 |
if (grub_zlib_decompress (s, slen, 0, d, dlen) == (grub_ssize_t) dlen) |
409 |
if (grub_zlib_decompress (s, slen, 0, d, dlen) < 0) |
297 |
return GRUB_ERR_NONE; |
410 |
return grub_errno; |
298 |
|
411 |
return GRUB_ERR_NONE; |
299 |
if (!grub_errno) |
|
|
300 |
grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, |
301 |
"premature end of compressed"); |
302 |
return grub_errno; |
303 |
} |
412 |
} |
304 |
|
413 |
|
305 |
static grub_err_t |
414 |
static grub_err_t |
Lines 356-361
Link Here
|
356 |
|
465 |
|
357 |
static grub_err_t zio_read_data (blkptr_t * bp, grub_zfs_endian_t endian, |
466 |
static grub_err_t zio_read_data (blkptr_t * bp, grub_zfs_endian_t endian, |
358 |
void *buf, struct grub_zfs_data *data); |
467 |
void *buf, struct grub_zfs_data *data); |
|
|
468 |
static grub_err_t zio_read_common (blkptr_t * bp, dva_t *dva, |
469 |
grub_zfs_endian_t endian, void *buf, |
470 |
struct grub_zfs_data *data); |
471 |
static const char * nvlist_next_nvpair (const char *nvl, const char *nvpair); |
472 |
static char *nvpair_name (const char *nvp); |
473 |
static grub_err_t scan_devices (struct grub_zfs_data *, char *, grub_device_t); |
359 |
|
474 |
|
360 |
/* |
475 |
/* |
361 |
* Our own version of log2(). Same thing as highbit()-1. |
476 |
* Our own version of log2(). Same thing as highbit()-1. |
Lines 371-377
Link Here
|
371 |
num = num >> 1; |
486 |
num = num >> 1; |
372 |
} |
487 |
} |
373 |
|
488 |
|
374 |
return i; |
489 |
return (i); |
375 |
} |
490 |
} |
376 |
|
491 |
|
377 |
/* Checksum Functions */ |
492 |
/* Checksum Functions */ |
Lines 391-401
Link Here
|
391 |
{zio_checksum_off, 0, 0, "off"}, |
506 |
{zio_checksum_off, 0, 0, "off"}, |
392 |
{zio_checksum_SHA256, 1, 1, "label"}, |
507 |
{zio_checksum_SHA256, 1, 1, "label"}, |
393 |
{zio_checksum_SHA256, 1, 1, "gang_header"}, |
508 |
{zio_checksum_SHA256, 1, 1, "gang_header"}, |
394 |
{NULL, 0, 0, "zilog"}, |
509 |
{fletcher_2, 0, 1, "zilog"}, |
395 |
{fletcher_2, 0, 0, "fletcher2"}, |
510 |
{fletcher_2, 0, 0, "fletcher2"}, |
396 |
{fletcher_4, 1, 0, "fletcher4"}, |
511 |
{fletcher_4, 1, 0, "fletcher4"}, |
397 |
{zio_checksum_SHA256, 1, 0, "SHA256"}, |
512 |
{zio_checksum_SHA256, 1, 0, "SHA256"}, |
398 |
{NULL, 0, 0, "zilog2"}, |
513 |
{fletcher_4, 0, 1, "zilog2"}, |
399 |
{zio_checksum_SHA256, 1, 0, "SHA256+MAC"}, |
514 |
{zio_checksum_SHA256, 1, 0, "SHA256+MAC"}, |
400 |
}; |
515 |
}; |
401 |
|
516 |
|
Lines 418-424
Link Here
|
418 |
{ |
533 |
{ |
419 |
grub_dprintf ("zfs", "unknown checksum function %d\n", checksum); |
534 |
grub_dprintf ("zfs", "unknown checksum function %d\n", checksum); |
420 |
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, |
535 |
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, |
421 |
"unknown checksum function %d", checksum); |
536 |
N_("unknown checksum function %d"), checksum); |
422 |
} |
537 |
} |
423 |
|
538 |
|
424 |
if (ci->ci_eck) |
539 |
if (ci->ci_eck) |
Lines 479-497
Link Here
|
479 |
|
594 |
|
480 |
if (grub_zfs_to_cpu64 (ub1->ub_txg, ub1_endian) |
595 |
if (grub_zfs_to_cpu64 (ub1->ub_txg, ub1_endian) |
481 |
< grub_zfs_to_cpu64 (ub2->ub_txg, ub2_endian)) |
596 |
< grub_zfs_to_cpu64 (ub2->ub_txg, ub2_endian)) |
482 |
return -1; |
597 |
return (1); |
483 |
if (grub_zfs_to_cpu64 (ub1->ub_txg, ub1_endian) |
598 |
if (grub_zfs_to_cpu64 (ub1->ub_txg, ub1_endian) |
484 |
> grub_zfs_to_cpu64 (ub2->ub_txg, ub2_endian)) |
599 |
> grub_zfs_to_cpu64 (ub2->ub_txg, ub2_endian)) |
485 |
return 1; |
600 |
return (-1); |
486 |
|
601 |
|
487 |
if (grub_zfs_to_cpu64 (ub1->ub_timestamp, ub1_endian) |
602 |
if (grub_zfs_to_cpu64 (ub1->ub_timestamp, ub1_endian) |
488 |
< grub_zfs_to_cpu64 (ub2->ub_timestamp, ub2_endian)) |
603 |
< grub_zfs_to_cpu64 (ub2->ub_timestamp, ub2_endian)) |
489 |
return -1; |
604 |
return (1); |
490 |
if (grub_zfs_to_cpu64 (ub1->ub_timestamp, ub1_endian) |
605 |
if (grub_zfs_to_cpu64 (ub1->ub_timestamp, ub1_endian) |
491 |
> grub_zfs_to_cpu64 (ub2->ub_timestamp, ub2_endian)) |
606 |
> grub_zfs_to_cpu64 (ub2->ub_timestamp, ub2_endian)) |
492 |
return 1; |
607 |
return (-1); |
493 |
|
608 |
|
494 |
return 0; |
609 |
return (0); |
495 |
} |
610 |
} |
496 |
|
611 |
|
497 |
/* |
612 |
/* |
Lines 502-511
Link Here
|
502 |
* |
617 |
* |
503 |
*/ |
618 |
*/ |
504 |
static grub_err_t |
619 |
static grub_err_t |
505 |
uberblock_verify (uberblock_phys_t * ub, grub_uint64_t offset, |
620 |
uberblock_verify (uberblock_t *uber, grub_uint64_t offset, int ashift) |
506 |
grub_size_t s) |
|
|
507 |
{ |
621 |
{ |
508 |
uberblock_t *uber = &ub->ubp_uberblock; |
|
|
509 |
grub_err_t err; |
622 |
grub_err_t err; |
510 |
grub_zfs_endian_t endian = GRUB_ZFS_UNKNOWN_ENDIAN; |
623 |
grub_zfs_endian_t endian = GRUB_ZFS_UNKNOWN_ENDIAN; |
511 |
zio_cksum_t zc; |
624 |
zio_cksum_t zc; |
Lines 520-1835
Link Here
|
520 |
endian = GRUB_ZFS_BIG_ENDIAN; |
633 |
endian = GRUB_ZFS_BIG_ENDIAN; |
521 |
|
634 |
|
522 |
if (endian == GRUB_ZFS_UNKNOWN_ENDIAN) |
635 |
if (endian == GRUB_ZFS_UNKNOWN_ENDIAN) |
523 |
return grub_error (GRUB_ERR_BAD_FS, "invalid uberblock magic"); |
636 |
return grub_error (GRUB_ERR_BAD_FS, N_("invalid uberblock magic")); |
524 |
|
637 |
|
525 |
grub_memset (&zc, 0, sizeof (zc)); |
638 |
grub_memset (&zc, 0, sizeof (zc)); |
526 |
|
639 |
|
527 |
zc.zc_word[0] = grub_cpu_to_zfs64 (offset, endian); |
640 |
zc.zc_word[0] = grub_cpu_to_zfs64 (offset, endian); |
528 |
err = zio_checksum_verify (zc, ZIO_CHECKSUM_LABEL, endian, |
641 |
err = zio_checksum_verify (zc, ZIO_CHECKSUM_LABEL, endian, |
529 |
(char *) ub, s); |
642 |
(char *) uber, VDEV_UBERBLOCK_SIZE(ashift)); |
530 |
|
643 |
|
531 |
return err; |
644 |
return err; |
532 |
} |
645 |
} |
533 |
|
646 |
|
534 |
/* |
647 |
/* |
535 |
* Find the best uberblock. |
648 |
* Check if this vdev is online and is in a good state. |
536 |
* Return: |
|
|
537 |
* Success - Pointer to the best uberblock. |
538 |
* Failure - NULL |
539 |
*/ |
649 |
*/ |
540 |
static uberblock_phys_t * |
650 |
int |
541 |
find_bestub (uberblock_phys_t * ub_array, |
651 |
grub_zfs_vdev_validate (const char *nv) |
542 |
const struct grub_zfs_device_desc *desc) |
|
|
543 |
{ |
652 |
{ |
544 |
uberblock_phys_t *ubbest = NULL, *ubptr; |
653 |
grub_uint64_t ival = 0; |
545 |
int i; |
|
|
546 |
grub_disk_addr_t offset; |
547 |
grub_err_t err = GRUB_ERR_NONE; |
548 |
int ub_shift; |
549 |
|
550 |
ub_shift = desc->ashift; |
551 |
if (ub_shift < VDEV_UBERBLOCK_SHIFT) |
552 |
ub_shift = VDEV_UBERBLOCK_SHIFT; |
553 |
|
654 |
|
554 |
for (i = 0; i < (VDEV_UBERBLOCK_RING >> ub_shift); i++) |
655 |
if (grub_zfs_nvlist_lookup_uint64 (nv, ZPOOL_CONFIG_OFFLINE, &ival) && ival) |
|
|
656 |
{ |
657 |
grub_dprintf ("zfs", "vdev_validate: ZPOOL_CONFIG_OFFLINE\n"); |
658 |
return (1); |
659 |
} |
660 |
if ((grub_zfs_nvlist_lookup_uint64 (nv, ZPOOL_CONFIG_FAULTED, &ival) && ival) && |
661 |
!(grub_zfs_nvlist_lookup_uint64 (nv, ZPOOL_CONFIG_DEGRADED, &ival) && ival)) |
662 |
{ |
663 |
grub_dprintf ("zfs", "vdev_validate: ZPOOL_CONFIG_FAULTED\n"); |
664 |
return (1); |
665 |
} |
666 |
if (grub_zfs_nvlist_lookup_uint64 (nv, ZPOOL_CONFIG_REMOVED, &ival) && ival) |
555 |
{ |
667 |
{ |
556 |
offset = (desc->vdev_phys_sector << SPA_MINBLOCKSHIFT) + VDEV_PHYS_SIZE |
668 |
grub_dprintf ("zfs", "vdev_validate: ZPOOL_CONFIG_REMOVED\n"); |
557 |
+ (i << ub_shift); |
669 |
return (1); |
558 |
|
670 |
|
559 |
ubptr = (uberblock_phys_t *) ((grub_properly_aligned_t *) ub_array |
|
|
560 |
+ ((i << ub_shift) |
561 |
/ sizeof (grub_properly_aligned_t))); |
562 |
err = uberblock_verify (ubptr, offset, 1 << ub_shift); |
563 |
if (err) |
564 |
{ |
565 |
grub_errno = GRUB_ERR_NONE; |
566 |
continue; |
567 |
} |
568 |
if (ubbest == NULL |
569 |
|| vdev_uberblock_compare (&(ubptr->ubp_uberblock), |
570 |
&(ubbest->ubp_uberblock)) > 0) |
571 |
ubbest = ubptr; |
572 |
} |
671 |
} |
573 |
if (!ubbest) |
|
|
574 |
grub_errno = err; |
575 |
|
672 |
|
576 |
return ubbest; |
673 |
return (0); |
577 |
} |
674 |
} |
578 |
|
675 |
|
579 |
static inline grub_size_t |
676 |
static int |
580 |
get_psize (blkptr_t * bp, grub_zfs_endian_t endian) |
677 |
check_feature(const char *name, grub_uint64_t val, |
|
|
678 |
struct grub_zfs_dir_ctx *ctx __attribute__((unused))) |
581 |
{ |
679 |
{ |
582 |
return ((((grub_zfs_to_cpu64 ((bp)->blk_prop, endian) >> 16) & 0xffff) + 1) |
680 |
int i; |
583 |
<< SPA_MINBLOCKSHIFT); |
|
|
584 |
} |
585 |
|
681 |
|
586 |
static grub_uint64_t |
682 |
if (val == 0) /* value is not set */ |
587 |
dva_get_offset (const dva_t *dva, grub_zfs_endian_t endian) |
683 |
return (0); |
588 |
{ |
684 |
if(name[0] == 0) /* empty name */ |
589 |
grub_dprintf ("zfs", "dva=%llx, %llx\n", |
685 |
return (0); |
590 |
(unsigned long long) dva->dva_word[0], |
686 |
|
591 |
(unsigned long long) dva->dva_word[1]); |
687 |
for (i = 0; spa_feature_names[i] != NULL; i++ ) |
592 |
return grub_zfs_to_cpu64 ((dva)->dva_word[1], |
688 |
if (grub_strcmp(name, spa_feature_names[i]) == 0) |
593 |
endian) << SPA_MINBLOCKSHIFT; |
689 |
{ |
|
|
690 |
grub_dprintf ("zfs", "check_feature: %s ok\n", name); |
691 |
return (0); |
692 |
} |
693 |
return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET, "unknown feature: %s", name); |
594 |
} |
694 |
} |
595 |
|
695 |
|
596 |
static grub_err_t |
696 |
struct scan_devices_ctx { |
597 |
zfs_fetch_nvlist (struct grub_zfs_device_desc *diskdesc, char **nvlist) |
697 |
struct grub_zfs_data *data; |
|
|
698 |
char *name; |
699 |
grub_device_t dev; |
700 |
int missing_vdev; |
701 |
int missing_children; |
702 |
}; |
703 |
|
704 |
static int |
705 |
scan_devices_iter(const char *name, void *hook_data) |
598 |
{ |
706 |
{ |
|
|
707 |
struct scan_devices_ctx *ctx = hook_data; |
708 |
struct grub_zfs_data *data = ctx->data; |
709 |
struct zfs_dev_notzfs *dev_notzfs; |
710 |
grub_device_t dev; |
711 |
grub_uint64_t u; |
712 |
unsigned i, j; |
713 |
int original = 0; |
714 |
char *dev_name; |
715 |
char *config; |
599 |
grub_err_t err; |
716 |
grub_err_t err; |
600 |
|
717 |
|
601 |
*nvlist = 0; |
718 |
grub_dprintf("zfs", "scan_devices: %s\n", name); |
602 |
|
|
|
603 |
if (!diskdesc->dev) |
604 |
return grub_error (GRUB_ERR_BUG, "member drive unknown"); |
605 |
|
719 |
|
606 |
*nvlist = grub_malloc (VDEV_PHYS_SIZE); |
720 |
/* scan our config first */ |
607 |
|
721 |
ctx->missing_vdev = data->n_devices_allocated - data->n_devices_attached; |
608 |
/* Read in the vdev name-value pair list (112K). */ |
722 |
ctx->missing_children = 0; |
609 |
err = grub_disk_read (diskdesc->dev->disk, diskdesc->vdev_phys_sector, 0, |
723 |
for (i = 0; i<data->n_devices_allocated; i++) |
610 |
VDEV_PHYS_SIZE, *nvlist); |
|
|
611 |
if (err) |
612 |
{ |
724 |
{ |
613 |
grub_free (*nvlist); |
725 |
if (data->devices_attached[i].guid == 0) /* not attached */ |
614 |
*nvlist = 0; |
726 |
continue; |
615 |
return err; |
|
|
616 |
} |
617 |
return GRUB_ERR_NONE; |
618 |
} |
619 |
|
620 |
static grub_err_t |
621 |
fill_vdev_info_real (struct grub_zfs_data *data, |
622 |
const char *nvlist, |
623 |
struct grub_zfs_device_desc *fill, |
624 |
struct grub_zfs_device_desc *insert, |
625 |
int *inserted, |
626 |
unsigned ashift) |
627 |
{ |
628 |
char *type; |
629 |
|
630 |
type = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_TYPE); |
631 |
|
632 |
if (!type) |
633 |
return grub_errno; |
634 |
|
727 |
|
635 |
if (!grub_zfs_nvlist_lookup_uint64 (nvlist, "id", &(fill->id))) |
728 |
for (j = 0; j < data->devices_attached[i].n_children; j++) |
636 |
{ |
729 |
{ |
637 |
grub_free (type); |
730 |
if (data->devices_attached[i].children[j].guid == 0) |
638 |
return grub_error (GRUB_ERR_BAD_FS, "couldn't find vdev id"); |
731 |
ctx->missing_children++; |
|
|
732 |
} |
639 |
} |
733 |
} |
640 |
|
734 |
|
641 |
if (!grub_zfs_nvlist_lookup_uint64 (nvlist, "guid", &(fill->guid))) |
735 |
if (ctx->missing_vdev == 0 && ctx->missing_children == 0) |
642 |
{ |
736 |
{ |
643 |
grub_free (type); |
737 |
/* nothing to do */ |
644 |
return grub_error (GRUB_ERR_BAD_FS, "couldn't find vdev id"); |
738 |
return 1; |
645 |
} |
739 |
} |
646 |
|
740 |
|
647 |
{ |
741 |
for (dev_notzfs = zfs_dev_notzfs_list; |
648 |
grub_uint64_t par; |
742 |
dev_notzfs != NULL; dev_notzfs = dev_notzfs->next) |
649 |
if (grub_zfs_nvlist_lookup_uint64 (nvlist, "ashift", &par)) |
743 |
if (grub_strcmp(name, dev_notzfs->dev_name) == 0) |
650 |
fill->ashift = par; |
|
|
651 |
else if (ashift != 0xffffffff) |
652 |
fill->ashift = ashift; |
653 |
else |
654 |
{ |
744 |
{ |
655 |
grub_free (type); |
745 |
grub_dprintf("zfs", "scan_devices_iter: found cached non-zfs " |
656 |
return grub_error (GRUB_ERR_BAD_FS, "couldn't find ashift"); |
746 |
"disk dev: %s\n", dev_notzfs->dev_name); |
|
|
747 |
return 0; |
657 |
} |
748 |
} |
658 |
} |
|
|
659 |
|
749 |
|
660 |
fill->max_children_ashift = 0; |
750 |
if (grub_strcmp(name, ctx->name) == 0) |
661 |
|
751 |
|
662 |
if (grub_strcmp (type, VDEV_TYPE_DISK) == 0 |
|
|
663 |
|| grub_strcmp (type, VDEV_TYPE_FILE) == 0) |
664 |
{ |
752 |
{ |
665 |
fill->type = DEVICE_LEAF; |
753 |
dev = ctx->dev; |
|
|
754 |
dev_name = ctx->name; |
755 |
original = 1; |
756 |
} |
757 |
else |
758 |
{ |
759 |
dev = grub_device_open (name); |
760 |
if (!dev) |
761 |
return 0; |
762 |
if (!dev->disk) |
666 |
|
763 |
|
667 |
if (!fill->dev && fill->guid == insert->guid) |
|
|
668 |
{ |
764 |
{ |
669 |
fill->dev = insert->dev; |
765 |
grub_device_close (dev); |
670 |
fill->vdev_phys_sector = insert->vdev_phys_sector; |
766 |
return 0; |
671 |
fill->current_uberblock = insert->current_uberblock; |
|
|
672 |
fill->original = insert->original; |
673 |
if (!data->device_original) |
674 |
data->device_original = fill; |
675 |
insert->ashift = fill->ashift; |
676 |
*inserted = 1; |
677 |
} |
767 |
} |
|
|
768 |
dev_name = grub_strdup(name); |
678 |
|
769 |
|
679 |
grub_free (type); |
|
|
680 |
|
770 |
|
681 |
return GRUB_ERR_NONE; |
|
|
682 |
} |
771 |
} |
683 |
|
772 |
|
684 |
if (grub_strcmp (type, VDEV_TYPE_MIRROR) == 0 |
773 |
if ((err = vdev_disk_read_rootlabel (dev, &config)) != GRUB_ERR_NONE) |
685 |
|| grub_strcmp (type, VDEV_TYPE_RAIDZ) == 0) |
|
|
686 |
{ |
774 |
{ |
687 |
int nelm, i; |
775 |
dev_notzfs = grub_malloc(sizeof (struct zfs_dev_notzfs)); |
|
|
776 |
if (dev_notzfs) |
688 |
|
777 |
|
689 |
if (grub_strcmp (type, VDEV_TYPE_MIRROR) == 0) |
|
|
690 |
fill->type = DEVICE_MIRROR; |
691 |
else |
692 |
{ |
778 |
{ |
693 |
grub_uint64_t par; |
779 |
dev_notzfs->dev_name = grub_strdup(name); |
694 |
fill->type = DEVICE_RAIDZ; |
780 |
dev_notzfs->dev_id = dev->disk->id; |
695 |
if (!grub_zfs_nvlist_lookup_uint64 (nvlist, "nparity", &par)) |
781 |
if (zfs_dev_notzfs_list) |
696 |
{ |
782 |
dev_notzfs->next = zfs_dev_notzfs_list; |
697 |
grub_free (type); |
783 |
else |
698 |
return grub_error (GRUB_ERR_BAD_FS, "couldn't find raidz parity"); |
784 |
dev_notzfs->next = NULL; |
699 |
} |
785 |
zfs_dev_notzfs_list = dev_notzfs; |
700 |
fill->nparity = par; |
|
|
701 |
} |
786 |
} |
|
|
787 |
if (!original) |
702 |
|
788 |
|
703 |
nelm = grub_zfs_nvlist_lookup_nvlist_array_get_nelm (nvlist, |
|
|
704 |
ZPOOL_CONFIG_CHILDREN); |
705 |
|
706 |
if (nelm <= 0) |
707 |
{ |
789 |
{ |
708 |
grub_free (type); |
790 |
grub_device_close (dev); |
709 |
return grub_error (GRUB_ERR_BAD_FS, "incorrect mirror VDEV"); |
791 |
grub_free (dev_name); |
710 |
} |
792 |
} |
|
|
793 |
return 0; |
794 |
} |
711 |
|
795 |
|
712 |
if (!fill->children) |
796 |
u = 0; |
|
|
797 |
if (grub_zfs_nvlist_lookup_uint64 (config, ZPOOL_CONFIG_POOL_GUID, &u) |
798 |
&& data->guid != u) |
799 |
{ |
800 |
grub_free (config); |
801 |
if (!original) |
713 |
{ |
802 |
{ |
714 |
fill->n_children = nelm; |
803 |
grub_device_close (dev); |
715 |
|
804 |
grub_free (dev_name); |
716 |
fill->children = grub_zalloc (fill->n_children |
|
|
717 |
* sizeof (fill->children[0])); |
718 |
} |
805 |
} |
719 |
|
806 |
|
720 |
for (i = 0; i < nelm; i++) |
807 |
return 0; |
721 |
{ |
808 |
} |
722 |
char *child; |
|
|
723 |
grub_err_t err; |
724 |
|
809 |
|
725 |
child = grub_zfs_nvlist_lookup_nvlist_array |
810 |
grub_dprintf ("zfs", "disk from our pool: %s\n", name); |
726 |
(nvlist, ZPOOL_CONFIG_CHILDREN, i); |
|
|
727 |
|
811 |
|
728 |
err = fill_vdev_info_real (data, child, &fill->children[i], insert, |
812 |
err = vdev_attach(data, dev, config, dev_name, original); |
729 |
inserted, fill->ashift); |
813 |
grub_free (config); |
730 |
|
814 |
|
731 |
grub_free (child); |
815 |
/* check the vdev tree again */ |
|
|
816 |
ctx->missing_vdev = data->n_devices_allocated - data->n_devices_attached; |
817 |
ctx->missing_children = 0; |
818 |
for (i = 0; i<data->n_devices_allocated; i++) |
819 |
{ |
820 |
if (data->devices_attached[i].guid == 0) /* not attached */ |
821 |
continue; |
732 |
|
822 |
|
733 |
if (err) |
823 |
for (j = 0; j < data->devices_attached[i].n_children; j++) |
734 |
{ |
824 |
{ |
735 |
grub_free (type); |
825 |
if (data->devices_attached[i].children[j].guid == 0) |
736 |
return err; |
826 |
ctx->missing_children++; |
737 |
} |
|
|
738 |
if (fill->children[i].ashift > fill->max_children_ashift) |
739 |
fill->max_children_ashift = fill->children[i].ashift; |
740 |
} |
827 |
} |
741 |
grub_free (type); |
|
|
742 |
return GRUB_ERR_NONE; |
743 |
} |
828 |
} |
744 |
|
829 |
|
745 |
grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "vdev %s isn't supported", type); |
830 |
if (ctx->missing_vdev == 0 && ctx->missing_children == 0) |
746 |
grub_free (type); |
831 |
{ |
747 |
return grub_errno; |
832 |
/* done */ |
|
|
833 |
return 1; |
834 |
} |
835 |
|
836 |
return 0; |
748 |
} |
837 |
} |
749 |
|
838 |
|
|
|
839 |
/* |
840 |
* we iterate over all disks grub_device_iterate() will provide, till |
841 |
* we have filled all vdevs and children. |
842 |
*/ |
750 |
static grub_err_t |
843 |
static grub_err_t |
751 |
fill_vdev_info (struct grub_zfs_data *data, |
844 |
scan_devices (struct grub_zfs_data *data, char *name, grub_device_t dev) |
752 |
char *nvlist, struct grub_zfs_device_desc *diskdesc, |
|
|
753 |
int *inserted) |
754 |
{ |
845 |
{ |
755 |
grub_uint64_t id; |
846 |
struct scan_devices_ctx ctx; |
756 |
unsigned i; |
|
|
757 |
|
847 |
|
758 |
*inserted = 0; |
848 |
ctx.data = data; |
|
|
849 |
ctx.name = name; /* disk name from zfs_mount() caller */ |
850 |
ctx.dev = dev; /* disk device from zfs_mount() caller */ |
851 |
ctx.missing_vdev = 0; |
852 |
ctx.missing_children = 0; |
759 |
|
853 |
|
760 |
if (!grub_zfs_nvlist_lookup_uint64 (nvlist, "id", &id)) |
854 |
grub_device_iterate (scan_devices_iter, (void *) &ctx); |
761 |
return grub_error (GRUB_ERR_BAD_FS, "couldn't find vdev id"); |
|
|
762 |
|
855 |
|
763 |
for (i = 0; i < data->n_devices_attached; i++) |
856 |
/* scan is done, fix device states in vdevs */ |
764 |
if (data->devices_attached[i].id == id) |
|
|
765 |
return fill_vdev_info_real (data, nvlist, &data->devices_attached[i], |
766 |
diskdesc, inserted, 0xffffffff); |
767 |
|
768 |
data->n_devices_attached++; |
769 |
if (data->n_devices_attached > data->n_devices_allocated) |
770 |
{ |
771 |
void *tmp; |
772 |
data->n_devices_allocated = 2 * data->n_devices_attached + 1; |
773 |
data->devices_attached |
774 |
= grub_realloc (tmp = data->devices_attached, |
775 |
data->n_devices_allocated |
776 |
* sizeof (data->devices_attached[0])); |
777 |
if (!data->devices_attached) |
778 |
{ |
779 |
data->devices_attached = tmp; |
780 |
return grub_errno; |
781 |
} |
782 |
} |
783 |
|
857 |
|
784 |
grub_memset (&data->devices_attached[data->n_devices_attached - 1], |
858 |
if (ctx.missing_vdev != 0 || ctx.missing_children != 0) |
785 |
0, sizeof (data->devices_attached[data->n_devices_attached - 1])); |
859 |
{ |
|
|
860 |
return GRUB_ERR_BAD_FS; |
861 |
} |
786 |
|
862 |
|
787 |
return fill_vdev_info_real (data, nvlist, |
863 |
return GRUB_ERR_NONE; |
788 |
&data->devices_attached[data->n_devices_attached - 1], |
|
|
789 |
diskdesc, inserted, 0xffffffff); |
790 |
} |
864 |
} |
791 |
|
865 |
|
|
|
866 |
/* Powers of 2 in the Galois field. */ |
867 |
static const grub_uint8_t vdev_raidz_pow2[256] = { |
868 |
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, |
869 |
0x1d, 0x3a, 0x74, 0xe8, 0xcd, 0x87, 0x13, 0x26, |
870 |
0x4c, 0x98, 0x2d, 0x5a, 0xb4, 0x75, 0xea, 0xc9, |
871 |
0x8f, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, |
872 |
0x9d, 0x27, 0x4e, 0x9c, 0x25, 0x4a, 0x94, 0x35, |
873 |
0x6a, 0xd4, 0xb5, 0x77, 0xee, 0xc1, 0x9f, 0x23, |
874 |
0x46, 0x8c, 0x05, 0x0a, 0x14, 0x28, 0x50, 0xa0, |
875 |
0x5d, 0xba, 0x69, 0xd2, 0xb9, 0x6f, 0xde, 0xa1, |
876 |
0x5f, 0xbe, 0x61, 0xc2, 0x99, 0x2f, 0x5e, 0xbc, |
877 |
0x65, 0xca, 0x89, 0x0f, 0x1e, 0x3c, 0x78, 0xf0, |
878 |
0xfd, 0xe7, 0xd3, 0xbb, 0x6b, 0xd6, 0xb1, 0x7f, |
879 |
0xfe, 0xe1, 0xdf, 0xa3, 0x5b, 0xb6, 0x71, 0xe2, |
880 |
0xd9, 0xaf, 0x43, 0x86, 0x11, 0x22, 0x44, 0x88, |
881 |
0x0d, 0x1a, 0x34, 0x68, 0xd0, 0xbd, 0x67, 0xce, |
882 |
0x81, 0x1f, 0x3e, 0x7c, 0xf8, 0xed, 0xc7, 0x93, |
883 |
0x3b, 0x76, 0xec, 0xc5, 0x97, 0x33, 0x66, 0xcc, |
884 |
0x85, 0x17, 0x2e, 0x5c, 0xb8, 0x6d, 0xda, 0xa9, |
885 |
0x4f, 0x9e, 0x21, 0x42, 0x84, 0x15, 0x2a, 0x54, |
886 |
0xa8, 0x4d, 0x9a, 0x29, 0x52, 0xa4, 0x55, 0xaa, |
887 |
0x49, 0x92, 0x39, 0x72, 0xe4, 0xd5, 0xb7, 0x73, |
888 |
0xe6, 0xd1, 0xbf, 0x63, 0xc6, 0x91, 0x3f, 0x7e, |
889 |
0xfc, 0xe5, 0xd7, 0xb3, 0x7b, 0xf6, 0xf1, 0xff, |
890 |
0xe3, 0xdb, 0xab, 0x4b, 0x96, 0x31, 0x62, 0xc4, |
891 |
0x95, 0x37, 0x6e, 0xdc, 0xa5, 0x57, 0xae, 0x41, |
892 |
0x82, 0x19, 0x32, 0x64, 0xc8, 0x8d, 0x07, 0x0e, |
893 |
0x1c, 0x38, 0x70, 0xe0, 0xdd, 0xa7, 0x53, 0xa6, |
894 |
0x51, 0xa2, 0x59, 0xb2, 0x79, 0xf2, 0xf9, 0xef, |
895 |
0xc3, 0x9b, 0x2b, 0x56, 0xac, 0x45, 0x8a, 0x09, |
896 |
0x12, 0x24, 0x48, 0x90, 0x3d, 0x7a, 0xf4, 0xf5, |
897 |
0xf7, 0xf3, 0xfb, 0xeb, 0xcb, 0x8b, 0x0b, 0x16, |
898 |
0x2c, 0x58, 0xb0, 0x7d, 0xfa, 0xe9, 0xcf, 0x83, |
899 |
0x1b, 0x36, 0x6c, 0xd8, 0xad, 0x47, 0x8e, 0x01 |
900 |
}; |
901 |
|
902 |
/* Logs of 2 in the Galois field. */ |
903 |
static const grub_uint8_t vdev_raidz_log2[256] = { |
904 |
0x00, 0x00, 0x01, 0x19, 0x02, 0x32, 0x1a, 0xc6, |
905 |
0x03, 0xdf, 0x33, 0xee, 0x1b, 0x68, 0xc7, 0x4b, |
906 |
0x04, 0x64, 0xe0, 0x0e, 0x34, 0x8d, 0xef, 0x81, |
907 |
0x1c, 0xc1, 0x69, 0xf8, 0xc8, 0x08, 0x4c, 0x71, |
908 |
0x05, 0x8a, 0x65, 0x2f, 0xe1, 0x24, 0x0f, 0x21, |
909 |
0x35, 0x93, 0x8e, 0xda, 0xf0, 0x12, 0x82, 0x45, |
910 |
0x1d, 0xb5, 0xc2, 0x7d, 0x6a, 0x27, 0xf9, 0xb9, |
911 |
0xc9, 0x9a, 0x09, 0x78, 0x4d, 0xe4, 0x72, 0xa6, |
912 |
0x06, 0xbf, 0x8b, 0x62, 0x66, 0xdd, 0x30, 0xfd, |
913 |
0xe2, 0x98, 0x25, 0xb3, 0x10, 0x91, 0x22, 0x88, |
914 |
0x36, 0xd0, 0x94, 0xce, 0x8f, 0x96, 0xdb, 0xbd, |
915 |
0xf1, 0xd2, 0x13, 0x5c, 0x83, 0x38, 0x46, 0x40, |
916 |
0x1e, 0x42, 0xb6, 0xa3, 0xc3, 0x48, 0x7e, 0x6e, |
917 |
0x6b, 0x3a, 0x28, 0x54, 0xfa, 0x85, 0xba, 0x3d, |
918 |
0xca, 0x5e, 0x9b, 0x9f, 0x0a, 0x15, 0x79, 0x2b, |
919 |
0x4e, 0xd4, 0xe5, 0xac, 0x73, 0xf3, 0xa7, 0x57, |
920 |
0x07, 0x70, 0xc0, 0xf7, 0x8c, 0x80, 0x63, 0x0d, |
921 |
0x67, 0x4a, 0xde, 0xed, 0x31, 0xc5, 0xfe, 0x18, |
922 |
0xe3, 0xa5, 0x99, 0x77, 0x26, 0xb8, 0xb4, 0x7c, |
923 |
0x11, 0x44, 0x92, 0xd9, 0x23, 0x20, 0x89, 0x2e, |
924 |
0x37, 0x3f, 0xd1, 0x5b, 0x95, 0xbc, 0xcf, 0xcd, |
925 |
0x90, 0x87, 0x97, 0xb2, 0xdc, 0xfc, 0xbe, 0x61, |
926 |
0xf2, 0x56, 0xd3, 0xab, 0x14, 0x2a, 0x5d, 0x9e, |
927 |
0x84, 0x3c, 0x39, 0x53, 0x47, 0x6d, 0x41, 0xa2, |
928 |
0x1f, 0x2d, 0x43, 0xd8, 0xb7, 0x7b, 0xa4, 0x76, |
929 |
0xc4, 0x17, 0x49, 0xec, 0x7f, 0x0c, 0x6f, 0xf6, |
930 |
0x6c, 0xa1, 0x3b, 0x52, 0x29, 0x9d, 0x55, 0xaa, |
931 |
0xfb, 0x60, 0x86, 0xb1, 0xbb, 0xcc, 0x3e, 0x5a, |
932 |
0xcb, 0x59, 0x5f, 0xb0, 0x9c, 0xa9, 0xa0, 0x51, |
933 |
0x0b, 0xf5, 0x16, 0xeb, 0x7a, 0x75, 0x2c, 0xd7, |
934 |
0x4f, 0xae, 0xd5, 0xe9, 0xe6, 0xe7, 0xad, 0xe8, |
935 |
0x74, 0xd6, 0xf4, 0xea, 0xa8, 0x50, 0x58, 0xaf, |
936 |
}; |
937 |
|
792 |
/* |
938 |
/* |
793 |
* For a given XDR packed nvlist, verify the first 4 bytes and move on. |
939 |
* Multiply a given number by 2 raised to the given power. |
794 |
* |
|
|
795 |
* An XDR packed nvlist is encoded as (comments from nvs_xdr_create) : |
796 |
* |
797 |
* encoding method/host endian (4 bytes) |
798 |
* nvl_version (4 bytes) |
799 |
* nvl_nvflag (4 bytes) |
800 |
* encoded nvpairs: |
801 |
* encoded size of the nvpair (4 bytes) |
802 |
* decoded size of the nvpair (4 bytes) |
803 |
* name string size (4 bytes) |
804 |
* name string data (sizeof(NV_ALIGN4(string)) |
805 |
* data type (4 bytes) |
806 |
* # of elements in the nvpair (4 bytes) |
807 |
* data |
808 |
* 2 zero's for the last nvpair |
809 |
* (end of the entire list) (8 bytes) |
810 |
* |
811 |
*/ |
940 |
*/ |
|
|
941 |
static grub_uint8_t |
942 |
vdev_raidz_exp2(unsigned a, int exp) |
943 |
{ |
944 |
if (a == 0) |
945 |
return (0); |
946 |
|
947 |
exp += vdev_raidz_log2[a]; |
948 |
if (exp > 255) |
949 |
exp -= 255; |
950 |
|
951 |
return (vdev_raidz_pow2[exp]); |
952 |
} |
812 |
|
953 |
|
813 |
/* |
954 |
/* |
814 |
* The nvlist_next_nvpair() function returns a handle to the next nvpair in the |
955 |
* vdev_raidz_map_get() is hacked from vdev_raidz_map_alloc() in |
815 |
* list following nvpair. If nvpair is NULL, the first pair is returned. If |
956 |
* usr/src/uts/common/fs/zfs/vdev_raidz.c. If that routine changes, |
816 |
* nvpair is the last pair in the nvlist, NULL is returned. |
957 |
* this might also need changing. |
817 |
*/ |
958 |
*/ |
818 |
static const char * |
|
|
819 |
nvlist_next_nvpair (const char *nvl, const char *nvpair) |
820 |
{ |
821 |
const char *nvp; |
822 |
int encode_size; |
823 |
int name_len; |
824 |
if (nvl == NULL) |
825 |
return NULL; |
826 |
|
959 |
|
827 |
if (nvpair == NULL) |
960 |
#ifndef MIN |
828 |
{ |
961 |
#define MIN(a, b) ((a) < (b) ? (a) : (b)) |
829 |
/* skip over header, nvl_version and nvl_nvflag */ |
962 |
#endif |
830 |
nvpair = nvl + 4 * 3; |
963 |
#ifndef roundup |
831 |
} |
964 |
#define roundup(x, y) (grub_divmod64 ( (x)+((y)-1), (y), NULL) *(y)) |
832 |
else |
965 |
#endif |
|
|
966 |
#ifndef offsetof |
967 |
#define offsetof(s, m) ((grub_size_t)(&(((s *)0)->m))) |
968 |
#endif |
969 |
|
970 |
static raidz_map_t * |
971 |
vdev_raidz_map_alloc(void *data, grub_uint64_t size, grub_uint64_t offset, |
972 |
grub_uint64_t unit_shift, grub_uint64_t dcols, |
973 |
grub_uint64_t nparity) |
974 |
{ |
975 |
raidz_map_t *rm; |
976 |
grub_uint64_t b = offset >> unit_shift; |
977 |
grub_uint64_t s = size >> unit_shift; |
978 |
grub_uint64_t f, o, q, r, c, bc, col, acols, scols, coff, devidx, asize, tot; |
979 |
|
980 |
o = grub_divmod64(b, dcols, NULL) << unit_shift; |
981 |
(void) grub_divmod64(b, dcols, &f); |
982 |
q = grub_divmod64(s, dcols - nparity, NULL); |
983 |
r = s - q * (dcols - nparity); |
984 |
bc = (r == 0 ? 0 : r + nparity); |
985 |
tot = s + nparity * (q + (r == 0 ? 0 : 1)); |
986 |
|
987 |
if (q == 0) |
833 |
{ |
988 |
{ |
834 |
/* skip to the next nvpair */ |
989 |
acols = bc; |
835 |
encode_size = grub_be_to_cpu32 (grub_get_unaligned32(nvpair)); |
990 |
scols = MIN(dcols, roundup(bc, nparity + 1)); |
836 |
nvpair += encode_size; |
|
|
837 |
/*If encode_size equals 0 nvlist_next_nvpair would return |
838 |
* the same pair received in input, leading to an infinite loop. |
839 |
* If encode_size is less than 0, this will move the pointer |
840 |
* backwards, *possibly* examinining two times the same nvpair |
841 |
* and potentially getting into an infinite loop. */ |
842 |
if(encode_size <= 0) |
843 |
{ |
844 |
grub_dprintf ("zfs", "nvpair with size <= 0\n"); |
845 |
grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist"); |
846 |
return NULL; |
847 |
} |
848 |
} |
991 |
} |
849 |
/* 8 bytes of 0 marks the end of the list */ |
992 |
else |
850 |
if (grub_get_unaligned64 (nvpair) == 0) |
|
|
851 |
return NULL; |
852 |
/*consistency checks*/ |
853 |
if (nvpair + 4 * 3 >= nvl + VDEV_PHYS_SIZE) |
854 |
{ |
993 |
{ |
855 |
grub_dprintf ("zfs", "nvlist overflow\n"); |
994 |
acols = dcols; |
856 |
grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist"); |
995 |
scols = dcols; |
857 |
return NULL; |
|
|
858 |
} |
996 |
} |
859 |
encode_size = grub_be_to_cpu32 (grub_get_unaligned32(nvpair)); |
|
|
860 |
|
997 |
|
861 |
nvp = nvpair + 4*2; |
998 |
rm = grub_malloc(offsetof(raidz_map_t, rm_col[scols])); |
862 |
name_len = grub_be_to_cpu32 (grub_get_unaligned32 (nvp)); |
|
|
863 |
nvp += 4; |
864 |
|
999 |
|
865 |
nvp = nvp + ((name_len + 3) & ~3); // align |
1000 |
if (rm == NULL) |
866 |
if (nvp + 4 >= nvl + VDEV_PHYS_SIZE |
|
|
867 |
|| encode_size < 0 |
868 |
|| nvp + 4 + encode_size > nvl + VDEV_PHYS_SIZE) |
869 |
{ |
1001 |
{ |
870 |
grub_dprintf ("zfs", "nvlist overflow\n"); |
|
|
871 |
grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist"); |
872 |
return NULL; |
1002 |
return NULL; |
873 |
} |
1003 |
} |
874 |
/* end consistency checks */ |
|
|
875 |
|
1004 |
|
876 |
return nvpair; |
1005 |
rm->rm_cols = acols; |
877 |
} |
1006 |
rm->rm_scols = scols; |
|
|
1007 |
rm->rm_bigcols = bc; |
1008 |
rm->rm_skipstart = bc; |
1009 |
rm->rm_missingdata = 0; |
1010 |
rm->rm_missingparity = 0; |
1011 |
rm->rm_firstdatacol = nparity; |
1012 |
rm->rm_datacopy = NULL; |
1013 |
rm->rm_reports = 0; |
1014 |
rm->rm_freed = 0; |
1015 |
rm->rm_ecksuminjected = 0; |
1016 |
|
1017 |
asize = 0; |
1018 |
|
1019 |
for (c = 0; c < scols; c++) |
1020 |
{ |
1021 |
col = f + c; |
1022 |
coff = o; |
1023 |
if (col >= dcols) |
1024 |
{ |
1025 |
col -= dcols; |
1026 |
coff += 1ULL << unit_shift; |
1027 |
} |
1028 |
rm->rm_col[c].rc_devidx = col; |
1029 |
rm->rm_col[c].rc_offset = coff; |
1030 |
rm->rm_col[c].rc_data = NULL; |
1031 |
rm->rm_col[c].rc_gdata = NULL; |
1032 |
rm->rm_col[c].rc_error = 0; |
1033 |
rm->rm_col[c].rc_tried = 0; |
1034 |
rm->rm_col[c].rc_skipped = 0; |
1035 |
|
1036 |
if (c >= acols) |
1037 |
rm->rm_col[c].rc_size = 0; |
1038 |
else if (c < bc) |
1039 |
rm->rm_col[c].rc_size = (q + 1) << unit_shift; |
1040 |
else |
1041 |
rm->rm_col[c].rc_size = q << unit_shift; |
878 |
|
1042 |
|
879 |
/* |
1043 |
asize += rm->rm_col[c].rc_size; |
880 |
* This function returns 0 on success and 1 on failure. On success, a string |
1044 |
} |
881 |
* containing the name of nvpair is saved in buf. |
|
|
882 |
*/ |
883 |
static int |
884 |
nvpair_name (const char *nvp, char **buf, grub_size_t *buflen) |
885 |
{ |
886 |
/* skip over encode/decode size */ |
887 |
nvp += 4 * 2; |
888 |
|
889 |
*buf = (char *) (nvp + 4); |
890 |
*buflen = grub_be_to_cpu32 (grub_get_unaligned32 (nvp)); |
891 |
|
1045 |
|
892 |
return 0; |
1046 |
rm->rm_asize = roundup(asize, (nparity + 1) << unit_shift); |
893 |
} |
1047 |
rm->rm_nskip = roundup(tot, nparity + 1) - tot; |
894 |
|
1048 |
|
895 |
/* |
1049 |
for (c = 0; c < rm->rm_firstdatacol; c++) |
896 |
* This function retrieves the value of the nvpair in the form of enumerated |
1050 |
rm->rm_col[c].rc_data = grub_malloc (rm->rm_col[c].rc_size); |
897 |
* type data_type_t. |
|
|
898 |
*/ |
899 |
static int |
900 |
nvpair_type (const char *nvp) |
901 |
{ |
902 |
int name_len, type; |
903 |
|
1051 |
|
904 |
/* skip over encode/decode size */ |
1052 |
rm->rm_col[c].rc_data = data; |
905 |
nvp += 4 * 2; |
|
|
906 |
|
1053 |
|
907 |
/* skip over name_len */ |
1054 |
for (c = c + 1; c < acols; c++) |
908 |
name_len = grub_be_to_cpu32 (grub_get_unaligned32 (nvp)); |
1055 |
rm->rm_col[c].rc_data = (char *)rm->rm_col[c - 1].rc_data + |
909 |
nvp += 4; |
1056 |
rm->rm_col[c - 1].rc_size; |
910 |
|
1057 |
|
911 |
/* skip over name */ |
1058 |
/* |
912 |
nvp = nvp + ((name_len + 3) & ~3); /* align */ |
1059 |
* If all data stored spans all columns, there's a danger that parity |
|
|
1060 |
* will always be on the same device and, since parity isn't read |
1061 |
* during normal operation, that that device's I/O bandwidth won't be |
1062 |
* used effectively. We therefore switch the parity every 1MB. |
1063 |
* |
1064 |
* ... at least that was, ostensibly, the theory. As a practical |
1065 |
* matter unless we juggle the parity between all devices evenly, we |
1066 |
* won't see any benefit. Further, occasional writes that aren't a |
1067 |
* multiple of the LCM of the number of children and the minimum |
1068 |
* stripe width are sufficient to avoid pessimal behavior. |
1069 |
* Unfortunately, this decision created an implicit on-disk format |
1070 |
* requirement that we need to support for all eternity, but only |
1071 |
* for single-parity RAID-Z. |
1072 |
* |
1073 |
* If we intend to skip a sector in the zeroth column for padding |
1074 |
* we must make sure to note this swap. We will never intend to |
1075 |
* skip the first column since at least one data and one parity |
1076 |
* column must appear in each row. |
1077 |
*/ |
913 |
|
1078 |
|
914 |
type = grub_be_to_cpu32 (grub_get_unaligned32 (nvp)); |
1079 |
if (rm->rm_firstdatacol == 1 && (offset & (1ULL << 20))) |
|
|
1080 |
{ |
1081 |
devidx = rm->rm_col[0].rc_devidx; |
1082 |
o = rm->rm_col[0].rc_offset; |
1083 |
rm->rm_col[0].rc_devidx = rm->rm_col[1].rc_devidx; |
1084 |
rm->rm_col[0].rc_offset = rm->rm_col[1].rc_offset; |
1085 |
rm->rm_col[1].rc_devidx = devidx; |
1086 |
rm->rm_col[1].rc_offset = o; |
915 |
|
1087 |
|
916 |
return type; |
1088 |
if (rm->rm_skipstart == 0) |
|
|
1089 |
rm->rm_skipstart = 1; |
1090 |
} |
1091 |
|
1092 |
return (rm); |
917 |
} |
1093 |
} |
918 |
|
1094 |
|
919 |
static int |
1095 |
static void |
920 |
nvpair_value (const char *nvp,char **val, |
1096 |
vdev_raidz_map_free(raidz_map_t *rm) |
921 |
grub_size_t *size_out, grub_size_t *nelm_out) |
|
|
922 |
{ |
1097 |
{ |
923 |
int name_len,nelm,encode_size; |
1098 |
grub_uint64_t c; |
924 |
|
1099 |
|
925 |
/* skip over encode/decode size */ |
1100 |
for (c = 0; c < rm->rm_firstdatacol; c++) |
926 |
encode_size = grub_be_to_cpu32 (grub_get_unaligned32(nvp)); |
1101 |
{ |
927 |
nvp += 8; |
1102 |
grub_free (rm->rm_col[c].rc_data); |
928 |
|
1103 |
|
929 |
/* skip over name_len */ |
1104 |
if (rm->rm_col[c].rc_gdata != NULL) |
930 |
name_len = grub_be_to_cpu32 (grub_get_unaligned32 (nvp)); |
1105 |
grub_free (rm->rm_col[c].rc_gdata); |
931 |
nvp += 4; |
|
|
932 |
|
933 |
/* skip over name */ |
934 |
nvp = nvp + ((name_len + 3) & ~3); /* align */ |
935 |
|
936 |
/* skip over type */ |
937 |
nvp += 4; |
938 |
nelm = grub_be_to_cpu32 (grub_get_unaligned32 (nvp)); |
939 |
nvp +=4; |
940 |
if (nelm < 1) |
941 |
{ |
942 |
grub_error (GRUB_ERR_BAD_FS, "empty nvpair"); |
943 |
return 0; |
944 |
} |
1106 |
} |
945 |
*val = (char *) nvp; |
1107 |
|
946 |
*size_out = encode_size; |
1108 |
if (rm->rm_datacopy != NULL) |
947 |
if (nelm_out) |
1109 |
grub_free (rm->rm_datacopy); |
948 |
*nelm_out = nelm; |
1110 |
grub_free (rm); |
949 |
|
|
|
950 |
return 1; |
951 |
} |
1111 |
} |
952 |
|
1112 |
|
953 |
/* |
|
|
954 |
* Check the disk label information and retrieve needed vdev name-value pairs. |
955 |
* |
956 |
*/ |
957 |
static grub_err_t |
1113 |
static grub_err_t |
958 |
check_pool_label (struct grub_zfs_data *data, |
1114 |
zio_checksum_error(blkptr_t *bp, grub_zfs_endian_t endian, void *buf) |
959 |
struct grub_zfs_device_desc *diskdesc, |
|
|
960 |
int *inserted) |
961 |
{ |
1115 |
{ |
962 |
grub_uint64_t pool_state, txg = 0; |
1116 |
zio_cksum_t zc; |
963 |
char *nvlist,*features; |
1117 |
grub_uint32_t checksum; |
964 |
#if 0 |
1118 |
grub_size_t size; |
965 |
char *nv; |
1119 |
grub_uint64_t offset; |
966 |
#endif |
|
|
967 |
grub_uint64_t poolguid; |
968 |
grub_uint64_t version; |
969 |
int found; |
970 |
grub_err_t err; |
971 |
grub_zfs_endian_t endian; |
972 |
vdev_phys_t *phys; |
973 |
zio_cksum_t emptycksum; |
974 |
|
975 |
*inserted = 0; |
976 |
|
977 |
err = zfs_fetch_nvlist (diskdesc, &nvlist); |
978 |
if (err) |
979 |
return err; |
980 |
|
981 |
phys = (vdev_phys_t*) nvlist; |
982 |
if (grub_zfs_to_cpu64 (phys->vp_zbt.zec_magic, |
983 |
GRUB_ZFS_LITTLE_ENDIAN) |
984 |
== ZEC_MAGIC) |
985 |
endian = GRUB_ZFS_LITTLE_ENDIAN; |
986 |
else if (grub_zfs_to_cpu64 (phys->vp_zbt.zec_magic, |
987 |
GRUB_ZFS_BIG_ENDIAN) |
988 |
== ZEC_MAGIC) |
989 |
endian = GRUB_ZFS_BIG_ENDIAN; |
990 |
else |
991 |
{ |
992 |
grub_free (nvlist); |
993 |
return grub_error (GRUB_ERR_BAD_FS, |
994 |
"bad vdev_phys_t.vp_zbt.zec_magic number"); |
995 |
} |
996 |
/* Now check the integrity of the vdev_phys_t structure though checksum. */ |
997 |
ZIO_SET_CHECKSUM(&emptycksum, diskdesc->vdev_phys_sector << 9, 0, 0, 0); |
998 |
err = zio_checksum_verify (emptycksum, ZIO_CHECKSUM_LABEL, endian, |
999 |
nvlist, VDEV_PHYS_SIZE); |
1000 |
if (err) |
1001 |
return err; |
1002 |
|
1120 |
|
1003 |
grub_dprintf ("zfs", "check 2 passed\n"); |
1121 |
grub_memset (&zc, 0, sizeof (zc)); |
1004 |
|
1122 |
|
1005 |
found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_STATE, |
1123 |
if (BP_IS_GANG(bp, endian)) |
1006 |
&pool_state); |
|
|
1007 |
if (! found) |
1008 |
{ |
1124 |
{ |
1009 |
grub_free (nvlist); |
1125 |
dva_t *dva = BP_IDENTITY(bp); |
1010 |
if (! grub_errno) |
1126 |
grub_uint64_t txg = BP_PHYSICAL_BIRTH(bp); |
1011 |
grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_POOL_STATE " not found"); |
1127 |
checksum = ZIO_CHECKSUM_GANG_HEADER; |
1012 |
return grub_errno; |
1128 |
size = SPA_GANGBLOCKSIZE; |
|
|
1129 |
offset = DVA_GET_OFFSET (dva, endian); |
1130 |
ZIO_SET_CHECKSUM (&zc, DVA_GET_VDEV(dva), offset, txg, 0); |
1013 |
} |
1131 |
} |
1014 |
grub_dprintf ("zfs", "check 3 passed\n"); |
1132 |
else |
1015 |
|
|
|
1016 |
if (pool_state == POOL_STATE_DESTROYED) |
1017 |
{ |
1133 |
{ |
1018 |
grub_free (nvlist); |
1134 |
checksum = BP_GET_CHECKSUM(bp, endian); |
1019 |
return grub_error (GRUB_ERR_BAD_FS, "zpool is marked as destroyed"); |
1135 |
size = BP_GET_PSIZE(bp, endian); |
|
|
1136 |
zc = bp->blk_cksum; |
1020 |
} |
1137 |
} |
1021 |
grub_dprintf ("zfs", "check 4 passed\n"); |
1138 |
return zio_checksum_verify (zc, checksum, endian, buf, size); |
|
|
1139 |
} |
1022 |
|
1140 |
|
1023 |
found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_TXG, &txg); |
1141 |
static void |
1024 |
if (!found) |
1142 |
vdev_raidz_generate_parity_pq(raidz_map_t *rm) |
1025 |
{ |
1143 |
{ |
1026 |
grub_free (nvlist); |
1144 |
grub_uint64_t *p, *q, *src, pcnt, ccnt, mask, i; |
1027 |
if (! grub_errno) |
1145 |
int c; |
1028 |
grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_POOL_TXG " not found"); |
|
|
1029 |
return grub_errno; |
1030 |
} |
1031 |
grub_dprintf ("zfs", "check 6 passed\n"); |
1032 |
|
1146 |
|
1033 |
/* not an active device */ |
1147 |
pcnt = grub_divmod64(rm->rm_col[VDEV_RAIDZ_P].rc_size, sizeof (src[0]), NULL); |
1034 |
if (txg == 0) |
|
|
1035 |
{ |
1036 |
grub_free (nvlist); |
1037 |
return grub_error (GRUB_ERR_BAD_FS, "zpool isn't active"); |
1038 |
} |
1039 |
grub_dprintf ("zfs", "check 7 passed\n"); |
1040 |
|
1148 |
|
1041 |
found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_VERSION, |
1149 |
for (c = rm->rm_firstdatacol; c < (int) rm->rm_cols; c++) |
1042 |
&version); |
|
|
1043 |
if (! found) |
1044 |
{ |
1150 |
{ |
1045 |
grub_free (nvlist); |
1151 |
src = rm->rm_col[c].rc_data; |
1046 |
if (! grub_errno) |
1152 |
p = rm->rm_col[VDEV_RAIDZ_P].rc_data; |
1047 |
grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_VERSION " not found"); |
1153 |
q = rm->rm_col[VDEV_RAIDZ_Q].rc_data; |
1048 |
return grub_errno; |
|
|
1049 |
} |
1050 |
grub_dprintf ("zfs", "check 8 passed\n"); |
1051 |
|
1154 |
|
1052 |
if (!SPA_VERSION_IS_SUPPORTED(version)) |
1155 |
ccnt = grub_divmod64(rm->rm_col[c].rc_size, sizeof (src[0]), NULL); |
1053 |
{ |
|
|
1054 |
grub_free (nvlist); |
1055 |
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, |
1056 |
"too new version %llu > %llu", |
1057 |
(unsigned long long) version, |
1058 |
(unsigned long long) SPA_VERSION_BEFORE_FEATURES); |
1059 |
} |
1060 |
grub_dprintf ("zfs", "check 9 passed\n"); |
1061 |
|
1156 |
|
1062 |
found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_GUID, |
1157 |
if (c == (int) rm->rm_firstdatacol) |
1063 |
&(diskdesc->guid)); |
1158 |
{ |
1064 |
if (! found) |
1159 |
for (i = 0; i < ccnt; i++, src++, p++, q++) |
1065 |
{ |
1160 |
{ |
1066 |
grub_free (nvlist); |
1161 |
*p = *src; |
1067 |
if (! grub_errno) |
1162 |
*q = *src; |
1068 |
grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_GUID " not found"); |
1163 |
} |
1069 |
return grub_errno; |
1164 |
for (; i < pcnt; i++, src++, p++, q++) |
1070 |
} |
1165 |
{ |
|
|
1166 |
*p = 0; |
1167 |
*q = 0; |
1168 |
} |
1169 |
} |
1170 |
else |
1171 |
{ |
1172 |
for (i = 0; i < ccnt; i++, src++, p++, q++) |
1173 |
{ |
1174 |
*p ^= *src; |
1071 |
|
1175 |
|
1072 |
found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_GUID, |
1176 |
VDEV_RAIDZ_64MUL_2(*q, mask); |
1073 |
&poolguid); |
1177 |
*q ^= *src; |
1074 |
if (! found) |
1178 |
} |
1075 |
{ |
|
|
1076 |
grub_free (nvlist); |
1077 |
if (! grub_errno) |
1078 |
grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_POOL_GUID " not found"); |
1079 |
return grub_errno; |
1080 |
} |
1081 |
|
1179 |
|
1082 |
grub_dprintf ("zfs", "check 11 passed\n"); |
1180 |
/* |
|
|
1181 |
* Treat short columns as though they are full of 0s. |
1182 |
* Note that there's therefore nothing needed for P. |
1183 |
*/ |
1184 |
for (; i < pcnt; i++, q++) |
1185 |
VDEV_RAIDZ_64MUL_2(*q, mask); |
1186 |
} |
1187 |
} |
1188 |
} |
1083 |
|
1189 |
|
1084 |
if (data->mounted && data->guid != poolguid) |
1190 |
static int |
1085 |
return grub_error (GRUB_ERR_BAD_FS, "another zpool"); |
1191 |
vdev_raidz_reconstruct_p(raidz_map_t *rm, int *tgts) |
1086 |
else |
1192 |
{ |
1087 |
data->guid = poolguid; |
1193 |
grub_uint64_t *dst, *src, xcount, ccount, count, i; |
|
|
1194 |
int x = tgts[0]; |
1195 |
int c; |
1088 |
|
1196 |
|
1089 |
{ |
1197 |
xcount = grub_divmod64(rm->rm_col[x].rc_size, sizeof (src[0]), NULL); |
1090 |
char *nv; |
|
|
1091 |
nv = grub_zfs_nvlist_lookup_nvlist (nvlist, ZPOOL_CONFIG_VDEV_TREE); |
1092 |
|
1198 |
|
1093 |
if (!nv) |
1199 |
src = rm->rm_col[VDEV_RAIDZ_P].rc_data; |
1094 |
{ |
1200 |
dst = rm->rm_col[x].rc_data; |
1095 |
grub_free (nvlist); |
1201 |
for (i = 0; i < xcount; i++, dst++, src++) |
1096 |
return grub_error (GRUB_ERR_BAD_FS, "couldn't find vdev tree"); |
1202 |
*dst = *src; |
1097 |
} |
1203 |
for (c = rm->rm_firstdatacol; c < (int) rm->rm_cols; c++) |
1098 |
err = fill_vdev_info (data, nv, diskdesc, inserted); |
|
|
1099 |
if (err) |
1100 |
{ |
1101 |
grub_free (nv); |
1102 |
grub_free (nvlist); |
1103 |
return err; |
1104 |
} |
1105 |
grub_free (nv); |
1106 |
} |
1107 |
grub_dprintf ("zfs", "check 10 passed\n"); |
1108 |
features = grub_zfs_nvlist_lookup_nvlist(nvlist, |
1109 |
ZPOOL_CONFIG_FEATURES_FOR_READ); |
1110 |
if (features) |
1111 |
{ |
1204 |
{ |
1112 |
const char *nvp=NULL; |
1205 |
src = rm->rm_col[c].rc_data; |
1113 |
char name[MAX_SUPPORTED_FEATURE_STRLEN + 1]; |
1206 |
dst = rm->rm_col[x].rc_data; |
1114 |
char *nameptr; |
1207 |
if (c == x) |
1115 |
grub_size_t namelen; |
1208 |
continue; |
1116 |
while ((nvp = nvlist_next_nvpair(features, nvp)) != NULL) |
1209 |
|
1117 |
{ |
1210 |
ccount = grub_divmod64(rm->rm_col[c].rc_size, sizeof (src[0]), NULL); |
1118 |
nvpair_name (nvp, &nameptr, &namelen); |
1211 |
count = MIN(ccount, xcount); |
1119 |
if(namelen > MAX_SUPPORTED_FEATURE_STRLEN) |
1212 |
|
1120 |
namelen = MAX_SUPPORTED_FEATURE_STRLEN; |
1213 |
for (i = 0; i < count; i++, dst++, src++) |
1121 |
grub_memcpy (name, nameptr, namelen); |
1214 |
{ |
1122 |
name[namelen] = '\0'; |
1215 |
*dst ^= *src; |
1123 |
grub_dprintf("zfs","str=%s\n",name); |
|
|
1124 |
if (check_feature(name,1, NULL) != 0) |
1125 |
{ |
1126 |
grub_dprintf("zfs","feature missing in check_pool_label:%s\n",name); |
1127 |
err= grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET," check_pool_label missing feature '%s' for read",name); |
1128 |
return err; |
1129 |
} |
1130 |
} |
1216 |
} |
1131 |
} |
1217 |
} |
1132 |
grub_dprintf ("zfs", "check 12 passed (feature flags)\n"); |
|
|
1133 |
grub_free (nvlist); |
1134 |
|
1218 |
|
1135 |
return GRUB_ERR_NONE; |
1219 |
return (1 << VDEV_RAIDZ_P); |
1136 |
} |
1220 |
} |
1137 |
|
1221 |
|
1138 |
static grub_err_t |
1222 |
static int |
1139 |
scan_disk (grub_device_t dev, struct grub_zfs_data *data, |
1223 |
vdev_raidz_reconstruct_q(raidz_map_t *rm, int *tgts) |
1140 |
int original, int *inserted) |
|
|
1141 |
{ |
1224 |
{ |
1142 |
int label = 0; |
1225 |
grub_uint64_t *dst, *src, xcount, ccount, count, mask, i; |
1143 |
uberblock_phys_t *ub_array, *ubbest = NULL; |
1226 |
grub_uint8_t *b; |
1144 |
vdev_boot_header_t *bh; |
1227 |
int x = tgts[0]; |
1145 |
grub_err_t err; |
1228 |
int c, j, exp; |
1146 |
int vdevnum; |
|
|
1147 |
struct grub_zfs_device_desc desc; |
1148 |
|
1229 |
|
1149 |
ub_array = grub_malloc (VDEV_UBERBLOCK_RING); |
1230 |
xcount = grub_divmod64(rm->rm_col[x].rc_size, sizeof (src[0]), NULL); |
1150 |
if (!ub_array) |
|
|
1151 |
return grub_errno; |
1152 |
|
1231 |
|
1153 |
bh = grub_malloc (VDEV_BOOT_HEADER_SIZE); |
1232 |
for (c = rm->rm_firstdatacol; c < (int) rm->rm_cols; c++) |
1154 |
if (!bh) |
|
|
1155 |
{ |
1233 |
{ |
1156 |
grub_free (ub_array); |
1234 |
src = rm->rm_col[c].rc_data; |
1157 |
return grub_errno; |
1235 |
dst = rm->rm_col[x].rc_data; |
1158 |
} |
|
|
1159 |
|
1160 |
vdevnum = VDEV_LABELS; |
1161 |
|
1162 |
desc.dev = dev; |
1163 |
desc.original = original; |
1164 |
|
1236 |
|
1165 |
/* Don't check back labels on CDROM. */ |
1237 |
if (c == x) |
1166 |
if (grub_disk_get_size (dev->disk) == GRUB_DISK_SIZE_UNKNOWN) |
1238 |
ccount = 0; |
1167 |
vdevnum = VDEV_LABELS / 2; |
1239 |
else |
|
|
1240 |
ccount = grub_divmod64(rm->rm_col[c].rc_size, sizeof (src[0]), NULL); |
1168 |
|
1241 |
|
1169 |
for (label = 0; ubbest == NULL && label < vdevnum; label++) |
1242 |
count = MIN(ccount, xcount); |
1170 |
{ |
1243 |
if (c == (int) rm->rm_firstdatacol) |
1171 |
desc.vdev_phys_sector |
|
|
1172 |
= label * (sizeof (vdev_label_t) >> SPA_MINBLOCKSHIFT) |
1173 |
+ ((VDEV_SKIP_SIZE + VDEV_BOOT_HEADER_SIZE) >> SPA_MINBLOCKSHIFT) |
1174 |
+ (label < VDEV_LABELS / 2 ? 0 : |
1175 |
ALIGN_DOWN (grub_disk_get_size (dev->disk), sizeof (vdev_label_t)) |
1176 |
- VDEV_LABELS * (sizeof (vdev_label_t) >> SPA_MINBLOCKSHIFT)); |
1177 |
|
1178 |
/* Read in the uberblock ring (128K). */ |
1179 |
err = grub_disk_read (dev->disk, desc.vdev_phys_sector |
1180 |
+ (VDEV_PHYS_SIZE >> SPA_MINBLOCKSHIFT), |
1181 |
0, VDEV_UBERBLOCK_RING, (char *) ub_array); |
1182 |
if (err) |
1183 |
{ |
1244 |
{ |
1184 |
grub_errno = GRUB_ERR_NONE; |
1245 |
for (i = 0; i < count; i++, dst++, src++) |
1185 |
continue; |
1246 |
*dst = *src; |
1186 |
} |
|
|
1187 |
grub_dprintf ("zfs", "label ok %d\n", label); |
1188 |
|
1247 |
|
1189 |
err = check_pool_label (data, &desc, inserted); |
1248 |
for (; i < xcount; i++, dst++) |
1190 |
if (err || !*inserted) |
1249 |
*dst = 0; |
1191 |
{ |
|
|
1192 |
grub_errno = GRUB_ERR_NONE; |
1193 |
continue; |
1194 |
} |
1250 |
} |
1195 |
|
1251 |
else |
1196 |
ubbest = find_bestub (ub_array, &desc); |
|
|
1197 |
if (!ubbest) |
1198 |
{ |
1252 |
{ |
1199 |
grub_dprintf ("zfs", "No uberblock found\n"); |
1253 |
for (i = 0; i < count; i++, dst++, src++) |
1200 |
grub_errno = GRUB_ERR_NONE; |
1254 |
{ |
1201 |
continue; |
1255 |
VDEV_RAIDZ_64MUL_2(*dst, mask); |
|
|
1256 |
*dst ^= *src; |
1257 |
} |
1258 |
|
1259 |
for (; i < xcount; i++, dst++) |
1260 |
VDEV_RAIDZ_64MUL_2(*dst, mask); |
1202 |
} |
1261 |
} |
|
|
1262 |
} |
1203 |
|
1263 |
|
1204 |
grub_memmove (&(desc.current_uberblock), |
1264 |
src = rm->rm_col[VDEV_RAIDZ_Q].rc_data; |
1205 |
&ubbest->ubp_uberblock, sizeof (uberblock_t)); |
1265 |
dst = rm->rm_col[x].rc_data; |
1206 |
if (original) |
1266 |
exp = 255 - (rm->rm_cols - 1 - x); |
1207 |
grub_memmove (&(data->current_uberblock), |
|
|
1208 |
&ubbest->ubp_uberblock, sizeof (uberblock_t)); |
1209 |
|
1267 |
|
1210 |
#if 0 |
1268 |
for (i = 0; i < xcount; i++, dst++, src++) |
1211 |
if (find_best_root && |
1269 |
{ |
1212 |
vdev_uberblock_compare (&ubbest->ubp_uberblock, |
1270 |
*dst ^= *src; |
1213 |
&(current_uberblock)) <= 0) |
1271 |
for (j = 0, b = (grub_uint8_t *)dst; j < 8; j++, b++) |
1214 |
continue; |
1272 |
*b = vdev_raidz_exp2(*b, exp); |
1215 |
#endif |
|
|
1216 |
grub_free (ub_array); |
1217 |
grub_free (bh); |
1218 |
return GRUB_ERR_NONE; |
1219 |
} |
1273 |
} |
1220 |
|
|
|
1221 |
grub_free (ub_array); |
1222 |
grub_free (bh); |
1223 |
|
1274 |
|
1224 |
return grub_error (GRUB_ERR_BAD_FS, "couldn't find a valid label"); |
1275 |
return (1 << VDEV_RAIDZ_Q); |
1225 |
} |
1276 |
} |
1226 |
|
1277 |
|
1227 |
/* Helper for scan_devices. */ |
|
|
1228 |
static int |
1278 |
static int |
1229 |
scan_devices_iter (const char *name, void *hook_data) |
1279 |
vdev_raidz_reconstruct_pq(raidz_map_t *rm, int *tgts) |
1230 |
{ |
1280 |
{ |
1231 |
struct grub_zfs_data *data = hook_data; |
1281 |
grub_uint8_t *p, *q, *pxy, *qxy, *xd, *yd, tmp, a, b, aexp, bexp; |
1232 |
grub_device_t dev; |
1282 |
void *pdata, *qdata; |
1233 |
grub_err_t err; |
1283 |
grub_uint64_t xsize, ysize, i; |
1234 |
int inserted; |
1284 |
int x = tgts[0]; |
|
|
1285 |
int y = tgts[1]; |
1235 |
|
1286 |
|
1236 |
dev = grub_device_open (name); |
1287 |
/* |
1237 |
if (!dev) |
1288 |
* Move the parity data aside -- we're going to compute parity as |
1238 |
return 0; |
1289 |
* though columns x and y were full of zeros -- Pxy and Qxy. We want to |
1239 |
if (!dev->disk) |
1290 |
* reuse the parity generation mechanism without trashing the actual |
1240 |
{ |
1291 |
* parity so we make those columns appear to be full of zeros by |
1241 |
grub_device_close (dev); |
1292 |
* setting their lengths to zero. |
1242 |
return 0; |
1293 |
*/ |
1243 |
} |
1294 |
pdata = rm->rm_col[VDEV_RAIDZ_P].rc_data; |
1244 |
err = scan_disk (dev, data, 0, &inserted); |
1295 |
qdata = rm->rm_col[VDEV_RAIDZ_Q].rc_data; |
1245 |
if (err == GRUB_ERR_BAD_FS) |
1296 |
xsize = rm->rm_col[x].rc_size; |
1246 |
{ |
1297 |
ysize = rm->rm_col[y].rc_size; |
1247 |
grub_device_close (dev); |
1298 |
|
1248 |
grub_errno = GRUB_ERR_NONE; |
1299 |
rm->rm_col[VDEV_RAIDZ_P].rc_data = |
1249 |
return 0; |
1300 |
grub_malloc(rm->rm_col[VDEV_RAIDZ_P].rc_size); |
1250 |
} |
1301 |
rm->rm_col[VDEV_RAIDZ_Q].rc_data = |
1251 |
if (err) |
1302 |
grub_malloc(rm->rm_col[VDEV_RAIDZ_Q].rc_size); |
|
|
1303 |
rm->rm_col[x].rc_size = 0; |
1304 |
rm->rm_col[y].rc_size = 0; |
1305 |
|
1306 |
vdev_raidz_generate_parity_pq(rm); |
1307 |
|
1308 |
rm->rm_col[x].rc_size = xsize; |
1309 |
rm->rm_col[y].rc_size = ysize; |
1310 |
|
1311 |
p = pdata; |
1312 |
q = qdata; |
1313 |
pxy = rm->rm_col[VDEV_RAIDZ_P].rc_data; |
1314 |
qxy = rm->rm_col[VDEV_RAIDZ_Q].rc_data; |
1315 |
xd = rm->rm_col[x].rc_data; |
1316 |
yd = rm->rm_col[y].rc_data; |
1317 |
|
1318 |
/* |
1319 |
* We now have: |
1320 |
* Pxy = P + D_x + D_y |
1321 |
* Qxy = Q + 2^(ndevs - 1 - x) * D_x + 2^(ndevs - 1 - y) * D_y |
1322 |
* |
1323 |
* We can then solve for D_x: |
1324 |
* D_x = A * (P + Pxy) + B * (Q + Qxy) |
1325 |
* where |
1326 |
* A = 2^(x - y) * (2^(x - y) + 1)^-1 |
1327 |
* B = 2^(ndevs - 1 - x) * (2^(x - y) + 1)^-1 |
1328 |
* |
1329 |
* With D_x in hand, we can easily solve for D_y: |
1330 |
* D_y = P + Pxy + D_x |
1331 |
*/ |
1332 |
|
1333 |
a = vdev_raidz_pow2[255 + x - y]; |
1334 |
b = vdev_raidz_pow2[255 - (rm->rm_cols - 1 - x)]; |
1335 |
tmp = 255 - vdev_raidz_log2[a ^ 1]; |
1336 |
|
1337 |
aexp = vdev_raidz_log2[vdev_raidz_exp2(a, tmp)]; |
1338 |
bexp = vdev_raidz_log2[vdev_raidz_exp2(b, tmp)]; |
1339 |
|
1340 |
for (i = 0; i < xsize; i++, p++, q++, pxy++, qxy++, xd++, yd++) |
1252 |
{ |
1341 |
{ |
1253 |
grub_device_close (dev); |
1342 |
*xd = vdev_raidz_exp2(*p ^ *pxy, aexp) ^ vdev_raidz_exp2(*q ^ *qxy, bexp); |
1254 |
grub_print_error (); |
1343 |
|
1255 |
return 0; |
1344 |
if (i < ysize) |
|
|
1345 |
*yd = *p ^ *pxy ^ *xd; |
1256 |
} |
1346 |
} |
1257 |
|
1347 |
|
1258 |
if (!inserted) |
1348 |
grub_free(rm->rm_col[VDEV_RAIDZ_P].rc_data); |
1259 |
grub_device_close (dev); |
1349 |
grub_free(rm->rm_col[VDEV_RAIDZ_Q].rc_data); |
1260 |
|
1350 |
|
1261 |
return 0; |
1351 |
/* |
|
|
1352 |
* Restore the saved parity data. |
1353 |
*/ |
1354 |
rm->rm_col[VDEV_RAIDZ_P].rc_data = pdata; |
1355 |
rm->rm_col[VDEV_RAIDZ_Q].rc_data = qdata; |
1356 |
|
1357 |
return ((1 << VDEV_RAIDZ_P) | (1 << VDEV_RAIDZ_Q)); |
1262 |
} |
1358 |
} |
1263 |
|
1359 |
|
1264 |
static grub_err_t |
1360 |
static void |
1265 |
scan_devices (struct grub_zfs_data *data) |
1361 |
vdev_raidz_matrix_init(int n, int nmap, int *map, grub_uint8_t **rows) |
1266 |
{ |
1362 |
{ |
1267 |
grub_device_iterate (scan_devices_iter, data); |
1363 |
int i, j; |
1268 |
return GRUB_ERR_NONE; |
1364 |
int pow; |
|
|
1365 |
|
1366 |
/* |
1367 |
* Fill in the missing rows of interest. |
1368 |
*/ |
1369 |
for (i = 0; i < nmap; i++) |
1370 |
{ |
1371 |
pow = map[i] * n; |
1372 |
if (pow > 255) |
1373 |
pow -= 255; |
1374 |
|
1375 |
for (j = 0; j < n; j++) |
1376 |
{ |
1377 |
pow -= map[i]; |
1378 |
if (pow < 0) |
1379 |
pow += 255; |
1380 |
rows[i][j] = vdev_raidz_pow2[pow]; |
1381 |
} |
1382 |
} |
1269 |
} |
1383 |
} |
1270 |
|
1384 |
|
1271 |
/* x**y. */ |
1385 |
static void |
1272 |
static grub_uint8_t powx[255 * 2]; |
1386 |
vdev_raidz_matrix_invert(raidz_map_t *rm, int n, int nmissing, int *missing, |
1273 |
/* Such an s that x**s = y */ |
1387 |
grub_uint8_t **rows, grub_uint8_t **invrows, const grub_uint8_t *used) |
1274 |
static int powx_inv[256]; |
|
|
1275 |
static const grub_uint8_t poly = 0x1d; |
1276 |
|
1277 |
/* perform the operation a ^= b * (x ** (known_idx * recovery_pow) ) */ |
1278 |
static inline void |
1279 |
xor_out (grub_uint8_t *a, const grub_uint8_t *b, grub_size_t s, |
1280 |
unsigned known_idx, unsigned recovery_pow) |
1281 |
{ |
1388 |
{ |
1282 |
unsigned add; |
1389 |
int i, j, ii, jj; |
|
|
1390 |
grub_uint8_t log; |
1283 |
|
1391 |
|
1284 |
/* Simple xor. */ |
1392 |
/* |
1285 |
if (known_idx == 0 || recovery_pow == 0) |
1393 |
* First initialize the storage where we'll compute the inverse rows. |
|
|
1394 |
*/ |
1395 |
for (i = 0; i < nmissing; i++) |
1286 |
{ |
1396 |
{ |
1287 |
grub_crypto_xor (a, a, b, s); |
1397 |
for (j = 0; j < n; j++) |
1288 |
return; |
1398 |
invrows[i][j] = (i == j) ? 1 : 0; |
|
|
1399 |
} |
1400 |
|
1401 |
/* |
1402 |
* Subtract all trivial rows from the rows of consequence. |
1403 |
*/ |
1404 |
for (i = 0; i < nmissing; i++) |
1405 |
{ |
1406 |
for (j = nmissing; j < n; j++) |
1407 |
{ |
1408 |
jj = used[j] - rm->rm_firstdatacol; |
1409 |
invrows[i][j] = rows[i][jj]; |
1410 |
rows[i][jj] = 0; |
1411 |
} |
1412 |
} |
1413 |
|
1414 |
/* |
1415 |
* For each of the rows of interest, we must normalize it and subtract |
1416 |
* a multiple of it from the other rows. |
1417 |
*/ |
1418 |
for (i = 0; i < nmissing; i++) |
1419 |
{ |
1420 |
/* |
1421 |
* Compute the inverse of the first element and multiply each |
1422 |
* element in the row by that value. |
1423 |
*/ |
1424 |
log = 255 - vdev_raidz_log2[rows[i][missing[i]]]; |
1425 |
|
1426 |
for (j = 0; j < n; j++) |
1427 |
{ |
1428 |
rows[i][j] = vdev_raidz_exp2(rows[i][j], log); |
1429 |
invrows[i][j] = vdev_raidz_exp2(invrows[i][j], log); |
1430 |
} |
1431 |
|
1432 |
for (ii = 0; ii < nmissing; ii++) |
1433 |
{ |
1434 |
if (i == ii) |
1435 |
continue; |
1436 |
|
1437 |
log = vdev_raidz_log2[rows[ii][missing[i]]]; |
1438 |
|
1439 |
for (j = 0; j < n; j++) |
1440 |
{ |
1441 |
rows[ii][j] ^= vdev_raidz_exp2(rows[i][j], log); |
1442 |
invrows[ii][j] ^= vdev_raidz_exp2(invrows[i][j], log); |
1443 |
} |
1444 |
} |
1289 |
} |
1445 |
} |
1290 |
add = (known_idx * recovery_pow) % 255; |
|
|
1291 |
for (;s--; b++, a++) |
1292 |
if (*b) |
1293 |
*a ^= powx[powx_inv[*b] + add]; |
1294 |
} |
1446 |
} |
1295 |
|
1447 |
|
1296 |
static inline grub_uint8_t |
1448 |
static void |
1297 |
gf_mul (grub_uint8_t a, grub_uint8_t b) |
1449 |
vdev_raidz_matrix_reconstruct(raidz_map_t *rm, int n, int nmissing, |
|
|
1450 |
int *missing, grub_uint8_t **invrows, const grub_uint8_t *used) |
1298 |
{ |
1451 |
{ |
1299 |
if (a == 0 || b == 0) |
1452 |
int i, j, x, cc, c; |
1300 |
return 0; |
1453 |
grub_uint8_t *src; |
1301 |
return powx[powx_inv[a] + powx_inv[b]]; |
1454 |
grub_uint64_t ccount; |
1302 |
} |
1455 |
grub_uint8_t *dst[VDEV_RAIDZ_MAXPARITY]; |
|
|
1456 |
grub_uint64_t dcount[VDEV_RAIDZ_MAXPARITY]; |
1457 |
grub_uint8_t log = 0; |
1458 |
grub_uint8_t val; |
1459 |
int ll; |
1460 |
grub_uint8_t *invlog[VDEV_RAIDZ_MAXPARITY]; |
1461 |
grub_uint8_t *p, *pp; |
1462 |
grub_size_t psize; |
1303 |
|
1463 |
|
1304 |
#define MAX_NBUFS 4 |
1464 |
psize = sizeof (invlog[0][0]) * n * nmissing; |
|
|
1465 |
p = grub_malloc(psize); |
1305 |
|
1466 |
|
1306 |
static grub_err_t |
1467 |
for (pp = p, i = 0; i < nmissing; i++) |
1307 |
recovery (grub_uint8_t *bufs[4], grub_size_t s, const int nbufs, |
|
|
1308 |
const unsigned *powers, |
1309 |
const unsigned *idx) |
1310 |
{ |
1311 |
grub_dprintf ("zfs", "recovering %u buffers\n", nbufs); |
1312 |
/* Now we have */ |
1313 |
/* b_i = sum (r_j* (x ** (powers[i] * idx[j])))*/ |
1314 |
/* Let's invert the matrix in question. */ |
1315 |
switch (nbufs) |
1316 |
{ |
1468 |
{ |
1317 |
/* Easy: r_0 = bufs[0] / (x << (powers[i] * idx[j])). */ |
1469 |
invlog[i] = pp; |
1318 |
case 1: |
1470 |
pp += n; |
1319 |
{ |
1471 |
} |
1320 |
int add; |
1472 |
|
1321 |
grub_uint8_t *a; |
1473 |
for (i = 0; i < nmissing; i++) |
1322 |
if (powers[0] == 0 || idx[0] == 0) |
1474 |
{ |
1323 |
return GRUB_ERR_NONE; |
1475 |
for (j = 0; j < n; j++) |
1324 |
add = 255 - ((powers[0] * idx[0]) % 255); |
1476 |
invlog[i][j] = vdev_raidz_log2[invrows[i][j]]; |
1325 |
for (a = bufs[0]; s--; a++) |
1477 |
} |
1326 |
if (*a) |
1478 |
|
1327 |
*a = powx[powx_inv[*a] + add]; |
1479 |
for (i = 0; i < n; i++) |
1328 |
return GRUB_ERR_NONE; |
1480 |
{ |
1329 |
} |
1481 |
c = used[i]; |
1330 |
/* Case 2x2: Let's use the determinant formula. */ |
|
|
1331 |
case 2: |
1332 |
{ |
1333 |
grub_uint8_t det, det_inv; |
1334 |
grub_uint8_t matrixinv[2][2]; |
1335 |
unsigned i; |
1336 |
/* The determinant is: */ |
1337 |
det = (powx[(powers[0] * idx[0] + powers[1] * idx[1]) % 255] |
1338 |
^ powx[(powers[0] * idx[1] + powers[1] * idx[0]) % 255]); |
1339 |
if (det == 0) |
1340 |
return grub_error (GRUB_ERR_BAD_FS, "singular recovery matrix"); |
1341 |
det_inv = powx[255 - powx_inv[det]]; |
1342 |
matrixinv[0][0] = gf_mul (powx[(powers[1] * idx[1]) % 255], det_inv); |
1343 |
matrixinv[1][1] = gf_mul (powx[(powers[0] * idx[0]) % 255], det_inv); |
1344 |
matrixinv[0][1] = gf_mul (powx[(powers[0] * idx[1]) % 255], det_inv); |
1345 |
matrixinv[1][0] = gf_mul (powx[(powers[1] * idx[0]) % 255], det_inv); |
1346 |
for (i = 0; i < s; i++) |
1347 |
{ |
1348 |
grub_uint8_t b0, b1; |
1349 |
b0 = bufs[0][i]; |
1350 |
b1 = bufs[1][i]; |
1351 |
|
1352 |
bufs[0][i] = (gf_mul (b0, matrixinv[0][0]) |
1353 |
^ gf_mul (b1, matrixinv[0][1])); |
1354 |
bufs[1][i] = (gf_mul (b0, matrixinv[1][0]) |
1355 |
^ gf_mul (b1, matrixinv[1][1])); |
1356 |
} |
1357 |
return GRUB_ERR_NONE; |
1358 |
} |
1359 |
/* Otherwise use Gauss. */ |
1360 |
case 3: |
1361 |
{ |
1362 |
grub_uint8_t matrix1[MAX_NBUFS][MAX_NBUFS], matrix2[MAX_NBUFS][MAX_NBUFS]; |
1363 |
int i, j, k; |
1364 |
|
1482 |
|
1365 |
for (i = 0; i < nbufs; i++) |
1483 |
src = rm->rm_col[c].rc_data; |
1366 |
for (j = 0; j < nbufs; j++) |
1484 |
ccount = rm->rm_col[c].rc_size; |
1367 |
matrix1[i][j] = powx[(powers[i] * idx[j]) % 255]; |
1485 |
for (j = 0; j < nmissing; j++) |
1368 |
for (i = 0; i < nbufs; i++) |
1486 |
{ |
1369 |
for (j = 0; j < nbufs; j++) |
1487 |
cc = missing[j] + rm->rm_firstdatacol; |
1370 |
matrix2[i][j] = 0; |
1488 |
|
1371 |
for (i = 0; i < nbufs; i++) |
1489 |
dst[j] = rm->rm_col[cc].rc_data; |
1372 |
matrix2[i][i] = 1; |
1490 |
dcount[j] = rm->rm_col[cc].rc_size; |
|
|
1491 |
} |
1373 |
|
1492 |
|
1374 |
for (i = 0; i < nbufs; i++) |
1493 |
for (x = 0; x < (int) ccount; x++, src++) |
1375 |
{ |
1494 |
{ |
1376 |
grub_uint8_t mul; |
1495 |
if (*src != 0) |
1377 |
for (j = i; j < nbufs; j++) |
1496 |
log = vdev_raidz_log2[*src]; |
1378 |
if (matrix1[i][j]) |
1497 |
|
1379 |
break; |
1498 |
for (cc = 0; cc < nmissing; cc++) |
1380 |
if (j == nbufs) |
|
|
1381 |
return grub_error (GRUB_ERR_BAD_FS, "singular recovery matrix"); |
1382 |
if (j != i) |
1383 |
{ |
1499 |
{ |
1384 |
int xchng; |
1500 |
if (x >= (int) dcount[cc]) |
1385 |
xchng = j; |
1501 |
continue; |
1386 |
for (j = 0; j < nbufs; j++) |
1502 |
|
1387 |
{ |
1503 |
if (*src == 0) |
1388 |
grub_uint8_t t; |
1504 |
val = 0; |
1389 |
t = matrix1[xchng][j]; |
1505 |
else |
1390 |
matrix1[xchng][j] = matrix1[i][j]; |
|
|
1391 |
matrix1[i][j] = t; |
1392 |
} |
1393 |
for (j = 0; j < nbufs; j++) |
1394 |
{ |
1506 |
{ |
1395 |
grub_uint8_t t; |
1507 |
if ((ll = log + invlog[cc][i]) >= 255) |
1396 |
t = matrix2[xchng][j]; |
1508 |
ll -= 255; |
1397 |
matrix2[xchng][j] = matrix2[i][j]; |
1509 |
val = vdev_raidz_pow2[ll]; |
1398 |
matrix2[i][j] = t; |
|
|
1399 |
} |
1510 |
} |
1400 |
} |
|
|
1401 |
mul = powx[255 - powx_inv[matrix1[i][i]]]; |
1402 |
for (j = 0; j < nbufs; j++) |
1403 |
matrix1[i][j] = gf_mul (matrix1[i][j], mul); |
1404 |
for (j = 0; j < nbufs; j++) |
1405 |
matrix2[i][j] = gf_mul (matrix2[i][j], mul); |
1406 |
for (j = i + 1; j < nbufs; j++) |
1407 |
{ |
1408 |
mul = matrix1[j][i]; |
1409 |
for (k = 0; k < nbufs; k++) |
1410 |
matrix1[j][k] ^= gf_mul (matrix1[i][k], mul); |
1411 |
for (k = 0; k < nbufs; k++) |
1412 |
matrix2[j][k] ^= gf_mul (matrix2[i][k], mul); |
1413 |
} |
1414 |
} |
1415 |
for (i = nbufs - 1; i >= 0; i--) |
1416 |
{ |
1417 |
for (j = 0; j < i; j++) |
1418 |
{ |
1419 |
grub_uint8_t mul; |
1420 |
mul = matrix1[j][i]; |
1421 |
for (k = 0; k < nbufs; k++) |
1422 |
matrix1[j][k] ^= gf_mul (matrix1[i][k], mul); |
1423 |
for (k = 0; k < nbufs; k++) |
1424 |
matrix2[j][k] ^= gf_mul (matrix2[i][k], mul); |
1425 |
} |
1426 |
} |
1427 |
|
1511 |
|
1428 |
for (i = 0; i < (int) s; i++) |
1512 |
if (i == 0) |
1429 |
{ |
1513 |
dst[cc][x] = val; |
1430 |
grub_uint8_t b[MAX_NBUFS]; |
1514 |
else |
1431 |
for (j = 0; j < nbufs; j++) |
1515 |
dst[cc][x] ^= val; |
1432 |
b[j] = bufs[j][i]; |
|
|
1433 |
for (j = 0; j < nbufs; j++) |
1434 |
{ |
1435 |
bufs[j][i] = 0; |
1436 |
for (k = 0; k < nbufs; k++) |
1437 |
bufs[j][i] ^= gf_mul (matrix2[j][k], b[k]); |
1438 |
} |
1516 |
} |
1439 |
} |
1517 |
} |
1440 |
return GRUB_ERR_NONE; |
1518 |
} |
1441 |
} |
1519 |
|
1442 |
default: |
1520 |
grub_free(p); |
1443 |
return grub_error (GRUB_ERR_BUG, "too big matrix"); |
|
|
1444 |
} |
1445 |
} |
1521 |
} |
1446 |
|
1522 |
|
1447 |
static grub_err_t |
1523 |
static int |
1448 |
read_device (grub_uint64_t offset, struct grub_zfs_device_desc *desc, |
1524 |
vdev_raidz_reconstruct_general(raidz_map_t *rm, int *tgts, int ntgts) |
1449 |
grub_size_t len, void *buf) |
|
|
1450 |
{ |
1525 |
{ |
1451 |
switch (desc->type) |
1526 |
int n, i, c, t, tt; |
|
|
1527 |
int nmissing_rows; |
1528 |
int missing_rows[VDEV_RAIDZ_MAXPARITY]; |
1529 |
int parity_map[VDEV_RAIDZ_MAXPARITY]; |
1530 |
|
1531 |
grub_uint8_t *p, *pp; |
1532 |
grub_size_t psize; |
1533 |
|
1534 |
grub_uint8_t *rows[VDEV_RAIDZ_MAXPARITY]; |
1535 |
grub_uint8_t *invrows[VDEV_RAIDZ_MAXPARITY]; |
1536 |
grub_uint8_t *used; |
1537 |
|
1538 |
int code = 0; |
1539 |
|
1540 |
|
1541 |
n = rm->rm_cols - rm->rm_firstdatacol; |
1542 |
|
1543 |
/* |
1544 |
* Figure out which data columns are missing. |
1545 |
*/ |
1546 |
nmissing_rows = 0; |
1547 |
for (t = 0; t < ntgts; t++) |
1452 |
{ |
1548 |
{ |
1453 |
case DEVICE_LEAF: |
1549 |
if (tgts[t] >= (int) rm->rm_firstdatacol) |
1454 |
{ |
1550 |
missing_rows[nmissing_rows++] = tgts[t] - rm->rm_firstdatacol; |
1455 |
grub_uint64_t sector; |
1551 |
} |
1456 |
sector = DVA_OFFSET_TO_PHYS_SECTOR (offset); |
1552 |
|
1457 |
if (!desc->dev) |
1553 |
/* |
1458 |
{ |
1554 |
* Figure out which parity columns to use to help generate the missing |
1459 |
return grub_error (GRUB_ERR_BAD_FS, |
1555 |
* data columns. |
|
|
1556 |
*/ |
1557 |
for (tt = 0, c = 0, i = 0; i < nmissing_rows; c++) |
1558 |
{ |
1559 |
/* |
1560 |
* Skip any targeted parity columns. |
1561 |
*/ |
1562 |
if (c == tgts[tt]) |
1563 |
{ |
1564 |
tt++; |
1565 |
continue; |
1566 |
} |
1567 |
|
1568 |
code |= 1 << c; |
1569 |
|
1570 |
parity_map[i] = c; |
1571 |
i++; |
1572 |
} |
1573 |
|
1574 |
psize = (sizeof (rows[0][0]) + sizeof (invrows[0][0])) * |
1575 |
nmissing_rows * n + sizeof (used[0]) * n; |
1576 |
p = grub_malloc(psize); |
1577 |
|
1578 |
for (pp = p, i = 0; i < nmissing_rows; i++) |
1579 |
{ |
1580 |
rows[i] = pp; |
1581 |
pp += n; |
1582 |
invrows[i] = pp; |
1583 |
pp += n; |
1584 |
} |
1585 |
used = pp; |
1586 |
|
1587 |
for (i = 0; i < nmissing_rows; i++) |
1588 |
used[i] = parity_map[i]; |
1589 |
|
1590 |
for (tt = 0, c = rm->rm_firstdatacol; c < (int) rm->rm_cols; c++) |
1591 |
{ |
1592 |
if (tt < (int) nmissing_rows && |
1593 |
c == missing_rows[tt] + (int) rm->rm_firstdatacol) |
1594 |
{ |
1595 |
tt++; |
1596 |
continue; |
1597 |
} |
1598 |
|
1599 |
used[i] = c; |
1600 |
i++; |
1601 |
} |
1602 |
|
1603 |
/* |
1604 |
* Initialize the interesting rows of the matrix. |
1605 |
*/ |
1606 |
vdev_raidz_matrix_init(n, nmissing_rows, parity_map, rows); |
1607 |
|
1608 |
/* |
1609 |
* Invert the matrix. |
1610 |
*/ |
1611 |
vdev_raidz_matrix_invert(rm, n, nmissing_rows, missing_rows, rows, |
1612 |
invrows, used); |
1613 |
|
1614 |
/* |
1615 |
* Reconstruct the missing data using the generated matrix. |
1616 |
*/ |
1617 |
vdev_raidz_matrix_reconstruct(rm, n, nmissing_rows, missing_rows, |
1618 |
invrows, used); |
1619 |
|
1620 |
grub_free(p); |
1621 |
|
1622 |
return (code); |
1623 |
} |
1624 |
|
1625 |
static int |
1626 |
vdev_raidz_reconstruct(raidz_map_t *rm, int *t, int nt) |
1627 |
{ |
1628 |
int tgts[VDEV_RAIDZ_MAXPARITY], *dt; |
1629 |
int ntgts; |
1630 |
int i, c; |
1631 |
int code; |
1632 |
int nbadparity, nbaddata; |
1633 |
int parity_valid[VDEV_RAIDZ_MAXPARITY]; |
1634 |
|
1635 |
nbadparity = rm->rm_firstdatacol; |
1636 |
nbaddata = rm->rm_cols - nbadparity; |
1637 |
ntgts = 0; |
1638 |
for (i = 0, c = 0; c < (int) rm->rm_cols; c++) |
1639 |
{ |
1640 |
if (c < (int) rm->rm_firstdatacol) |
1641 |
parity_valid[c] = B_FALSE; |
1642 |
|
1643 |
if (i < nt && c == t[i]) |
1644 |
{ |
1645 |
tgts[ntgts++] = c; |
1646 |
i++; |
1647 |
} |
1648 |
else if (rm->rm_col[c].rc_error != 0) |
1649 |
{ |
1650 |
tgts[ntgts++] = c; |
1651 |
} |
1652 |
else if (c >= (int) rm->rm_firstdatacol) |
1653 |
{ |
1654 |
nbaddata--; |
1655 |
} |
1656 |
else |
1657 |
{ |
1658 |
parity_valid[c] = B_TRUE; |
1659 |
nbadparity--; |
1660 |
} |
1661 |
} |
1662 |
|
1663 |
dt = &tgts[nbadparity]; |
1664 |
|
1665 |
switch (nbaddata) |
1666 |
{ |
1667 |
case 1: |
1668 |
if (parity_valid[VDEV_RAIDZ_P]) |
1669 |
return (vdev_raidz_reconstruct_p(rm, dt)); |
1670 |
|
1671 |
if (parity_valid[VDEV_RAIDZ_Q]) |
1672 |
return (vdev_raidz_reconstruct_q(rm, dt)); |
1673 |
|
1674 |
break; |
1675 |
case 2: |
1676 |
if (parity_valid[VDEV_RAIDZ_P] && parity_valid[VDEV_RAIDZ_Q]) |
1677 |
return (vdev_raidz_reconstruct_pq(rm, dt)); |
1678 |
|
1679 |
break; |
1680 |
} |
1681 |
|
1682 |
code = vdev_raidz_reconstruct_general(rm, tgts, ntgts); |
1683 |
return (code); |
1684 |
} |
1685 |
|
1686 |
static mirror_map_t * |
1687 |
vdev_mirror_map_alloc(struct grub_zfs_device_desc *vd, grub_uint64_t offset, |
1688 |
grub_uint64_t children) |
1689 |
{ |
1690 |
mirror_map_t *mm = NULL; |
1691 |
mirror_child_t *mc; |
1692 |
int c; |
1693 |
|
1694 |
c = (int) children; |
1695 |
mm = grub_zalloc(offsetof(mirror_map_t, mm_child[c])); |
1696 |
mm->mm_children = c; |
1697 |
mm->mm_replacing = B_FALSE; |
1698 |
mm->mm_preferred = ((int)offset >> 21) % c; |
1699 |
mm->mm_root = B_TRUE; |
1700 |
mm->mm_offset = offset; |
1701 |
|
1702 |
for (c = 0; c < mm->mm_children; c++) |
1703 |
{ |
1704 |
mc = &mm->mm_child[c]; |
1705 |
mc->mc_vd = &vd->children[c]; |
1706 |
mc->mc_offset = offset; |
1707 |
} |
1708 |
|
1709 |
return (mm); |
1710 |
} |
1711 |
|
1712 |
static int |
1713 |
vdev_mirror_child_select(mirror_map_t *mm) |
1714 |
{ |
1715 |
mirror_child_t *mc = NULL; |
1716 |
int c, i; |
1717 |
|
1718 |
for (i = 0, c = mm->mm_preferred; i < mm->mm_children; i++, c++) |
1719 |
{ |
1720 |
if (c >= mm->mm_children) |
1721 |
c = 0; |
1722 |
mc = &mm->mm_child[c]; |
1723 |
if (mc->mc_tried || mc->mc_skipped) |
1724 |
continue; |
1725 |
if (mc->mc_vd->dev_state == DEVICE_ERROR) |
1726 |
{ |
1727 |
mc->mc_error = GRUB_ERR_IO; |
1728 |
mc->mc_tried = 1; /* don't even try */ |
1729 |
mc->mc_skipped = 1; |
1730 |
continue; |
1731 |
} |
1732 |
return (c); |
1733 |
} |
1734 |
for (c = 0; c < mm->mm_children; c++) |
1735 |
if (!mm->mm_child[c].mc_tried) |
1736 |
return (c); |
1737 |
|
1738 |
return -1; |
1739 |
} |
1740 |
|
1741 |
static grub_err_t |
1742 |
read_device (grub_uint64_t offset, struct grub_zfs_device_desc *desc, |
1743 |
grub_size_t len, void *buf, void **priv) |
1744 |
{ |
1745 |
grub_err_t err = GRUB_ERR_NONE; |
1746 |
|
1747 |
if (priv != NULL) |
1748 |
*priv = NULL; |
1749 |
|
1750 |
switch (desc->type) |
1751 |
{ |
1752 |
case DEVICE_LEAF: |
1753 |
{ |
1754 |
grub_uint64_t sector; |
1755 |
sector = DVA_OFFSET_TO_PHYS_SECTOR (offset); |
1756 |
grub_dprintf("zfs", "read_device: offset %llx sector %llx\n", |
1757 |
(unsigned long long) offset, |
1758 |
(unsigned long long) sector); |
1759 |
if (!desc->dev) |
1760 |
{ |
1761 |
return grub_error (GRUB_ERR_BAD_FS, |
1460 |
N_("couldn't find a necessary member device " |
1762 |
N_("couldn't find a necessary member device " |
1461 |
"of multi-device filesystem")); |
1763 |
"of multi-device filesystem")); |
1462 |
} |
1764 |
} |
|
|
1765 |
if (desc->dev_state == DEVICE_ERROR) |
1766 |
{ |
1767 |
return grub_error (GRUB_ERR_BAD_DEVICE, "dev state is NOT OK.\n"); |
1768 |
} |
1463 |
/* read in a data block */ |
1769 |
/* read in a data block */ |
1464 |
return grub_disk_read (desc->dev->disk, sector, 0, len, buf); |
1770 |
return grub_disk_read (desc->dev->disk, sector, 0, len, buf); |
1465 |
} |
1771 |
} |
1466 |
case DEVICE_MIRROR: |
1772 |
case DEVICE_MIRROR: |
1467 |
{ |
1773 |
{ |
1468 |
grub_err_t err = GRUB_ERR_NONE; |
1774 |
mirror_map_t *mm = NULL; |
1469 |
unsigned i; |
1775 |
|
1470 |
if (desc->n_children <= 0) |
1776 |
if (desc->n_children <= 0) |
1471 |
return grub_error (GRUB_ERR_BAD_FS, |
1777 |
return grub_error (GRUB_ERR_BAD_FS, |
1472 |
"non-positive number of mirror children"); |
1778 |
"non-positive number of mirror children"); |
1473 |
for (i = 0; i < desc->n_children; i++) |
1779 |
|
|
|
1780 |
mm = vdev_mirror_map_alloc(desc, offset, desc->n_children); |
1781 |
if (mm == NULL) |
1782 |
err = grub_errno; |
1783 |
else |
1474 |
{ |
1784 |
{ |
1475 |
err = read_device (offset, &desc->children[i], |
1785 |
mm->mm_buf = buf; |
1476 |
len, buf); |
1786 |
mm->mm_size = len; |
1477 |
if (!err) |
|
|
1478 |
break; |
1479 |
grub_errno = GRUB_ERR_NONE; |
1480 |
} |
1787 |
} |
1481 |
grub_errno = err; |
|
|
1482 |
|
1788 |
|
|
|
1789 |
*priv = mm; |
1483 |
return err; |
1790 |
return err; |
1484 |
} |
1791 |
} |
1485 |
case DEVICE_RAIDZ: |
1792 |
case DEVICE_RAIDZ: |
1486 |
{ |
1793 |
{ |
1487 |
unsigned c = 0; |
1794 |
raidz_map_t *rm; |
1488 |
grub_uint64_t high; |
1795 |
raidz_col_t *rc; |
1489 |
grub_uint64_t devn; |
1796 |
grub_int64_t c; |
1490 |
grub_uint64_t m; |
1797 |
struct grub_zfs_device_desc *cvd; |
1491 |
grub_uint32_t s, orig_s; |
|
|
1492 |
void *orig_buf = buf; |
1493 |
grub_size_t orig_len = len; |
1494 |
grub_uint8_t *recovery_buf[4]; |
1495 |
grub_size_t recovery_len[4]; |
1496 |
unsigned recovery_idx[4]; |
1497 |
unsigned failed_devices = 0; |
1498 |
int idx, orig_idx; |
1499 |
|
1798 |
|
1500 |
if (desc->nparity < 1 || desc->nparity > 3) |
1799 |
if (desc->nparity < 1 || desc->nparity > 3) |
1501 |
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, |
1800 |
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, |
1502 |
"raidz%d is not supported", desc->nparity); |
1801 |
"raidz%d is not supported", desc->nparity); |
1503 |
|
1802 |
|
1504 |
orig_s = (((len + (1 << desc->ashift) - 1) >> desc->ashift) |
1803 |
return grub_error(GRUB_ERR_BAD_FS, |
1505 |
+ (desc->n_children - desc->nparity) - 1); |
1804 |
"too little devices for given parity"); |
1506 |
s = orig_s; |
1805 |
rm = vdev_raidz_map_alloc(buf, len, offset, desc->ashift, |
1507 |
|
1806 |
desc->n_children, desc->nparity); |
1508 |
high = grub_divmod64 ((offset >> desc->ashift), |
1807 |
if (rm == NULL) |
1509 |
desc->n_children, &m); |
1808 |
return grub_errno; |
1510 |
if (desc->nparity == 2) |
1809 |
|
1511 |
c = 2; |
1810 |
grub_dprintf("zfs", "read_device: cols = %" PRIuGRUB_UINT64_T |
1512 |
if (desc->nparity == 3) |
1811 |
", firstdatacol = %" PRIuGRUB_UINT64_T "\n", |
1513 |
c = 3; |
1812 |
rm->rm_cols, rm->rm_firstdatacol); |
1514 |
if (((len + (1 << desc->ashift) - 1) >> desc->ashift) |
1813 |
|
1515 |
>= (desc->n_children - desc->nparity)) |
1814 |
/* |
1516 |
idx = (desc->n_children - desc->nparity - 1); |
1815 |
* Iterate over the columns in reverse order so that we hit the parity |
1517 |
else |
1816 |
* last -- any errors along the way will force us to read the parity. |
1518 |
idx = ((len + (1 << desc->ashift) - 1) >> desc->ashift) - 1; |
1817 |
*/ |
1519 |
orig_idx = idx; |
1818 |
for (c = rm->rm_cols - 1; c >= 0; c--) |
1520 |
while (len > 0) |
|
|
1521 |
{ |
1819 |
{ |
1522 |
grub_size_t csize; |
1820 |
rc = &rm->rm_col[c]; |
1523 |
grub_uint32_t bsize; |
1821 |
cvd = &desc->children[rc->rc_devidx]; |
1524 |
grub_err_t err; |
1822 |
if(cvd->dev_state == DEVICE_ERROR) |
1525 |
bsize = s / (desc->n_children - desc->nparity); |
|
|
1526 |
|
1527 |
if (desc->nparity == 1 |
1528 |
&& ((offset >> (desc->ashift + 20 - desc->max_children_ashift)) |
1529 |
& 1) == c) |
1530 |
c++; |
1531 |
|
1532 |
high = grub_divmod64 ((offset >> desc->ashift) + c, |
1533 |
desc->n_children, &devn); |
1534 |
csize = bsize << desc->ashift; |
1535 |
if (csize > len) |
1536 |
csize = len; |
1537 |
|
1538 |
grub_dprintf ("zfs", "RAIDZ mapping 0x%" PRIxGRUB_UINT64_T |
1539 |
"+%u (%" PRIxGRUB_SIZE ", %" PRIxGRUB_UINT32_T |
1540 |
") -> (0x%" PRIxGRUB_UINT64_T ", 0x%" |
1541 |
PRIxGRUB_UINT64_T ")\n", |
1542 |
offset >> desc->ashift, c, len, bsize, high, |
1543 |
devn); |
1544 |
err = read_device ((high << desc->ashift) |
1545 |
| (offset & ((1 << desc->ashift) - 1)), |
1546 |
&desc->children[devn], |
1547 |
csize, buf); |
1548 |
if (err && failed_devices < desc->nparity) |
1549 |
{ |
1823 |
{ |
1550 |
recovery_buf[failed_devices] = buf; |
1824 |
if ((grub_uint64_t)c >= rm->rm_firstdatacol) |
1551 |
recovery_len[failed_devices] = csize; |
1825 |
rm->rm_missingdata++; |
1552 |
recovery_idx[failed_devices] = idx; |
1826 |
else |
1553 |
failed_devices++; |
1827 |
rm->rm_missingparity++; |
1554 |
grub_errno = err = 0; |
1828 |
rc->rc_error = GRUB_ERR_IO; |
1555 |
} |
1829 |
rc->rc_tried = 1; /* don't even try */ |
1556 |
if (err) |
1830 |
rc->rc_skipped = 1; |
1557 |
return err; |
1831 |
continue; |
1558 |
|
1832 |
} |
1559 |
c++; |
1833 |
grub_dprintf("zfs", "%" PRIuGRUB_UINT64_T ":%" PRIxGRUB_UINT64_T |
1560 |
idx--; |
1834 |
":%" PRIxGRUB_UINT64_T "\n", rc->rc_devidx, |
1561 |
s--; |
1835 |
rc->rc_offset, rc->rc_size); |
1562 |
buf = (char *) buf + csize; |
1836 |
if ((grub_uint64_t)c >= rm->rm_firstdatacol || |
1563 |
len -= csize; |
1837 |
rm->rm_missingdata > 0) |
1564 |
} |
|
|
1565 |
if (failed_devices) |
1566 |
{ |
1567 |
unsigned redundancy_pow[4]; |
1568 |
unsigned cur_redundancy_pow = 0; |
1569 |
unsigned n_redundancy = 0; |
1570 |
unsigned i, j; |
1571 |
grub_err_t err; |
1572 |
|
1573 |
/* Compute mul. x**s has a period of 255. */ |
1574 |
if (powx[0] == 0) |
1575 |
{ |
1838 |
{ |
1576 |
grub_uint8_t cur = 1; |
1839 |
err = read_device (rc->rc_offset, cvd, rc->rc_size, |
1577 |
for (i = 0; i < 255; i++) |
1840 |
rc->rc_data, NULL); |
|
|
1841 |
rc->rc_error = err; |
1842 |
rc->rc_tried = 1; |
1843 |
rc->rc_skipped = 0; |
1844 |
if (err) |
1578 |
{ |
1845 |
{ |
1579 |
powx[i] = cur; |
1846 |
/* missing data will trigger parity read */ |
1580 |
powx[i + 255] = cur; |
1847 |
if ((grub_uint64_t)c >= rm->rm_firstdatacol) |
1581 |
powx_inv[cur] = i; |
1848 |
rm->rm_missingdata++; |
1582 |
if (cur & 0x80) |
|
|
1583 |
cur = (cur << 1) ^ poly; |
1584 |
else |
1849 |
else |
1585 |
cur <<= 1; |
1850 |
rm->rm_missingparity++; |
1586 |
} |
|
|
1587 |
} |
1588 |
|
1589 |
/* Read redundancy data. */ |
1590 |
for (n_redundancy = 0, cur_redundancy_pow = 0; |
1591 |
n_redundancy < failed_devices; |
1592 |
cur_redundancy_pow++) |
1593 |
{ |
1594 |
high = grub_divmod64 ((offset >> desc->ashift) |
1595 |
+ cur_redundancy_pow |
1596 |
+ ((desc->nparity == 1) |
1597 |
&& ((offset >> (desc->ashift + 20 |
1598 |
- desc->max_children_ashift)) |
1599 |
& 1)), |
1600 |
desc->n_children, &devn); |
1601 |
err = read_device ((high << desc->ashift) |
1602 |
| (offset & ((1 << desc->ashift) - 1)), |
1603 |
&desc->children[devn], |
1604 |
recovery_len[n_redundancy], |
1605 |
recovery_buf[n_redundancy]); |
1606 |
/* Ignore error if we may still have enough devices. */ |
1607 |
if (err && n_redundancy + desc->nparity - cur_redundancy_pow - 1 |
1608 |
>= failed_devices) |
1609 |
{ |
1610 |
grub_errno = GRUB_ERR_NONE; |
1611 |
continue; |
1612 |
} |
1851 |
} |
1613 |
if (err) |
|
|
1614 |
return err; |
1615 |
redundancy_pow[n_redundancy] = cur_redundancy_pow; |
1616 |
n_redundancy++; |
1617 |
} |
1618 |
/* Now xor-our the parts we already know. */ |
1619 |
buf = orig_buf; |
1620 |
len = orig_len; |
1621 |
s = orig_s; |
1622 |
idx = orig_idx; |
1623 |
|
1624 |
while (len > 0) |
1625 |
{ |
1626 |
grub_size_t csize; |
1627 |
csize = ((s / (desc->n_children - desc->nparity)) |
1628 |
<< desc->ashift); |
1629 |
if (csize > len) |
1630 |
csize = len; |
1631 |
|
1632 |
for (j = 0; j < failed_devices; j++) |
1633 |
if (buf == recovery_buf[j]) |
1634 |
break; |
1635 |
|
1636 |
if (j == failed_devices) |
1637 |
for (j = 0; j < failed_devices; j++) |
1638 |
xor_out (recovery_buf[j], buf, |
1639 |
csize < recovery_len[j] ? csize : recovery_len[j], |
1640 |
idx, redundancy_pow[j]); |
1641 |
|
1642 |
s--; |
1643 |
buf = (char *) buf + csize; |
1644 |
len -= csize; |
1645 |
idx--; |
1646 |
} |
1647 |
for (i = 0; i < failed_devices |
1648 |
&& recovery_len[i] == recovery_len[0]; |
1649 |
i++); |
1650 |
/* Since the chunks have variable length handle the last block |
1651 |
separately. */ |
1652 |
if (i != failed_devices) |
1653 |
{ |
1654 |
grub_uint8_t *tmp_recovery_buf[4]; |
1655 |
for (j = 0; j < i; j++) |
1656 |
tmp_recovery_buf[j] = recovery_buf[j] + recovery_len[failed_devices - 1]; |
1657 |
err = recovery (tmp_recovery_buf, recovery_len[0] - recovery_len[failed_devices - 1], i, redundancy_pow, |
1658 |
recovery_idx); |
1659 |
if (err) |
1660 |
return err; |
1661 |
} |
1852 |
} |
1662 |
err = recovery (recovery_buf, recovery_len[failed_devices - 1], |
|
|
1663 |
failed_devices, redundancy_pow, recovery_idx); |
1664 |
if (err) |
1665 |
return err; |
1666 |
} |
1853 |
} |
|
|
1854 |
*priv = rm; |
1855 |
|
1667 |
return GRUB_ERR_NONE; |
1856 |
return GRUB_ERR_NONE; |
1668 |
} |
1857 |
} |
1669 |
} |
1858 |
} |
1670 |
return grub_error (GRUB_ERR_BAD_FS, "unsupported device type"); |
1859 |
return grub_error (GRUB_ERR_BAD_FS, "unsupported device type"); |
1671 |
} |
1860 |
} |
1672 |
|
1861 |
|
1673 |
static grub_err_t |
1862 |
static int |
1674 |
read_dva (const dva_t *dva, |
1863 |
vdev_raidz_combrec(blkptr_t *bp, grub_zfs_endian_t endian, raidz_map_t *rm, |
1675 |
grub_zfs_endian_t endian, struct grub_zfs_data *data, |
1864 |
int total_errors, int data_errors) |
1676 |
void *buf, grub_size_t len) |
|
|
1677 |
{ |
1865 |
{ |
1678 |
grub_uint64_t offset; |
1866 |
raidz_col_t *rc; |
1679 |
unsigned i; |
1867 |
void *orig[VDEV_RAIDZ_MAXPARITY]; |
1680 |
grub_err_t err = 0; |
1868 |
int tstore[VDEV_RAIDZ_MAXPARITY + 2]; |
1681 |
int try = 0; |
1869 |
int *tgts = &tstore[1]; |
1682 |
offset = dva_get_offset (dva, endian); |
1870 |
int current, next, i, c, n; |
|
|
1871 |
int code, ret = 0; |
1683 |
|
1872 |
|
1684 |
for (try = 0; try < 2; try++) |
1873 |
/* |
|
|
1874 |
* This simplifies one edge condition. |
1875 |
*/ |
1876 |
tgts[-1] = -1; |
1877 |
|
1878 |
for (n = 1; n <= (int) rm->rm_firstdatacol - total_errors; n++) |
1685 |
{ |
1879 |
{ |
1686 |
for (i = 0; i < data->n_devices_attached; i++) |
1880 |
/* |
1687 |
if (data->devices_attached[i].id == DVA_GET_VDEV (dva)) |
1881 |
* Initialize the targets array by finding the first n columns |
1688 |
{ |
1882 |
* that contain no error. |
1689 |
err = read_device (offset, &data->devices_attached[i], len, buf); |
1883 |
* |
1690 |
if (!err) |
1884 |
* If there were no data errors, we need to ensure that we're |
1691 |
return GRUB_ERR_NONE; |
1885 |
* always explicitly attempting to reconstruct at least one |
1692 |
break; |
1886 |
* data column. To do this, we simply push the highest target |
1693 |
} |
1887 |
* up into the data columns. |
1694 |
if (try == 1) |
1888 |
*/ |
1695 |
break; |
1889 |
for (c = 0, i = 0; i < n; i++) |
1696 |
err = scan_devices (data); |
1890 |
{ |
1697 |
if (err) |
1891 |
if (i == n - 1 && data_errors == 0 && c < (int) rm->rm_firstdatacol) |
1698 |
return err; |
1892 |
{ |
1699 |
} |
1893 |
c = rm->rm_firstdatacol; |
1700 |
if (!err) |
1894 |
} |
1701 |
return grub_error (GRUB_ERR_BAD_FS, "unknown device %d", |
|
|
1702 |
(int) DVA_GET_VDEV (dva)); |
1703 |
return err; |
1704 |
} |
1705 |
|
1895 |
|
1706 |
/* |
1896 |
while (rm->rm_col[c].rc_error != 0) |
1707 |
* Read a block of data based on the gang block address dva, |
1897 |
c++; |
1708 |
* and put its data in buf. |
|
|
1709 |
* |
1710 |
*/ |
1711 |
static grub_err_t |
1712 |
zio_read_gang (blkptr_t * bp, grub_zfs_endian_t endian, dva_t * dva, void *buf, |
1713 |
struct grub_zfs_data *data) |
1714 |
{ |
1715 |
zio_gbh_phys_t *zio_gb; |
1716 |
unsigned i; |
1717 |
grub_err_t err; |
1718 |
zio_cksum_t zc; |
1719 |
|
1898 |
|
1720 |
grub_memset (&zc, 0, sizeof (zc)); |
1899 |
tgts[i] = c++; |
|
|
1900 |
} |
1721 |
|
1901 |
|
1722 |
zio_gb = grub_malloc (SPA_GANGBLOCKSIZE); |
1902 |
/* |
1723 |
if (!zio_gb) |
1903 |
* Setting tgts[n] simplifies the other edge condition. |
1724 |
return grub_errno; |
1904 |
*/ |
1725 |
grub_dprintf ("zfs", endian == GRUB_ZFS_LITTLE_ENDIAN ? "little-endian gang\n" |
1905 |
tgts[n] = rm->rm_cols; |
1726 |
:"big-endian gang\n"); |
|
|
1727 |
|
1906 |
|
1728 |
err = read_dva (dva, endian, data, zio_gb, SPA_GANGBLOCKSIZE); |
1907 |
orig[n - 1] = grub_malloc(rm->rm_col[0].rc_size); |
1729 |
if (err) |
|
|
1730 |
{ |
1731 |
grub_free (zio_gb); |
1732 |
return err; |
1733 |
} |
1734 |
|
1908 |
|
1735 |
/* XXX */ |
1909 |
current = 0; |
1736 |
/* self checksuming the gang block header */ |
1910 |
next = tgts[current]; |
1737 |
ZIO_SET_CHECKSUM (&zc, DVA_GET_VDEV (dva), |
|
|
1738 |
dva_get_offset (dva, endian), bp->blk_birth, 0); |
1739 |
err = zio_checksum_verify (zc, ZIO_CHECKSUM_GANG_HEADER, endian, |
1740 |
(char *) zio_gb, SPA_GANGBLOCKSIZE); |
1741 |
if (err) |
1742 |
{ |
1743 |
grub_free (zio_gb); |
1744 |
return err; |
1745 |
} |
1746 |
|
1911 |
|
1747 |
endian = (grub_zfs_to_cpu64 (bp->blk_prop, endian) >> 63) & 1; |
1912 |
while (current != n) |
|
|
1913 |
{ |
1914 |
tgts[current] = next; |
1915 |
current = 0; |
1748 |
|
1916 |
|
1749 |
for (i = 0; i < SPA_GBH_NBLKPTRS; i++) |
1917 |
/* |
1750 |
{ |
1918 |
* Save off the original data that we're going to |
1751 |
if (zio_gb->zg_blkptr[i].blk_birth == 0) |
1919 |
* attempt to reconstruct. |
1752 |
continue; |
1920 |
*/ |
|
|
1921 |
for (i = 0; i < n; i++) |
1922 |
{ |
1923 |
c = tgts[i]; |
1924 |
rc = &rm->rm_col[c]; |
1925 |
grub_memcpy(orig[i], rc->rc_data, rc->rc_size); |
1926 |
} |
1753 |
|
1927 |
|
1754 |
err = zio_read_data (&zio_gb->zg_blkptr[i], endian, buf, data); |
1928 |
/* |
1755 |
if (err) |
1929 |
* Attempt a reconstruction and exit the outer loop on |
1756 |
{ |
1930 |
* success. |
1757 |
grub_free (zio_gb); |
1931 |
*/ |
1758 |
return err; |
1932 |
code = vdev_raidz_reconstruct(rm, tgts, n); |
1759 |
} |
1933 |
if (zio_checksum_error(bp, endian, |
1760 |
buf = (char *) buf + get_psize (&zio_gb->zg_blkptr[i], endian); |
1934 |
rm->rm_col[rm->rm_firstdatacol].rc_data) == 0) |
1761 |
} |
1935 |
{ |
1762 |
grub_free (zio_gb); |
1936 |
for (i = 0; i < n; i++) |
1763 |
return GRUB_ERR_NONE; |
1937 |
{ |
1764 |
} |
1938 |
c = tgts[i]; |
|
|
1939 |
rc = &rm->rm_col[c]; |
1940 |
rc->rc_error = GRUB_ERR_IO; |
1941 |
} |
1765 |
|
1942 |
|
1766 |
/* |
1943 |
ret = code; |
1767 |
* Read in a block of raw data to buf. |
1944 |
goto done; |
1768 |
*/ |
1945 |
} |
1769 |
static grub_err_t |
|
|
1770 |
zio_read_data (blkptr_t * bp, grub_zfs_endian_t endian, void *buf, |
1771 |
struct grub_zfs_data *data) |
1772 |
{ |
1773 |
int i, psize; |
1774 |
grub_err_t err = GRUB_ERR_NONE; |
1775 |
|
1946 |
|
1776 |
psize = get_psize (bp, endian); |
1947 |
/* |
|
|
1948 |
* Restore the original data. |
1949 |
*/ |
1950 |
for (i = 0; i < n; i++) |
1951 |
{ |
1952 |
c = tgts[i]; |
1953 |
rc = &rm->rm_col[c]; |
1954 |
grub_memcpy(rc->rc_data, orig[i], rc->rc_size); |
1955 |
} |
1777 |
|
1956 |
|
1778 |
/* pick a good dva from the block pointer */ |
1957 |
do { |
1779 |
for (i = 0; i < SPA_DVAS_PER_BP; i++) |
1958 |
/* |
1780 |
{ |
1959 |
* Find the next valid column after the current |
1781 |
if (bp->blk_dva[i].dva_word[0] == 0 && bp->blk_dva[i].dva_word[1] == 0) |
1960 |
* position.. |
1782 |
continue; |
1961 |
*/ |
|
|
1962 |
for (next = tgts[current] + 1; |
1963 |
next < (int) rm->rm_cols && rm->rm_col[next].rc_error != 0; |
1964 |
next++) |
1965 |
continue; |
1783 |
|
1966 |
|
1784 |
if ((grub_zfs_to_cpu64 (bp->blk_dva[i].dva_word[1], endian)>>63) & 1) |
1967 |
/* |
1785 |
err = zio_read_gang (bp, endian, &bp->blk_dva[i], buf, data); |
1968 |
* If that spot is available, we're done here. |
1786 |
else |
1969 |
*/ |
1787 |
err = read_dva (&bp->blk_dva[i], endian, data, buf, psize); |
1970 |
if (next != tgts[current + 1]) |
1788 |
if (!err) |
1971 |
break; |
1789 |
return GRUB_ERR_NONE; |
1972 |
|
1790 |
grub_errno = GRUB_ERR_NONE; |
1973 |
/* |
|
|
1974 |
* Otherwise, find the next valid column after |
1975 |
* the previous position. |
1976 |
*/ |
1977 |
for (c = tgts[current - 1] + 1; rm->rm_col[c].rc_error != 0; c++) |
1978 |
continue; |
1979 |
|
1980 |
tgts[current] = c; |
1981 |
current++; |
1982 |
|
1983 |
} while (current != n); |
1984 |
} |
1791 |
} |
1985 |
} |
|
|
1986 |
n--; |
1792 |
|
1987 |
|
1793 |
if (!err) |
1988 |
done: |
1794 |
err = grub_error (GRUB_ERR_BAD_FS, "couldn't find a valid DVA"); |
1989 |
for (i = 0; i < n; i++) |
1795 |
grub_errno = err; |
1990 |
grub_free(orig[i]); |
1796 |
|
1991 |
|
1797 |
return err; |
1992 |
return (ret); |
1798 |
} |
1993 |
} |
1799 |
|
1994 |
|
1800 |
/* |
|
|
1801 |
* Read in a block of data, verify its checksum, decompress if needed, |
1802 |
* and put the uncompressed data in buf. |
1803 |
*/ |
1804 |
static grub_err_t |
1995 |
static grub_err_t |
1805 |
zio_read (blkptr_t *bp, grub_zfs_endian_t endian, void **buf, |
1996 |
vdev_raidz_io_done(blkptr_t *bp, struct grub_zfs_device_desc *desc, |
1806 |
grub_size_t *size, struct grub_zfs_data *data) |
1997 |
grub_zfs_endian_t endian, raidz_map_t *rm) |
1807 |
{ |
1998 |
{ |
1808 |
grub_size_t lsize, psize; |
1999 |
raidz_col_t *rc; |
1809 |
unsigned int comp, encrypted; |
2000 |
int unexpected_errors = 0; |
1810 |
char *compbuf = NULL; |
2001 |
int parity_errors = 0; |
1811 |
grub_err_t err; |
2002 |
int parity_untried = 0; |
1812 |
zio_cksum_t zc = bp->blk_cksum; |
2003 |
int data_errors = 0; |
1813 |
grub_uint32_t checksum; |
2004 |
int total_errors = 0; |
1814 |
|
2005 |
int n, c; |
1815 |
*buf = NULL; |
2006 |
int tgts[VDEV_RAIDZ_MAXPARITY]; |
|
|
2007 |
int code; |
2008 |
grub_err_t err = GRUB_ERR_NONE; |
1816 |
|
2009 |
|
1817 |
checksum = (grub_zfs_to_cpu64((bp)->blk_prop, endian) >> 40) & 0xff; |
2010 |
for (c = 0; c < (int)rm->rm_cols; c++) |
1818 |
comp = (grub_zfs_to_cpu64((bp)->blk_prop, endian)>>32) & 0xff; |
2011 |
{ |
1819 |
encrypted = ((grub_zfs_to_cpu64((bp)->blk_prop, endian) >> 60) & 3); |
2012 |
rc = &rm->rm_col[c]; |
1820 |
lsize = (BP_IS_HOLE(bp) ? 0 : |
2013 |
if (rc->rc_error) |
1821 |
(((grub_zfs_to_cpu64 ((bp)->blk_prop, endian) & 0xffff) + 1) |
2014 |
{ |
1822 |
<< SPA_MINBLOCKSHIFT)); |
2015 |
if (c < (int)rm->rm_firstdatacol) |
1823 |
psize = get_psize (bp, endian); |
2016 |
parity_errors++; |
|
|
2017 |
else |
2018 |
data_errors++; |
1824 |
|
2019 |
|
1825 |
if (size) |
2020 |
if (!rc->rc_skipped) |
1826 |
*size = lsize; |
2021 |
unexpected_errors++; |
1827 |
|
2022 |
|
1828 |
if (comp >= ZIO_COMPRESS_FUNCTIONS) |
2023 |
total_errors++; |
1829 |
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, |
2024 |
} |
1830 |
"compression algorithm %u not supported\n", (unsigned int) comp); |
2025 |
else if (c < (int)rm->rm_firstdatacol && !rc->rc_tried) |
|
|
2026 |
{ |
2027 |
parity_untried++; |
2028 |
} |
2029 |
} |
2030 |
/* |
2031 |
* There are three potential phases for a read: |
2032 |
* 1. produce valid data from the columns read |
2033 |
* 2. read all disks and try again |
2034 |
* 3. perform combinatorial reconstruction |
2035 |
* |
2036 |
* Each phase is progressively both more expensive and less likely to |
2037 |
* occur. If we encounter more errors than we can repair or all phases |
2038 |
* fail, we have no choice but to return an error. |
2039 |
*/ |
1831 |
|
2040 |
|
1832 |
if (comp != ZIO_COMPRESS_OFF && decomp_table[comp].decomp_func == NULL) |
2041 |
/* |
|
|
2042 |
* If the number of errors we saw was correctable -- less than or equal |
2043 |
* to the number of parity disks read -- attempt to produce data that |
2044 |
* has a valid checksum. Naturally, this case applies in the absence of |
2045 |
* any errors. |
2046 |
*/ |
2047 |
if (total_errors <= (int)rm->rm_firstdatacol - parity_untried) |
2048 |
{ |
2049 |
if (data_errors == 0) |
2050 |
{ |
2051 |
rc = &rm->rm_col[rm->rm_firstdatacol]; |
2052 |
if ((err = zio_checksum_error(bp, endian, rc->rc_data)) == 0) |
2053 |
{ |
2054 |
goto done; |
2055 |
} |
2056 |
else |
2057 |
rm->rm_ecksuminjected = 1; |
2058 |
} |
2059 |
else |
2060 |
{ |
2061 |
n = 0; |
2062 |
for (c = rm->rm_firstdatacol; c < (int)rm->rm_cols; c++) |
2063 |
{ |
2064 |
rc = &rm->rm_col[c]; |
2065 |
if (rc->rc_error != 0) |
2066 |
tgts[n++] = c; |
2067 |
} |
2068 |
code = vdev_raidz_reconstruct(rm, tgts, n); |
2069 |
rc = &rm->rm_col[rm->rm_firstdatacol]; |
2070 |
if ((err = zio_checksum_error(bp, endian, rc->rc_data)) == 0) |
2071 |
{ |
2072 |
goto done; |
2073 |
} |
2074 |
else |
2075 |
rm->rm_ecksuminjected = 1; |
2076 |
} |
2077 |
} |
2078 |
/* |
2079 |
* if all else fails. make sure we have read all columns and |
2080 |
* check again. |
2081 |
*/ |
2082 |
unexpected_errors = 1; |
2083 |
rm->rm_missingdata = 0; |
2084 |
rm->rm_missingparity = 0; |
2085 |
|
2086 |
for (c = 0; c < (int) rm->rm_cols; c++) |
2087 |
{ |
2088 |
struct grub_zfs_device_desc *cvd; |
2089 |
if (rm->rm_col[c].rc_tried) |
2090 |
continue; |
2091 |
|
2092 |
do { |
2093 |
rc = &rm->rm_col[c]; |
2094 |
if (rc->rc_tried) |
2095 |
continue; |
2096 |
|
2097 |
cvd = &desc->children[rc->rc_devidx]; |
2098 |
err = read_device (rc->rc_offset, cvd, rc->rc_size, |
2099 |
rc->rc_data, NULL); |
2100 |
rc->rc_error = err; |
2101 |
rc->rc_tried = 1; |
2102 |
rc->rc_skipped = 0; |
2103 |
} while (++c < (int) rm->rm_cols); |
2104 |
|
2105 |
/* and repeat the check */ |
2106 |
return vdev_raidz_io_done(bp, desc, endian, rm); |
2107 |
} |
2108 |
|
2109 |
/* |
2110 |
* all columns are read, it could still be the silent data corruption. |
2111 |
*/ |
2112 |
err = GRUB_ERR_IO; |
2113 |
|
2114 |
if (total_errors < (int) rm->rm_firstdatacol) |
2115 |
{ |
2116 |
code = vdev_raidz_combrec(bp, endian, rm, total_errors, data_errors); |
2117 |
if (code != 0) |
2118 |
err = GRUB_ERR_NONE; |
2119 |
} |
2120 |
|
2121 |
done: |
2122 |
grub_dprintf("zfs", "vdev_raidz_io_done (%d):\n" |
2123 |
"\tdata errors: %d\n" |
2124 |
"\tparity errors: %d\n" |
2125 |
"\tparity untried: %d\n" |
2126 |
"\tunexpected errors: %d\n" |
2127 |
"\ttotal errors: %d\n", err, data_errors, parity_errors, |
2128 |
parity_untried, unexpected_errors, total_errors); |
2129 |
|
2130 |
vdev_raidz_map_free(rm); |
2131 |
return err; |
2132 |
} |
2133 |
|
2134 |
static grub_err_t |
2135 |
vdev_mirror_io_done(blkptr_t *bp, grub_zfs_endian_t endian, mirror_map_t *mm) |
2136 |
{ |
2137 |
mirror_child_t *mc = NULL; |
2138 |
int c; |
2139 |
grub_err_t err = GRUB_ERR_NONE; |
2140 |
|
2141 |
while ((c = vdev_mirror_child_select(mm)) >= 0) |
2142 |
{ |
2143 |
grub_dprintf("zfs", "reading mirror child: %d\n", c); |
2144 |
mc = &mm->mm_child[c]; |
2145 |
err = read_device (mm->mm_offset, mc->mc_vd, mm->mm_size, |
2146 |
mm->mm_buf, NULL); |
2147 |
mc->mc_tried = 1; |
2148 |
mc->mc_skipped = 0; |
2149 |
if (err == GRUB_ERR_NONE) |
2150 |
{ |
2151 |
err = zio_checksum_error(bp, endian, mm->mm_buf); |
2152 |
if (err == GRUB_ERR_NONE) |
2153 |
break; |
2154 |
} |
2155 |
mc->mc_error = err; |
2156 |
} |
2157 |
|
2158 |
grub_free(mm); |
2159 |
return err; |
2160 |
} |
2161 |
|
2162 |
static grub_err_t |
2163 |
read_dva (blkptr_t *bp, const dva_t *dva, grub_zfs_endian_t endian, |
2164 |
struct grub_zfs_data *data, void *buf, grub_size_t len) |
2165 |
{ |
2166 |
grub_uint64_t offset; |
2167 |
grub_size_t align; |
2168 |
grub_size_t asize; |
2169 |
void *abuf = NULL, *orig_buf = NULL; |
2170 |
unsigned i; |
2171 |
void *priv; |
2172 |
grub_err_t err = GRUB_ERR_NONE; |
2173 |
offset = DVA_GET_OFFSET (dva, endian); |
2174 |
struct grub_zfs_device_desc *desc; |
2175 |
|
2176 |
for (i = 0; i < data->n_devices_attached; i++) |
2177 |
if (data->devices_attached[i].id == DVA_GET_VDEV (dva)) |
2178 |
{ |
2179 |
desc = &data->devices_attached[i]; |
2180 |
align = 1 << desc->ashift; |
2181 |
|
2182 |
if (P2PHASE(len, align) != 0) { |
2183 |
grub_dprintf("zfs", "read_dva: unaligned read: %" |
2184 |
PRIdGRUB_SSIZE "(%" PRIdGRUB_SSIZE ")\n", |
2185 |
len, P2ROUNDUP(len, align)); |
2186 |
asize = P2ROUNDUP(len, align); |
2187 |
abuf = grub_malloc(asize); |
2188 |
orig_buf = buf; |
2189 |
} else { |
2190 |
asize = len; |
2191 |
abuf = buf; |
2192 |
} |
2193 |
|
2194 |
grub_dprintf("zfs", "read_dva vdev: %d\n", i); |
2195 |
err = read_device (offset, desc, asize, abuf, &priv); |
2196 |
if (err != GRUB_ERR_NONE) |
2197 |
break; |
2198 |
|
2199 |
if (data->devices_attached[i].type == DEVICE_MIRROR) |
2200 |
{ |
2201 |
mirror_map_t *mm = priv; |
2202 |
err = vdev_mirror_io_done(bp, endian, mm); |
2203 |
} |
2204 |
if (data->devices_attached[i].type == DEVICE_RAIDZ) |
2205 |
{ |
2206 |
raidz_map_t *rm = priv; |
2207 |
err = vdev_raidz_io_done(bp, desc, endian, rm); |
2208 |
} |
2209 |
if (data->devices_attached[i].type == DEVICE_LEAF) |
2210 |
{ |
2211 |
err = zio_checksum_error(bp, endian, abuf); |
2212 |
} |
2213 |
|
2214 |
if (err == GRUB_ERR_NONE) |
2215 |
{ |
2216 |
if (orig_buf != NULL) |
2217 |
{ |
2218 |
grub_memcpy(buf, abuf, len); |
2219 |
grub_free(abuf); |
2220 |
} |
2221 |
return err; |
2222 |
} |
2223 |
break; |
2224 |
} |
2225 |
|
2226 |
if (orig_buf != NULL) |
2227 |
grub_free(abuf); |
2228 |
|
2229 |
if (!err) |
2230 |
return grub_error (GRUB_ERR_BAD_FS, "unknown device %d", |
2231 |
(int) DVA_GET_VDEV (dva)); |
2232 |
return err; |
2233 |
} |
2234 |
|
2235 |
/* |
2236 |
* Read a block of data based on the gang block address dva, |
2237 |
* and put its data in buf. |
2238 |
*/ |
2239 |
static grub_err_t |
2240 |
zio_read_gang_data (blkptr_t * bp, grub_zfs_endian_t endian, void *buf, |
2241 |
struct grub_zfs_data *data) |
2242 |
{ |
2243 |
int i; |
2244 |
|
2245 |
/* pick a good dva from the block pointer */ |
2246 |
for (i = 0; i < BP_GET_NDVAS(bp); i++) |
2247 |
{ |
2248 |
if (zio_read_common(bp, &bp->blk_dva[i], endian, buf, data) == GRUB_ERR_NONE) |
2249 |
return GRUB_ERR_NONE; |
2250 |
} |
2251 |
return grub_error (GRUB_ERR_BAD_FS, "couldn't find a valid DVA"); |
2252 |
} |
2253 |
|
2254 |
/* |
2255 |
* Read gang block header, verify its checksum, loop through all gang blocks |
2256 |
* to collect its data based on the gang block address dva and put it in buf. |
2257 |
* |
2258 |
*/ |
2259 |
static grub_err_t |
2260 |
zio_read_gang (blkptr_t * bp, grub_zfs_endian_t endian, dva_t * dva, void *buf, |
2261 |
struct grub_zfs_data *data) |
2262 |
{ |
2263 |
zio_gbh_phys_t *zio_gb; |
2264 |
unsigned i; |
2265 |
grub_err_t err; |
2266 |
|
2267 |
zio_gb = grub_malloc (SPA_GANGBLOCKSIZE); |
2268 |
if (!zio_gb) |
2269 |
return grub_errno; |
2270 |
grub_dprintf ("zfs", endian == GRUB_ZFS_LITTLE_ENDIAN ? "little-endian gang\n" |
2271 |
:"big-endian gang\n"); |
2272 |
|
2273 |
err = read_dva (bp, dva, endian, data, zio_gb, SPA_GANGBLOCKSIZE); |
2274 |
if (err) |
2275 |
{ |
2276 |
grub_free (zio_gb); |
2277 |
return err; |
2278 |
} |
2279 |
|
2280 |
endian = (grub_zfs_to_cpu64 (bp->blk_prop, endian) >> 63) & 1; |
2281 |
|
2282 |
for (i = 0; i < SPA_GBH_NBLKPTRS; i++) |
2283 |
{ |
2284 |
if (zio_gb->zg_blkptr[i].blk_birth == 0) |
2285 |
continue; |
2286 |
|
2287 |
err = zio_read_gang_data (&zio_gb->zg_blkptr[i], endian, buf, data); |
2288 |
if (err) |
2289 |
{ |
2290 |
grub_free (zio_gb); |
2291 |
return err; |
2292 |
} |
2293 |
buf = (char *) buf + BP_GET_PSIZE (&zio_gb->zg_blkptr[i], endian); |
2294 |
} |
2295 |
grub_free (zio_gb); |
2296 |
return GRUB_ERR_NONE; |
2297 |
} |
2298 |
|
2299 |
/* |
2300 |
* Read in a block of raw data to buf. |
2301 |
*/ |
2302 |
static grub_err_t |
2303 |
zio_read_common (blkptr_t * bp, dva_t *dva, grub_zfs_endian_t endian, |
2304 |
void *buf, struct grub_zfs_data *data) |
2305 |
{ |
2306 |
int psize; |
2307 |
grub_err_t err = GRUB_ERR_NONE; |
2308 |
|
2309 |
psize = BP_GET_PSIZE (bp, endian); |
2310 |
|
2311 |
if (dva->dva_word[0] == 0 && dva->dva_word[1] == 0) |
2312 |
return grub_error (GRUB_ERR_BAD_FS, "couldn't find a valid DVA"); |
2313 |
|
2314 |
if (BP_IS_GANG(bp, endian)) |
2315 |
err = zio_read_gang (bp, endian, dva, buf, data); |
2316 |
else |
2317 |
err = read_dva (bp, dva, endian, data, buf, psize); |
2318 |
|
2319 |
return err; |
2320 |
|
2321 |
} |
2322 |
|
2323 |
/* |
2324 |
* Loop through DVAs to read in a block of raw data to buf and verify |
2325 |
* the checksum. |
2326 |
*/ |
2327 |
static grub_err_t |
2328 |
zio_read_data (blkptr_t * bp, grub_zfs_endian_t endian, void *buf, |
2329 |
struct grub_zfs_data *data) |
2330 |
{ |
2331 |
int i; |
2332 |
grub_err_t err = GRUB_ERR_NONE; |
2333 |
|
2334 |
/* pick a good dva from the block pointer */ |
2335 |
for (i = 0; i < BP_GET_NDVAS(bp); i++) |
2336 |
{ |
2337 |
if (zio_read_common(bp, &bp->blk_dva[i], endian, buf, data) != GRUB_ERR_NONE) |
2338 |
{ |
2339 |
grub_errno = GRUB_ERR_NONE; |
2340 |
continue; |
2341 |
} |
2342 |
/* if no errors, return from here */ |
2343 |
return GRUB_ERR_NONE; |
2344 |
} |
2345 |
|
2346 |
err = grub_error (GRUB_ERR_BAD_FS, "couldn't find a valid DVA"); |
2347 |
grub_errno = err; |
2348 |
|
2349 |
return err; |
2350 |
} |
2351 |
|
2352 |
/* |
2353 |
* buf must be at least BPE_GET_PSIZE(bp) bytes long (which will never be |
2354 |
* more than BPE_PAYLOAD_SIZE bytes). |
2355 |
*/ |
2356 |
static grub_err_t |
2357 |
decode_embedded_bp_compressed(const blkptr_t *bp, grub_zfs_endian_t endian, |
2358 |
void *buf) |
2359 |
{ |
2360 |
grub_size_t psize, i; |
2361 |
grub_uint8_t *buf8 = buf; |
2362 |
grub_uint64_t w = 0; |
2363 |
const grub_uint64_t *bp64 = (const grub_uint64_t *)bp; |
2364 |
|
2365 |
psize = BPE_GET_PSIZE(bp, endian); |
2366 |
|
2367 |
/* |
2368 |
* Decode the words of the block pointer into the byte array. |
2369 |
* Low bits of first word are the first byte (little endian). |
2370 |
*/ |
2371 |
for (i = 0; i < psize; i++) { |
2372 |
if (i % sizeof (w) == 0) { |
2373 |
/* beginning of a word */ |
2374 |
w = grub_zfs_to_cpu64(*bp64, endian); |
2375 |
bp64++; |
2376 |
if (!BPE_IS_PAYLOADWORD(bp, bp64)) |
2377 |
bp64++; |
2378 |
} |
2379 |
buf8[i] = BF64_GET(w, (i % sizeof (w)) * NBBY, NBBY); |
2380 |
} |
2381 |
return GRUB_ERR_NONE; |
2382 |
} |
2383 |
|
2384 |
/* |
2385 |
* Read in a block of data, verify its checksum, decompress if needed, |
2386 |
* and put the uncompressed data in buf. |
2387 |
*/ |
2388 |
static grub_err_t |
2389 |
zio_read (blkptr_t *bp, grub_zfs_endian_t endian, void **buf, |
2390 |
grub_size_t *size, struct grub_zfs_data *data) |
2391 |
{ |
2392 |
grub_size_t lsize, psize; |
2393 |
unsigned int comp, encrypted; |
2394 |
char *compbuf = NULL; |
2395 |
zio_cksum_t zc = bp->blk_cksum; |
2396 |
grub_err_t err; |
2397 |
|
2398 |
*buf = NULL; |
2399 |
|
2400 |
comp = BP_GET_COMPRESS(bp, endian); |
2401 |
encrypted = ((grub_zfs_to_cpu64((bp)->blk_prop, endian) >> 60) & 3); |
2402 |
|
2403 |
grub_dprintf("zfs", "zio_read compress %d\n", (unsigned int) comp); |
2404 |
if (BP_IS_EMBEDDED(bp, endian)) { |
2405 |
if(BPE_GET_ETYPE(bp, endian) != BP_EMBEDDED_TYPE_DATA) { |
2406 |
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, |
2407 |
"unsupported embedded BP (type=%u)\n", |
2408 |
(int) BPE_GET_ETYPE(bp, endian)); |
2409 |
} |
2410 |
lsize = BPE_GET_LSIZE(bp, endian); |
2411 |
psize = BPE_GET_PSIZE(bp, endian); |
2412 |
} else { |
2413 |
lsize = BP_GET_LSIZE(bp, endian); |
2414 |
psize = BP_GET_PSIZE(bp, endian); |
2415 |
} |
2416 |
|
2417 |
grub_dprintf("zfs", "zio_read: size %" PRIdGRUB_SSIZE "/%" |
2418 |
PRIdGRUB_SSIZE "\n", lsize, psize); |
2419 |
if (comp >= ZIO_COMPRESS_FUNCTIONS) |
2420 |
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, |
2421 |
"compression algorithm %u not supported\n", (unsigned int) comp); |
2422 |
|
2423 |
if (comp != ZIO_COMPRESS_OFF && decomp_table[comp].decomp_func == NULL) |
1833 |
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, |
2424 |
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, |
1834 |
"compression algorithm %s not supported\n", decomp_table[comp].name); |
2425 |
"compression algorithm %s not supported\n", decomp_table[comp].name); |
1835 |
|
2426 |
|
Lines 1841-1863
Link Here
|
1841 |
return grub_errno; |
2432 |
return grub_errno; |
1842 |
} |
2433 |
} |
1843 |
else |
2434 |
else |
1844 |
compbuf = *buf = grub_malloc (lsize); |
|
|
1845 |
|
1846 |
grub_dprintf ("zfs", "endian = %d\n", endian); |
1847 |
err = zio_read_data (bp, endian, compbuf, data); |
1848 |
if (err) |
1849 |
{ |
2435 |
{ |
1850 |
grub_free (compbuf); |
2436 |
compbuf = *buf = grub_malloc (lsize); |
1851 |
*buf = NULL; |
2437 |
if (! compbuf) |
1852 |
return err; |
2438 |
return grub_errno; |
1853 |
} |
2439 |
} |
1854 |
grub_memset (compbuf, 0, ALIGN_UP (psize, 16) - psize); |
|
|
1855 |
|
2440 |
|
1856 |
err = zio_checksum_verify (zc, checksum, endian, |
2441 |
if (size) |
1857 |
compbuf, psize); |
2442 |
*size = lsize; |
|
|
2443 |
|
2444 |
grub_dprintf ("zfs", "endian = %d\n", endian); |
2445 |
if (BP_IS_EMBEDDED(bp, endian)) { |
2446 |
err = decode_embedded_bp_compressed(bp, endian, compbuf); |
2447 |
} else { |
2448 |
err = zio_read_data (bp, endian, compbuf, data); |
2449 |
grub_memset (compbuf, 0, ALIGN_UP (psize, 16) - psize); |
2450 |
} |
2451 |
|
1858 |
if (err) |
2452 |
if (err) |
1859 |
{ |
2453 |
{ |
1860 |
grub_dprintf ("zfs", "incorrect checksum\n"); |
|
|
1861 |
grub_free (compbuf); |
2454 |
grub_free (compbuf); |
1862 |
*buf = NULL; |
2455 |
*buf = NULL; |
1863 |
return err; |
2456 |
return err; |
Lines 1950-1972
Link Here
|
1950 |
grub_zfs_endian_t endian; |
2543 |
grub_zfs_endian_t endian; |
1951 |
grub_err_t err = GRUB_ERR_NONE; |
2544 |
grub_err_t err = GRUB_ERR_NONE; |
1952 |
|
2545 |
|
1953 |
bp = grub_malloc (sizeof (blkptr_t)); |
|
|
1954 |
if (!bp) |
1955 |
return grub_errno; |
1956 |
|
1957 |
endian = dn->endian; |
2546 |
endian = dn->endian; |
1958 |
for (level = dn->dn.dn_nlevels - 1; level >= 0; level--) |
2547 |
for (level = dn->dn.dn_nlevels - 1; level >= 0; level--) |
1959 |
{ |
2548 |
{ |
1960 |
grub_dprintf ("zfs", "endian = %d\n", endian); |
2549 |
grub_dprintf ("zfs", "endian = %d\n", endian); |
1961 |
idx = (blkid >> (epbs * level)) & ((1 << epbs) - 1); |
2550 |
idx = (blkid >> (epbs * level)) & ((1 << epbs) - 1); |
1962 |
*bp = bp_array[idx]; |
2551 |
bp = &bp_array[idx]; |
1963 |
if (bp_array != dn->dn.dn_blkptr) |
2552 |
if (BP_IS_HOLE (bp, endian)) |
1964 |
{ |
|
|
1965 |
grub_free (bp_array); |
1966 |
bp_array = 0; |
1967 |
} |
1968 |
|
1969 |
if (BP_IS_HOLE (bp)) |
1970 |
{ |
2553 |
{ |
1971 |
grub_size_t size = grub_zfs_to_cpu16 (dn->dn.dn_datablkszsec, |
2554 |
grub_size_t size = grub_zfs_to_cpu16 (dn->dn.dn_datablkszsec, |
1972 |
dn->endian) |
2555 |
dn->endian) |
Lines 1993-1998
Link Here
|
1993 |
endian = (grub_zfs_to_cpu64 (bp->blk_prop, endian) >> 63) & 1; |
2576 |
endian = (grub_zfs_to_cpu64 (bp->blk_prop, endian) >> 63) & 1; |
1994 |
if (err) |
2577 |
if (err) |
1995 |
break; |
2578 |
break; |
|
|
2579 |
if (bp_array != dn->dn.dn_blkptr) |
2580 |
grub_free (bp_array); |
1996 |
bp_array = tmpbuf; |
2581 |
bp_array = tmpbuf; |
1997 |
} |
2582 |
} |
1998 |
if (bp_array != dn->dn.dn_blkptr) |
2583 |
if (bp_array != dn->dn.dn_blkptr) |
Lines 2000-2006
Link Here
|
2000 |
if (endian_out) |
2585 |
if (endian_out) |
2001 |
*endian_out = endian; |
2586 |
*endian_out = endian; |
2002 |
|
2587 |
|
2003 |
grub_free (bp); |
|
|
2004 |
return err; |
2588 |
return err; |
2005 |
} |
2589 |
} |
2006 |
|
2590 |
|
Lines 2030-2040
Link Here
|
2030 |
return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file `%s' not found"), name); |
2614 |
return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file `%s' not found"), name); |
2031 |
} |
2615 |
} |
2032 |
|
2616 |
|
|
|
2617 |
/* |
2618 |
* mzap_value_search: Looks up value and returns property name. |
2619 |
*/ |
2620 |
static grub_err_t |
2621 |
mzap_value_search (mzap_phys_t *zapobj, grub_zfs_endian_t endian, |
2622 |
int objsize, char *name, grub_uint64_t *value) |
2623 |
{ |
2624 |
int i, chunks; |
2625 |
mzap_ent_phys_t *mzap_ent = zapobj->mz_chunk; |
2626 |
grub_uint64_t mze_val; |
2627 |
|
2628 |
chunks = objsize / MZAP_ENT_LEN - 1; |
2629 |
for (i = 0; i < chunks; i++) |
2630 |
{ |
2631 |
mze_val = grub_zfs_to_cpu64 (mzap_ent[i].mze_value, endian); |
2632 |
if (mze_val == *value) |
2633 |
{ |
2634 |
grub_memcpy (name, mzap_ent[i].mze_name, grub_strlen |
2635 |
(mzap_ent[i].mze_name) + 1); |
2636 |
return GRUB_ERR_NONE; |
2637 |
} |
2638 |
} |
2639 |
|
2640 |
return grub_error (GRUB_ERR_FILE_NOT_FOUND, |
2641 |
"mzap_value_search: couldn't find %s", value); |
2642 |
} |
2643 |
|
2033 |
static int |
2644 |
static int |
2034 |
mzap_iterate (mzap_phys_t * zapobj, grub_zfs_endian_t endian, int objsize, |
2645 |
mzap_iterate (mzap_phys_t * zapobj, grub_zfs_endian_t endian, int objsize, |
2035 |
int (*hook) (const char *name, grub_uint64_t val, |
2646 |
int (*hook) (const char *name, grub_uint64_t val, |
2036 |
struct grub_zfs_dir_ctx *ctx), |
2647 |
struct grub_zfs_dir_ctx *ctx), |
2037 |
struct grub_zfs_dir_ctx *ctx) |
2648 |
struct grub_zfs_dir_ctx *ctx) |
2038 |
{ |
2649 |
{ |
2039 |
int i, chunks; |
2650 |
int i, chunks; |
2040 |
mzap_ent_phys_t *mzap_ent = zapobj->mz_chunk; |
2651 |
mzap_ent_phys_t *mzap_ent = zapobj->mz_chunk; |
Lines 2088-2094
Link Here
|
2088 |
*/ |
2699 |
*/ |
2089 |
crc &= ~((1ULL << (64 - ZAP_HASHBITS)) - 1); |
2700 |
crc &= ~((1ULL << (64 - ZAP_HASHBITS)) - 1); |
2090 |
|
2701 |
|
2091 |
return crc; |
2702 |
return (crc); |
2092 |
} |
2703 |
} |
2093 |
|
2704 |
|
2094 |
/* |
2705 |
/* |
Lines 2110-2116
Link Here
|
2110 |
while (n--) |
2721 |
while (n--) |
2111 |
{ |
2722 |
{ |
2112 |
if (grub_toupper (*t1) != grub_toupper (*t2)) |
2723 |
if (grub_toupper (*t1) != grub_toupper (*t2)) |
2113 |
return (int) grub_toupper (*t1) - (int) grub_toupper (*t2); |
2724 |
return (int) grub_toupper (*t1) - (int) grub_toupper (*t2); |
2114 |
|
2725 |
|
2115 |
t1++; |
2726 |
t1++; |
2116 |
t2++; |
2727 |
t2++; |
Lines 2298-2306
Link Here
|
2298 |
fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap, |
2909 |
fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap, |
2299 |
grub_size_t name_elem_length, |
2910 |
grub_size_t name_elem_length, |
2300 |
int (*hook) (const void *name, grub_size_t name_length, |
2911 |
int (*hook) (const void *name, grub_size_t name_length, |
2301 |
const void *val_in, |
2912 |
const void *val_in, grub_size_t nelem, |
2302 |
grub_size_t nelem, grub_size_t elemsize, |
2913 |
grub_size_t elemsize, void *data), |
2303 |
void *data), |
|
|
2304 |
void *hook_data, struct grub_zfs_data *data) |
2914 |
void *hook_data, struct grub_zfs_data *data) |
2305 |
{ |
2915 |
{ |
2306 |
zap_leaf_phys_t *l; |
2916 |
zap_leaf_phys_t *l; |
Lines 2331-2341
Link Here
|
2331 |
for (idx = 0; idx < (1ULL << zap->zap_ptrtbl.zt_shift); idx++) |
2941 |
for (idx = 0; idx < (1ULL << zap->zap_ptrtbl.zt_shift); idx++) |
2332 |
{ |
2942 |
{ |
2333 |
blkid = grub_zfs_to_cpu64 (((grub_uint64_t *) zap)[idx + (1 << (blksft - 3 - 1))], |
2943 |
blkid = grub_zfs_to_cpu64 (((grub_uint64_t *) zap)[idx + (1 << (blksft - 3 - 1))], |
2334 |
zap_dnode->endian); |
2944 |
zap_dnode->endian); |
2335 |
|
2945 |
|
2336 |
for (idx2 = 0; idx2 < idx; idx2++) |
2946 |
for (idx2 = 0; idx2 < idx; idx2++) |
2337 |
if (blkid == grub_zfs_to_cpu64 (((grub_uint64_t *) zap)[idx2 + (1 << (blksft - 3 - 1))], |
2947 |
if (blkid == grub_zfs_to_cpu64 (((grub_uint64_t *) zap)[idx2 + (1 << (blksft - 3 - 1))], |
2338 |
zap_dnode->endian)) |
2948 |
zap_dnode->endian)) |
2339 |
break; |
2949 |
break; |
2340 |
if (idx2 != idx) |
2950 |
if (idx2 != idx) |
2341 |
continue; |
2951 |
continue; |
Lines 2361-2415
Link Here
|
2361 |
} |
2971 |
} |
2362 |
|
2972 |
|
2363 |
for (chunk = 0; chunk < ZAP_LEAF_NUMCHUNKS (blksft); chunk++) |
2973 |
for (chunk = 0; chunk < ZAP_LEAF_NUMCHUNKS (blksft); chunk++) |
2364 |
{ |
2974 |
{ |
2365 |
char *buf; |
2975 |
char *buf; |
2366 |
struct zap_leaf_entry *le; |
2976 |
struct zap_leaf_entry *le; |
2367 |
char *val; |
2977 |
char *val; |
2368 |
grub_size_t val_length; |
2978 |
grub_size_t val_length; |
2369 |
le = ZAP_LEAF_ENTRY (l, blksft, chunk); |
2979 |
le = ZAP_LEAF_ENTRY (l, blksft, chunk); |
2370 |
|
|
|
2371 |
/* Verify the chunk entry */ |
2372 |
if (le->le_type != ZAP_CHUNK_ENTRY) |
2373 |
continue; |
2374 |
|
2980 |
|
2375 |
buf = grub_malloc (grub_zfs_to_cpu16 (le->le_name_length, endian) |
2981 |
/* Verify the chunk entry */ |
2376 |
* name_elem_length + 1); |
2982 |
if (le->le_type != ZAP_CHUNK_ENTRY) |
2377 |
if (zap_leaf_array_get (l, endian, blksft, |
|
|
2378 |
grub_zfs_to_cpu16 (le->le_name_chunk, |
2379 |
endian), |
2380 |
grub_zfs_to_cpu16 (le->le_name_length, |
2381 |
endian) |
2382 |
* name_elem_length, buf)) |
2383 |
{ |
2384 |
grub_free (buf); |
2385 |
continue; |
2983 |
continue; |
2386 |
} |
|
|
2387 |
buf[le->le_name_length * name_elem_length] = 0; |
2388 |
|
2984 |
|
2389 |
val_length = ((int) le->le_value_length |
2985 |
buf = grub_malloc (grub_zfs_to_cpu16 (le->le_name_length, endian) |
2390 |
* (int) le->le_int_size); |
2986 |
* name_elem_length + 1); |
2391 |
val = grub_malloc (grub_zfs_to_cpu16 (val_length, endian)); |
2987 |
if (zap_leaf_array_get (l, endian, blksft, |
2392 |
if (zap_leaf_array_get (l, endian, blksft, |
2988 |
grub_zfs_to_cpu16 (le->le_name_chunk, |
2393 |
grub_zfs_to_cpu16 (le->le_value_chunk, |
2989 |
endian), |
2394 |
endian), |
2990 |
grub_zfs_to_cpu16 (le->le_name_length, |
2395 |
val_length, val)) |
2991 |
endian) |
2396 |
{ |
2992 |
* name_elem_length, buf)) |
2397 |
grub_free (buf); |
2993 |
{ |
2398 |
grub_free (val); |
2994 |
grub_free (buf); |
2399 |
continue; |
2995 |
continue; |
2400 |
} |
2996 |
} |
|
|
2997 |
buf[le->le_name_length * name_elem_length] = 0; |
2401 |
|
2998 |
|
2402 |
if (hook (buf, le->le_name_length, |
2999 |
val_length = ((int) le->le_value_length |
2403 |
val, le->le_value_length, le->le_int_size, hook_data)) |
3000 |
* (int) le->le_int_size); |
2404 |
{ |
3001 |
val = grub_malloc (grub_zfs_to_cpu16 (val_length, endian)); |
2405 |
grub_free (l); |
3002 |
if (zap_leaf_array_get (l, endian, blksft, |
2406 |
return 1; |
3003 |
grub_zfs_to_cpu16 (le->le_value_chunk, |
2407 |
} |
3004 |
endian), |
2408 |
grub_free (buf); |
3005 |
val_length, val)) |
2409 |
grub_free (val); |
3006 |
{ |
2410 |
} |
3007 |
grub_free (buf); |
2411 |
grub_free (l); |
3008 |
grub_free (val); |
2412 |
} |
3009 |
continue; |
|
|
3010 |
} |
3011 |
|
3012 |
if (hook (buf, le->le_name_length, |
3013 |
val, le->le_value_length, le->le_int_size, hook_data)) |
3014 |
{ |
3015 |
grub_free (l); |
3016 |
return 1; |
3017 |
} |
3018 |
grub_free (buf); |
3019 |
grub_free (val); |
3020 |
} |
3021 |
grub_free (l); |
3022 |
} |
2413 |
return 0; |
3023 |
return 0; |
2414 |
} |
3024 |
} |
2415 |
|
3025 |
|
Lines 2463-2578
Link Here
|
2463 |
return grub_error (GRUB_ERR_BAD_FS, "unknown ZAP type"); |
3073 |
return grub_error (GRUB_ERR_BAD_FS, "unknown ZAP type"); |
2464 |
} |
3074 |
} |
2465 |
|
3075 |
|
2466 |
/* Context for zap_iterate_u64. */ |
3076 |
/* |
2467 |
struct zap_iterate_u64_ctx |
3077 |
* Read in the data of a zap object and find the property name for a |
2468 |
{ |
3078 |
* matching value. |
2469 |
int (*hook) (const char *, grub_uint64_t, struct grub_zfs_dir_ctx *); |
3079 |
* |
2470 |
struct grub_zfs_dir_ctx *dir_ctx; |
3080 |
*/ |
2471 |
}; |
3081 |
static grub_err_t |
2472 |
|
3082 |
zap_value_search (dnode_end_t *zap_dnode, char *name, grub_uint64_t *val, |
2473 |
/* Helper for zap_iterate_u64. */ |
3083 |
struct grub_zfs_data *data) |
2474 |
static int |
|
|
2475 |
zap_iterate_u64_transform (const void *name, |
2476 |
grub_size_t namelen __attribute__ ((unused)), |
2477 |
const void *val_in, |
2478 |
grub_size_t nelem, |
2479 |
grub_size_t elemsize, |
2480 |
void *data) |
2481 |
{ |
2482 |
struct zap_iterate_u64_ctx *ctx = data; |
2483 |
|
2484 |
if (elemsize != sizeof (grub_uint64_t) || nelem != 1) |
2485 |
return 0; |
2486 |
return ctx->hook (name, grub_be_to_cpu64 (*(const grub_uint64_t *) val_in), |
2487 |
ctx->dir_ctx); |
2488 |
} |
2489 |
|
2490 |
static int |
2491 |
zap_iterate_u64 (dnode_end_t * zap_dnode, |
2492 |
int (*hook) (const char *name, grub_uint64_t val, |
2493 |
struct grub_zfs_dir_ctx *ctx), |
2494 |
struct grub_zfs_data *data, struct grub_zfs_dir_ctx *ctx) |
2495 |
{ |
3084 |
{ |
2496 |
grub_uint64_t block_type; |
3085 |
grub_uint64_t block_type; |
2497 |
int size; |
3086 |
int size; |
2498 |
void *zapbuf; |
3087 |
void *zapbuf; |
2499 |
grub_err_t err; |
3088 |
grub_err_t err; |
2500 |
int ret; |
|
|
2501 |
grub_zfs_endian_t endian; |
3089 |
grub_zfs_endian_t endian; |
2502 |
|
3090 |
|
|
|
3091 |
grub_dprintf ("zfs", "zap_value_search: looking for '%lld'\n", (unsigned long long)*val); |
3092 |
|
2503 |
/* Read in the first block of the zap object data. */ |
3093 |
/* Read in the first block of the zap object data. */ |
2504 |
size = grub_zfs_to_cpu16 (zap_dnode->dn.dn_datablkszsec, zap_dnode->endian) << SPA_MINBLOCKSHIFT; |
3094 |
size = grub_zfs_to_cpu16 (zap_dnode->dn.dn_datablkszsec, |
|
|
3095 |
zap_dnode->endian) << SPA_MINBLOCKSHIFT; |
2505 |
err = dmu_read (zap_dnode, 0, &zapbuf, &endian, data); |
3096 |
err = dmu_read (zap_dnode, 0, &zapbuf, &endian, data); |
2506 |
if (err) |
3097 |
if (err) |
2507 |
return 0; |
3098 |
return err; |
2508 |
block_type = grub_zfs_to_cpu64 (*((grub_uint64_t *) zapbuf), endian); |
3099 |
block_type = grub_zfs_to_cpu64 (*((grub_uint64_t *) zapbuf), endian); |
2509 |
|
3100 |
|
2510 |
grub_dprintf ("zfs", "zap iterate\n"); |
3101 |
grub_dprintf ("zfs", "zap_value_search: zap read\n"); |
2511 |
|
3102 |
|
2512 |
if (block_type == ZBT_MICRO) |
3103 |
if (block_type == ZBT_MICRO) |
2513 |
{ |
3104 |
{ |
2514 |
grub_dprintf ("zfs", "micro zap\n"); |
3105 |
grub_dprintf ("zfs", "zap_value_search: micro zap value search\n"); |
2515 |
ret = mzap_iterate (zapbuf, endian, size, hook, ctx); |
3106 |
err = (mzap_value_search (zapbuf, endian, size, name, val)); |
|
|
3107 |
grub_dprintf ("zfs", "zap_value_search: returned %d\n", err); |
2516 |
grub_free (zapbuf); |
3108 |
grub_free (zapbuf); |
2517 |
return ret; |
3109 |
return err; |
2518 |
} |
3110 |
} |
2519 |
else if (block_type == ZBT_HEADER) |
3111 |
else if (block_type == ZBT_HEADER) |
2520 |
{ |
3112 |
{ |
2521 |
struct zap_iterate_u64_ctx transform_ctx = { |
|
|
2522 |
.hook = hook, |
2523 |
.dir_ctx = ctx |
2524 |
}; |
2525 |
|
2526 |
grub_dprintf ("zfs", "fat zap\n"); |
2527 |
/* this is a fat zap */ |
3113 |
/* this is a fat zap */ |
2528 |
ret = fzap_iterate (zap_dnode, zapbuf, 1, |
3114 |
grub_dprintf ("zfs", "fat zap value search not supported\n"); |
2529 |
zap_iterate_u64_transform, &transform_ctx, data); |
|
|
2530 |
grub_free (zapbuf); |
3115 |
grub_free (zapbuf); |
2531 |
return ret; |
3116 |
return grub_error (GRUB_ERR_BAD_FS, "fat zap value search not supported"); |
2532 |
} |
3117 |
} |
2533 |
grub_error (GRUB_ERR_BAD_FS, "unknown ZAP type"); |
3118 |
|
2534 |
return 0; |
3119 |
return grub_error (GRUB_ERR_BAD_FS, "zap_value_search: unknown ZAP type"); |
2535 |
} |
3120 |
} |
2536 |
|
3121 |
|
2537 |
static int |
3122 |
/* Context for zap_iterate_u64. */ |
2538 |
zap_iterate (dnode_end_t * zap_dnode, |
3123 |
struct zap_iterate_u64_ctx |
2539 |
grub_size_t nameelemlen, |
|
|
2540 |
int (*hook) (const void *name, grub_size_t namelen, |
2541 |
const void *val_in, |
2542 |
grub_size_t nelem, grub_size_t elemsize, |
2543 |
void *data), |
2544 |
void *hook_data, struct grub_zfs_data *data) |
2545 |
{ |
3124 |
{ |
2546 |
grub_uint64_t block_type; |
3125 |
int (*hook) (const char *, grub_uint64_t, struct grub_zfs_dir_ctx *); |
2547 |
void *zapbuf; |
3126 |
struct grub_zfs_dir_ctx *dir_ctx; |
2548 |
grub_err_t err; |
3127 |
}; |
2549 |
int ret; |
|
|
2550 |
grub_zfs_endian_t endian; |
2551 |
|
3128 |
|
2552 |
/* Read in the first block of the zap object data. */ |
3129 |
/* Helper for zap_iterate_u64. */ |
2553 |
err = dmu_read (zap_dnode, 0, &zapbuf, &endian, data); |
3130 |
static int |
2554 |
if (err) |
3131 |
zap_iterate_u64_transform (const void *name, |
2555 |
return 0; |
3132 |
grub_size_t namelen __attribute__ ((unused)), |
2556 |
block_type = grub_zfs_to_cpu64 (*((grub_uint64_t *) zapbuf), endian); |
3133 |
const void *val_in, |
|
|
3134 |
grub_size_t nelem, |
3135 |
grub_size_t elemsize, |
3136 |
void *data) |
3137 |
{ |
3138 |
struct zap_iterate_u64_ctx *ctx = data; |
3139 |
|
3140 |
if (elemsize != sizeof (grub_uint64_t) || nelem != 1) |
3141 |
return 0; |
3142 |
return ctx->hook(name, |
3143 |
grub_be_to_cpu64 (*(const grub_uint64_t *) val_in), ctx->dir_ctx); |
3144 |
} |
2557 |
|
3145 |
|
2558 |
grub_dprintf ("zfs", "zap iterate\n"); |
3146 |
static int |
|
|
3147 |
zap_iterate_u64 (dnode_end_t * zap_dnode, |
3148 |
int (*hook) (const char *name, grub_uint64_t val, |
3149 |
struct grub_zfs_dir_ctx *ctx), |
3150 |
struct grub_zfs_data *data, struct grub_zfs_dir_ctx *ctx) |
3151 |
{ |
3152 |
grub_uint64_t block_type; |
3153 |
int size; |
3154 |
void *zapbuf; |
3155 |
grub_err_t err; |
3156 |
int ret; |
3157 |
grub_zfs_endian_t endian; |
3158 |
|
3159 |
/* Read in the first block of the zap object data. */ |
3160 |
size = grub_zfs_to_cpu16(zap_dnode->dn.dn_datablkszsec, |
3161 |
zap_dnode->endian) << SPA_MINBLOCKSHIFT; |
3162 |
err = dmu_read (zap_dnode, 0, &zapbuf, &endian, data); |
3163 |
if (err) |
3164 |
return 0; |
3165 |
block_type = grub_zfs_to_cpu64 (*((grub_uint64_t *) zapbuf), endian); |
3166 |
|
3167 |
grub_dprintf ("zfs", "zap iterate\n"); |
3168 |
|
3169 |
if (block_type == ZBT_MICRO) { |
3170 |
grub_dprintf ("zfs", "micro zap\n"); |
3171 |
ret = mzap_iterate (zapbuf, endian, size, hook, ctx); |
3172 |
grub_free (zapbuf); |
3173 |
return ret; |
3174 |
} else if (block_type == ZBT_HEADER) { |
3175 |
struct zap_iterate_u64_ctx transform_ctx = { |
3176 |
.hook = hook, |
3177 |
.dir_ctx = ctx |
3178 |
}; |
3179 |
grub_dprintf ("zfs", "fat zap\n"); |
3180 |
/* this is a fat zap */ |
3181 |
ret = fzap_iterate (zap_dnode, zapbuf, 1, |
3182 |
zap_iterate_u64_transform, &transform_ctx, data); |
3183 |
grub_free (zapbuf); |
3184 |
return ret; |
3185 |
} |
3186 |
grub_error (GRUB_ERR_BAD_FS, "unknown ZAP type"); |
3187 |
return 0; |
3188 |
} |
2559 |
|
3189 |
|
2560 |
if (block_type == ZBT_MICRO) |
3190 |
static int |
2561 |
{ |
3191 |
zap_iterate (dnode_end_t * zap_dnode, grub_size_t nameelemlen, |
2562 |
grub_error (GRUB_ERR_BAD_FS, "micro ZAP where FAT ZAP expected"); |
3192 |
int (*hook) (const void *name, grub_size_t namelen, const void *val_in, |
2563 |
return 0; |
3193 |
grub_size_t nelem, grub_size_t elemsize, void *data), |
2564 |
} |
3194 |
void *hook_data, struct grub_zfs_data *data) |
2565 |
if (block_type == ZBT_HEADER) |
3195 |
{ |
2566 |
{ |
3196 |
grub_uint64_t block_type; |
2567 |
grub_dprintf ("zfs", "fat zap\n"); |
3197 |
void *zapbuf; |
2568 |
/* this is a fat zap */ |
3198 |
grub_err_t err; |
2569 |
ret = fzap_iterate (zap_dnode, zapbuf, nameelemlen, hook, hook_data, |
3199 |
int ret; |
2570 |
data); |
3200 |
grub_zfs_endian_t endian; |
2571 |
grub_free (zapbuf); |
3201 |
|
2572 |
return ret; |
3202 |
/* Read in the first block of the zap object data. */ |
2573 |
} |
3203 |
err = dmu_read(zap_dnode, 0, &zapbuf, &endian, data); |
2574 |
grub_error (GRUB_ERR_BAD_FS, "unknown ZAP type"); |
3204 |
if (err) |
2575 |
return 0; |
3205 |
return 0; |
|
|
3206 |
block_type = grub_zfs_to_cpu64(*((grub_uint64_t *) zapbuf), endian); |
3207 |
|
3208 |
grub_dprintf("zfs", "zap iterate\n"); |
3209 |
|
3210 |
if (block_type == ZBT_MICRO) { |
3211 |
grub_error(GRUB_ERR_BAD_FS, "micro ZAP where FAT ZAP expected"); |
3212 |
return 0; |
3213 |
} |
3214 |
if (block_type == ZBT_HEADER) { |
3215 |
grub_dprintf ("zfs", "fat zap\n"); |
3216 |
/* this is a fat zap */ |
3217 |
ret = fzap_iterate(zap_dnode, zapbuf, nameelemlen, hook, |
3218 |
hook_data, data); |
3219 |
grub_free(zapbuf); |
3220 |
return ret; |
3221 |
} |
3222 |
grub_error(GRUB_ERR_BAD_FS, "unknown ZAP type"); |
3223 |
return 0; |
2576 |
} |
3224 |
} |
2577 |
|
3225 |
|
2578 |
|
3226 |
|
Lines 2608-2614
Link Here
|
2608 |
grub_memmove (&(buf->dn), &(data->dnode_buf)[idx], DNODE_SIZE); |
3256 |
grub_memmove (&(buf->dn), &(data->dnode_buf)[idx], DNODE_SIZE); |
2609 |
buf->endian = data->dnode_endian; |
3257 |
buf->endian = data->dnode_endian; |
2610 |
if (type && buf->dn.dn_type != type) |
3258 |
if (type && buf->dn.dn_type != type) |
2611 |
return grub_error(GRUB_ERR_BAD_FS, "incorrect dnode type"); |
3259 |
return grub_error(GRUB_ERR_BAD_FS, "[1] incorrect dnode type: %d != %d\n", buf->dn.dn_type, type); |
2612 |
return GRUB_ERR_NONE; |
3260 |
return GRUB_ERR_NONE; |
2613 |
} |
3261 |
} |
2614 |
|
3262 |
|
Lines 2620-2625
Link Here
|
2620 |
grub_dprintf ("zfs", "alive\n"); |
3268 |
grub_dprintf ("zfs", "alive\n"); |
2621 |
|
3269 |
|
2622 |
grub_free (data->dnode_buf); |
3270 |
grub_free (data->dnode_buf); |
|
|
3271 |
data->dnode_buf = NULL; |
2623 |
grub_free (data->dnode_mdn); |
3272 |
grub_free (data->dnode_mdn); |
2624 |
data->dnode_mdn = grub_malloc (sizeof (*mdn)); |
3273 |
data->dnode_mdn = grub_malloc (sizeof (*mdn)); |
2625 |
if (! data->dnode_mdn) |
3274 |
if (! data->dnode_mdn) |
Lines 2639-2645
Link Here
|
2639 |
grub_memmove (&(buf->dn), (dnode_phys_t *) dnbuf + idx, DNODE_SIZE); |
3288 |
grub_memmove (&(buf->dn), (dnode_phys_t *) dnbuf + idx, DNODE_SIZE); |
2640 |
buf->endian = endian; |
3289 |
buf->endian = endian; |
2641 |
if (type && buf->dn.dn_type != type) |
3290 |
if (type && buf->dn.dn_type != type) |
2642 |
return grub_error(GRUB_ERR_BAD_FS, "incorrect dnode type"); |
3291 |
return grub_error(GRUB_ERR_BAD_FS, "[2] incorrect dnode type: %d != %d\n", buf->dn.dn_type, type); |
2643 |
|
3292 |
|
2644 |
return GRUB_ERR_NONE; |
3293 |
return GRUB_ERR_NONE; |
2645 |
} |
3294 |
} |
Lines 2801-2807
Link Here
|
2801 |
grub_size_t block; |
3450 |
grub_size_t block; |
2802 |
grub_size_t blksz; |
3451 |
grub_size_t blksz; |
2803 |
blksz = (grub_zfs_to_cpu16 (dnode_path->dn.dn.dn_datablkszsec, |
3452 |
blksz = (grub_zfs_to_cpu16 (dnode_path->dn.dn.dn_datablkszsec, |
2804 |
dnode_path->dn.endian) |
3453 |
dnode_path->dn.endian) |
2805 |
<< SPA_MINBLOCKSHIFT); |
3454 |
<< SPA_MINBLOCKSHIFT); |
2806 |
|
3455 |
|
2807 |
sym_value = grub_malloc (sym_sz); |
3456 |
sym_value = grub_malloc (sym_sz); |
Lines 2846-2856
Link Here
|
2846 |
grub_free (dn_new); |
3495 |
grub_free (dn_new); |
2847 |
} |
3496 |
} |
2848 |
else while (dnode_path != root) |
3497 |
else while (dnode_path != root) |
2849 |
{ |
3498 |
{ |
2850 |
dn_new = dnode_path; |
3499 |
dn_new = dnode_path; |
2851 |
dnode_path = dn_new->next; |
3500 |
dnode_path = dn_new->next; |
2852 |
grub_free (dn_new); |
3501 |
grub_free (dn_new); |
2853 |
} |
3502 |
} |
2854 |
} |
3503 |
} |
2855 |
if (dnode_path->dn.dn.dn_bonustype == DMU_OT_SA) |
3504 |
if (dnode_path->dn.dn.dn_bonustype == DMU_OT_SA) |
2856 |
{ |
3505 |
{ |
Lines 2907-2917
Link Here
|
2907 |
grub_free (dn_new); |
3556 |
grub_free (dn_new); |
2908 |
} |
3557 |
} |
2909 |
else while (dnode_path != root) |
3558 |
else while (dnode_path != root) |
2910 |
{ |
3559 |
{ |
2911 |
dn_new = dnode_path; |
3560 |
dn_new = dnode_path; |
2912 |
dnode_path = dn_new->next; |
3561 |
dnode_path = dn_new->next; |
2913 |
grub_free (dn_new); |
3562 |
grub_free (dn_new); |
2914 |
} |
3563 |
} |
2915 |
} |
3564 |
} |
2916 |
} |
3565 |
} |
2917 |
} |
3566 |
} |
Lines 2929-2985
Link Here
|
2929 |
return err; |
3578 |
return err; |
2930 |
} |
3579 |
} |
2931 |
|
3580 |
|
2932 |
#if 0 |
3581 |
/* |
|
|
3582 |
* Get the default 'bootfs' dataset name using rootfs object number |
3583 |
* |
3584 |
*/ |
3585 |
static grub_err_t |
3586 |
get_default_bootfsname (dnode_end_t * mosmdn, grub_uint64_t bootfsobj, |
3587 |
struct grub_zfs_data *data, char **bootfsname) |
3588 |
{ |
3589 |
dnode_end_t dn; |
3590 |
dnode_end_t mdn; |
3591 |
grub_uint64_t dirobj; |
3592 |
grub_uint64_t parentobj; |
3593 |
grub_uint64_t childobj; |
3594 |
grub_uint64_t rootobj; |
3595 |
grub_size_t buf_size; |
3596 |
grub_err_t err = GRUB_ERR_NONE; |
3597 |
char *bootfs; |
3598 |
|
3599 |
*bootfsname = 0; |
3600 |
if ((grub_errno = dnode_get (mosmdn, DMU_POOL_DIRECTORY_OBJECT, |
3601 |
DMU_OT_OBJECT_DIRECTORY, &mdn, data))) |
3602 |
return (grub_errno); |
3603 |
|
3604 |
err = zap_lookup (&mdn, DMU_POOL_ROOT_DATASET, &rootobj, data, 0); |
3605 |
if (err) |
3606 |
return err; |
3607 |
|
3608 |
if ((grub_errno = dnode_get (mosmdn, bootfsobj, DMU_OT_DSL_DATASET, &dn, data))) |
3609 |
return (grub_errno); |
3610 |
|
3611 |
dirobj = grub_zfs_to_cpu64 (((dsl_dataset_phys_t *) |
3612 |
DN_BONUS (&dn.dn))->ds_dir_obj, dn.endian); |
3613 |
|
3614 |
buf_size = BOOTFSNAME_SIZE; |
3615 |
bootfs = grub_zalloc(buf_size); |
3616 |
do |
3617 |
{ |
3618 |
if ((grub_errno = dnode_get (mosmdn, dirobj, DMU_OT_DSL_DIR, &dn, data))) |
3619 |
{ |
3620 |
grub_free (bootfs); |
3621 |
return (grub_errno); |
3622 |
} |
3623 |
|
3624 |
parentobj = grub_zfs_to_cpu64 ((((dsl_dir_phys_t *) |
3625 |
DN_BONUS (&dn.dn)))->dd_parent_obj, dn.endian); |
3626 |
|
3627 |
if ((grub_errno = dnode_get (mosmdn, parentobj, DMU_OT_DSL_DIR, &dn, data))) |
3628 |
{ |
3629 |
grub_free (bootfs); |
3630 |
return (grub_errno); |
3631 |
} |
3632 |
|
3633 |
childobj = grub_zfs_to_cpu64 ((((dsl_dir_phys_t *) |
3634 |
DN_BONUS (&dn.dn)))->dd_child_dir_zapobj, dn.endian); |
3635 |
|
3636 |
if ((grub_errno = dnode_get (mosmdn, childobj, |
3637 |
DMU_OT_DSL_DIR_CHILD_MAP, &dn, data))) |
3638 |
{ |
3639 |
grub_free (bootfs); |
3640 |
return (grub_errno); |
3641 |
} |
3642 |
|
3643 |
char cname[64]; |
3644 |
grub_memset (cname, 0, sizeof(cname)); |
3645 |
|
3646 |
if (zap_value_search (&dn, cname, &dirobj, data)) |
3647 |
{ |
3648 |
grub_free (bootfs); |
3649 |
return (GRUB_ERR_BAD_FS); |
3650 |
} |
3651 |
|
3652 |
grub_size_t cname_len = grub_strlen(cname); |
3653 |
cname[cname_len++] = '/'; |
3654 |
|
3655 |
grub_size_t bootfs_len= grub_strlen(bootfs); |
3656 |
grub_size_t expected_len = bootfs_len + cname_len; |
3657 |
if (expected_len >= buf_size) |
3658 |
{ |
3659 |
while((buf_size = buf_size * 2) < expected_len); |
3660 |
char *tmp = grub_realloc (bootfs, buf_size); |
3661 |
if (! tmp) |
3662 |
{ |
3663 |
grub_free (bootfs); |
3664 |
return (grub_errno); |
3665 |
} |
3666 |
bootfs = tmp; |
3667 |
grub_memset((bootfs + bootfs_len), 0, (buf_size - bootfs_len)); |
3668 |
} |
3669 |
|
3670 |
/* create space for parent dataset name */ |
3671 |
grub_memmove((bootfs + cname_len), bootfs, bootfs_len); |
3672 |
grub_memmove(bootfs, cname, cname_len); |
3673 |
|
3674 |
} while ((dirobj = parentobj) != rootobj); |
3675 |
|
3676 |
/* remove trailing slash */ |
3677 |
*(bootfs + grub_strlen(bootfs) - 1) = '\0'; |
3678 |
*bootfsname = bootfs; |
3679 |
|
3680 |
grub_dprintf ("zfs", "get_default_bootfsname: %s\n", *bootfsname); |
3681 |
return (0); |
3682 |
} |
3683 |
|
2933 |
/* |
3684 |
/* |
2934 |
* Get the default 'bootfs' property value from the rootpool. |
3685 |
* Get the default 'bootfs' property value from the rootpool. |
2935 |
* |
3686 |
* |
2936 |
*/ |
3687 |
*/ |
2937 |
static grub_err_t |
3688 |
static grub_err_t |
2938 |
get_default_bootfsobj (dnode_phys_t * mosmdn, grub_uint64_t * obj, |
3689 |
get_default_bootfsobj (dnode_end_t * mosmdn, grub_uint64_t * obj, |
2939 |
struct grub_zfs_data *data) |
3690 |
struct grub_zfs_data *data) |
2940 |
{ |
3691 |
{ |
2941 |
grub_uint64_t objnum = 0; |
3692 |
grub_uint64_t objnum = 0; |
2942 |
dnode_phys_t *dn; |
3693 |
dnode_end_t dn; |
2943 |
if (!dn) |
|
|
2944 |
return grub_errno; |
2945 |
|
3694 |
|
|
|
3695 |
grub_dprintf ("zfs", "get_default_bootfsobj called\n"); |
2946 |
if ((grub_errno = dnode_get (mosmdn, DMU_POOL_DIRECTORY_OBJECT, |
3696 |
if ((grub_errno = dnode_get (mosmdn, DMU_POOL_DIRECTORY_OBJECT, |
2947 |
DMU_OT_OBJECT_DIRECTORY, dn, data))) |
3697 |
DMU_OT_OBJECT_DIRECTORY, &dn, data))) |
2948 |
{ |
|
|
2949 |
grub_free (dn); |
2950 |
return (grub_errno); |
3698 |
return (grub_errno); |
2951 |
} |
|
|
2952 |
|
3699 |
|
2953 |
/* |
3700 |
/* |
2954 |
* find the object number for 'pool_props', and get the dnode |
3701 |
* find the object number for 'pool_props', and get the dnode |
2955 |
* of the 'pool_props'. |
3702 |
* of the 'pool_props'. |
2956 |
*/ |
3703 |
*/ |
2957 |
if (zap_lookup (dn, DMU_POOL_PROPS, &objnum, data)) |
3704 |
if (zap_lookup (&dn, DMU_POOL_PROPS, &objnum, data, 0)) |
2958 |
{ |
|
|
2959 |
grub_free (dn); |
2960 |
return (GRUB_ERR_BAD_FS); |
3705 |
return (GRUB_ERR_BAD_FS); |
2961 |
} |
3706 |
|
2962 |
if ((grub_errno = dnode_get (mosmdn, objnum, DMU_OT_POOL_PROPS, dn, data))) |
3707 |
if ((grub_errno = dnode_get (mosmdn, objnum, DMU_OT_POOL_PROPS, &dn, data))) |
2963 |
{ |
|
|
2964 |
grub_free (dn); |
2965 |
return (grub_errno); |
3708 |
return (grub_errno); |
2966 |
} |
3709 |
|
2967 |
if (zap_lookup (dn, ZPOOL_PROP_BOOTFS, &objnum, data)) |
3710 |
if (zap_lookup (&dn, ZPOOL_PROP_BOOTFS, &objnum, data, 0)) |
2968 |
{ |
|
|
2969 |
grub_free (dn); |
2970 |
return (GRUB_ERR_BAD_FS); |
3711 |
return (GRUB_ERR_BAD_FS); |
2971 |
} |
|
|
2972 |
|
3712 |
|
2973 |
if (!objnum) |
3713 |
if (!objnum) |
2974 |
{ |
|
|
2975 |
grub_free (dn); |
2976 |
return (GRUB_ERR_BAD_FS); |
3714 |
return (GRUB_ERR_BAD_FS); |
2977 |
} |
|
|
2978 |
|
3715 |
|
2979 |
*obj = objnum; |
3716 |
*obj = objnum; |
|
|
3717 |
|
2980 |
return (0); |
3718 |
return (0); |
2981 |
} |
3719 |
} |
2982 |
#endif |
3720 |
|
2983 |
/* |
3721 |
/* |
2984 |
* Given a MOS metadnode, get the metadnode of a given filesystem name (fsname), |
3722 |
* Given a MOS metadnode, get the metadnode of a given filesystem name (fsname), |
2985 |
* e.g. pool/rootfs, or a given object number (obj), e.g. the object number |
3723 |
* e.g. pool/rootfs, or a given object number (obj), e.g. the object number |
Lines 3036-3041
Link Here
|
3036 |
*fsname = 0; |
3774 |
*fsname = 0; |
3037 |
|
3775 |
|
3038 |
childobj = grub_zfs_to_cpu64 ((((dsl_dir_phys_t *) DN_BONUS (&mdn->dn)))->dd_child_dir_zapobj, mdn->endian); |
3776 |
childobj = grub_zfs_to_cpu64 ((((dsl_dir_phys_t *) DN_BONUS (&mdn->dn)))->dd_child_dir_zapobj, mdn->endian); |
|
|
3777 |
if (childobj == 0) |
3778 |
return grub_error(GRUB_ERR_BAD_FS, "file system not found"); |
3779 |
|
3039 |
err = dnode_get (mosmdn, childobj, |
3780 |
err = dnode_get (mosmdn, childobj, |
3040 |
DMU_OT_DSL_DIR_CHILD_MAP, mdn, data); |
3781 |
DMU_OT_DSL_DIR_CHILD_MAP, mdn, data); |
3041 |
if (err) |
3782 |
if (err) |
Lines 3084-3344
Link Here
|
3084 |
/* Context for dnode_get_fullpath. */ |
3825 |
/* Context for dnode_get_fullpath. */ |
3085 |
struct dnode_get_fullpath_ctx |
3826 |
struct dnode_get_fullpath_ctx |
3086 |
{ |
3827 |
{ |
3087 |
struct subvolume *subvol; |
3828 |
struct subvolume *subvol; |
3088 |
grub_uint64_t salt; |
3829 |
grub_uint64_t salt; |
3089 |
int keyn; |
3830 |
int keyn; |
3090 |
}; |
3831 |
}; |
3091 |
|
3832 |
|
3092 |
/* Helper for dnode_get_fullpath. */ |
3833 |
/* Helper for dnode_get_fullpath. */ |
3093 |
static int |
3834 |
static int |
3094 |
count_zap_keys (const void *name __attribute__ ((unused)), |
3835 |
count_zap_keys (const void *name __attribute__ ((unused)), |
3095 |
grub_size_t namelen __attribute__ ((unused)), |
3836 |
grub_size_t namelen __attribute__ ((unused)), |
3096 |
const void *val_in __attribute__ ((unused)), |
3837 |
const void *val_in __attribute__ ((unused)), |
3097 |
grub_size_t nelem __attribute__ ((unused)), |
3838 |
grub_size_t nelem __attribute__ ((unused)), |
3098 |
grub_size_t elemsize __attribute__ ((unused)), |
3839 |
grub_size_t elemsize __attribute__ ((unused)), |
3099 |
void *data) |
3840 |
void *data) |
3100 |
{ |
3841 |
{ |
3101 |
struct dnode_get_fullpath_ctx *ctx = data; |
3842 |
struct dnode_get_fullpath_ctx *ctx = data; |
3102 |
|
3843 |
|
3103 |
ctx->subvol->nkeys++; |
3844 |
ctx->subvol->nkeys++; |
3104 |
return 0; |
3845 |
return 0; |
3105 |
} |
3846 |
} |
3106 |
|
3847 |
|
3107 |
/* Helper for dnode_get_fullpath. */ |
3848 |
/* Helper for dnode_get_fullpath. */ |
3108 |
static int |
3849 |
static int |
3109 |
load_zap_key (const void *name, grub_size_t namelen, const void *val_in, |
3850 |
load_zap_key (const void *name, grub_size_t namelen, const void *val_in, |
3110 |
grub_size_t nelem, grub_size_t elemsize, void *data) |
3851 |
grub_size_t nelem, grub_size_t elemsize, void *data) |
3111 |
{ |
3852 |
{ |
3112 |
struct dnode_get_fullpath_ctx *ctx = data; |
3853 |
struct dnode_get_fullpath_ctx *ctx = data; |
3113 |
|
3854 |
|
3114 |
if (namelen != 1) |
3855 |
if (namelen != 1) { |
3115 |
{ |
3856 |
grub_dprintf("zfs", |
3116 |
grub_dprintf ("zfs", "Unexpected key index size %" PRIuGRUB_SIZE "\n", |
3857 |
"Unexpected key index size %" PRIuGRUB_SIZE "\n", namelen); |
3117 |
namelen); |
3858 |
return 0; |
3118 |
return 0; |
3859 |
} |
3119 |
} |
|
|
3120 |
|
3860 |
|
3121 |
if (elemsize != 1) |
3861 |
if (elemsize != 1) { |
3122 |
{ |
3862 |
grub_dprintf("zfs", |
3123 |
grub_dprintf ("zfs", "Unexpected key element size %" PRIuGRUB_SIZE "\n", |
3863 |
"Unexpected key element size %" PRIuGRUB_SIZE "\n", |
3124 |
elemsize); |
3864 |
elemsize); |
3125 |
return 0; |
3865 |
return 0; |
3126 |
} |
3866 |
} |
3127 |
|
3867 |
|
3128 |
ctx->subvol->keyring[ctx->keyn].txg = |
3868 |
ctx->subvol->keyring[ctx->keyn].txg = |
3129 |
grub_be_to_cpu64 (*(grub_uint64_t *) name); |
3869 |
grub_be_to_cpu64(*(grub_uint64_t *) name); |
3130 |
ctx->subvol->keyring[ctx->keyn].algo = |
3870 |
ctx->subvol->keyring[ctx->keyn].algo = |
3131 |
grub_le_to_cpu64 (*(grub_uint64_t *) val_in); |
3871 |
grub_le_to_cpu64(*(grub_uint64_t *) val_in); |
3132 |
ctx->subvol->keyring[ctx->keyn].cipher = |
3872 |
ctx->subvol->keyring[ctx->keyn].cipher = |
3133 |
grub_zfs_load_key (val_in, nelem, ctx->salt, |
3873 |
grub_zfs_load_key(val_in, nelem, ctx->salt, |
3134 |
ctx->subvol->keyring[ctx->keyn].algo); |
3874 |
ctx->subvol->keyring[ctx->keyn].algo); |
3135 |
ctx->keyn++; |
3875 |
ctx->keyn++; |
3136 |
return 0; |
3876 |
return 0; |
3137 |
} |
3877 |
} |
3138 |
|
3878 |
|
3139 |
static grub_err_t |
3879 |
static grub_err_t |
3140 |
dnode_get_fullpath (const char *fullpath, struct subvolume *subvol, |
3880 |
dnode_get_fullpath (const char *fullpath, struct subvolume *subvol, |
3141 |
dnode_end_t * dn, int *isfs, |
3881 |
dnode_end_t *dn, int *isfs, struct grub_zfs_data *data) |
3142 |
struct grub_zfs_data *data) |
|
|
3143 |
{ |
3882 |
{ |
3144 |
char *fsname, *snapname; |
3883 |
char *fsname, *snapname; |
3145 |
const char *ptr_at, *filename; |
3884 |
const char *ptr_at, *filename; |
3146 |
grub_uint64_t headobj; |
3885 |
grub_uint64_t headobj; |
3147 |
grub_uint64_t keychainobj; |
3886 |
grub_uint64_t keychainobj; |
3148 |
grub_err_t err; |
3887 |
grub_err_t err; |
3149 |
|
3888 |
|
3150 |
ptr_at = grub_strchr (fullpath, '@'); |
3889 |
ptr_at = grub_strchr(fullpath, '@'); |
3151 |
if (! ptr_at) |
3890 |
if (!ptr_at) { |
3152 |
{ |
3891 |
*isfs = 1; |
3153 |
*isfs = 1; |
3892 |
filename = 0; |
3154 |
filename = 0; |
3893 |
snapname = 0; |
3155 |
snapname = 0; |
3894 |
fsname = grub_strdup(fullpath); |
3156 |
fsname = grub_strdup (fullpath); |
3895 |
} else { |
3157 |
} |
3896 |
const char *ptr_slash = grub_strchr(ptr_at, '/'); |
3158 |
else |
3897 |
|
3159 |
{ |
3898 |
*isfs = 0; |
3160 |
const char *ptr_slash = grub_strchr (ptr_at, '/'); |
3899 |
fsname = grub_malloc(ptr_at - fullpath + 1); |
3161 |
|
3900 |
if (!fsname) |
3162 |
*isfs = 0; |
3901 |
return grub_errno; |
3163 |
fsname = grub_malloc (ptr_at - fullpath + 1); |
3902 |
grub_memcpy(fsname, fullpath, ptr_at - fullpath); |
3164 |
if (!fsname) |
3903 |
fsname[ptr_at - fullpath] = 0; |
3165 |
return grub_errno; |
3904 |
if (ptr_at[1] && ptr_at[1] != '/') { |
3166 |
grub_memcpy (fsname, fullpath, ptr_at - fullpath); |
3905 |
snapname = grub_malloc(ptr_slash - ptr_at); |
3167 |
fsname[ptr_at - fullpath] = 0; |
3906 |
if (!snapname) { |
3168 |
if (ptr_at[1] && ptr_at[1] != '/') |
3907 |
grub_free(fsname); |
3169 |
{ |
3908 |
return grub_errno; |
3170 |
snapname = grub_malloc (ptr_slash - ptr_at); |
3909 |
} |
3171 |
if (!snapname) |
3910 |
grub_memcpy(snapname, ptr_at + 1, |
3172 |
{ |
3911 |
ptr_slash - ptr_at - 1); |
3173 |
grub_free (fsname); |
3912 |
snapname[ptr_slash - ptr_at - 1] = 0; |
3174 |
return grub_errno; |
3913 |
} else |
3175 |
} |
3914 |
snapname = 0; |
3176 |
grub_memcpy (snapname, ptr_at + 1, ptr_slash - ptr_at - 1); |
3915 |
if (ptr_slash) |
3177 |
snapname[ptr_slash - ptr_at - 1] = 0; |
3916 |
filename = ptr_slash; |
3178 |
} |
3917 |
else |
3179 |
else |
3918 |
filename = "/"; |
3180 |
snapname = 0; |
3919 |
grub_dprintf("zfs", |
3181 |
if (ptr_slash) |
3920 |
"fsname = '%s' snapname='%s' filename = '%s'\n", |
3182 |
filename = ptr_slash; |
|
|
3183 |
else |
3184 |
filename = "/"; |
3185 |
grub_dprintf ("zfs", "fsname = '%s' snapname='%s' filename = '%s'\n", |
3186 |
fsname, snapname, filename); |
3921 |
fsname, snapname, filename); |
3187 |
} |
3922 |
} |
3188 |
grub_dprintf ("zfs", "alive\n"); |
3923 |
grub_dprintf ("zfs", "alive\n"); |
3189 |
err = get_filesystem_dnode (&(data->mos), fsname, dn, data); |
3924 |
err = get_filesystem_dnode(&(data->mos), fsname, dn, data); |
3190 |
if (err) |
3925 |
if (err) { |
3191 |
{ |
3926 |
grub_free(fsname); |
3192 |
grub_free (fsname); |
3927 |
grub_free(snapname); |
3193 |
grub_free (snapname); |
3928 |
return err; |
3194 |
return err; |
3929 |
} |
3195 |
} |
|
|
3196 |
|
3197 |
grub_dprintf ("zfs", "alive\n"); |
3198 |
|
3930 |
|
3199 |
headobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&dn->dn))->dd_head_dataset_obj, dn->endian); |
3931 |
grub_dprintf("zfs", "alive\n"); |
3200 |
|
3932 |
|
3201 |
grub_dprintf ("zfs", "endian = %d\n", subvol->mdn.endian); |
3933 |
headobj = grub_zfs_to_cpu64( |
|
|
3934 |
((dsl_dir_phys_t *) DN_BONUS(&dn->dn))->dd_head_dataset_obj, |
3935 |
dn->endian); |
3936 |
|
3937 |
grub_dprintf("zfs", "endian = %d\n", subvol->mdn.endian); |
3938 |
|
3939 |
err = dnode_get(&(data->mos), headobj, DMU_OT_DSL_DATASET, |
3940 |
&subvol->mdn, data); |
3941 |
if (err) { |
3942 |
grub_free(fsname); |
3943 |
grub_free(snapname); |
3944 |
return err; |
3945 |
} |
3946 |
grub_dprintf ("zfs", "endian = %d\n", subvol->mdn.endian); |
3202 |
|
3947 |
|
3203 |
err = dnode_get (&(data->mos), headobj, DMU_OT_DSL_DATASET, &subvol->mdn, |
3948 |
keychainobj = grub_zfs_to_cpu64 ( |
3204 |
data); |
3949 |
((dsl_dir_phys_t *) DN_BONUS(&dn->dn))->keychain, dn->endian); |
3205 |
if (err) |
3950 |
if (grub_zfs_load_key && keychainobj) { |
3206 |
{ |
3951 |
struct dnode_get_fullpath_ctx ctx = { |
3207 |
grub_free (fsname); |
3952 |
.subvol = subvol, |
3208 |
grub_free (snapname); |
3953 |
.keyn = 0 |
3209 |
return err; |
3954 |
}; |
3210 |
} |
3955 |
dnode_end_t keychain_dn, props_dn; |
3211 |
grub_dprintf ("zfs", "endian = %d\n", subvol->mdn.endian); |
3956 |
grub_uint64_t propsobj; |
|
|
3957 |
propsobj = grub_zfs_to_cpu64( |
3958 |
((dsl_dir_phys_t *) DN_BONUS(&dn->dn))->dd_props_zapobj, |
3959 |
dn->endian); |
3960 |
|
3961 |
err = dnode_get(&(data->mos), propsobj, DMU_OT_DSL_PROPS, |
3962 |
&props_dn, data); |
3963 |
if (err) { |
3964 |
grub_free(fsname); |
3965 |
grub_free(snapname); |
3966 |
return err; |
3967 |
} |
3212 |
|
3968 |
|
3213 |
keychainobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&dn->dn))->keychain, dn->endian); |
3969 |
err = zap_lookup (&props_dn, "salt", &ctx.salt, data, 0); |
3214 |
if (grub_zfs_load_key && keychainobj) |
3970 |
if (err == GRUB_ERR_FILE_NOT_FOUND) { |
3215 |
{ |
3971 |
err = 0; |
3216 |
struct dnode_get_fullpath_ctx ctx = { |
3972 |
grub_errno = 0; |
3217 |
.subvol = subvol, |
3973 |
ctx.salt = 0; |
3218 |
.keyn = 0 |
3974 |
} |
3219 |
}; |
3975 |
if (err) { |
3220 |
dnode_end_t keychain_dn, props_dn; |
3976 |
grub_dprintf("zfs", "failed here\n"); |
3221 |
grub_uint64_t propsobj; |
3977 |
return err; |
3222 |
propsobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&dn->dn))->dd_props_zapobj, dn->endian); |
3978 |
} |
3223 |
|
3979 |
|
3224 |
err = dnode_get (&(data->mos), propsobj, DMU_OT_DSL_PROPS, |
3980 |
err = dnode_get(&(data->mos), keychainobj, DMU_OT_DSL_KEYCHAIN, |
3225 |
&props_dn, data); |
3981 |
&keychain_dn, data); |
3226 |
if (err) |
3982 |
if (err) { |
3227 |
{ |
3983 |
grub_free(fsname); |
3228 |
grub_free (fsname); |
3984 |
grub_free(snapname); |
3229 |
grub_free (snapname); |
3985 |
return err; |
3230 |
return err; |
3986 |
} |
|
|
3987 |
subvol->nkeys = 0; |
3988 |
zap_iterate(&keychain_dn, 8, count_zap_keys, &ctx, data); |
3989 |
subvol->keyring = grub_zalloc(subvol->nkeys * |
3990 |
sizeof (subvol->keyring[0])); |
3991 |
if (!subvol->keyring) { |
3992 |
grub_free(fsname); |
3993 |
grub_free(snapname); |
3994 |
return err; |
3995 |
} |
3996 |
zap_iterate(&keychain_dn, 8, load_zap_key, &ctx, data); |
3231 |
} |
3997 |
} |
3232 |
|
3998 |
|
3233 |
err = zap_lookup (&props_dn, "salt", &ctx.salt, data, 0); |
3999 |
if (snapname) { |
3234 |
if (err == GRUB_ERR_FILE_NOT_FOUND) |
4000 |
grub_uint64_t snapobj; |
3235 |
{ |
|
|
3236 |
err = 0; |
3237 |
grub_errno = 0; |
3238 |
ctx.salt = 0; |
3239 |
} |
3240 |
if (err) |
3241 |
{ |
3242 |
grub_dprintf ("zfs", "failed here\n"); |
3243 |
return err; |
3244 |
} |
3245 |
|
4001 |
|
3246 |
err = dnode_get (&(data->mos), keychainobj, DMU_OT_DSL_KEYCHAIN, |
4002 |
snapobj = grub_zfs_to_cpu64( |
3247 |
&keychain_dn, data); |
4003 |
((dsl_dataset_phys_t *) |
3248 |
if (err) |
4004 |
DN_BONUS(&subvol->mdn.dn))->ds_snapnames_zapobj, |
3249 |
{ |
4005 |
subvol->mdn.endian); |
3250 |
grub_free (fsname); |
4006 |
|
3251 |
grub_free (snapname); |
4007 |
err = dnode_get(&(data->mos), snapobj, |
3252 |
return err; |
4008 |
DMU_OT_DSL_DS_SNAP_MAP, &subvol->mdn, data); |
3253 |
} |
4009 |
if (!err) |
3254 |
subvol->nkeys = 0; |
4010 |
err = zap_lookup(&subvol->mdn, snapname, |
3255 |
zap_iterate (&keychain_dn, 8, count_zap_keys, &ctx, data); |
4011 |
&headobj, data, 0); |
3256 |
subvol->keyring = grub_zalloc (subvol->nkeys * sizeof (subvol->keyring[0])); |
4012 |
if (!err) |
3257 |
if (!subvol->keyring) |
4013 |
err = dnode_get(&(data->mos), headobj, |
3258 |
{ |
4014 |
DMU_OT_DSL_DATASET, &subvol->mdn, data); |
3259 |
grub_free (fsname); |
4015 |
if (err) { |
3260 |
grub_free (snapname); |
4016 |
grub_free(fsname); |
3261 |
return err; |
4017 |
grub_free(snapname); |
|
|
4018 |
return err; |
4019 |
} |
3262 |
} |
4020 |
} |
3263 |
zap_iterate (&keychain_dn, 8, load_zap_key, &ctx, data); |
|
|
3264 |
} |
3265 |
|
3266 |
if (snapname) |
3267 |
{ |
3268 |
grub_uint64_t snapobj; |
3269 |
|
3270 |
snapobj = grub_zfs_to_cpu64 (((dsl_dataset_phys_t *) DN_BONUS (&subvol->mdn.dn))->ds_snapnames_zapobj, subvol->mdn.endian); |
3271 |
|
4021 |
|
3272 |
err = dnode_get (&(data->mos), snapobj, |
4022 |
subvol->obj = headobj; |
3273 |
DMU_OT_DSL_DS_SNAP_MAP, &subvol->mdn, data); |
|
|
3274 |
if (!err) |
3275 |
err = zap_lookup (&subvol->mdn, snapname, &headobj, data, 0); |
3276 |
if (!err) |
3277 |
err = dnode_get (&(data->mos), headobj, DMU_OT_DSL_DATASET, |
3278 |
&subvol->mdn, data); |
3279 |
if (err) |
3280 |
{ |
3281 |
grub_free (fsname); |
3282 |
grub_free (snapname); |
3283 |
return err; |
3284 |
} |
3285 |
} |
3286 |
|
4023 |
|
3287 |
subvol->obj = headobj; |
4024 |
make_mdn(&subvol->mdn, data); |
3288 |
|
4025 |
|
3289 |
make_mdn (&subvol->mdn, data); |
4026 |
grub_dprintf("zfs", "endian = %d\n", subvol->mdn.endian); |
3290 |
|
|
|
3291 |
grub_dprintf ("zfs", "endian = %d\n", subvol->mdn.endian); |
3292 |
|
4027 |
|
3293 |
if (*isfs) |
4028 |
if (*isfs) { |
3294 |
{ |
4029 |
grub_free(fsname); |
3295 |
grub_free (fsname); |
4030 |
grub_free(snapname); |
3296 |
grub_free (snapname); |
4031 |
return GRUB_ERR_NONE; |
3297 |
return GRUB_ERR_NONE; |
4032 |
} |
3298 |
} |
4033 |
err = dnode_get_path(subvol, filename, dn, data); |
3299 |
err = dnode_get_path (subvol, filename, dn, data); |
4034 |
grub_free(fsname); |
3300 |
grub_free (fsname); |
4035 |
grub_free(snapname); |
3301 |
grub_free (snapname); |
4036 |
return err; |
3302 |
return err; |
|
|
3303 |
} |
4037 |
} |
3304 |
|
4038 |
|
3305 |
static int |
4039 |
/* |
3306 |
nvlist_find_value (const char *nvlist_in, const char *name, |
4040 |
* Checks whether the MOS features that are active are supported by this |
3307 |
int valtype, char **val, |
4041 |
* (GRUB's) implementation of ZFS. |
3308 |
grub_size_t *size_out, grub_size_t *nelm_out) |
4042 |
* |
|
|
4043 |
* Return: |
4044 |
* 0: Success. |
4045 |
* errnum: Failure. |
4046 |
*/ |
4047 |
static grub_err_t |
4048 |
check_mos_features(dnode_end_t *mosmdn, struct grub_zfs_data *data) |
3309 |
{ |
4049 |
{ |
3310 |
grub_size_t nvp_name_len, name_len = grub_strlen(name); |
4050 |
dnode_end_t dn; |
3311 |
int type; |
4051 |
grub_uint64_t objnum; |
3312 |
const char *nvpair=NULL,*nvlist=nvlist_in; |
4052 |
grub_err_t errnum = GRUB_ERR_NONE; |
3313 |
char *nvp_name; |
4053 |
|
|
|
4054 |
if ((errnum = dnode_get(mosmdn, DMU_POOL_DIRECTORY_OBJECT, |
4055 |
DMU_OT_OBJECT_DIRECTORY, &dn, data)) != 0) |
4056 |
return (errnum); |
4057 |
|
4058 |
/* |
4059 |
* Find the object number for 'features_for_read' and retrieve its |
4060 |
* corresponding dnode. Note that we don't check features_for_write |
4061 |
* because GRUB is not opening the pool for write. |
4062 |
*/ |
4063 |
errnum = zap_lookup(&dn, DMU_POOL_FEATURES_FOR_READ, &objnum, data, 0); |
4064 |
if(errnum != 0) { |
4065 |
/* this pool does not support features */ |
4066 |
if(errnum == GRUB_ERR_FILE_NOT_FOUND) |
4067 |
errnum = GRUB_ERR_NONE; |
4068 |
|
4069 |
return (errnum); |
4070 |
} |
4071 |
|
4072 |
if ((errnum = dnode_get(mosmdn, objnum, DMU_OTN_ZAP_METADATA, |
4073 |
&dn, data)) != 0) |
4074 |
return (errnum); |
3314 |
|
4075 |
|
3315 |
/* Verify if the 1st and 2nd byte in the nvlist are valid. */ |
4076 |
return (zap_iterate_u64(&dn, check_feature, data, NULL)); |
3316 |
/* NOTE: independently of what endianness header announces all |
4077 |
} |
3317 |
subsequent values are big-endian. */ |
|
|
3318 |
if (nvlist[0] != NV_ENCODE_XDR || (nvlist[1] != NV_LITTLE_ENDIAN |
3319 |
&& nvlist[1] != NV_BIG_ENDIAN)) |
3320 |
{ |
3321 |
grub_dprintf ("zfs", "incorrect nvlist header\n"); |
3322 |
grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist"); |
3323 |
return 0; |
3324 |
} |
3325 |
|
4078 |
|
3326 |
/* |
4079 |
/* |
3327 |
* Loop thru the nvpair list |
4080 |
* For a given XDR packed nvlist, verify the first 4 bytes and move on. |
3328 |
* The XDR representation of an integer is in big-endian byte order. |
4081 |
* |
3329 |
*/ |
4082 |
* An XDR packed nvlist is encoded as (comments from nvs_xdr_create) : |
3330 |
while ((nvpair=nvlist_next_nvpair(nvlist,nvpair))) |
4083 |
* |
3331 |
{ |
4084 |
* encoding method/host endian (4 bytes) |
3332 |
nvpair_name(nvpair,&nvp_name, &nvp_name_len); |
4085 |
* nvl_version (4 bytes) |
3333 |
type = nvpair_type(nvpair); |
4086 |
* nvl_nvflag (4 bytes) |
3334 |
if (type == valtype |
4087 |
* encoded nvpairs: |
3335 |
&& (nvp_name_len == name_len |
4088 |
* encoded size of the nvpair (4 bytes) |
3336 |
|| (nvp_name_len > name_len && nvp_name[name_len] == '\0')) |
4089 |
* decoded size of the nvpair (4 bytes) |
3337 |
&& grub_memcmp (nvp_name, name, name_len) == 0) |
4090 |
* name string size (4 bytes) |
3338 |
{ |
4091 |
* name string data (sizeof(NV_ALIGN4(string)) |
3339 |
return nvpair_value(nvpair,val,size_out,nelm_out); |
4092 |
* data type (4 bytes) |
3340 |
} |
4093 |
* # of elements in the nvpair (4 bytes) |
3341 |
} |
4094 |
* data |
|
|
4095 |
* 2 zero's for the last nvpair |
4096 |
* (end of the entire list) (8 bytes) |
4097 |
* |
4098 |
*/ |
4099 |
|
4100 |
/* |
4101 |
* The nvlist_next_nvpair() function returns a handle to the next nvpair in the |
4102 |
* list following nvpair. If nvpair is NULL, the first pair is returned. If |
4103 |
* nvpair is the last pair in the nvlist, NULL is returned. |
4104 |
*/ |
4105 |
static const char * |
4106 |
nvlist_next_nvpair (const char *nvl, const char *nvpair) |
4107 |
{ |
4108 |
const char *nvp; |
4109 |
int encode_size; |
4110 |
int name_len; |
4111 |
if (nvl == NULL) |
4112 |
return NULL; |
4113 |
|
4114 |
if (nvpair == NULL) |
4115 |
{ |
4116 |
/* skip over header, nvl_version and nvl_nvflag */ |
4117 |
nvpair = nvl + 4 * 3; |
4118 |
} |
4119 |
else |
4120 |
{ |
4121 |
/* skip to the next nvpair */ |
4122 |
encode_size = grub_be_to_cpu32 (grub_get_unaligned32(nvpair)); |
4123 |
nvpair += encode_size; |
4124 |
/*If encode_size equals 0 nvlist_next_nvpair would return |
4125 |
* the same pair received in input, leading to an infinite loop. |
4126 |
* If encode_size is less than 0, this will move the pointer |
4127 |
* backwards, *possibly* examinining two times the same nvpair |
4128 |
* and potentially getting into an infinite loop. */ |
4129 |
if(encode_size <= 0) |
4130 |
{ |
4131 |
grub_dprintf ("zfs", "nvpair with size <= 0\n"); |
4132 |
grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist"); |
4133 |
return NULL; |
4134 |
} |
4135 |
} |
4136 |
/* 8 bytes of 0 marks the end of the list */ |
4137 |
if (grub_get_unaligned64 (nvpair) == 0) |
4138 |
return NULL; |
4139 |
/*consistency checks*/ |
4140 |
if (nvpair + 4 * 3 >= nvl + VDEV_PHYS_SIZE) |
4141 |
{ |
4142 |
grub_dprintf ("zfs", "nvlist overflow\n"); |
4143 |
grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist"); |
4144 |
return NULL; |
4145 |
} |
4146 |
encode_size = grub_be_to_cpu32 (grub_get_unaligned32(nvpair)); |
4147 |
|
4148 |
nvp = nvpair + 4*2; |
4149 |
name_len = grub_be_to_cpu32 (grub_get_unaligned32 (nvp)); |
4150 |
nvp += 4; |
4151 |
|
4152 |
nvp = nvp + ((name_len + 3) & ~3); /* align */ |
4153 |
if (nvp + 4 >= nvl + VDEV_PHYS_SIZE |
4154 |
|| encode_size < 0 |
4155 |
|| nvp + 4 + encode_size > nvl + VDEV_PHYS_SIZE) |
4156 |
{ |
4157 |
grub_dprintf ("zfs", "nvlist overflow\n"); |
4158 |
grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist"); |
4159 |
return NULL; |
4160 |
} |
4161 |
/* end consistency checks */ |
4162 |
|
4163 |
return nvpair; |
4164 |
} |
4165 |
|
4166 |
/* |
4167 |
* This function returns 0 on success and 1 on failure. On success, a string |
4168 |
* containing the name of nvpair is saved in buf. |
4169 |
*/ |
4170 |
static char * |
4171 |
nvpair_name(const char *nvp) |
4172 |
{ |
4173 |
int len; |
4174 |
char *buf = NULL; |
4175 |
|
4176 |
/* skip over encode/decode size */ |
4177 |
nvp += 4 * 2; |
4178 |
len = grub_be_to_cpu32 (grub_get_unaligned32 (nvp)); |
4179 |
buf = grub_malloc(len + 1); |
4180 |
if (buf ) { |
4181 |
grub_memmove(buf, nvp + 4, len); |
4182 |
buf[len] = '\0'; |
4183 |
} |
4184 |
return buf; |
4185 |
} |
4186 |
|
4187 |
#if 0 |
4188 |
/* |
4189 |
* This function retrieves the value of the nvpair in the form of enumerated |
4190 |
* type data_type_t. |
4191 |
*/ |
4192 |
static int |
4193 |
nvpair_type (const char *nvp) |
4194 |
{ |
4195 |
int name_len, type; |
4196 |
|
4197 |
/* skip over encode/decode size */ |
4198 |
nvp += 4 * 2; |
4199 |
|
4200 |
/* skip over name_len */ |
4201 |
name_len = grub_be_to_cpu32 (grub_get_unaligned32 (nvp)); |
4202 |
nvp += 4; |
4203 |
|
4204 |
/* skip over name */ |
4205 |
nvp = nvp + ((name_len + 3) & ~3); /* align */ |
4206 |
|
4207 |
type = grub_be_to_cpu32 (grub_get_unaligned32 (nvp)); |
4208 |
|
4209 |
return type; |
4210 |
} |
4211 |
|
4212 |
static int |
4213 |
nvpair_value (const char *nvp,char **val, |
4214 |
grub_size_t *size_out, grub_size_t *nelm_out) |
4215 |
{ |
4216 |
int name_len,nelm,encode_size; |
4217 |
|
4218 |
/* skip over encode/decode size */ |
4219 |
encode_size = grub_be_to_cpu32 (grub_get_unaligned32(nvp)); |
4220 |
nvp += 8; |
4221 |
|
4222 |
/* skip over name_len */ |
4223 |
name_len = grub_be_to_cpu32 (grub_get_unaligned32 (nvp)); |
4224 |
nvp += 4; |
4225 |
|
4226 |
/* skip over name */ |
4227 |
nvp = nvp + ((name_len + 3) & ~3); /* align */ |
4228 |
|
4229 |
/* skip over type */ |
4230 |
nvp += 4; |
4231 |
nelm = grub_be_to_cpu32 (grub_get_unaligned32 (nvp)); |
4232 |
nvp +=4; |
4233 |
if (nelm < 1) |
4234 |
{ |
4235 |
grub_error (GRUB_ERR_BAD_FS, "empty nvpair"); |
4236 |
return 0; |
4237 |
} |
4238 |
*val = (char *) nvp; |
4239 |
*size_out = encode_size; |
4240 |
if (nelm_out) |
4241 |
*nelm_out = nelm; |
4242 |
|
4243 |
return 1; |
4244 |
} |
4245 |
#endif |
4246 |
|
4247 |
static int |
4248 |
nvlist_find_value (const char *nvlist_in, const char *name, |
4249 |
int valtype, char **val, |
4250 |
grub_size_t *size_out, grub_size_t *nelm_out) |
4251 |
{ |
4252 |
int name_len, type, encode_size; |
4253 |
const char *nvpair, *nvp_name, *nvlist = nvlist_in; |
4254 |
|
4255 |
/* Verify if the 1st and 2nd byte in the nvlist are valid. */ |
4256 |
/* NOTE: independently of what endianness header announces all |
4257 |
subsequent values are big-endian. */ |
4258 |
if (nvlist[0] != NV_ENCODE_XDR || (nvlist[1] != NV_LITTLE_ENDIAN |
4259 |
&& nvlist[1] != NV_BIG_ENDIAN)) |
4260 |
{ |
4261 |
grub_dprintf ("zfs", "incorrect nvlist header\n"); |
4262 |
grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist"); |
4263 |
return 0; |
4264 |
} |
4265 |
|
4266 |
/* skip the header, nvl_version, and nvl_nvflag */ |
4267 |
nvlist = nvlist + 4 * 3; |
4268 |
/* |
4269 |
* Loop thru the nvpair list |
4270 |
* The XDR representation of an integer is in big-endian byte order. |
4271 |
*/ |
4272 |
while ((encode_size = grub_be_to_cpu32 (grub_get_unaligned32 (nvlist)))) |
4273 |
{ |
4274 |
int nelm; |
4275 |
|
4276 |
if (nvlist + 4 * 4 >= nvlist_in + VDEV_PHYS_SIZE) |
4277 |
{ |
4278 |
grub_dprintf("zfs", "nvlist overflow\n"); |
4279 |
grub_error(GRUB_ERR_BAD_FS, "incorrect nvlist"); |
4280 |
return 0; |
4281 |
} |
4282 |
|
4283 |
nvpair = nvlist + 4 * 2; /* skip the encode/decode size */ |
4284 |
|
4285 |
name_len = grub_be_to_cpu32 (grub_get_unaligned32 (nvpair)); |
4286 |
nvpair += 4; |
4287 |
|
4288 |
nvp_name = nvpair; |
4289 |
nvpair = nvpair + ((name_len + 3) & ~3); /* align */ |
4290 |
|
4291 |
if (nvpair + 8 >= nvlist_in + VDEV_PHYS_SIZE |
4292 |
|| encode_size < 0 |
4293 |
|| nvpair + 8 + encode_size > nvlist_in + VDEV_PHYS_SIZE) |
4294 |
{ |
4295 |
grub_dprintf("zfs", "nvlist overflow\n"); |
4296 |
grub_error(GRUB_ERR_BAD_FS, "incorrect nvlist"); |
4297 |
return 0; |
4298 |
} |
4299 |
|
4300 |
type = grub_be_to_cpu32 (grub_get_unaligned32 (nvpair)); |
4301 |
nvpair += 4; |
4302 |
|
4303 |
nelm = grub_be_to_cpu32 (grub_get_unaligned32 (nvpair)); |
4304 |
if (nelm < 1) |
4305 |
return grub_error (GRUB_ERR_BAD_FS, "empty nvpair"); |
4306 |
|
4307 |
nvpair += 4; |
4308 |
|
4309 |
if ((grub_strncmp (nvp_name, name, name_len) == 0) && type == valtype) |
4310 |
{ |
4311 |
*val = (char *) nvpair; |
4312 |
*size_out = encode_size; |
4313 |
if (nelm_out) |
4314 |
*nelm_out = nelm; |
4315 |
return 1; |
4316 |
} |
4317 |
|
4318 |
nvlist += encode_size; /* goto the next nvpair */ |
4319 |
} |
3342 |
return 0; |
4320 |
return 0; |
3343 |
} |
4321 |
} |
3344 |
|
4322 |
|
Lines 3497-3588
Link Here
|
3497 |
} |
4475 |
} |
3498 |
|
4476 |
|
3499 |
static void |
4477 |
static void |
3500 |
unmount_device (struct grub_zfs_device_desc *desc) |
4478 |
mount_device (struct grub_zfs_device_desc *desc, grub_device_t dev, char *name) |
|
|
4479 |
{ |
4480 |
unsigned i; |
4481 |
switch (desc->type) |
4482 |
{ |
4483 |
case DEVICE_LEAF: |
4484 |
if (desc->dev_name) |
4485 |
{ |
4486 |
if (grub_strcmp(desc->dev_name, name) == 0) |
4487 |
{ |
4488 |
grub_dprintf ("zfs", "mount_device: using device %s\n", name); |
4489 |
desc->dev = dev; |
4490 |
desc->original = 1; |
4491 |
} |
4492 |
else |
4493 |
{ |
4494 |
desc->original = 0; /* just to be safe */ |
4495 |
grub_dprintf ("zfs", "mount_device: open device %s\n", name); |
4496 |
if (desc->dev == NULL) |
4497 |
desc->dev = grub_device_open (desc->dev_name); |
4498 |
} |
4499 |
} |
4500 |
return; |
4501 |
case DEVICE_RAIDZ: |
4502 |
case DEVICE_MIRROR: |
4503 |
for (i = 0; i < desc->n_children; i++) |
4504 |
mount_device (&desc->children[i], dev, name); |
4505 |
return; |
4506 |
} |
4507 |
} |
4508 |
|
4509 |
static void |
4510 |
unmount_device (struct grub_zfs_device_desc *desc, int zcached) |
3501 |
{ |
4511 |
{ |
3502 |
unsigned i; |
4512 |
unsigned i; |
|
|
4513 |
|
4514 |
if (desc->config) |
4515 |
grub_free (desc->config); |
4516 |
|
3503 |
switch (desc->type) |
4517 |
switch (desc->type) |
3504 |
{ |
4518 |
{ |
3505 |
case DEVICE_LEAF: |
4519 |
case DEVICE_LEAF: |
3506 |
if (!desc->original && desc->dev) |
4520 |
if (desc->dev) |
3507 |
grub_device_close (desc->dev); |
4521 |
{ |
|
|
4522 |
/* |
4523 |
* make sure we dont close dev provided by caller of zfs_mount() |
4524 |
*/ |
4525 |
if (!desc->original) |
4526 |
{ |
4527 |
grub_dprintf ("zfs", "unmount_device: closing device %s\n", |
4528 |
desc->dev_name); |
4529 |
grub_device_close (desc->dev); |
4530 |
} |
4531 |
desc->dev = NULL; |
4532 |
} |
4533 |
desc->original = 0; /* next caller may use different device */ |
4534 |
if (! zcached) |
4535 |
grub_free (desc->dev_name); |
3508 |
return; |
4536 |
return; |
3509 |
case DEVICE_RAIDZ: |
4537 |
case DEVICE_RAIDZ: |
3510 |
case DEVICE_MIRROR: |
4538 |
case DEVICE_MIRROR: |
3511 |
for (i = 0; i < desc->n_children; i++) |
4539 |
for (i = 0; i < desc->n_children; i++) |
3512 |
unmount_device (&desc->children[i]); |
4540 |
unmount_device (&desc->children[i], zcached); |
3513 |
grub_free (desc->children); |
|
|
3514 |
return; |
4541 |
return; |
3515 |
} |
4542 |
} |
3516 |
} |
4543 |
} |
|
|
4544 |
|
4545 |
static void |
4546 |
zfs_unmount (struct grub_zfs_data *data) |
4547 |
{ |
4548 |
unsigned i; |
4549 |
|
4550 |
grub_dprintf("zfs", "zfs_unmount: %p\n", data); |
4551 |
|
4552 |
if (data == NULL) |
4553 |
return; |
4554 |
|
4555 |
grub_free (data->label); |
4556 |
data->label = NULL; |
4557 |
grub_free (data->dnode_buf); |
4558 |
data->dnode_buf = NULL; |
4559 |
grub_free (data->dnode_mdn); |
4560 |
data->dnode_mdn = NULL; |
4561 |
grub_free (data->file_buf); |
4562 |
data->file_buf = NULL; |
4563 |
data->file_start = 0; |
4564 |
data->file_end = 0; |
4565 |
data->dnode_start = 0; |
4566 |
data->dnode_end = 0; |
4567 |
|
4568 |
for (i = 0; i < data->subvol.nkeys; i++) |
4569 |
grub_crypto_cipher_close (data->subvol.keyring[i].cipher); |
4570 |
grub_free (data->subvol.keyring); |
4571 |
data->subvol.nkeys = 0; |
4572 |
data->subvol.keyring = NULL; |
4573 |
|
4574 |
for (i = 0; i < data->n_devices_attached; i++) |
4575 |
{ |
4576 |
unmount_device (&data->devices_attached[i], data->zcached); |
4577 |
if (! data->zcached) |
4578 |
grub_free (data->devices_attached[i].children); |
4579 |
} |
4580 |
if (! data->zcached) |
4581 |
{ |
4582 |
grub_free (data->devices_attached); |
4583 |
grub_free (data); |
4584 |
} |
4585 |
} |
4586 |
|
4587 |
/* |
4588 |
* Free all the caches |
4589 |
*/ |
4590 |
static void |
4591 |
zfs_free_caches (void) |
4592 |
{ |
4593 |
unsigned int i; |
4594 |
struct grub_zfs_data *data; |
4595 |
struct zfs_mount_cache *zcache, *zcache_next; |
4596 |
struct zfs_dev_notzfs *dev_notzfs, *dev_notzfs_next; |
4597 |
|
4598 |
/* free the zfs mount cache list */ |
4599 |
zcache = zfs_mount_cache_list; |
4600 |
while (zcache != NULL) |
4601 |
{ |
4602 |
data = zcache->zcache_zfs_data; |
4603 |
if (data) |
4604 |
{ |
4605 |
for (i = 0; i < data->n_devices_attached; i++) |
4606 |
{ |
4607 |
unmount_device (&data->devices_attached[i], 0); |
4608 |
grub_free (data->devices_attached[i].children); |
4609 |
} |
4610 |
grub_free (data->devices_attached); |
4611 |
|
4612 |
for (i = 0; i < data->subvol.nkeys; i++) |
4613 |
grub_crypto_cipher_close (data->subvol.keyring[i].cipher); |
4614 |
grub_free (data->subvol.keyring); |
4615 |
|
4616 |
grub_free (data); |
4617 |
zcache->zcache_zfs_data = NULL; |
4618 |
} |
4619 |
|
4620 |
grub_free (zcache->zcache_pool_name); |
4621 |
zcache->zcache_pool_name = NULL; |
4622 |
zcache->zcache_pool_guid = 0; |
4623 |
|
4624 |
zcache_next = zcache->next; |
4625 |
grub_free (zcache); |
4626 |
zcache = zcache_next; |
4627 |
} |
4628 |
zfs_mount_cache_list = NULL; |
4629 |
|
4630 |
/* free the cache list for non-zfs disk dev */ |
4631 |
dev_notzfs = zfs_dev_notzfs_list; |
4632 |
while (dev_notzfs != NULL) |
4633 |
{ |
4634 |
grub_free (dev_notzfs->dev_name); |
4635 |
dev_notzfs_next = dev_notzfs->next; |
4636 |
grub_free (dev_notzfs); |
4637 |
dev_notzfs = dev_notzfs_next; |
4638 |
} |
4639 |
zfs_dev_notzfs_list = NULL; |
4640 |
} |
4641 |
|
4642 |
static grub_off_t |
4643 |
vdev_label_offset(grub_uint64_t psize, int l, grub_uint64_t offset) |
4644 |
{ |
4645 |
return (offset + l * sizeof (vdev_label_t) + (l < VDEV_LABELS / 2 ? |
4646 |
0 : psize - VDEV_LABELS * sizeof (vdev_label_t))); |
4647 |
} |
4648 |
|
4649 |
static grub_err_t |
4650 |
vdev_disk_read_rootlabel(grub_device_t dev, char **config) |
4651 |
{ |
4652 |
int vdevnum; |
4653 |
int l; |
4654 |
vdev_phys_t *vp; |
4655 |
grub_uint64_t s, size; |
4656 |
grub_err_t err; |
4657 |
|
4658 |
vdevnum = VDEV_LABELS; |
4659 |
|
4660 |
vp = grub_malloc (VDEV_PHYS_SIZE); |
4661 |
*config = NULL; |
4662 |
|
4663 |
if (!vp) |
4664 |
{ |
4665 |
grub_dprintf("zfs", "vdev_phys_t allocation failed.\n"); |
4666 |
return grub_errno; |
4667 |
} |
4668 |
|
4669 |
size = s = grub_disk_get_size (dev->disk); |
4670 |
|
4671 |
/* Don't check back labels on CDROM. */ |
4672 |
if (s == GRUB_DISK_SIZE_UNKNOWN) |
4673 |
vdevnum = VDEV_LABELS / 2; |
4674 |
else |
4675 |
{ |
4676 |
/* grub_disk_get_size() returns sector count */ |
4677 |
s = s << dev->disk->log_sector_size; |
4678 |
size = P2ALIGN_TYPED(s, sizeof (vdev_label_t), grub_uint64_t); |
4679 |
} |
4680 |
|
4681 |
for (l = 0; l < vdevnum; l++) |
4682 |
{ |
4683 |
grub_uint64_t state, txg; |
4684 |
grub_off_t offset; |
4685 |
char *nvl; |
4686 |
|
4687 |
offset = vdev_label_offset(size, l, 0); |
4688 |
offset += VDEV_SKIP_SIZE; /* pad1 */ |
4689 |
offset += VDEV_BOOT_HEADER_SIZE; /* boot header */ |
4690 |
|
4691 |
/* Read in the vdev_phys. */ |
4692 |
grub_dprintf ("zfs", "vdev_disk_read_rootlabel: label[%d] %" |
4693 |
PRIuGRUB_UINT64_T "\n", l, offset); |
4694 |
|
4695 |
err = grub_disk_read (dev->disk, 0, offset, |
4696 |
VDEV_PHYS_SIZE, (char *) vp); |
4697 |
if (err) |
4698 |
{ |
4699 |
grub_errno = GRUB_ERR_NONE; |
4700 |
continue; |
4701 |
} |
4702 |
else |
4703 |
{ |
4704 |
zio_cksum_t zc; |
4705 |
grub_zfs_endian_t endian; |
4706 |
|
4707 |
if (grub_zfs_to_cpu64 (vp->vp_zbt.zec_magic, |
4708 |
GRUB_ZFS_LITTLE_ENDIAN) == ZEC_MAGIC) |
4709 |
endian = GRUB_ZFS_LITTLE_ENDIAN; |
4710 |
else if (grub_zfs_to_cpu64 (vp->vp_zbt.zec_magic, |
4711 |
GRUB_ZFS_BIG_ENDIAN) == ZEC_MAGIC) |
4712 |
endian = GRUB_ZFS_BIG_ENDIAN; |
4713 |
else |
4714 |
continue; |
4715 |
|
4716 |
ZIO_SET_CHECKSUM (&zc, offset, 0, 0, 0); |
4717 |
err = zio_checksum_verify (zc, ZIO_CHECKSUM_LABEL, endian, |
4718 |
(char *)vp, VDEV_PHYS_SIZE); |
4719 |
if (err) |
4720 |
{ |
4721 |
grub_errno = GRUB_ERR_NONE; |
4722 |
continue; |
4723 |
} |
4724 |
} |
4725 |
|
4726 |
nvl = vp->vp_nvlist; |
4727 |
if (!grub_zfs_nvlist_lookup_uint64 (nvl, ZPOOL_CONFIG_POOL_STATE, |
4728 |
&state) && state >= POOL_STATE_DESTROYED) |
4729 |
{ |
4730 |
continue; |
4731 |
} |
4732 |
|
4733 |
if (!grub_zfs_nvlist_lookup_uint64 (nvl, ZPOOL_CONFIG_POOL_TXG, |
4734 |
&txg) && txg == 0) |
4735 |
{ |
4736 |
continue; |
4737 |
} |
4738 |
|
4739 |
*config = grub_malloc(VDEV_PHYS_SIZE - sizeof (zio_eck_t)); |
4740 |
if (!*config) |
4741 |
{ |
4742 |
grub_dprintf("zfs", "nvlist allocation failed.\n"); |
4743 |
grub_free(vp); |
4744 |
return grub_errno; |
4745 |
} |
4746 |
grub_memcpy(*config, nvl, VDEV_PHYS_SIZE - sizeof (zio_eck_t)); |
4747 |
break; |
4748 |
} |
4749 |
|
4750 |
grub_free(vp); |
4751 |
if (*config == NULL) |
4752 |
err = GRUB_ERR_BAD_FS; |
4753 |
|
4754 |
return err; |
4755 |
} |
4756 |
|
4757 |
/* add device to grub_zfs_device_desc */ |
4758 |
static grub_err_t |
4759 |
vdev_add(struct grub_zfs_device_desc *desc, grub_device_t dev, char *nv, |
4760 |
char *dev_name, int original) |
4761 |
{ |
4762 |
char *type; |
4763 |
grub_uint64_t u; |
4764 |
|
4765 |
type = grub_zfs_nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE); |
4766 |
|
4767 |
if (grub_strcmp (type, VDEV_TYPE_MIRROR) == 0) |
4768 |
desc->type = DEVICE_MIRROR; |
4769 |
else if (grub_strcmp (type, VDEV_TYPE_RAIDZ) == 0) |
4770 |
desc->type = DEVICE_RAIDZ; |
4771 |
else if (grub_strcmp (type, VDEV_TYPE_DISK) == 0 || |
4772 |
grub_strcmp (type, VDEV_TYPE_FILE) == 0) |
4773 |
desc->type = DEVICE_LEAF; |
4774 |
else |
4775 |
{ |
4776 |
grub_dprintf("zfs", "vdev_add: vdev %d unknown type %s\n", |
4777 |
(int)desc->id, type); |
4778 |
grub_free (type); |
4779 |
return GRUB_ERR_BAD_FS; |
4780 |
} |
4781 |
grub_free (type); |
4782 |
|
4783 |
if (desc->type > DEVICE_LEAF) |
4784 |
{ |
4785 |
unsigned i; |
4786 |
desc->n_children = grub_zfs_nvlist_lookup_nvlist_array_get_nelm |
4787 |
(nv, ZPOOL_CONFIG_CHILDREN); |
4788 |
desc->children = grub_zalloc (sizeof (desc->children[0]) |
4789 |
* desc->n_children); |
4790 |
if (! desc->children) |
4791 |
{ |
4792 |
grub_dprintf("zfs", "vdev_add: out of memory\n"); |
4793 |
return GRUB_ERR_OUT_OF_MEMORY; |
4794 |
} |
4795 |
/* set children state to DEVICE_ERROR */ |
4796 |
for (i = 0; i < desc->n_children; i++) |
4797 |
desc->children[i].dev_state = DEVICE_ERROR; |
4798 |
} |
4799 |
else |
4800 |
{ |
4801 |
desc->n_children = 0; |
4802 |
if (grub_zfs_vdev_validate(nv) || dev == NULL) |
4803 |
desc->dev_state = DEVICE_ERROR; |
4804 |
else |
4805 |
desc->dev_state = DEVICE_OK; |
4806 |
desc->dev = dev; |
4807 |
desc->dev_name = dev_name; |
4808 |
desc->original = original; |
4809 |
desc->ashift = dev->disk->log_sector_size; |
4810 |
grub_dprintf("zfs", "vdev_add: added disk %s, state: %d original: %d\n", |
4811 |
desc->dev_name, desc->dev_state, desc->original); |
4812 |
} |
4813 |
|
4814 |
if (desc->type == DEVICE_RAIDZ) |
4815 |
{ |
4816 |
if (!grub_zfs_nvlist_lookup_uint64 (nv, ZPOOL_CONFIG_NPARITY, &u)) |
4817 |
{ |
4818 |
grub_dprintf("zfs", "vdev_add: can't get parity\n"); |
4819 |
return GRUB_ERR_BAD_FS; |
4820 |
} |
4821 |
desc->nparity = u; |
4822 |
} |
4823 |
|
4824 |
if (grub_zfs_nvlist_lookup_uint64 (nv, ZPOOL_CONFIG_ASHIFT, &u)) |
4825 |
desc->ashift = u; |
4826 |
|
4827 |
grub_dprintf("zfs", "vdev_add: ashift: %d\n", desc->ashift); |
4828 |
|
4829 |
return GRUB_ERR_NONE; |
4830 |
} |
4831 |
|
4832 |
/* attach device to vdev tree */ |
4833 |
static grub_err_t |
4834 |
vdev_attach(struct grub_zfs_data *data, grub_device_t dev, char *config, |
4835 |
char *dev_name, int original) |
4836 |
{ |
4837 |
grub_uint64_t id, guid, txg, n_children = 0; |
4838 |
struct grub_zfs_device_desc *desc; |
4839 |
char *nvtop; |
4840 |
unsigned i; |
4841 |
grub_err_t err = GRUB_ERR_NONE; |
4842 |
|
4843 |
if (!grub_zfs_nvlist_lookup_uint64 (config, ZPOOL_CONFIG_POOL_TXG, &txg)) |
4844 |
{ |
4845 |
grub_dprintf ("zfs", "can't read vdev txg\n"); |
4846 |
return GRUB_ERR_BAD_FS; |
4847 |
} |
4848 |
if (!grub_zfs_nvlist_lookup_uint64 (config, ZPOOL_CONFIG_TOP_GUID, &guid)) |
4849 |
{ |
4850 |
grub_dprintf ("zfs", "vdev_attach: can't read top guid\n"); |
4851 |
return GRUB_ERR_BAD_FS; |
4852 |
} |
4853 |
|
4854 |
nvtop = grub_zfs_nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE); |
4855 |
if (!nvtop) |
4856 |
{ |
4857 |
grub_dprintf("zfs", "read vdev tree failed\n"); |
4858 |
return GRUB_ERR_BAD_FS; |
4859 |
} |
4860 |
|
4861 |
if (!grub_zfs_nvlist_lookup_uint64 (nvtop, ZPOOL_CONFIG_ID, &id)) |
4862 |
{ |
4863 |
grub_dprintf ("zfs", "can't read vdev id\n"); |
4864 |
grub_free (nvtop); |
4865 |
return GRUB_ERR_BAD_FS; |
4866 |
} |
4867 |
grub_dprintf ("zfs", "vdev id: %" PRIxGRUB_UINT64_T " guid: %" |
4868 |
PRIxGRUB_UINT64_T "\n", id, guid); |
4869 |
|
4870 |
if (id > data->n_devices_allocated) |
4871 |
{ |
4872 |
data->devices_attached = grub_realloc(data->devices_attached, |
4873 |
sizeof (data->devices_attached[0]) |
4874 |
* (id + 1)); |
4875 |
for (i = data->n_devices_allocated; i < (id + 1); i++) |
4876 |
grub_memset(&data->devices_attached[i], 0, |
4877 |
sizeof (data->devices_attached[0])); |
4878 |
data->n_devices_allocated = id + 1; |
4879 |
} |
4880 |
|
4881 |
desc = &data->devices_attached[id]; |
4882 |
|
4883 |
/* is it new vdev? */ |
4884 |
if (desc->guid == 0) |
4885 |
{ |
4886 |
grub_dprintf ("zfs", "adding vdev: %d guid: %" |
4887 |
PRIxGRUB_UINT64_T "\n", (int)id, guid); |
4888 |
desc->id = id; |
4889 |
desc->guid = guid; |
4890 |
desc->txg = txg; |
4891 |
err = vdev_add(desc, dev, nvtop, dev_name, original); |
4892 |
if (err) |
4893 |
{ |
4894 |
grub_dprintf ("zfs", "vdev_add failed\n"); |
4895 |
grub_free (nvtop); |
4896 |
return err; |
4897 |
} |
4898 |
|
4899 |
data->n_devices_attached++; |
4900 |
} |
4901 |
else |
4902 |
{ |
4903 |
/* this vdev is set up, so the top guid must match with vdev guid */ |
4904 |
if (desc->guid != guid) |
4905 |
{ |
4906 |
grub_dprintf ("zfs", "vdev_attach: the top vdev guid mismatch\n"); |
4907 |
grub_free (nvtop); |
4908 |
return GRUB_ERR_BAD_FS; |
4909 |
} |
4910 |
} |
4911 |
|
4912 |
/* add us in child list if needed */ |
4913 |
if (!grub_zfs_nvlist_lookup_uint64 (config, ZPOOL_CONFIG_GUID, &guid)) |
4914 |
{ |
4915 |
grub_dprintf ("zfs", "vdev_attach: can't read guid\n"); |
4916 |
grub_free (nvtop); |
4917 |
return GRUB_ERR_BAD_FS; |
4918 |
} |
4919 |
|
4920 |
if (desc->type > DEVICE_LEAF) |
4921 |
{ |
4922 |
n_children = grub_zfs_nvlist_lookup_nvlist_array_get_nelm |
4923 |
(nvtop, ZPOOL_CONFIG_CHILDREN); |
4924 |
if (n_children > desc->n_children) |
4925 |
{ |
4926 |
desc->children = grub_realloc(desc->children, |
4927 |
sizeof (desc->children[0]) |
4928 |
* n_children); |
4929 |
for (i = desc->n_children; i < n_children; i++) |
4930 |
grub_memset(&desc->children[i], 0, sizeof (desc->children[0])); |
4931 |
desc->n_children = n_children; |
4932 |
} |
4933 |
} |
4934 |
|
4935 |
for (i = 0; i < desc->n_children; i++) |
4936 |
{ |
4937 |
grub_uint64_t cguid; |
4938 |
struct grub_zfs_device_desc *cdesc; |
4939 |
char *child; |
4940 |
|
4941 |
child = grub_zfs_nvlist_lookup_nvlist_array(nvtop, |
4942 |
ZPOOL_CONFIG_CHILDREN, i); |
4943 |
|
4944 |
if (!grub_zfs_nvlist_lookup_uint64 (child, ZPOOL_CONFIG_ID, &id)) |
4945 |
{ |
4946 |
grub_dprintf ("zfs", "vdev_attach: can't read id\n"); |
4947 |
grub_free (child); |
4948 |
grub_free (nvtop); |
4949 |
return GRUB_ERR_BAD_FS; |
4950 |
} |
4951 |
|
4952 |
if (!grub_zfs_nvlist_lookup_uint64 (child, ZPOOL_CONFIG_GUID, &cguid)) |
4953 |
{ |
4954 |
grub_dprintf ("zfs", "vdev_attach: can't read guid\n"); |
4955 |
grub_free (child); |
4956 |
grub_free (nvtop); |
4957 |
return GRUB_ERR_BAD_FS; |
4958 |
} |
4959 |
|
4960 |
cdesc = &desc->children[id]; |
4961 |
if (cguid == guid && i == id && cdesc->guid == 0) |
4962 |
{ |
4963 |
grub_dprintf ("zfs", "adding child: %d guid: %" |
4964 |
PRIxGRUB_UINT64_T "\n", i, guid); |
4965 |
|
4966 |
cdesc->id = id; |
4967 |
cdesc->guid = guid; |
4968 |
if (cdesc->txg < txg) |
4969 |
{ |
4970 |
cdesc->txg = txg; |
4971 |
if (cdesc->config != NULL) |
4972 |
grub_free (cdesc->config); |
4973 |
cdesc->config = child; |
4974 |
} |
4975 |
|
4976 |
err = vdev_add(cdesc, dev, child, dev_name, original); |
4977 |
if (err) |
4978 |
{ |
4979 |
grub_dprintf ("zfs", "vdev_add failed\n"); |
4980 |
if (cdesc->config == child) |
4981 |
cdesc->config = NULL; |
4982 |
grub_free (child); |
4983 |
grub_free (nvtop); |
4984 |
return err; |
4985 |
} |
4986 |
cdesc->top_vdev = desc; |
4987 |
if (desc->ashift < cdesc->ashift) |
4988 |
desc->ashift = cdesc->ashift; |
4989 |
} |
4990 |
/* update child dev_state if needed */ |
4991 |
if (cdesc->txg < txg) |
4992 |
{ |
4993 |
cdesc->txg = txg; |
4994 |
if (cdesc->config != NULL) |
4995 |
grub_free (cdesc->config); |
4996 |
cdesc->config = child; |
4997 |
} |
4998 |
if (cdesc->dev == NULL) |
4999 |
cdesc->dev_state = DEVICE_ERROR; |
5000 |
else if (grub_zfs_vdev_validate(cdesc->config)) |
5001 |
cdesc->dev_state = DEVICE_ERROR; |
5002 |
if (cdesc->config != child) |
5003 |
grub_free (child); |
5004 |
} |
5005 |
|
5006 |
grub_free (nvtop); |
5007 |
return err; |
5008 |
} |
5009 |
|
5010 |
/* |
5011 |
* read 'best' uberblock from disk. so we read UB array from each label |
5012 |
* from each vdev and looking for highest txg. |
5013 |
*/ |
5014 |
static void |
5015 |
vdev_uberblock_load(struct grub_zfs_data *data, |
5016 |
struct grub_zfs_device_desc *desc) |
5017 |
{ |
5018 |
int vdevnum, l, ashift; |
5019 |
grub_uint64_t s, size; |
5020 |
grub_uint8_t *ub_array; |
5021 |
grub_err_t err; |
5022 |
|
5023 |
if (desc->dev == NULL) |
5024 |
return; |
5025 |
|
5026 |
if (desc->top_vdev) |
5027 |
ashift = desc->top_vdev->ashift; |
5028 |
else |
5029 |
ashift = desc->ashift; |
5030 |
|
5031 |
grub_dprintf("zfs", "vdev_uberblock_load: %s ashift: %d\n", |
5032 |
desc->dev_name, ashift); |
5033 |
vdevnum = VDEV_LABELS; |
5034 |
|
5035 |
ub_array = grub_zalloc (VDEV_UBERBLOCK_SIZE(ashift)); |
5036 |
if (!ub_array) |
5037 |
{ |
5038 |
grub_dprintf("zfs", "ub_array allocation failed.\n"); |
5039 |
return; |
5040 |
} |
5041 |
|
5042 |
size = s = grub_disk_get_size (desc->dev->disk); |
5043 |
/* Don't check back labels on CDROM. */ |
5044 |
if (s == GRUB_DISK_SIZE_UNKNOWN) |
5045 |
vdevnum = VDEV_LABELS / 2; |
5046 |
else |
5047 |
{ |
5048 |
/* grub_disk_get_size() returns sector count */ |
5049 |
s = s << desc->dev->disk->log_sector_size; |
5050 |
size = P2ALIGN_TYPED(s, sizeof (vdev_label_t), grub_uint64_t); |
5051 |
} |
5052 |
|
5053 |
for (l = 0; l < vdevnum; l++) |
5054 |
{ |
5055 |
grub_off_t offset; |
5056 |
int n; |
5057 |
|
5058 |
for (n = 0; n < VDEV_UBERBLOCK_COUNT(ashift); n++) |
5059 |
{ |
5060 |
offset = vdev_label_offset(size, l, VDEV_UBERBLOCK_OFFSET(ashift, n)); |
5061 |
err = grub_disk_read (desc->dev->disk, 0, offset, |
5062 |
VDEV_UBERBLOCK_SIZE(ashift), (char *)ub_array); |
5063 |
if (err) |
5064 |
{ |
5065 |
grub_dprintf ("zfs", "grub_disk_read() failed\n"); |
5066 |
grub_errno = GRUB_ERR_NONE; |
5067 |
continue; |
5068 |
} |
5069 |
err = uberblock_verify ((uberblock_t *)ub_array, offset, ashift); |
5070 |
if (err) |
5071 |
{ |
5072 |
grub_errno = GRUB_ERR_NONE; |
5073 |
continue; |
5074 |
} |
5075 |
if (data->current_uberblock.ub_magic == 0 || |
5076 |
vdev_uberblock_compare(&data->current_uberblock, |
5077 |
(uberblock_t *)ub_array) > 0) |
5078 |
{ |
5079 |
grub_memmove(&(data->current_uberblock), ub_array, |
5080 |
sizeof (uberblock_t)); |
5081 |
} |
5082 |
} |
5083 |
} |
5084 |
grub_free (ub_array); |
5085 |
} |
5086 |
|
5087 |
/* |
5088 |
* zfs_mount() locates a valid uberblock of the root pool and |
5089 |
* read in its MOS to the device grub_zfs_data structure. |
5090 |
* |
5091 |
* zfs_mount() is called frequently by GRUB2 zfs interfaces, so |
5092 |
* a cache mechanism is implemented to save the successful zfs |
5093 |
* mount data for devices. This is good for zfs mount performance. |
5094 |
* |
5095 |
*/ |
5096 |
static struct grub_zfs_data * |
5097 |
zfs_mount (grub_device_t dev) |
5098 |
{ |
5099 |
struct grub_zfs_data *data = NULL; |
5100 |
struct zfs_mount_cache *zcache = NULL; |
5101 |
objset_phys_t *osp = 0; |
5102 |
grub_size_t ospsize; |
5103 |
grub_zfs_endian_t ub_endian = GRUB_ZFS_UNKNOWN_ENDIAN; |
5104 |
uberblock_t *ub; |
5105 |
unsigned int i, j; |
5106 |
char *diskname, *partname, *fullname, *pname; |
5107 |
char *features, *config = NULL; |
5108 |
grub_uint64_t u; |
5109 |
grub_err_t err; |
5110 |
|
5111 |
grub_errno = GRUB_ERR_NONE; |
5112 |
if (! dev->disk) |
5113 |
{ |
5114 |
grub_error (GRUB_ERR_BAD_DEVICE, "not a disk"); |
5115 |
grub_errno = GRUB_ERR_BAD_DEVICE; |
5116 |
return NULL; |
5117 |
} |
5118 |
|
5119 |
diskname = (char *)dev->disk->name; |
5120 |
partname = grub_partition_get_name(dev->disk->partition); |
5121 |
if (partname[0] != 0) |
5122 |
{ |
5123 |
fullname = grub_xasprintf("%s,%s", diskname, partname); |
5124 |
} |
5125 |
else |
5126 |
fullname = grub_strdup (diskname); |
5127 |
grub_free (partname); |
5128 |
|
5129 |
if ((err = vdev_disk_read_rootlabel(dev, &config)) != GRUB_ERR_NONE) |
5130 |
{ |
5131 |
grub_error (err, "Cannot read the pool label from '%s'", fullname); |
5132 |
grub_free (fullname); |
5133 |
if (grub_errno == GRUB_ERR_NONE) |
5134 |
grub_errno = err; |
5135 |
return NULL; |
5136 |
} |
5137 |
|
5138 |
pname = grub_zfs_nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME); |
5139 |
if (!pname) |
5140 |
{ |
5141 |
grub_error (err, "Incorrect pool label from '%s'", fullname); |
5142 |
grub_free (fullname); |
5143 |
grub_free (config); |
5144 |
if (grub_errno == GRUB_ERR_NONE) |
5145 |
grub_errno = GRUB_ERR_BAD_FS; |
5146 |
return NULL; |
5147 |
} |
5148 |
|
5149 |
if (!grub_zfs_nvlist_lookup_uint64 (config, ZPOOL_CONFIG_VERSION, &u)) |
5150 |
{ |
5151 |
grub_free (fullname); |
5152 |
grub_free (config); |
5153 |
grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_VERSION " not found"); |
5154 |
if (grub_errno == GRUB_ERR_NONE) |
5155 |
grub_errno = GRUB_ERR_BAD_FS; |
5156 |
|
5157 |
return NULL; |
5158 |
} |
5159 |
|
5160 |
if (!SPA_VERSION_IS_SUPPORTED(u)) |
5161 |
{ |
5162 |
grub_free (fullname); |
5163 |
grub_free (config); |
5164 |
|
5165 |
grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, |
5166 |
"ZFS SPA version %" PRIuGRUB_UINT64_T "is not compatible with this " |
5167 |
"GRUB2 ZFS reader code.\nSupported Oracle ZFS is %" PRIuGRUB_UINT64_T |
5168 |
"\nSupported OpenZFS version is %" PRIuGRUB_UINT64_T "\n", |
5169 |
(unsigned long long) u, |
5170 |
(unsigned long long) SPA_VERSION_ORACLE, |
5171 |
(unsigned long long) SPA_VERSION); |
5172 |
if (grub_errno == GRUB_ERR_NONE) |
5173 |
grub_errno = GRUB_ERR_NOT_IMPLEMENTED_YET; |
5174 |
|
5175 |
return NULL; |
5176 |
} |
5177 |
|
5178 |
features = grub_zfs_nvlist_lookup_nvlist (config, |
5179 |
ZPOOL_CONFIG_FEATURES_FOR_READ); |
5180 |
if (features) |
5181 |
{ |
5182 |
const char *nvp; |
5183 |
char *name; |
5184 |
|
5185 |
for (nvp = nvlist_next_nvpair(features, NULL); nvp != NULL; |
5186 |
nvp = nvlist_next_nvpair(features, nvp)) { |
5187 |
name = nvpair_name(nvp); |
5188 |
if (name) { |
5189 |
err = check_feature(name, 1, NULL); |
5190 |
if (err) { |
5191 |
grub_free (name); |
5192 |
grub_free (features); |
5193 |
grub_free (fullname); |
5194 |
grub_free (config); |
5195 |
grub_errno = err; |
5196 |
return NULL; |
5197 |
} |
5198 |
grub_free (name); |
5199 |
} |
5200 |
} |
5201 |
grub_free (features); |
5202 |
} |
5203 |
grub_dprintf ("zfs", "zfs_mount: attempting to mount \"%s\" from %s\n", |
5204 |
pname, fullname); |
5205 |
|
5206 |
/* check the zfs mount cache list first */ |
5207 |
for (zcache = zfs_mount_cache_list; zcache != NULL; zcache = zcache->next) |
5208 |
{ |
5209 |
grub_dprintf ("zfs", "zfs_mount: zcached %s\n", zcache->zcache_pool_name); |
5210 |
if (grub_strcmp (pname, zcache->zcache_pool_name) != 0) |
5211 |
continue; |
5212 |
|
5213 |
data = zcache->zcache_zfs_data; |
5214 |
data->file_buf = 0; |
5215 |
data->file_start = 0; |
5216 |
data->file_end = 0; |
5217 |
data->dnode_buf = 0; |
5218 |
data->dnode_mdn = 0; |
5219 |
data->dnode_start = 0; |
5220 |
data->dnode_end = 0; |
5221 |
data->dnode_endian = 0; |
5222 |
data->label = pname; |
5223 |
grub_memset(&data->dnode, 0, sizeof (data->dnode)); |
5224 |
grub_memset(&data->subvol, 0, sizeof (data->subvol)); |
5225 |
|
5226 |
grub_free (config); |
5227 |
|
5228 |
for (i = 0; i < data->n_devices_attached; i++) |
5229 |
{ |
5230 |
mount_device (&data->devices_attached[i], dev, fullname); |
5231 |
} |
5232 |
grub_free (fullname); |
5233 |
/* need to check if dev is actually usable */ |
5234 |
return data; |
5235 |
} |
5236 |
|
5237 |
/* allocate the zfs mount data structure */ |
5238 |
data = grub_zalloc (sizeof (*data)); |
5239 |
if (! data) |
5240 |
{ |
5241 |
grub_error (GRUB_ERR_OUT_OF_MEMORY, "zfs data allocation failed"); |
5242 |
grub_free (pname); |
5243 |
grub_free (config); |
5244 |
grub_free (fullname); |
5245 |
grub_errno = GRUB_ERR_OUT_OF_MEMORY; |
5246 |
return 0; |
5247 |
} |
5248 |
|
5249 |
/* need to do a new mount */ |
5250 |
data->label = pname; |
5251 |
|
5252 |
if (!grub_zfs_nvlist_lookup_uint64 (config, ZPOOL_CONFIG_POOL_GUID, &u)) |
5253 |
{ |
5254 |
grub_dprintf ("zfs", "can't read pool guid\n"); |
5255 |
grub_free (config); |
5256 |
zfs_unmount (data); |
5257 |
grub_free (fullname); |
5258 |
if (grub_errno == GRUB_ERR_NONE) |
5259 |
grub_errno = GRUB_ERR_BAD_FS; |
5260 |
return NULL; |
5261 |
} |
5262 |
data->guid = u; |
5263 |
grub_dprintf ("zfs", "pool guid: %" PRIxGRUB_UINT64_T "\n", u); |
5264 |
|
5265 |
if (!grub_zfs_nvlist_lookup_uint64 (config, ZPOOL_CONFIG_POOL_STATE, &u)) |
5266 |
{ |
5267 |
grub_dprintf ("zfs", "can't read pool state\n"); |
5268 |
grub_free (config); |
5269 |
zfs_unmount (data); |
5270 |
grub_free (fullname); |
5271 |
if (grub_errno == GRUB_ERR_NONE) |
5272 |
grub_errno = GRUB_ERR_BAD_FS; |
5273 |
return NULL; |
5274 |
} |
5275 |
data->state = u; |
5276 |
|
5277 |
if (!grub_zfs_nvlist_lookup_uint64 (config, ZPOOL_CONFIG_VDEV_CHILDREN, &u)) |
5278 |
{ |
5279 |
grub_dprintf ("zfs", "can't read vdev children count\n"); |
5280 |
grub_free (config); |
5281 |
grub_free (fullname); |
5282 |
zfs_unmount (data); |
5283 |
if (grub_errno == GRUB_ERR_NONE) |
5284 |
grub_errno = GRUB_ERR_BAD_FS; |
5285 |
return NULL; |
5286 |
} |
5287 |
|
5288 |
/* set up memory for top level vdevs */ |
5289 |
data->n_devices_allocated = u; |
5290 |
data->devices_attached = grub_zalloc (sizeof (data->devices_attached[0]) |
5291 |
* data->n_devices_allocated); |
5292 |
if (! data->devices_attached) |
5293 |
{ |
5294 |
grub_dprintf ("zfs", "can't allocate top level vdevs\n"); |
5295 |
grub_free (config); |
5296 |
grub_free (fullname); |
5297 |
zfs_unmount (data); |
5298 |
if (grub_errno == GRUB_ERR_NONE) |
5299 |
grub_errno = GRUB_ERR_BAD_FS; |
5300 |
return NULL; |
5301 |
} |
5302 |
|
5303 |
data->n_devices_attached = 0; |
5304 |
|
5305 |
/* |
5306 |
* check if the pool has multiple vdevs/children, add the disks. |
5307 |
* as the zfs_mount() caller provides us open "dev" and will close it, |
5308 |
* we dont wanna store this descriptor, but instead we open new instance. |
5309 |
*/ |
5310 |
err = scan_devices(data, fullname, dev); |
5311 |
if (err) |
5312 |
{ |
5313 |
/* we are missing disks, check if we have enough parity to continue */ |
5314 |
if (data->n_devices_attached == data->n_devices_allocated) |
5315 |
{ |
5316 |
unsigned missing = 0; |
5317 |
struct grub_zfs_device_desc *desc; |
5318 |
/* |
5319 |
* only need to check raidz, as missing leaf can't get here |
5320 |
* and mirror means we have at least 1 disk in mirror |
5321 |
*/ |
5322 |
err = GRUB_ERR_NONE; |
5323 |
for (i = 0; i < data->n_devices_attached; i++) |
5324 |
{ |
5325 |
desc = &data->devices_attached[i]; |
5326 |
if (desc->type == DEVICE_RAIDZ) |
5327 |
{ |
5328 |
for (j = 0; j < desc->n_children; j++) |
5329 |
if (desc->children[j].dev == NULL) |
5330 |
missing++; |
5331 |
if (missing > desc->nparity) |
5332 |
err = grub_error (GRUB_ERR_BAD_FS, |
5333 |
N_("pool %s is missing too many devices"), |
5334 |
data->label); |
5335 |
} |
5336 |
} |
5337 |
} |
5338 |
} |
3517 |
|
5339 |
|
3518 |
static void |
5340 |
/* if dev_state is DEVICE_ERROR, we need to use another device for mount */ |
3519 |
zfs_unmount (struct grub_zfs_data *data) |
|
|
3520 |
{ |
3521 |
unsigned i; |
3522 |
for (i = 0; i < data->n_devices_attached; i++) |
5341 |
for (i = 0; i < data->n_devices_attached; i++) |
3523 |
unmount_device (&data->devices_attached[i]); |
5342 |
{ |
3524 |
grub_free (data->devices_attached); |
5343 |
struct grub_zfs_device_desc *desc; |
3525 |
grub_free (data->dnode_buf); |
5344 |
desc = &data->devices_attached[i]; |
3526 |
grub_free (data->dnode_mdn); |
5345 |
if (err) |
3527 |
grub_free (data->file_buf); |
5346 |
break; |
3528 |
for (i = 0; i < data->subvol.nkeys; i++) |
|
|
3529 |
grub_crypto_cipher_close (data->subvol.keyring[i].cipher); |
3530 |
grub_free (data->subvol.keyring); |
3531 |
grub_free (data); |
3532 |
} |
3533 |
|
5347 |
|
3534 |
/* |
5348 |
if (desc->type == DEVICE_LEAF) |
3535 |
* zfs_mount() locates a valid uberblock of the root pool and read in its MOS |
5349 |
{ |
3536 |
* to the memory address MOS. |
5350 |
if (desc->original && desc->dev_state == DEVICE_ERROR) |
3537 |
* |
5351 |
{ |
3538 |
*/ |
5352 |
err = GRUB_ERR_BAD_DEVICE; |
3539 |
static struct grub_zfs_data * |
5353 |
break; |
3540 |
zfs_mount (grub_device_t dev) |
5354 |
} |
3541 |
{ |
5355 |
} |
3542 |
struct grub_zfs_data *data = 0; |
5356 |
for (j = 0; j < desc->n_children; j++) |
3543 |
grub_err_t err; |
5357 |
{ |
3544 |
void *osp = 0; |
5358 |
if (desc->children[j].original && |
3545 |
grub_size_t ospsize; |
5359 |
desc->children[j].dev_state == DEVICE_ERROR) |
3546 |
grub_zfs_endian_t ub_endian = GRUB_ZFS_UNKNOWN_ENDIAN; |
5360 |
{ |
3547 |
uberblock_t *ub; |
5361 |
err = GRUB_ERR_BAD_DEVICE; |
3548 |
int inserted; |
5362 |
break; |
|
|
5363 |
} |
5364 |
} |
5365 |
} |
3549 |
|
5366 |
|
3550 |
if (! dev->disk) |
5367 |
if (err) |
3551 |
{ |
5368 |
{ |
3552 |
grub_error (GRUB_ERR_BAD_DEVICE, "not a disk"); |
5369 |
grub_errno = err; |
3553 |
return 0; |
5370 |
grub_dprintf("zfs", "zfs_mount failed: missing devices\n"); |
|
|
5371 |
grub_free (config); |
5372 |
zfs_unmount (data); |
5373 |
return NULL; |
3554 |
} |
5374 |
} |
3555 |
|
5375 |
|
3556 |
data = grub_zalloc (sizeof (*data)); |
5376 |
/* |
3557 |
if (!data) |
5377 |
* load the UB now. the obvious issue here is that we should load |
3558 |
return 0; |
5378 |
* an config based on this UB, so instead we just hope the pool |
3559 |
#if 0 |
5379 |
* current config is ok. from bootloader point of view, it just may |
3560 |
/* if it's our first time here, zero the best uberblock out */ |
5380 |
* be "good enough", as we will output the disk with best ub with |
3561 |
if (data->best_drive == 0 && data->best_part == 0 && find_best_root) |
5381 |
* "search" command to be set for root, and so subsequent pool access |
3562 |
grub_memset (¤t_uberblock, 0, sizeof (uberblock_t)); |
5382 |
* will load the best config. same for "zfs-bootfs", to inform kernel |
3563 |
#endif |
5383 |
* to start from best disk - even if the kernel is able to deal better |
|
|
5384 |
* with pool config, there are cases where kernel will drop out and |
5385 |
* asks to use another disk to boot from... |
5386 |
*/ |
5387 |
grub_dprintf("zfs", "pool: %s\n", data->label); |
5388 |
for (i = 0; i < data->n_devices_attached; i++) |
5389 |
if (data->devices_attached[i].type == DEVICE_LEAF) |
5390 |
{ |
5391 |
grub_dprintf("zfs", " %s\n", |
5392 |
data->devices_attached[i].dev_name); |
5393 |
vdev_uberblock_load(data, &data->devices_attached[i]); |
5394 |
} |
5395 |
else |
5396 |
{ |
5397 |
grub_dprintf("zfs", " %s-%u\n", |
5398 |
data->devices_attached[i].type == DEVICE_MIRROR? |
5399 |
"mirror" : "raidz", i); |
5400 |
for (j = 0; j < data->devices_attached[i].n_children; j++) |
5401 |
{ |
5402 |
struct grub_zfs_device_desc *desc; |
5403 |
desc = &data->devices_attached[i].children[j]; |
5404 |
grub_dprintf("zfs", " %s\n", desc->dev_name == NULL? |
5405 |
"[missing]" : desc->dev_name); |
5406 |
vdev_uberblock_load(data, desc); |
5407 |
} |
5408 |
} |
3564 |
|
5409 |
|
3565 |
data->n_devices_allocated = 16; |
5410 |
grub_free (config); |
3566 |
data->devices_attached = grub_malloc (sizeof (data->devices_attached[0]) |
5411 |
|
3567 |
* data->n_devices_allocated); |
5412 |
ub = &(data->current_uberblock); |
3568 |
data->n_devices_attached = 0; |
5413 |
|
3569 |
err = scan_disk (dev, data, 1, &inserted); |
5414 |
/* did we got UB from any of the disks? */ |
3570 |
if (err) |
5415 |
if (ub->ub_magic == 0) |
3571 |
{ |
5416 |
{ |
|
|
5417 |
grub_dprintf("zfs", "we have no uberblock, can not continue\n"); |
3572 |
zfs_unmount (data); |
5418 |
zfs_unmount (data); |
|
|
5419 |
if (grub_errno == GRUB_ERR_NONE) |
5420 |
grub_errno = GRUB_ERR_BAD_FS; |
3573 |
return NULL; |
5421 |
return NULL; |
3574 |
} |
5422 |
} |
3575 |
|
5423 |
|
3576 |
ub = &(data->current_uberblock); |
|
|
3577 |
ub_endian = (grub_zfs_to_cpu64 (ub->ub_magic, |
5424 |
ub_endian = (grub_zfs_to_cpu64 (ub->ub_magic, |
3578 |
GRUB_ZFS_LITTLE_ENDIAN) == UBERBLOCK_MAGIC |
5425 |
GRUB_ZFS_LITTLE_ENDIAN) == UBERBLOCK_MAGIC |
3579 |
? GRUB_ZFS_LITTLE_ENDIAN : GRUB_ZFS_BIG_ENDIAN); |
5426 |
? GRUB_ZFS_LITTLE_ENDIAN : GRUB_ZFS_BIG_ENDIAN); |
3580 |
|
5427 |
|
3581 |
err = zio_read (&ub->ub_rootbp, ub_endian, |
5428 |
err = zio_read (&ub->ub_rootbp, ub_endian, |
3582 |
&osp, &ospsize, data); |
5429 |
(void **) &osp, &ospsize, data); |
3583 |
if (err) |
5430 |
if (err) |
3584 |
{ |
5431 |
{ |
|
|
5432 |
grub_dprintf("zfs", "zio_read failed: %s\n", grub_errmsg ); |
3585 |
zfs_unmount (data); |
5433 |
zfs_unmount (data); |
|
|
5434 |
if (grub_errno == GRUB_ERR_NONE) |
5435 |
grub_errno = err; |
3586 |
return NULL; |
5436 |
return NULL; |
3587 |
} |
5437 |
} |
3588 |
|
5438 |
|
Lines 3591-3605
Link Here
|
3591 |
grub_error (GRUB_ERR_BAD_FS, "OSP too small"); |
5441 |
grub_error (GRUB_ERR_BAD_FS, "OSP too small"); |
3592 |
grub_free (osp); |
5442 |
grub_free (osp); |
3593 |
zfs_unmount (data); |
5443 |
zfs_unmount (data); |
|
|
5444 |
if (grub_errno == GRUB_ERR_NONE) |
5445 |
grub_errno = GRUB_ERR_BAD_FS; |
3594 |
return NULL; |
5446 |
return NULL; |
3595 |
} |
5447 |
} |
3596 |
|
5448 |
|
3597 |
if (ub->ub_version >= SPA_VERSION_FEATURES && |
5449 |
/* Got the MOS. Save it to data->mos. */ |
3598 |
check_mos_features(&((objset_phys_t *) osp)->os_meta_dnode,ub_endian, |
|
|
3599 |
data) != 0) |
3600 |
return NULL; |
3601 |
|
3602 |
/* Got the MOS. Save it at the memory addr MOS. */ |
3603 |
grub_memmove (&(data->mos.dn), &((objset_phys_t *) osp)->os_meta_dnode, |
5450 |
grub_memmove (&(data->mos.dn), &((objset_phys_t *) osp)->os_meta_dnode, |
3604 |
DNODE_SIZE); |
5451 |
DNODE_SIZE); |
3605 |
data->mos.endian = (grub_zfs_to_cpu64 (ub->ub_rootbp.blk_prop, |
5452 |
data->mos.endian = (grub_zfs_to_cpu64 (ub->ub_rootbp.blk_prop, |
Lines 3608-3613
Link Here
|
3608 |
|
5455 |
|
3609 |
data->mounted = 1; |
5456 |
data->mounted = 1; |
3610 |
|
5457 |
|
|
|
5458 |
if(ub->ub_version >= SPA_VERSION_FEATURES && |
5459 |
check_mos_features(&data->mos, data) != 0) |
5460 |
{ |
5461 |
zfs_unmount (data); |
5462 |
if (grub_errno == GRUB_ERR_NONE) |
5463 |
grub_errno = GRUB_ERR_BAD_FS; |
5464 |
return NULL; |
5465 |
} |
5466 |
|
5467 |
data->mounted = 1; /* mount succeeded */ |
5468 |
#if 0 |
5469 |
/* |
5470 |
* zfs_mount cache is currently disabled, as it was causing |
5471 |
* artefacts with gfx menu - so there must be some bugs in it. |
5472 |
*/ |
5473 |
if (zcache == NULL) /* allocate the zfs mount cache structure */ |
5474 |
zcache = grub_zalloc (sizeof (*zcache)); |
5475 |
else |
5476 |
zcache = NULL; /* intend for a non-cached mount */ |
5477 |
#endif |
5478 |
|
5479 |
if (zcache != NULL) /* cache this OK zfs mount */ |
5480 |
{ |
5481 |
zcache->zcache_zfs_data = data; |
5482 |
zcache->zcache_pool_guid = data->guid; |
5483 |
zcache->zcache_pool_name = grub_strdup(data->label); |
5484 |
zcache->next = zfs_mount_cache_list; |
5485 |
if (zcache->zcache_pool_name) |
5486 |
{ |
5487 |
zfs_mount_cache_list = zcache; |
5488 |
data->zcached = 1; |
5489 |
} |
5490 |
else |
5491 |
grub_free(zcache); |
5492 |
} |
5493 |
|
3611 |
return data; |
5494 |
return data; |
3612 |
} |
5495 |
} |
3613 |
|
5496 |
|
Lines 3615-3654
Link Here
|
3615 |
grub_zfs_fetch_nvlist (grub_device_t dev, char **nvlist) |
5498 |
grub_zfs_fetch_nvlist (grub_device_t dev, char **nvlist) |
3616 |
{ |
5499 |
{ |
3617 |
struct grub_zfs_data *zfs; |
5500 |
struct grub_zfs_data *zfs; |
3618 |
grub_err_t err; |
5501 |
grub_err_t err = GRUB_ERR_NONE; |
|
|
5502 |
unsigned i, j; |
5503 |
char *diskname, *partname, *fullname; |
3619 |
|
5504 |
|
3620 |
zfs = zfs_mount (dev); |
5505 |
zfs = zfs_mount (dev); |
3621 |
if (!zfs) |
5506 |
if (!zfs) |
3622 |
return grub_errno; |
5507 |
return grub_errno; |
3623 |
err = zfs_fetch_nvlist (zfs->device_original, nvlist); |
5508 |
|
|
|
5509 |
diskname = (char *)dev->disk->name; |
5510 |
partname = grub_partition_get_name(dev->disk->partition); |
5511 |
if (partname[0] != 0) |
5512 |
{ |
5513 |
fullname = grub_xasprintf("%s,%s", diskname, partname); |
5514 |
} |
5515 |
else |
5516 |
fullname = grub_strdup (diskname); |
5517 |
grub_free (partname); |
5518 |
|
5519 |
for (i = 0; i < zfs->n_devices_attached; i++) |
5520 |
{ |
5521 |
struct grub_zfs_device_desc *desc; |
5522 |
desc = &zfs->devices_attached[i]; |
5523 |
if (desc->type == DEVICE_LEAF) |
5524 |
{ |
5525 |
if (grub_strcmp(fullname, desc->dev_name) == 0) |
5526 |
err = vdev_disk_read_rootlabel (desc->dev, nvlist); |
5527 |
} |
5528 |
else |
5529 |
{ |
5530 |
for (j = 0; j < desc->n_children; j++) |
5531 |
if (grub_strcmp(fullname, desc->children[j].dev_name) == 0) |
5532 |
err = vdev_disk_read_rootlabel (desc->children[j].dev, nvlist); |
5533 |
} |
5534 |
} |
5535 |
|
5536 |
if (err) |
5537 |
grub_dprintf("zfs", "zfs_fetch_nvlist failed: device:%s\n", fullname); |
5538 |
grub_free (fullname); |
3624 |
zfs_unmount (zfs); |
5539 |
zfs_unmount (zfs); |
3625 |
return err; |
5540 |
return err; |
3626 |
} |
5541 |
} |
3627 |
|
5542 |
|
|
|
5543 |
/* |
5544 |
* Returns the pool name. |
5545 |
*/ |
3628 |
static grub_err_t |
5546 |
static grub_err_t |
3629 |
zfs_label (grub_device_t device, char **label) |
5547 |
zfs_label (grub_device_t device, char **label) |
3630 |
{ |
5548 |
{ |
3631 |
char *nvlist; |
|
|
3632 |
grub_err_t err; |
3633 |
struct grub_zfs_data *data; |
5549 |
struct grub_zfs_data *data; |
3634 |
|
5550 |
|
|
|
5551 |
*label = NULL; |
5552 |
|
3635 |
data = zfs_mount (device); |
5553 |
data = zfs_mount (device); |
3636 |
if (! data) |
5554 |
if (! data) |
3637 |
return grub_errno; |
5555 |
return grub_errno; |
3638 |
|
5556 |
|
3639 |
err = zfs_fetch_nvlist (data->device_original, &nvlist); |
5557 |
*label = grub_strdup(data->label); |
3640 |
if (err) |
5558 |
if (*label == NULL) |
3641 |
{ |
5559 |
grub_errno = GRUB_ERR_OUT_OF_MEMORY; |
3642 |
zfs_unmount (data); |
|
|
3643 |
return err; |
3644 |
} |
3645 |
|
3646 |
*label = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_POOL_NAME); |
3647 |
grub_free (nvlist); |
3648 |
zfs_unmount (data); |
5560 |
zfs_unmount (data); |
3649 |
return grub_errno; |
5561 |
return grub_errno; |
3650 |
} |
5562 |
} |
3651 |
|
5563 |
|
|
|
5564 |
/* |
5565 |
* Returns the pool GUID. |
5566 |
*/ |
3652 |
static grub_err_t |
5567 |
static grub_err_t |
3653 |
zfs_uuid (grub_device_t device, char **uuid) |
5568 |
zfs_uuid (grub_device_t device, char **uuid) |
3654 |
{ |
5569 |
{ |
Lines 3663-3669
Link Here
|
3663 |
*uuid = grub_xasprintf ("%016llx", (long long unsigned) data->guid); |
5578 |
*uuid = grub_xasprintf ("%016llx", (long long unsigned) data->guid); |
3664 |
zfs_unmount (data); |
5579 |
zfs_unmount (data); |
3665 |
if (! *uuid) |
5580 |
if (! *uuid) |
3666 |
return grub_errno; |
5581 |
{ |
|
|
5582 |
if (grub_errno == GRUB_ERR_NONE) |
5583 |
grub_errno = GRUB_ERR_OUT_OF_MEMORY; |
5584 |
return grub_errno; |
5585 |
} |
3667 |
return GRUB_ERR_NONE; |
5586 |
return GRUB_ERR_NONE; |
3668 |
} |
5587 |
} |
3669 |
|
5588 |
|
Lines 3692-3698
Link Here
|
3692 |
|
5611 |
|
3693 |
/* |
5612 |
/* |
3694 |
* zfs_open() locates a file in the rootpool by following the |
5613 |
* zfs_open() locates a file in the rootpool by following the |
3695 |
* MOS and places the dnode of the file in the memory address DNODE. |
5614 |
* MOS and places the dnode of the file in the device |
|
|
5615 |
* grub_zfs_data structure. |
3696 |
*/ |
5616 |
*/ |
3697 |
static grub_err_t |
5617 |
static grub_err_t |
3698 |
grub_zfs_open (struct grub_file *file, const char *fsfilename) |
5618 |
grub_zfs_open (struct grub_file *file, const char *fsfilename) |
Lines 3815-3823
Link Here
|
3815 |
grub_uint64_t blkid = grub_divmod64 (file->offset + read, blksz, 0); |
5735 |
grub_uint64_t blkid = grub_divmod64 (file->offset + read, blksz, 0); |
3816 |
grub_free (data->file_buf); |
5736 |
grub_free (data->file_buf); |
3817 |
data->file_buf = 0; |
5737 |
data->file_buf = 0; |
|
|
5738 |
data->file_start = data->file_end = 0; |
3818 |
|
5739 |
|
3819 |
err = dmu_read (&(data->dnode), blkid, &t, |
5740 |
err = dmu_read (&(data->dnode), blkid, &t, 0, data); |
3820 |
0, data); |
|
|
3821 |
data->file_buf = t; |
5741 |
data->file_buf = t; |
3822 |
if (err) |
5742 |
if (err) |
3823 |
{ |
5743 |
{ |
Lines 3874-3879
Link Here
|
3874 |
return err; |
5794 |
return err; |
3875 |
} |
5795 |
} |
3876 |
|
5796 |
|
|
|
5797 |
grub_err_t |
5798 |
grub_zfs_defaultbootfsobj (grub_device_t dev, grub_uint64_t *mdnobj) |
5799 |
{ |
5800 |
struct grub_zfs_data *data; |
5801 |
grub_err_t err; |
5802 |
|
5803 |
data = zfs_mount (dev); |
5804 |
if (! data) |
5805 |
return grub_errno; |
5806 |
|
5807 |
err = get_default_bootfsobj (&(data->mos), mdnobj, data); |
5808 |
zfs_unmount (data); |
5809 |
|
5810 |
return err; |
5811 |
} |
5812 |
|
5813 |
grub_err_t |
5814 |
grub_zfs_defaultbootfsname (grub_device_t dev, char **bootfsname) |
5815 |
{ |
5816 |
grub_uint64_t mdnobj; |
5817 |
struct grub_zfs_data *data; |
5818 |
grub_err_t err; |
5819 |
|
5820 |
data = zfs_mount (dev); |
5821 |
if (! data) |
5822 |
return grub_errno; |
5823 |
|
5824 |
err = get_default_bootfsobj (&(data->mos), &mdnobj, data); |
5825 |
if (! err) |
5826 |
err = get_default_bootfsname(&(data->mos), mdnobj, data, &(*bootfsname)); |
5827 |
|
5828 |
zfs_unmount (data); |
5829 |
|
5830 |
return err; |
5831 |
} |
5832 |
|
3877 |
static grub_err_t |
5833 |
static grub_err_t |
3878 |
fill_fs_info (struct grub_dirhook_info *info, |
5834 |
fill_fs_info (struct grub_dirhook_info *info, |
3879 |
dnode_end_t mdn, struct grub_zfs_data *data) |
5835 |
dnode_end_t mdn, struct grub_zfs_data *data) |
Lines 3984-4230
Link Here
|
3984 |
{ |
5940 |
{ |
3985 |
blkptr_t *bp = &dn.dn.dn_spill; |
5941 |
blkptr_t *bp = &dn.dn.dn_spill; |
3986 |
|
5942 |
|
3987 |
err = zio_read (bp, dn.endian, &sahdrp, NULL, ctx->data); |
5943 |
err = zio_read(bp, dn.endian, &sahdrp, NULL, ctx->data); |
3988 |
if (err) |
5944 |
if (err) |
3989 |
{ |
5945 |
{ |
3990 |
grub_print_error (); |
5946 |
grub_print_error(); |
3991 |
return 0; |
5947 |
return 0; |
3992 |
} |
5948 |
} |
3993 |
} |
5949 |
} |
3994 |
else |
5950 |
else |
3995 |
{ |
5951 |
{ |
3996 |
grub_error (GRUB_ERR_BAD_FS, "filesystem is corrupt"); |
5952 |
grub_error(GRUB_ERR_BAD_FS, "filesystem is corrupt"); |
3997 |
grub_print_error (); |
5953 |
grub_print_error(); |
3998 |
return 0; |
5954 |
return 0; |
3999 |
} |
5955 |
} |
4000 |
|
5956 |
|
4001 |
hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp)); |
5957 |
hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp)); |
4002 |
info.mtimeset = 1; |
5958 |
info.mtimeset = 1; |
4003 |
info.mtime = grub_zfs_to_cpu64 (grub_get_unaligned64 ((char *) sahdrp + hdrsize + SA_MTIME_OFFSET), dn.endian); |
5959 |
info.mtime = grub_zfs_to_cpu64(grub_get_unaligned64((char *) sahdrp + hdrsize + SA_MTIME_OFFSET), dn.endian); |
4004 |
info.case_insensitive = ctx->data->subvol.case_insensitive; |
5960 |
info.case_insensitive = ctx->data->subvol.case_insensitive; |
4005 |
} |
5961 |
} |
4006 |
|
5962 |
|
4007 |
if (dn.dn.dn_bonustype == DMU_OT_ZNODE) |
5963 |
if (dn.dn.dn_bonustype == DMU_OT_ZNODE) |
4008 |
{ |
5964 |
{ |
4009 |
info.mtimeset = 1; |
5965 |
info.mtimeset = 1; |
4010 |
info.mtime = grub_zfs_to_cpu64 (((znode_phys_t *) DN_BONUS (&dn.dn))->zp_mtime[0], |
5966 |
info.mtime = grub_zfs_to_cpu64(((znode_phys_t *) DN_BONUS (&dn.dn))->zp_mtime[0], |
4011 |
dn.endian); |
5967 |
dn.endian); |
4012 |
} |
5968 |
} |
4013 |
info.dir = (dn.dn.dn_type == DMU_OT_DIRECTORY_CONTENTS); |
5969 |
info.dir = (dn.dn.dn_type == DMU_OT_DIRECTORY_CONTENTS); |
4014 |
grub_dprintf ("zfs", "type=%d, name=%s\n", |
5970 |
grub_dprintf ("zfs", "type=%d, name=%s\n", |
4015 |
(int)dn.dn.dn_type, (char *)name); |
5971 |
(int)dn.dn.dn_type, (char *)name); |
4016 |
return ctx->hook (name, &info, ctx->hook_data); |
5972 |
return ctx->hook(name, &info, ctx->hook_data); |
4017 |
} |
5973 |
} |
4018 |
|
5974 |
|
4019 |
/* Helper for grub_zfs_dir. */ |
5975 |
/* Helper for grub_zfs_dir. */ |
4020 |
static int |
5976 |
static int |
4021 |
iterate_zap_fs (const char *name, grub_uint64_t val, |
5977 |
iterate_zap_fs(const char *name, grub_uint64_t val, |
4022 |
struct grub_zfs_dir_ctx *ctx) |
5978 |
struct grub_zfs_dir_ctx *ctx) |
4023 |
{ |
5979 |
{ |
4024 |
grub_err_t err; |
5980 |
grub_err_t err; |
4025 |
struct grub_dirhook_info info; |
5981 |
struct grub_dirhook_info info; |
4026 |
|
5982 |
dnode_end_t mdn; |
4027 |
dnode_end_t mdn; |
5983 |
err = dnode_get (&(ctx->data->mos), val, 0, &mdn, ctx->data); |
4028 |
err = dnode_get (&(ctx->data->mos), val, 0, &mdn, ctx->data); |
5984 |
if (err) { |
4029 |
if (err) |
5985 |
grub_errno = 0; |
4030 |
{ |
5986 |
return 0; |
4031 |
grub_errno = 0; |
5987 |
} |
4032 |
return 0; |
5988 |
if (mdn.dn.dn_type != DMU_OT_DSL_DIR) |
4033 |
} |
5989 |
return 0; |
4034 |
if (mdn.dn.dn_type != DMU_OT_DSL_DIR) |
5990 |
|
4035 |
return 0; |
5991 |
err = fill_fs_info (&info, mdn, ctx->data); |
|
|
5992 |
if (err) { |
5993 |
grub_errno = 0; |
5994 |
return 0; |
5995 |
} |
5996 |
return ctx->hook (name, &info, ctx->hook_data); |
4036 |
|
5997 |
|
4037 |
err = fill_fs_info (&info, mdn, ctx->data); |
|
|
4038 |
if (err) |
4039 |
{ |
4040 |
grub_errno = 0; |
4041 |
return 0; |
4042 |
} |
4043 |
return ctx->hook (name, &info, ctx->hook_data); |
4044 |
} |
5998 |
} |
4045 |
|
5999 |
|
4046 |
/* Helper for grub_zfs_dir. */ |
6000 |
/* Helper for grub_zfs_dir. */ |
4047 |
static int |
6001 |
static int |
4048 |
iterate_zap_snap (const char *name, grub_uint64_t val, |
6002 |
iterate_zap_snap(const char *name, grub_uint64_t val, |
4049 |
struct grub_zfs_dir_ctx *ctx) |
6003 |
struct grub_zfs_dir_ctx *ctx) |
4050 |
{ |
6004 |
{ |
4051 |
grub_err_t err; |
6005 |
grub_err_t err; |
4052 |
struct grub_dirhook_info info; |
6006 |
struct grub_dirhook_info info; |
4053 |
char *name2; |
6007 |
char *name2; |
4054 |
int ret; |
6008 |
int ret; |
4055 |
|
6009 |
dnode_end_t mdn; |
4056 |
dnode_end_t mdn; |
6010 |
|
4057 |
|
6011 |
err = dnode_get(&(ctx->data->mos), val, 0, &mdn, ctx->data); |
4058 |
err = dnode_get (&(ctx->data->mos), val, 0, &mdn, ctx->data); |
6012 |
if (err) { |
4059 |
if (err) |
6013 |
grub_errno = 0; |
4060 |
{ |
6014 |
return 0; |
4061 |
grub_errno = 0; |
6015 |
} |
4062 |
return 0; |
6016 |
|
4063 |
} |
6017 |
if (mdn.dn.dn_type != DMU_OT_DSL_DATASET) |
|
|
6018 |
return 0; |
6019 |
|
6020 |
err = fill_fs_info(&info, mdn, ctx->data); |
6021 |
if (err) { |
6022 |
grub_errno = 0; |
6023 |
return 0; |
6024 |
} |
6025 |
|
6026 |
name2 = grub_malloc(grub_strlen (name) + 2); |
6027 |
name2[0] = '@'; |
6028 |
grub_memcpy(name2 + 1, name, grub_strlen (name) + 1); |
6029 |
ret = ctx->hook(name2, &info, ctx->hook_data); |
6030 |
grub_free(name2); |
6031 |
return ret; |
4064 |
|
6032 |
|
4065 |
if (mdn.dn.dn_type != DMU_OT_DSL_DATASET) |
|
|
4066 |
return 0; |
4067 |
|
4068 |
err = fill_fs_info (&info, mdn, ctx->data); |
4069 |
if (err) |
4070 |
{ |
4071 |
grub_errno = 0; |
4072 |
return 0; |
4073 |
} |
4074 |
|
4075 |
name2 = grub_malloc (grub_strlen (name) + 2); |
4076 |
name2[0] = '@'; |
4077 |
grub_memcpy (name2 + 1, name, grub_strlen (name) + 1); |
4078 |
ret = ctx->hook (name2, &info, ctx->hook_data); |
4079 |
grub_free (name2); |
4080 |
return ret; |
4081 |
} |
6033 |
} |
4082 |
|
6034 |
|
4083 |
static grub_err_t |
6035 |
static grub_err_t |
4084 |
grub_zfs_dir (grub_device_t device, const char *path, |
6036 |
grub_zfs_dir (grub_device_t device, const char *path, |
4085 |
grub_fs_dir_hook_t hook, void *hook_data) |
6037 |
grub_fs_dir_hook_t hook, void *hook_data) |
4086 |
{ |
6038 |
{ |
4087 |
struct grub_zfs_dir_ctx ctx = { |
6039 |
struct grub_zfs_dir_ctx ctx = { |
4088 |
.hook = hook, |
6040 |
.hook = hook, |
4089 |
.hook_data = hook_data |
6041 |
.hook_data = hook_data |
4090 |
}; |
6042 |
}; |
4091 |
struct grub_zfs_data *data; |
6043 |
struct grub_zfs_data *data; |
4092 |
grub_err_t err; |
6044 |
grub_err_t err; |
4093 |
int isfs; |
6045 |
int isfs; |
4094 |
|
|
|
4095 |
data = zfs_mount (device); |
4096 |
if (! data) |
4097 |
return grub_errno; |
4098 |
err = dnode_get_fullpath (path, &(data->subvol), &(data->dnode), &isfs, data); |
4099 |
if (err) |
4100 |
{ |
4101 |
zfs_unmount (data); |
4102 |
return err; |
4103 |
} |
4104 |
ctx.data = data; |
4105 |
|
4106 |
if (isfs) |
4107 |
{ |
4108 |
grub_uint64_t childobj, headobj; |
4109 |
grub_uint64_t snapobj; |
4110 |
dnode_end_t dn; |
4111 |
struct grub_dirhook_info info; |
4112 |
|
4113 |
err = fill_fs_info (&info, data->dnode, data); |
4114 |
if (err) |
4115 |
{ |
4116 |
zfs_unmount (data); |
4117 |
return err; |
4118 |
} |
4119 |
if (hook ("@", &info, hook_data)) |
4120 |
{ |
4121 |
zfs_unmount (data); |
4122 |
return GRUB_ERR_NONE; |
4123 |
} |
4124 |
|
6046 |
|
4125 |
childobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&data->dnode.dn))->dd_child_dir_zapobj, data->dnode.endian); |
6047 |
data = zfs_mount(device); |
4126 |
headobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&data->dnode.dn))->dd_head_dataset_obj, data->dnode.endian); |
6048 |
if (!data) |
4127 |
err = dnode_get (&(data->mos), childobj, |
6049 |
return grub_errno; |
4128 |
DMU_OT_DSL_DIR_CHILD_MAP, &dn, data); |
6050 |
err = dnode_get_fullpath(path, &(data->subvol), &(data->dnode), |
4129 |
if (err) |
6051 |
&isfs, data); |
4130 |
{ |
6052 |
if (err) { |
4131 |
zfs_unmount (data); |
6053 |
grub_dprintf("zfs", "dnode_get_fullpath failed\n"); |
4132 |
return err; |
6054 |
zfs_unmount(data); |
|
|
6055 |
return err; |
4133 |
} |
6056 |
} |
|
|
6057 |
ctx.data = data; |
4134 |
|
6058 |
|
4135 |
zap_iterate_u64 (&dn, iterate_zap_fs, data, &ctx); |
6059 |
if (isfs) { |
|
|
6060 |
grub_uint64_t childobj, headobj; |
6061 |
grub_uint64_t snapobj; |
6062 |
dnode_end_t dn; |
6063 |
struct grub_dirhook_info info; |
6064 |
|
6065 |
err = fill_fs_info(&info, data->dnode, data); |
6066 |
if (err) { |
6067 |
zfs_unmount(data); |
6068 |
return err; |
6069 |
} |
6070 |
if (hook ("@", &info, hook_data)) { |
6071 |
zfs_unmount(data); |
6072 |
return GRUB_ERR_NONE; |
6073 |
} |
4136 |
|
6074 |
|
4137 |
err = dnode_get (&(data->mos), headobj, DMU_OT_DSL_DATASET, &dn, data); |
6075 |
childobj = grub_zfs_to_cpu64( |
4138 |
if (err) |
6076 |
((dsl_dir_phys_t *) |
4139 |
{ |
6077 |
DN_BONUS (&data->dnode.dn))->dd_child_dir_zapobj, |
4140 |
zfs_unmount (data); |
6078 |
data->dnode.endian); |
4141 |
return err; |
6079 |
|
4142 |
} |
6080 |
headobj = grub_zfs_to_cpu64( |
4143 |
|
6081 |
((dsl_dir_phys_t *) |
4144 |
snapobj = grub_zfs_to_cpu64 (((dsl_dataset_phys_t *) DN_BONUS (&dn.dn))->ds_snapnames_zapobj, dn.endian); |
6082 |
DN_BONUS (&data->dnode.dn))->dd_head_dataset_obj, |
4145 |
|
6083 |
data->dnode.endian); |
4146 |
err = dnode_get (&(data->mos), snapobj, |
6084 |
err = dnode_get (&(data->mos), childobj, |
4147 |
DMU_OT_DSL_DS_SNAP_MAP, &dn, data); |
6085 |
DMU_OT_DSL_DIR_CHILD_MAP, &dn, data); |
4148 |
if (err) |
6086 |
if (err) { |
4149 |
{ |
6087 |
zfs_unmount(data); |
4150 |
zfs_unmount (data); |
6088 |
return err; |
4151 |
return err; |
6089 |
} |
4152 |
} |
|
|
4153 |
|
4154 |
zap_iterate_u64 (&dn, iterate_zap_snap, data, &ctx); |
4155 |
} |
4156 |
else |
4157 |
{ |
4158 |
if (data->dnode.dn.dn_type != DMU_OT_DIRECTORY_CONTENTS) |
4159 |
{ |
4160 |
zfs_unmount (data); |
4161 |
return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory")); |
4162 |
} |
4163 |
zap_iterate_u64 (&(data->dnode), iterate_zap, data, &ctx); |
4164 |
} |
4165 |
zfs_unmount (data); |
4166 |
return grub_errno; |
4167 |
} |
4168 |
|
6090 |
|
4169 |
static int |
6091 |
zap_iterate_u64(&dn, iterate_zap_fs, data, &ctx); |
4170 |
check_feature (const char *name, grub_uint64_t val, |
|
|
4171 |
struct grub_zfs_dir_ctx *ctx __attribute__((unused))) |
4172 |
{ |
4173 |
int i; |
4174 |
if (val == 0) |
4175 |
return 0; |
4176 |
if (name[0] == 0) |
4177 |
return 0; |
4178 |
for (i = 0; spa_feature_names[i] != NULL; i++) |
4179 |
if (grub_strcmp (name, spa_feature_names[i]) == 0) |
4180 |
return 0; |
4181 |
return 1; |
4182 |
} |
4183 |
|
6092 |
|
4184 |
/* |
6093 |
err = dnode_get(&(data->mos), headobj, |
4185 |
* Checks whether the MOS features that are active are supported by this |
6094 |
DMU_OT_DSL_DATASET, &dn, data); |
4186 |
* (GRUB's) implementation of ZFS. |
6095 |
if (err) { |
4187 |
* |
6096 |
zfs_unmount(data); |
4188 |
* Return: |
6097 |
return err; |
4189 |
* 0: Success. |
6098 |
} |
4190 |
* errnum: Failure. |
|
|
4191 |
*/ |
4192 |
|
4193 |
static int |
4194 |
check_mos_features(dnode_phys_t *mosmdn_phys,grub_zfs_endian_t endian,struct grub_zfs_data* data ) |
4195 |
{ |
4196 |
grub_uint64_t objnum; |
4197 |
grub_uint8_t errnum = 0; |
4198 |
dnode_end_t dn,mosmdn; |
4199 |
mzap_phys_t* mzp; |
4200 |
grub_zfs_endian_t endianzap; |
4201 |
int size; |
4202 |
grub_memmove(&(mosmdn.dn),mosmdn_phys,sizeof(dnode_phys_t)); |
4203 |
mosmdn.endian=endian; |
4204 |
errnum = dnode_get(&mosmdn, DMU_POOL_DIRECTORY_OBJECT, |
4205 |
DMU_OT_OBJECT_DIRECTORY, &dn,data); |
4206 |
if (errnum != 0) |
4207 |
return errnum; |
4208 |
|
6099 |
|
4209 |
/* |
6100 |
snapobj = grub_zfs_to_cpu64( |
4210 |
* Find the object number for 'features_for_read' and retrieve its |
6101 |
((dsl_dataset_phys_t *) |
4211 |
* corresponding dnode. Note that we don't check features_for_write |
6102 |
DN_BONUS (&dn.dn))->ds_snapnames_zapobj, dn.endian); |
4212 |
* because GRUB is not opening the pool for write. |
6103 |
|
4213 |
*/ |
6104 |
err = dnode_get(&(data->mos), snapobj, |
4214 |
errnum = zap_lookup(&dn, DMU_POOL_FEATURES_FOR_READ, &objnum, data,0); |
6105 |
DMU_OT_DSL_DS_SNAP_MAP, &dn, data); |
4215 |
if (errnum != 0) |
6106 |
if (err) { |
4216 |
return errnum; |
6107 |
zfs_unmount(data); |
4217 |
|
6108 |
return err; |
4218 |
errnum = dnode_get(&mosmdn, objnum, DMU_OTN_ZAP_METADATA, &dn, data); |
6109 |
} |
4219 |
if (errnum != 0) |
|
|
4220 |
return errnum; |
4221 |
|
4222 |
errnum = dmu_read(&dn, 0, (void**)&mzp, &endianzap,data); |
4223 |
if (errnum != 0) |
4224 |
return errnum; |
4225 |
|
6110 |
|
4226 |
size = grub_zfs_to_cpu16 (dn.dn.dn_datablkszsec, dn.endian) << SPA_MINBLOCKSHIFT; |
6111 |
zap_iterate_u64(&dn, iterate_zap_snap, data, &ctx); |
4227 |
return mzap_iterate (mzp,endianzap, size, check_feature,NULL); |
6112 |
} else { |
|
|
6113 |
if (data->dnode.dn.dn_type != DMU_OT_DIRECTORY_CONTENTS) { |
6114 |
zfs_unmount (data); |
6115 |
return grub_error(GRUB_ERR_BAD_FILE_TYPE, |
6116 |
N_("not a directory")); |
6117 |
} |
6118 |
zap_iterate_u64(&(data->dnode), iterate_zap, data, &ctx); |
6119 |
} |
6120 |
zfs_unmount(data); |
6121 |
return grub_errno; |
4228 |
} |
6122 |
} |
4229 |
|
6123 |
|
4230 |
|
6124 |
|
Lines 4260-4265
Link Here
|
4260 |
} |
6154 |
} |
4261 |
#endif |
6155 |
#endif |
4262 |
|
6156 |
|
|
|
6157 |
/* GRUB2 zfs FS module interface structure */ |
4263 |
static struct grub_fs grub_zfs_fs = { |
6158 |
static struct grub_fs grub_zfs_fs = { |
4264 |
.name = "zfs", |
6159 |
.name = "zfs", |
4265 |
.dir = grub_zfs_dir, |
6160 |
.dir = grub_zfs_dir, |
Lines 4272-4278
Link Here
|
4272 |
#ifdef GRUB_UTIL |
6167 |
#ifdef GRUB_UTIL |
4273 |
.embed = grub_zfs_embed, |
6168 |
.embed = grub_zfs_embed, |
4274 |
.reserved_first_sector = 1, |
6169 |
.reserved_first_sector = 1, |
4275 |
.blocklist_install = 0, |
6170 |
.blocklist_install = 1, |
4276 |
#endif |
6171 |
#endif |
4277 |
.next = 0 |
6172 |
.next = 0 |
4278 |
}; |
6173 |
}; |
Lines 4288-4292
Link Here
|
4288 |
|
6183 |
|
4289 |
GRUB_MOD_FINI (zfs) |
6184 |
GRUB_MOD_FINI (zfs) |
4290 |
{ |
6185 |
{ |
|
|
6186 |
zfs_free_caches (); |
4291 |
grub_fs_unregister (&grub_zfs_fs); |
6187 |
grub_fs_unregister (&grub_zfs_fs); |
4292 |
} |
6188 |
} |