Changeset View
Changeset View
Standalone View
Standalone View
sys/cddl/boot/zfs/zfssubr.c
Show All 35 Lines | |||||
#define ASSERT0(x) ((void)0) | #define ASSERT0(x) ((void)0) | ||||
#define ASSERT(x) ((void)0) | #define ASSERT(x) ((void)0) | ||||
#define panic(...) do { \ | #define panic(...) do { \ | ||||
printf(__VA_ARGS__); \ | printf(__VA_ARGS__); \ | ||||
for (;;) ; \ | for (;;) ; \ | ||||
} while (0) | } while (0) | ||||
#define kmem_alloc(size, flag) zfs_alloc((size)) | #define kmem_alloc(size, flag) malloc((size)) | ||||
#define kmem_free(ptr, size) zfs_free((ptr), (size)) | #define kmem_free(ptr, size) free((ptr)) | ||||
static void | static void | ||||
zfs_init_crc(void) | zfs_init_crc(void) | ||||
{ | { | ||||
int i, j; | int i, j; | ||||
uint64_t *ct; | uint64_t *ct; | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 315 Lines • ▼ Show 20 Lines | zap_hash(uint64_t salt, const char *name) | ||||
* those are the onces that we first pay attention to when | * those are the onces that we first pay attention to when | ||||
* chosing the bucket. | * chosing the bucket. | ||||
*/ | */ | ||||
crc &= ~((1ULL << (64 - ZAP_HASHBITS)) - 1); | crc &= ~((1ULL << (64 - ZAP_HASHBITS)) - 1); | ||||
return (crc); | return (crc); | ||||
} | } | ||||
static void *zfs_alloc(size_t size); | |||||
static void zfs_free(void *ptr, size_t size); | |||||
typedef struct raidz_col { | typedef struct raidz_col { | ||||
uint64_t rc_devidx; /* child device index for I/O */ | uint64_t rc_devidx; /* child device index for I/O */ | ||||
uint64_t rc_offset; /* device offset */ | uint64_t rc_offset; /* device offset */ | ||||
uint64_t rc_size; /* I/O size */ | uint64_t rc_size; /* I/O size */ | ||||
void *rc_data; /* I/O data */ | void *rc_data; /* I/O data */ | ||||
int rc_error; /* I/O error for this device */ | int rc_error; /* I/O error for this device */ | ||||
uint8_t rc_tried; /* Did we attempt this I/O column? */ | uint8_t rc_tried; /* Did we attempt this I/O column? */ | ||||
uint8_t rc_skipped; /* Did we skip this I/O column? */ | uint8_t rc_skipped; /* Did we skip this I/O column? */ | ||||
▲ Show 20 Lines • Show All 586 Lines • ▼ Show 20 Lines | vdev_raidz_matrix_reconstruct(raidz_map_t *rm, int n, int nmissing, | ||||
uint8_t log, val; | uint8_t log, val; | ||||
int ll; | int ll; | ||||
uint8_t *invlog[VDEV_RAIDZ_MAXPARITY]; | uint8_t *invlog[VDEV_RAIDZ_MAXPARITY]; | ||||
uint8_t *p, *pp; | uint8_t *p, *pp; | ||||
size_t psize; | size_t psize; | ||||
log = 0; /* gcc */ | log = 0; /* gcc */ | ||||
psize = sizeof (invlog[0][0]) * n * nmissing; | psize = sizeof (invlog[0][0]) * n * nmissing; | ||||
p = zfs_alloc(psize); | p = malloc(psize); | ||||
if (p == NULL) { | |||||
printf("vdev_raidz_matrix_reconstruct: Out of memory\n"); | |||||
return; | |||||
} | |||||
for (pp = p, i = 0; i < nmissing; i++) { | for (pp = p, i = 0; i < nmissing; i++) { | ||||
invlog[i] = pp; | invlog[i] = pp; | ||||
pp += n; | pp += n; | ||||
} | } | ||||
for (i = 0; i < nmissing; i++) { | for (i = 0; i < nmissing; i++) { | ||||
for (j = 0; j < n; j++) { | for (j = 0; j < n; j++) { | ||||
Show All 39 Lines | for (x = 0; x < ccount; x++, src++) { | ||||
if (i == 0) | if (i == 0) | ||||
dst[cc][x] = val; | dst[cc][x] = val; | ||||
else | else | ||||
dst[cc][x] ^= val; | dst[cc][x] ^= val; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
zfs_free(p, psize); | free(p); | ||||
} | } | ||||
static int | static int | ||||
vdev_raidz_reconstruct_general(raidz_map_t *rm, int *tgts, int ntgts) | vdev_raidz_reconstruct_general(raidz_map_t *rm, int *tgts, int ntgts) | ||||
{ | { | ||||
int n, i, c, t, tt; | int n, i, c, t, tt; | ||||
int nmissing_rows; | int nmissing_rows; | ||||
int missing_rows[VDEV_RAIDZ_MAXPARITY]; | int missing_rows[VDEV_RAIDZ_MAXPARITY]; | ||||
▲ Show 20 Lines • Show All 160 Lines • ▼ Show 20 Lines | if (q == 0) { | ||||
scols = MIN(dcols, roundup(bc, nparity + 1)); | scols = MIN(dcols, roundup(bc, nparity + 1)); | ||||
} else { | } else { | ||||
acols = dcols; | acols = dcols; | ||||
scols = dcols; | scols = dcols; | ||||
} | } | ||||
ASSERT3U(acols, <=, scols); | ASSERT3U(acols, <=, scols); | ||||
rm = zfs_alloc(offsetof(raidz_map_t, rm_col[scols])); | rm = malloc(offsetof(raidz_map_t, rm_col[scols])); | ||||
if (rm == NULL) { | |||||
printf("vdev_raidz_map_alloc: out of memory\n"); | |||||
return (NULL); | |||||
} | |||||
rm->rm_cols = acols; | rm->rm_cols = acols; | ||||
rm->rm_scols = scols; | rm->rm_scols = scols; | ||||
rm->rm_bigcols = bc; | rm->rm_bigcols = bc; | ||||
rm->rm_skipstart = bc; | rm->rm_skipstart = bc; | ||||
rm->rm_missingdata = 0; | rm->rm_missingdata = 0; | ||||
rm->rm_missingparity = 0; | rm->rm_missingparity = 0; | ||||
rm->rm_firstdatacol = nparity; | rm->rm_firstdatacol = nparity; | ||||
rm->rm_reports = 0; | rm->rm_reports = 0; | ||||
Show All 27 Lines | vdev_raidz_map_alloc(void *data, off_t offset, size_t size, uint64_t unit_shift, | ||||
} | } | ||||
ASSERT3U(asize, ==, tot << unit_shift); | ASSERT3U(asize, ==, tot << unit_shift); | ||||
rm->rm_asize = roundup(asize, (nparity + 1) << unit_shift); | rm->rm_asize = roundup(asize, (nparity + 1) << unit_shift); | ||||
rm->rm_nskip = roundup(tot, nparity + 1) - tot; | rm->rm_nskip = roundup(tot, nparity + 1) - tot; | ||||
ASSERT3U(rm->rm_asize - asize, ==, rm->rm_nskip << unit_shift); | ASSERT3U(rm->rm_asize - asize, ==, rm->rm_nskip << unit_shift); | ||||
ASSERT3U(rm->rm_nskip, <=, nparity); | ASSERT3U(rm->rm_nskip, <=, nparity); | ||||
for (c = 0; c < rm->rm_firstdatacol; c++) | for (c = 0; c < rm->rm_firstdatacol; c++) { | ||||
rm->rm_col[c].rc_data = zfs_alloc(rm->rm_col[c].rc_size); | rm->rm_col[c].rc_data = malloc(rm->rm_col[c].rc_size); | ||||
/* Memory failure... unwind */ | |||||
if (rm->rm_col[c].rc_data == NULL) { | |||||
while (c != 0) { | |||||
free(rm->rm_col[--c].rc_data); | |||||
} | |||||
free(rm); | |||||
return (NULL); | |||||
} | |||||
} | |||||
rm->rm_col[c].rc_data = data; | rm->rm_col[c].rc_data = data; | ||||
for (c = c + 1; c < acols; c++) | for (c = c + 1; c < acols; c++) | ||||
rm->rm_col[c].rc_data = (char *)rm->rm_col[c - 1].rc_data + | rm->rm_col[c].rc_data = (char *)rm->rm_col[c - 1].rc_data + | ||||
rm->rm_col[c - 1].rc_size; | rm->rm_col[c - 1].rc_size; | ||||
/* | /* | ||||
* If all data stored spans all columns, there's a danger that parity | * If all data stored spans all columns, there's a danger that parity | ||||
Show All 34 Lines | |||||
} | } | ||||
static void | static void | ||||
vdev_raidz_map_free(raidz_map_t *rm) | vdev_raidz_map_free(raidz_map_t *rm) | ||||
{ | { | ||||
int c; | int c; | ||||
for (c = rm->rm_firstdatacol - 1; c >= 0; c--) | for (c = rm->rm_firstdatacol - 1; c >= 0; c--) | ||||
zfs_free(rm->rm_col[c].rc_data, rm->rm_col[c].rc_size); | free(rm->rm_col[c].rc_data); | ||||
zfs_free(rm, offsetof(raidz_map_t, rm_col[rm->rm_scols])); | free(rm); | ||||
} | } | ||||
static vdev_t * | static vdev_t * | ||||
vdev_child(vdev_t *pvd, uint64_t devidx) | vdev_child(vdev_t *pvd, uint64_t devidx) | ||||
{ | { | ||||
vdev_t *cvd; | vdev_t *cvd; | ||||
STAILQ_FOREACH(cvd, &pvd->v_children, v_childlink) { | STAILQ_FOREACH(cvd, &pvd->v_children, v_childlink) { | ||||
Show All 27 Lines | raidz_parity_verify(raidz_map_t *rm) | ||||
void *orig[VDEV_RAIDZ_MAXPARITY]; | void *orig[VDEV_RAIDZ_MAXPARITY]; | ||||
int c, ret = 0; | int c, ret = 0; | ||||
raidz_col_t *rc; | raidz_col_t *rc; | ||||
for (c = 0; c < rm->rm_firstdatacol; c++) { | for (c = 0; c < rm->rm_firstdatacol; c++) { | ||||
rc = &rm->rm_col[c]; | rc = &rm->rm_col[c]; | ||||
if (!rc->rc_tried || rc->rc_error != 0) | if (!rc->rc_tried || rc->rc_error != 0) | ||||
continue; | continue; | ||||
orig[c] = zfs_alloc(rc->rc_size); | orig[c] = malloc(rc->rc_size); | ||||
if (orig[c] == NULL) | |||||
panic("raidz_parity_verify: ENOMEM"); | |||||
bcopy(rc->rc_data, orig[c], rc->rc_size); | bcopy(rc->rc_data, orig[c], rc->rc_size); | ||||
} | } | ||||
vdev_raidz_generate_parity(rm); | vdev_raidz_generate_parity(rm); | ||||
for (c = rm->rm_firstdatacol - 1; c >= 0; c--) { | for (c = rm->rm_firstdatacol - 1; c >= 0; c--) { | ||||
rc = &rm->rm_col[c]; | rc = &rm->rm_col[c]; | ||||
if (!rc->rc_tried || rc->rc_error != 0) | if (!rc->rc_tried || rc->rc_error != 0) | ||||
continue; | continue; | ||||
if (bcmp(orig[c], rc->rc_data, rc->rc_size) != 0) { | if (bcmp(orig[c], rc->rc_data, rc->rc_size) != 0) { | ||||
rc->rc_error = ECKSUM; | rc->rc_error = ECKSUM; | ||||
ret++; | ret++; | ||||
} | } | ||||
zfs_free(orig[c], rc->rc_size); | free(orig[c]); | ||||
} | } | ||||
return (ret); | return (ret); | ||||
} | } | ||||
/* | /* | ||||
* Iterate over all combinations of bad data and attempt a reconstruction. | * Iterate over all combinations of bad data and attempt a reconstruction. | ||||
* Note that the algorithm below is non-optimal because it doesn't take into | * Note that the algorithm below is non-optimal because it doesn't take into | ||||
▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | for (n = 1; n <= rm->rm_firstdatacol - total_errors; n++) { | ||||
/* | /* | ||||
* These buffers were allocated in previous iterations. | * These buffers were allocated in previous iterations. | ||||
*/ | */ | ||||
for (i = 0; i < n - 1; i++) { | for (i = 0; i < n - 1; i++) { | ||||
ASSERT(orig[i] != NULL); | ASSERT(orig[i] != NULL); | ||||
} | } | ||||
orig[n - 1] = zfs_alloc(rm->rm_col[0].rc_size); | orig[n - 1] = malloc(rm->rm_col[0].rc_size); | ||||
if (orig[n - 1] == NULL) | |||||
panic("vdev_raidz_combrec: ENOMEM"); | |||||
current = 0; | current = 0; | ||||
next = tgts[current]; | next = tgts[current]; | ||||
while (current != n) { | while (current != n) { | ||||
tgts[current] = next; | tgts[current] = next; | ||||
current = 0; | current = 0; | ||||
▲ Show 20 Lines • Show All 66 Lines • ▼ Show 20 Lines | while (current != n) { | ||||
current++; | current++; | ||||
} while (current != n); | } while (current != n); | ||||
} | } | ||||
} | } | ||||
n--; | n--; | ||||
done: | done: | ||||
for (i = n - 1; i >= 0; i--) { | for (i = n - 1; i >= 0; i--) { | ||||
zfs_free(orig[i], rm->rm_col[0].rc_size); | free(orig[i]); | ||||
} | } | ||||
return (ret); | return (ret); | ||||
} | } | ||||
static int | static int | ||||
vdev_raidz_read(vdev_t *vd, const blkptr_t *bp, void *data, | vdev_raidz_read(vdev_t *vd, const blkptr_t *bp, void *data, | ||||
off_t offset, size_t bytes) | off_t offset, size_t bytes) | ||||
Show All 12 Lines | vdev_raidz_read(vdev_t *vd, const blkptr_t *bp, void *data, | ||||
int tgts[VDEV_RAIDZ_MAXPARITY]; | int tgts[VDEV_RAIDZ_MAXPARITY]; | ||||
int code; | int code; | ||||
rc = NULL; /* gcc */ | rc = NULL; /* gcc */ | ||||
error = 0; | error = 0; | ||||
rm = vdev_raidz_map_alloc(data, offset, bytes, tvd->v_ashift, | rm = vdev_raidz_map_alloc(data, offset, bytes, tvd->v_ashift, | ||||
vd->v_nchildren, vd->v_nparity); | vd->v_nchildren, vd->v_nparity); | ||||
if (rm == NULL) | |||||
return (ENOMEM); | |||||
/* | /* | ||||
* Iterate over the columns in reverse order so that we hit the parity | * Iterate over the columns in reverse order so that we hit the parity | ||||
* last -- any errors along the way will force us to read the parity. | * last -- any errors along the way will force us to read the parity. | ||||
*/ | */ | ||||
for (c = rm->rm_cols - 1; c >= 0; c--) { | for (c = rm->rm_cols - 1; c >= 0; c--) { | ||||
rc = &rm->rm_col[c]; | rc = &rm->rm_col[c]; | ||||
cvd = vdev_child(vd, rc->rc_devidx); | cvd = vdev_child(vd, rc->rc_devidx); | ||||
▲ Show 20 Lines • Show All 227 Lines • Show Last 20 Lines |