summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpjd <pjd@FreeBSD.org>2010-01-06 22:39:40 +0000
committerpjd <pjd@FreeBSD.org>2010-01-06 22:39:40 +0000
commit3201744022f81f74f12afe3f5cfd59a34d829dba (patch)
tree5fdf97685f5d27c9e1e0a6b19385dddb84f9c98b
parentf9e6c6a249caaf137a522b43d20cd40c4d8611c3 (diff)
downloadFreeBSD-src-3201744022f81f74f12afe3f5cfd59a34d829dba.zip
FreeBSD-src-3201744022f81f74f12afe3f5cfd59a34d829dba.tar.gz
Teach the (gpt)zfsboot and zfsloader raidz code to use its buffers
more efficiently. Before this patch, in the worst case memory use would increase exponentially on the number of drives in the raidz vdev. Submitted by: Matt Reimer <mattjreimer@gmail.com> Sponsored by: VPOP Technologies, Inc. Silence from: dfr
-rw-r--r--sys/cddl/boot/zfs/zfssubr.c50
1 files changed, 29 insertions, 21 deletions
diff --git a/sys/cddl/boot/zfs/zfssubr.c b/sys/cddl/boot/zfs/zfssubr.c
index 4013986..25d349b 100644
--- a/sys/cddl/boot/zfs/zfssubr.c
+++ b/sys/cddl/boot/zfs/zfssubr.c
@@ -454,7 +454,7 @@ vdev_raidz_reconstruct_q(raidz_col_t *cols, int nparity, int acols, int x)
static void
vdev_raidz_reconstruct_pq(raidz_col_t *cols, int nparity, int acols,
- int x, int y)
+ int x, int y, void *temp_p, void *temp_q)
{
uint8_t *p, *q, *pxy, *qxy, *xd, *yd, tmp, a, b, aexp, bexp;
void *pdata, *qdata;
@@ -478,10 +478,8 @@ vdev_raidz_reconstruct_pq(raidz_col_t *cols, int nparity, int acols,
xsize = cols[x].rc_size;
ysize = cols[y].rc_size;
- cols[VDEV_RAIDZ_P].rc_data =
- zfs_alloc_temp(cols[VDEV_RAIDZ_P].rc_size);
- cols[VDEV_RAIDZ_Q].rc_data =
- zfs_alloc_temp(cols[VDEV_RAIDZ_Q].rc_size);
+ cols[VDEV_RAIDZ_P].rc_data = temp_p;
+ cols[VDEV_RAIDZ_Q].rc_data = temp_q;
cols[x].rc_size = 0;
cols[y].rc_size = 0;
@@ -551,9 +549,12 @@ vdev_raidz_read(vdev_t *vdev, const blkptr_t *bp, void *buf,
uint64_t f = b % dcols;
uint64_t o = (b / dcols) << unit_shift;
uint64_t q, r, coff;
- int c, c1, bc, col, acols, devidx, asize, n;
+ int c, c1, bc, col, acols, devidx, asize, n, max_rc_size;
static raidz_col_t cols[16];
raidz_col_t *rc, *rc1;
+ void *orig, *orig1, *temp_p, *temp_q;
+
+ orig = orig1 = temp_p = temp_q = NULL;
q = s / (dcols - nparity);
r = s - q * (dcols - nparity);
@@ -561,6 +562,7 @@ vdev_raidz_read(vdev_t *vdev, const blkptr_t *bp, void *buf,
acols = (q == 0 ? bc : dcols);
asize = 0;
+ max_rc_size = 0;
for (c = 0; c < acols; c++) {
col = f + c;
@@ -577,6 +579,8 @@ vdev_raidz_read(vdev_t *vdev, const blkptr_t *bp, void *buf,
cols[c].rc_tried = 0;
cols[c].rc_skipped = 0;
asize += cols[c].rc_size;
+ if (cols[c].rc_size > max_rc_size)
+ max_rc_size = cols[c].rc_size;
}
asize = roundup(asize, (nparity + 1) << unit_shift);
@@ -777,8 +781,13 @@ reconstruct:
//ASSERT(c != acols);
//ASSERT(!rc->rc_skipped || rc->rc_error == ENXIO || rc->rc_error == ESTALE);
+ if (temp_p == NULL)
+ temp_p = zfs_alloc_temp(max_rc_size);
+ if (temp_q == NULL)
+ temp_q = zfs_alloc_temp(max_rc_size);
+
vdev_raidz_reconstruct_pq(cols, nparity, acols,
- c1, c);
+ c1, c, temp_p, temp_q);
if (zio_checksum_error(bp, buf) == 0)
return (0);
@@ -845,18 +854,12 @@ reconstruct:
return (EIO);
}
- asize = 0;
- for (c = 0; c < acols; c++) {
- rc = &cols[c];
- if (rc->rc_size > asize)
- asize = rc->rc_size;
- }
if (cols[VDEV_RAIDZ_P].rc_error == 0) {
/*
* Attempt to reconstruct the data from parity P.
*/
- void *orig;
- orig = zfs_alloc_temp(asize);
+ if (orig == NULL)
+ orig = zfs_alloc_temp(max_rc_size);
for (c = nparity; c < acols; c++) {
rc = &cols[c];
@@ -874,8 +877,8 @@ reconstruct:
/*
* Attempt to reconstruct the data from parity Q.
*/
- void *orig;
- orig = zfs_alloc_temp(asize);
+ if (orig == NULL)
+ orig = zfs_alloc_temp(max_rc_size);
for (c = nparity; c < acols; c++) {
rc = &cols[c];
@@ -895,9 +898,14 @@ reconstruct:
/*
* Attempt to reconstruct the data from both P and Q.
*/
- void *orig, *orig1;
- orig = zfs_alloc_temp(asize);
- orig1 = zfs_alloc_temp(asize);
+ if (orig == NULL)
+ orig = zfs_alloc_temp(max_rc_size);
+ if (orig1 == NULL)
+ orig1 = zfs_alloc_temp(max_rc_size);
+ if (temp_p == NULL)
+ temp_p = zfs_alloc_temp(max_rc_size);
+ if (temp_q == NULL)
+ temp_q = zfs_alloc_temp(max_rc_size);
for (c = nparity; c < acols - 1; c++) {
rc = &cols[c];
@@ -909,7 +917,7 @@ reconstruct:
memcpy(orig1, rc1->rc_data, rc1->rc_size);
vdev_raidz_reconstruct_pq(cols, nparity,
- acols, c, c1);
+ acols, c, c1, temp_p, temp_q);
if (zio_checksum_error(bp, buf) == 0)
return (0);
OpenPOWER on IntegriCloud