summaryrefslogtreecommitdiffstats
path: root/drivers/block/drbd/drbd_receiver.c
diff options
context:
space:
mode:
authorLars Ellenberg2011-11-17 14:32:12 +0100
committerPhilipp Reisner2012-11-08 16:58:10 +0100
commit615e087fbd7483fafa28c8a1a4d1656251e0604d (patch)
tree9bbaf911afe6437644a4e8800797cb440649ae8d /drivers/block/drbd/drbd_receiver.c
parentdrbd: Remove leftover prototype (diff)
downloadkernel-qcow2-linux-615e087fbd7483fafa28c8a1a4d1656251e0604d.tar.gz
kernel-qcow2-linux-615e087fbd7483fafa28c8a1a4d1656251e0604d.tar.xz
kernel-qcow2-linux-615e087fbd7483fafa28c8a1a4d1656251e0604d.zip
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>
Diffstat (limited to 'drivers/block/drbd/drbd_receiver.c')
-rw-r--r--drivers/block/drbd/drbd_receiver.c32
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();
}
}