* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
#include <sys/zfs_context.h>
#include <sys/spa.h>
#include <sys/vdev_impl.h>
kmem_free(mm, offsetof(mirror_map_t, mm_child[mm->mm_children]));
}
+static const zio_vsd_ops_t vdev_mirror_vsd_ops = {
+ vdev_mirror_map_free,
+ zio_vsd_default_cksum_report
+};
+
static mirror_map_t *
vdev_mirror_map_alloc(zio_t *zio)
{
c = BP_GET_NDVAS(zio->io_bp);
- mm = kmem_zalloc(offsetof(mirror_map_t, mm_child[c]), KM_SLEEP);
+ mm = kmem_zalloc(offsetof(mirror_map_t, mm_child[c]), KM_PUSHPAGE);
mm->mm_children = c;
mm->mm_replacing = B_FALSE;
mm->mm_preferred = spa_get_random(c);
} else {
c = vd->vdev_children;
- mm = kmem_zalloc(offsetof(mirror_map_t, mm_child[c]), KM_SLEEP);
+ mm = kmem_zalloc(offsetof(mirror_map_t, mm_child[c]), KM_PUSHPAGE);
mm->mm_children = c;
mm->mm_replacing = (vd->vdev_ops == &vdev_replacing_ops ||
vd->vdev_ops == &vdev_spare_ops);
}
zio->io_vsd = mm;
- zio->io_vsd_free = vdev_mirror_map_free;
+ zio->io_vsd_ops = &vdev_mirror_vsd_ops;
return (mm);
}
static int
-vdev_mirror_open(vdev_t *vd, uint64_t *asize, uint64_t *ashift)
+vdev_mirror_open(vdev_t *vd, uint64_t *asize, uint64_t *max_asize,
+ uint64_t *ashift)
{
- vdev_t *cvd;
- uint64_t c;
int numerrors = 0;
- int ret, lasterror = 0;
+ int lasterror = 0;
+ int c;
if (vd->vdev_children == 0) {
vd->vdev_stat.vs_aux = VDEV_AUX_BAD_LABEL;
return (EINVAL);
}
+ vdev_open_children(vd);
+
for (c = 0; c < vd->vdev_children; c++) {
- cvd = vd->vdev_child[c];
+ vdev_t *cvd = vd->vdev_child[c];
- if ((ret = vdev_open(cvd)) != 0) {
- lasterror = ret;
+ if (cvd->vdev_open_error) {
+ lasterror = cvd->vdev_open_error;
numerrors++;
continue;
}
*asize = MIN(*asize - 1, cvd->vdev_asize - 1) + 1;
+ *max_asize = MIN(*max_asize - 1, cvd->vdev_max_asize - 1) + 1;
*ashift = MAX(*ashift, cvd->vdev_ashift);
}
static void
vdev_mirror_close(vdev_t *vd)
{
- uint64_t c;
+ int c;
for (c = 0; c < vd->vdev_children; c++)
vdev_close(vd->vdev_child[c]);
mirror_child_t *mc = zio->io_private;
if (zio->io_error == 0) {
- zio_t *pio = zio->io_parent;
- mutex_enter(&pio->io_lock);
- ASSERT3U(zio->io_size, >=, pio->io_size);
- bcopy(zio->io_data, pio->io_data, pio->io_size);
- mutex_exit(&pio->io_lock);
+ zio_t *pio;
+
+ mutex_enter(&zio->io_lock);
+ while ((pio = zio_walk_parents(zio)) != NULL) {
+ mutex_enter(&pio->io_lock);
+ ASSERT3U(zio->io_size, >=, pio->io_size);
+ bcopy(zio->io_data, pio->io_data, pio->io_size);
+ mutex_exit(&pio->io_lock);
+ }
+ mutex_exit(&zio->io_lock);
}
zio_buf_free(zio->io_data, zio->io_size);
uint64_t txg = zio->io_txg;
int i, c;
- ASSERT(zio->io_bp == NULL || zio->io_bp->blk_birth == txg);
+ ASSERT(zio->io_bp == NULL || BP_PHYSICAL_BIRTH(zio->io_bp) == txg);
/*
* Try to find a child whose DTL doesn't contain the block to read.
mc->mc_skipped = 1;
continue;
}
- if (!vdev_dtl_contains(&mc->mc_vd->vdev_dtl_map, txg, 1))
+ if (!vdev_dtl_contains(mc->mc_vd, DTL_MISSING, txg, 1))
return (c);
mc->mc_error = ESTALE;
mc->mc_skipped = 1;
ASSERT(zio->io_type == ZIO_TYPE_WRITE);
/*
- * If this is a resilvering I/O to a replacing vdev,
- * only the last child should be written -- unless the
- * first child happens to have a DTL entry here as well.
- * All other writes go to all children.
+ * Writes go to all children.
*/
- if ((zio->io_flags & ZIO_FLAG_RESILVER) && mm->mm_replacing &&
- !vdev_dtl_contains(&mm->mm_child[0].mc_vd->vdev_dtl_map,
- zio->io_txg, 1)) {
- c = mm->mm_children - 1;
- children = 1;
- } else {
- c = 0;
- children = mm->mm_children;
- }
+ c = 0;
+ children = mm->mm_children;
}
while (children--) {
static int
vdev_mirror_worst_error(mirror_map_t *mm)
{
- int error[2] = { 0, 0 };
+ int c, error[2] = { 0, 0 };
- for (int c = 0; c < mm->mm_children; c++) {
+ for (c = 0; c < mm->mm_children; c++) {
mirror_child_t *mc = &mm->mm_child[c];
int s = mc->mc_speculative;
error[s] = zio_worst_error(error[s], mc->mc_error);
ASSERT(zio->io_error != 0);
}
- if (good_copies && (spa_mode & FWRITE) &&
+ if (good_copies && spa_writeable(zio->io_spa) &&
(unexpected_errors ||
(zio->io_flags & ZIO_FLAG_RESILVER) ||
((zio->io_flags & ZIO_FLAG_SCRUB) && mm->mm_replacing))) {
if (mc->mc_tried)
continue;
if (!(zio->io_flags & ZIO_FLAG_SCRUB) &&
- !vdev_dtl_contains(&mc->mc_vd->vdev_dtl_map,
+ !vdev_dtl_contains(mc->mc_vd, DTL_PARTIAL,
zio->io_txg, 1))
continue;
mc->mc_error = ESTALE;
mc->mc_vd, mc->mc_offset,
zio->io_data, zio->io_size,
ZIO_TYPE_WRITE, zio->io_priority,
- ZIO_FLAG_IO_REPAIR, NULL, NULL));
+ ZIO_FLAG_IO_REPAIR | (unexpected_errors ?
+ ZIO_FLAG_SELF_HEAL : 0), NULL, NULL));
}
}
}
vdev_mirror_io_start,
vdev_mirror_io_done,
vdev_mirror_state_change,
+ NULL,
+ NULL,
VDEV_TYPE_MIRROR, /* name of this vdev type */
B_FALSE /* not a leaf vdev */
};
vdev_mirror_io_start,
vdev_mirror_io_done,
vdev_mirror_state_change,
+ NULL,
+ NULL,
VDEV_TYPE_REPLACING, /* name of this vdev type */
B_FALSE /* not a leaf vdev */
};
vdev_mirror_io_start,
vdev_mirror_io_done,
vdev_mirror_state_change,
+ NULL,
+ NULL,
VDEV_TYPE_SPARE, /* name of this vdev type */
B_FALSE /* not a leaf vdev */
};