diff options
author | Josh Durgin <josh.durgin@dreamhost.com> | 2011-12-05 17:03:05 -0500 |
---|---|---|
committer | Sage Weil <sage@inktank.com> | 2012-07-30 21:15:40 -0400 |
commit | d1d25646543134d756a02ffe4e02073faa761f2c (patch) | |
tree | c68bf9aae4a362dd17f441f005bbdc7ca23fafb9 /drivers | |
parent | 93a24e084d67ba2fcb9a4c289135825b623ec864 (diff) |
rbd: use reference counting for the snap context
This prevents a race between requests with a given snap context and
header updates that free it. The osd client was already expecting the
snap context to be reference counted, since it get()s it in
ceph_osdc_build_request and put()s it when the request completes.
Also remove the second down_read()/up_read() on header_rwsem in
rbd_do_request, which wasn't actually preventing this race or
protecting any other data.
Signed-off-by: Josh Durgin <josh.durgin@dreamhost.com>
Reviewed-by: Alex Elder <elder@inktank.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/block/rbd.c | 36 |
1 files changed, 18 insertions, 18 deletions
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index a6bbda2e5eb8..988f94458f95 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c | |||
@@ -626,7 +626,7 @@ static void rbd_header_free(struct rbd_image_header *header) | |||
626 | kfree(header->object_prefix); | 626 | kfree(header->object_prefix); |
627 | kfree(header->snap_sizes); | 627 | kfree(header->snap_sizes); |
628 | kfree(header->snap_names); | 628 | kfree(header->snap_names); |
629 | kfree(header->snapc); | 629 | ceph_put_snap_context(header->snapc); |
630 | } | 630 | } |
631 | 631 | ||
632 | /* | 632 | /* |
@@ -902,13 +902,10 @@ static int rbd_do_request(struct request *rq, | |||
902 | dout("rbd_do_request object_name=%s ofs=%lld len=%lld\n", | 902 | dout("rbd_do_request object_name=%s ofs=%lld len=%lld\n", |
903 | object_name, len, ofs); | 903 | object_name, len, ofs); |
904 | 904 | ||
905 | down_read(&rbd_dev->header_rwsem); | ||
906 | |||
907 | osdc = &rbd_dev->rbd_client->client->osdc; | 905 | osdc = &rbd_dev->rbd_client->client->osdc; |
908 | req = ceph_osdc_alloc_request(osdc, flags, snapc, ops, | 906 | req = ceph_osdc_alloc_request(osdc, flags, snapc, ops, |
909 | false, GFP_NOIO, pages, bio); | 907 | false, GFP_NOIO, pages, bio); |
910 | if (!req) { | 908 | if (!req) { |
911 | up_read(&rbd_dev->header_rwsem); | ||
912 | ret = -ENOMEM; | 909 | ret = -ENOMEM; |
913 | goto done_pages; | 910 | goto done_pages; |
914 | } | 911 | } |
@@ -942,7 +939,6 @@ static int rbd_do_request(struct request *rq, | |||
942 | snapc, | 939 | snapc, |
943 | &mtime, | 940 | &mtime, |
944 | req->r_oid, req->r_oid_len); | 941 | req->r_oid, req->r_oid_len); |
945 | up_read(&rbd_dev->header_rwsem); | ||
946 | 942 | ||
947 | if (linger_req) { | 943 | if (linger_req) { |
948 | ceph_osdc_set_request_linger(osdc, req); | 944 | ceph_osdc_set_request_linger(osdc, req); |
@@ -1448,6 +1444,7 @@ static void rbd_rq_fn(struct request_queue *q) | |||
1448 | u64 ofs; | 1444 | u64 ofs; |
1449 | int num_segs, cur_seg = 0; | 1445 | int num_segs, cur_seg = 0; |
1450 | struct rbd_req_coll *coll; | 1446 | struct rbd_req_coll *coll; |
1447 | struct ceph_snap_context *snapc; | ||
1451 | 1448 | ||
1452 | /* peek at request from block layer */ | 1449 | /* peek at request from block layer */ |
1453 | if (!rq) | 1450 | if (!rq) |
@@ -1474,21 +1471,20 @@ static void rbd_rq_fn(struct request_queue *q) | |||
1474 | 1471 | ||
1475 | spin_unlock_irq(q->queue_lock); | 1472 | spin_unlock_irq(q->queue_lock); |
1476 | 1473 | ||
1477 | if (rbd_dev->snap_id != CEPH_NOSNAP) { | 1474 | down_read(&rbd_dev->header_rwsem); |
1478 | bool snap_exists; | ||
1479 | 1475 | ||
1480 | down_read(&rbd_dev->header_rwsem); | 1476 | if (rbd_dev->snap_id != CEPH_NOSNAP && !rbd_dev->snap_exists) { |
1481 | snap_exists = rbd_dev->snap_exists; | ||
1482 | up_read(&rbd_dev->header_rwsem); | 1477 | up_read(&rbd_dev->header_rwsem); |
1483 | 1478 | dout("request for non-existent snapshot"); | |
1484 | if (!snap_exists) { | 1479 | spin_lock_irq(q->queue_lock); |
1485 | dout("request for non-existent snapshot"); | 1480 | __blk_end_request_all(rq, -ENXIO); |
1486 | spin_lock_irq(q->queue_lock); | 1481 | continue; |
1487 | __blk_end_request_all(rq, -ENXIO); | ||
1488 | continue; | ||
1489 | } | ||
1490 | } | 1482 | } |
1491 | 1483 | ||
1484 | snapc = ceph_get_snap_context(rbd_dev->header.snapc); | ||
1485 | |||
1486 | up_read(&rbd_dev->header_rwsem); | ||
1487 | |||
1492 | dout("%s 0x%x bytes at 0x%llx\n", | 1488 | dout("%s 0x%x bytes at 0x%llx\n", |
1493 | do_write ? "write" : "read", | 1489 | do_write ? "write" : "read", |
1494 | size, blk_rq_pos(rq) * SECTOR_SIZE); | 1490 | size, blk_rq_pos(rq) * SECTOR_SIZE); |
@@ -1498,6 +1494,7 @@ static void rbd_rq_fn(struct request_queue *q) | |||
1498 | if (!coll) { | 1494 | if (!coll) { |
1499 | spin_lock_irq(q->queue_lock); | 1495 | spin_lock_irq(q->queue_lock); |
1500 | __blk_end_request_all(rq, -ENOMEM); | 1496 | __blk_end_request_all(rq, -ENOMEM); |
1497 | ceph_put_snap_context(snapc); | ||
1501 | continue; | 1498 | continue; |
1502 | } | 1499 | } |
1503 | 1500 | ||
@@ -1521,7 +1518,7 @@ static void rbd_rq_fn(struct request_queue *q) | |||
1521 | /* init OSD command: write or read */ | 1518 | /* init OSD command: write or read */ |
1522 | if (do_write) | 1519 | if (do_write) |
1523 | rbd_req_write(rq, rbd_dev, | 1520 | rbd_req_write(rq, rbd_dev, |
1524 | rbd_dev->header.snapc, | 1521 | snapc, |
1525 | ofs, | 1522 | ofs, |
1526 | op_size, bio, | 1523 | op_size, bio, |
1527 | coll, cur_seg); | 1524 | coll, cur_seg); |
@@ -1544,6 +1541,8 @@ next_seg: | |||
1544 | if (bp) | 1541 | if (bp) |
1545 | bio_pair_release(bp); | 1542 | bio_pair_release(bp); |
1546 | spin_lock_irq(q->queue_lock); | 1543 | spin_lock_irq(q->queue_lock); |
1544 | |||
1545 | ceph_put_snap_context(snapc); | ||
1547 | } | 1546 | } |
1548 | } | 1547 | } |
1549 | 1548 | ||
@@ -1744,7 +1743,8 @@ static int __rbd_refresh_header(struct rbd_device *rbd_dev) | |||
1744 | /* rbd_dev->header.object_prefix shouldn't change */ | 1743 | /* rbd_dev->header.object_prefix shouldn't change */ |
1745 | kfree(rbd_dev->header.snap_sizes); | 1744 | kfree(rbd_dev->header.snap_sizes); |
1746 | kfree(rbd_dev->header.snap_names); | 1745 | kfree(rbd_dev->header.snap_names); |
1747 | kfree(rbd_dev->header.snapc); | 1746 | /* osd requests may still refer to snapc */ |
1747 | ceph_put_snap_context(rbd_dev->header.snapc); | ||
1748 | 1748 | ||
1749 | rbd_dev->header.image_size = h.image_size; | 1749 | rbd_dev->header.image_size = h.image_size; |
1750 | rbd_dev->header.total_snaps = h.total_snaps; | 1750 | rbd_dev->header.total_snaps = h.total_snaps; |