aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorJosh Durgin <josh.durgin@dreamhost.com>2011-12-05 17:03:05 -0500
committerSage Weil <sage@inktank.com>2012-07-30 21:15:40 -0400
commitd1d25646543134d756a02ffe4e02073faa761f2c (patch)
treec68bf9aae4a362dd17f441f005bbdc7ca23fafb9 /drivers
parent93a24e084d67ba2fcb9a4c289135825b623ec864 (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.c36
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;