diff options
author | Lars Ellenberg <lars.ellenberg@linbit.com> | 2011-11-17 14:32:12 +0100 |
---|---|---|
committer | Philipp Reisner <philipp.reisner@linbit.com> | 2012-11-08 16:58:10 +0100 |
commit | 615e087fbd7483fafa28c8a1a4d1656251e0604d (patch) | |
tree | 9bbaf911afe6437644a4e8800797cb440649ae8d | |
parent | 03d63e1d1e705fdba4c0f6a3a119cc42504bb9ed (diff) |
drbd: add missing rcu locks around recently introduced idr_for_each
Recent commit
drbd: Move write_ordering from mdev to tconn
introduced a new idr_for_each loop over all volumes,
but did not take necessary rcu locks or krefs.
Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
-rw-r--r-- | drivers/block/drbd/drbd_receiver.c | 32 |
1 files changed, 20 insertions, 12 deletions
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index be8f469bc8f0..9c888e5b648f 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1096,22 +1096,30 @@ static void drbd_flush(struct drbd_tconn *tconn) int vnr; if (tconn->write_ordering >= WO_bdev_flush) { + rcu_read_lock(); idr_for_each_entry(&tconn->volumes, mdev, vnr) { - if (get_ldev(mdev)) { - rv = blkdev_issue_flush(mdev->ldev->backing_bdev, GFP_KERNEL, - NULL); - put_ldev(mdev); + if (!get_ldev(mdev)) + continue; + kref_get(&mdev->kref); + rcu_read_unlock(); - if (rv) { - dev_info(DEV, "local disk flush failed with status %d\n", rv); - /* would rather check on EOPNOTSUPP, but that is not reliable. - * don't try again for ANY return value != 0 - * if (rv == -EOPNOTSUPP) */ - drbd_bump_write_ordering(tconn, WO_drain_io); - break; - } + rv = blkdev_issue_flush(mdev->ldev->backing_bdev, + GFP_NOIO, NULL); + if (rv) { + dev_info(DEV, "local disk flush failed with status %d\n", rv); + /* would rather check on EOPNOTSUPP, but that is not reliable. + * don't try again for ANY return value != 0 + * if (rv == -EOPNOTSUPP) */ + drbd_bump_write_ordering(tconn, WO_drain_io); } + put_ldev(mdev); + kref_put(&mdev->kref, &drbd_minor_destroy); + + rcu_read_lock(); + if (rv) + break; } + rcu_read_unlock(); } } |