aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/rbd.c
diff options
context:
space:
mode:
authorAlex Elder <elder@dreamhost.com>2012-02-08 17:11:14 -0500
committerAlex Elder <elder@dreamhost.com>2012-03-22 11:47:50 -0400
commit32eec68d2f233e8a6ae1cd326022f6862e2b9ce3 (patch)
tree03a1f313541374d091bfa09e6028f18bb8c77c18 /drivers/block/rbd.c
parent593a9e7b34fa62d703b473ae923a9681556cdf74 (diff)
rbd: don't drop the rbd_id too early
Currently an rbd device's id is released when it is removed, but it is done before the code is run to clean up sysfs-related files (such as /sys/bus/rbd/devices/1). It's possible that an rbd is still in use after the rbd_remove() call has been made. It's essentially the same as an active inode that stays around after it has been removed--until its final close operation. This means that the id shows up as free for reuse at a time it should not be. The effect of this was seen by Jens Rehpoehler, who: - had a filesystem mounted on an rbd device - unmapped that filesystem (without unmounting) - found that the mount still worked properly - but hit a panic when he attempted to re-map a new rbd device This re-map attempt found the previously-unmapped id available. The subsequent attempt to reuse it was met with a panic while attempting to (re-)install the sysfs entry for the new mapped device. Fix this by holding off "putting" the rbd id, until the rbd_device release function is called--when the last reference is finally dropped. Note: This fixes: http://tracker.newdream.net/issues/1907 Signed-off-by: Alex Elder <elder@dreamhost.com> Signed-off-by: Sage Weil <sage@newdream.net>
Diffstat (limited to 'drivers/block/rbd.c')
-rw-r--r--drivers/block/rbd.c14
1 files changed, 9 insertions, 5 deletions
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index 568fa5b1206b..6bbd5af1f029 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -2421,7 +2421,12 @@ static ssize_t rbd_add(struct bus_type *bus,
2421 if (rc) 2421 if (rc)
2422 goto err_out_blkdev; 2422 goto err_out_blkdev;
2423 2423
2424 /* set up and announce blkdev mapping */ 2424 /*
2425 * At this point cleanup in the event of an error is the job
2426 * of the sysfs code (initiated by rbd_bus_del_dev()).
2427 *
2428 * Set up and announce blkdev mapping.
2429 */
2425 rc = rbd_init_disk(rbd_dev); 2430 rc = rbd_init_disk(rbd_dev);
2426 if (rc) 2431 if (rc)
2427 goto err_out_bus; 2432 goto err_out_bus;
@@ -2433,8 +2438,6 @@ static ssize_t rbd_add(struct bus_type *bus,
2433 return count; 2438 return count;
2434 2439
2435err_out_bus: 2440err_out_bus:
2436 rbd_id_put(rbd_dev);
2437
2438 /* this will also clean up rest of rbd_dev stuff */ 2441 /* this will also clean up rest of rbd_dev stuff */
2439 2442
2440 rbd_bus_del_dev(rbd_dev); 2443 rbd_bus_del_dev(rbd_dev);
@@ -2492,6 +2495,9 @@ static void rbd_dev_release(struct device *dev)
2492 /* clean up and free blkdev */ 2495 /* clean up and free blkdev */
2493 rbd_free_disk(rbd_dev); 2496 rbd_free_disk(rbd_dev);
2494 unregister_blkdev(rbd_dev->major, rbd_dev->name); 2497 unregister_blkdev(rbd_dev->major, rbd_dev->name);
2498
2499 /* done with the id, and with the rbd_dev */
2500 rbd_id_put(rbd_dev);
2495 kfree(rbd_dev); 2501 kfree(rbd_dev);
2496 2502
2497 /* release module ref */ 2503 /* release module ref */
@@ -2524,8 +2530,6 @@ static ssize_t rbd_remove(struct bus_type *bus,
2524 goto done; 2530 goto done;
2525 } 2531 }
2526 2532
2527 rbd_id_put(rbd_dev);
2528
2529 __rbd_remove_all_snaps(rbd_dev); 2533 __rbd_remove_all_snaps(rbd_dev);
2530 rbd_bus_del_dev(rbd_dev); 2534 rbd_bus_del_dev(rbd_dev);
2531 2535