Fix vdev_open_child() race on updating vdev_parent->vdev_nonrot

Updating vd->vdev_parent->vdev_nonrot in vdev_open_child()
is a race when vdev_open_child is called for many children
from a task queue.

vdev_open_child() is only called by vdev_open_children(), let
the latter update the parent vdev_nonrot member.  The update
was already there, so done twice previously.  Thus using the
same logic at the end in vdev_open_children() to update
vdev_nonrot, either we are vdev_uses_zvols() or not.

Reviewed-by: Richard Elling <Richard.Elling@RichardElling.com>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Haakan T Johansson <f96hajo@chalmers.se>
Closes #5162
This commit is contained in:
Håkan Johansson 2016-10-07 22:25:35 +02:00 committed by Brian Behlendorf
parent ccc92611b1
commit 4770aa0643

View File

@ -1124,7 +1124,6 @@ vdev_open_child(void *arg)
vd->vdev_open_thread = curthread; vd->vdev_open_thread = curthread;
vd->vdev_open_error = vdev_open(vd); vd->vdev_open_error = vdev_open(vd);
vd->vdev_open_thread = NULL; vd->vdev_open_thread = NULL;
vd->vdev_parent->vdev_nonrot &= vd->vdev_nonrot;
} }
static boolean_t static boolean_t
@ -1151,29 +1150,27 @@ vdev_open_children(vdev_t *vd)
int children = vd->vdev_children; int children = vd->vdev_children;
int c; int c;
vd->vdev_nonrot = B_TRUE;
/* /*
* in order to handle pools on top of zvols, do the opens * in order to handle pools on top of zvols, do the opens
* in a single thread so that the same thread holds the * in a single thread so that the same thread holds the
* spa_namespace_lock * spa_namespace_lock
*/ */
if (vdev_uses_zvols(vd)) { if (vdev_uses_zvols(vd)) {
for (c = 0; c < children; c++) { for (c = 0; c < children; c++)
vd->vdev_child[c]->vdev_open_error = vd->vdev_child[c]->vdev_open_error =
vdev_open(vd->vdev_child[c]); vdev_open(vd->vdev_child[c]);
vd->vdev_nonrot &= vd->vdev_child[c]->vdev_nonrot; } else {
}
return;
}
tq = taskq_create("vdev_open", children, minclsyspri, tq = taskq_create("vdev_open", children, minclsyspri,
children, children, TASKQ_PREPOPULATE); children, children, TASKQ_PREPOPULATE);
for (c = 0; c < children; c++) for (c = 0; c < children; c++)
VERIFY(taskq_dispatch(tq, vdev_open_child, vd->vdev_child[c], VERIFY(taskq_dispatch(tq, vdev_open_child,
TQ_SLEEP) != 0); vd->vdev_child[c], TQ_SLEEP) != 0);
taskq_destroy(tq); taskq_destroy(tq);
}
vd->vdev_nonrot = B_TRUE;
for (c = 0; c < children; c++) for (c = 0; c < children; c++)
vd->vdev_nonrot &= vd->vdev_child[c]->vdev_nonrot; vd->vdev_nonrot &= vd->vdev_child[c]->vdev_nonrot;