aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/drbd/drbd_main.c
diff options
context:
space:
mode:
authorLars Ellenberg <lars.ellenberg@linbit.com>2011-03-07 03:49:02 -0500
committerPhilipp Reisner <philipp.reisner@linbit.com>2011-10-14 10:48:07 -0400
commit569083c08dc16c043b4bdd473d41ff85a2b2df9e (patch)
tree14c2f8ed88fec74a74dc790b56b5819d17e1330d /drivers/block/drbd/drbd_main.c
parentda4a75d2ef064501f6756986af6ea330ba0585d7 (diff)
drbd: fix drbd_delete_device: remove vnr from volumes; idr_remove(); synchronize_rcu(); before cleanup
Still missing: rcu_readlock() on the various call sites that access/iterate over those idrs. We don't need a specific write lock, as we only modify from configuration context, which is already strictly serialized. 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_main.c')
-rw-r--r--drivers/block/drbd/drbd_main.c42
1 files changed, 24 insertions, 18 deletions
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c
index 997b2e214670..9f6db5947c65 100644
--- a/drivers/block/drbd/drbd_main.c
+++ b/drivers/block/drbd/drbd_main.c
@@ -2124,7 +2124,9 @@ void drbd_delete_device(unsigned int minor)
2124 if (!mdev) 2124 if (!mdev)
2125 return; 2125 return;
2126 2126
2127 idr_remove(&mdev->tconn->volumes, minor); 2127 idr_remove(&mdev->tconn->volumes, mdev->vnr);
2128 idr_remove(&minors, minor);
2129 synchronize_rcu();
2128 2130
2129 /* paranoia asserts */ 2131 /* paranoia asserts */
2130 D_ASSERT(mdev->open_cnt == 0); 2132 D_ASSERT(mdev->open_cnt == 0);
@@ -2153,7 +2155,6 @@ void drbd_delete_device(unsigned int minor)
2153 * allocated from drbd_new_device 2155 * allocated from drbd_new_device
2154 * and actually free the mdev itself */ 2156 * and actually free the mdev itself */
2155 drbd_free_mdev(mdev); 2157 drbd_free_mdev(mdev);
2156 idr_remove(&minors, minor);
2157} 2158}
2158 2159
2159static void drbd_cleanup(void) 2160static void drbd_cleanup(void)
@@ -2331,15 +2332,6 @@ enum drbd_ret_code conn_new_minor(struct drbd_tconn *tconn, unsigned int minor,
2331 return ERR_NOMEM; 2332 return ERR_NOMEM;
2332 2333
2333 mdev->tconn = tconn; 2334 mdev->tconn = tconn;
2334 if (!idr_pre_get(&tconn->volumes, GFP_KERNEL))
2335 goto out_no_idr;
2336 if (idr_get_new(&tconn->volumes, mdev, &vnr_got))
2337 goto out_no_idr;
2338 if (vnr_got != vnr) {
2339 dev_err(DEV, "vnr_got (%d) != vnr (%d)\n", vnr_got, vnr);
2340 goto out_no_q;
2341 }
2342
2343 mdev->minor = minor; 2335 mdev->minor = minor;
2344 2336
2345 drbd_init_set_defaults(mdev); 2337 drbd_init_set_defaults(mdev);
@@ -2395,19 +2387,35 @@ enum drbd_ret_code conn_new_minor(struct drbd_tconn *tconn, unsigned int minor,
2395 INIT_LIST_HEAD(&mdev->current_epoch->list); 2387 INIT_LIST_HEAD(&mdev->current_epoch->list);
2396 mdev->epochs = 1; 2388 mdev->epochs = 1;
2397 2389
2390 if (!idr_pre_get(&tconn->volumes, GFP_KERNEL))
2391 goto out_no_vol_idr;
2392 if (idr_get_new(&tconn->volumes, mdev, &vnr_got))
2393 goto out_no_vol_idr;
2394 if (vnr_got != vnr) {
2395 dev_err(DEV, "vnr_got (%d) != vnr (%d)\n", vnr_got, vnr);
2396 goto out_idr_remove_vol;
2397 }
2398
2398 if (!idr_pre_get(&minors, GFP_KERNEL)) 2399 if (!idr_pre_get(&minors, GFP_KERNEL))
2399 goto out_no_minor_idr; 2400 goto out_idr_remove_vol;
2400 if (idr_get_new(&minors, mdev, &minor_got)) 2401 if (idr_get_new(&minors, mdev, &minor_got))
2401 goto out_no_minor_idr; 2402 goto out_idr_remove_vol;
2402 if (minor_got != minor) { 2403 if (minor_got != minor) {
2403 idr_remove(&minors, minor_got); 2404 /* minor exists, or other idr strangeness? */
2404 goto out_no_minor_idr; 2405 dev_err(DEV, "available minor (%d) != requested minor (%d)\n",
2406 minor_got, minor);
2407 goto out_idr_remove_minor;
2405 } 2408 }
2406 add_disk(disk); 2409 add_disk(disk);
2407 2410
2408 return NO_ERROR; 2411 return NO_ERROR;
2409 2412
2410out_no_minor_idr: 2413out_idr_remove_minor:
2414 idr_remove(&minors, minor_got);
2415out_idr_remove_vol:
2416 idr_remove(&tconn->volumes, vnr_got);
2417 synchronize_rcu();
2418out_no_vol_idr:
2411 kfree(mdev->current_epoch); 2419 kfree(mdev->current_epoch);
2412out_no_epoch: 2420out_no_epoch:
2413 drbd_bm_cleanup(mdev); 2421 drbd_bm_cleanup(mdev);
@@ -2418,8 +2426,6 @@ out_no_io_page:
2418out_no_disk: 2426out_no_disk:
2419 blk_cleanup_queue(q); 2427 blk_cleanup_queue(q);
2420out_no_q: 2428out_no_q:
2421 idr_remove(&tconn->volumes, vnr_got);
2422out_no_idr:
2423 kfree(mdev); 2429 kfree(mdev);
2424 return ERR_NOMEM; 2430 return ERR_NOMEM;
2425} 2431}