summaryrefslogtreecommitdiffstats
path: root/drivers/block
diff options
context:
space:
mode:
authorAlex Elder <elder@inktank.com>2013-01-26 00:08:55 +0100
committerSage Weil <sage@inktank.com>2013-02-14 03:29:10 +0100
commit8eb87565306cf40a32f5d0883d008675cd2dd510 (patch)
treee999f857dbe1ccf18508590be9c818d7835b7201 /drivers/block
parentrbd: decrement obj request count when deleting (diff)
downloadlinux-8eb87565306cf40a32f5d0883d008675cd2dd510.tar.xz
linux-8eb87565306cf40a32f5d0883d008675cd2dd510.zip
rbd: don't drop watch requests on completion
When we register an osd request to linger, it means that request will stay around (under control of the osd client) until we've unregistered it. We do that for an rbd image's header object, and we keep a pointer to the object request associated with it. Keep a reference to the watch object request for as long as it is registered to linger. Drop it again after we've removed the linger registration. This resolves: http://tracker.ceph.com/issues/3937 (Note: this originally came about because the osd client was issuing a callback more than once. But that behavior will be changing soon, documented in tracker issue 3967.) Signed-off-by: Alex Elder <elder@inktank.com> Reviewed-by: Josh Durgin <josh.durgin@inktank.com>
Diffstat (limited to 'drivers/block')
-rw-r--r--drivers/block/rbd.c30
1 files changed, 21 insertions, 9 deletions
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index d3d15d06abc0..fd9656b5fdb9 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -1707,6 +1707,7 @@ static int rbd_dev_header_watch_sync(struct rbd_device *rbd_dev, int start)
&rbd_dev->watch_event);
if (ret < 0)
return ret;
+ rbd_assert(rbd_dev->watch_event != NULL);
}
ret = -ENOMEM;
@@ -1726,32 +1727,43 @@ static int rbd_dev_header_watch_sync(struct rbd_device *rbd_dev, int start)
if (!obj_request->osd_req)
goto out_cancel;
- if (start) {
+ if (start)
ceph_osdc_set_request_linger(osdc, obj_request->osd_req);
- rbd_dev->watch_request = obj_request;
- } else {
+ else
ceph_osdc_unregister_linger_request(osdc,
rbd_dev->watch_request->osd_req);
- rbd_dev->watch_request = NULL;
- }
ret = rbd_obj_request_submit(osdc, obj_request);
if (ret)
goto out_cancel;
ret = rbd_obj_request_wait(obj_request);
if (ret)
goto out_cancel;
-
ret = obj_request->result;
if (ret)
goto out_cancel;
- if (start)
- goto done; /* Done if setting up the watch request */
+ /*
+ * A watch request is set to linger, so the underlying osd
+ * request won't go away until we unregister it. We retain
+ * a pointer to the object request during that time (in
+ * rbd_dev->watch_request), so we'll keep a reference to
+ * it. We'll drop that reference (below) after we've
+ * unregistered it.
+ */
+ if (start) {
+ rbd_dev->watch_request = obj_request;
+
+ return 0;
+ }
+
+ /* We have successfully torn down the watch request */
+
+ rbd_obj_request_put(rbd_dev->watch_request);
+ rbd_dev->watch_request = NULL;
out_cancel:
/* Cancel the event if we're tearing down, or on error */
ceph_osdc_cancel_event(rbd_dev->watch_event);
rbd_dev->watch_event = NULL;
-done:
if (obj_request)
rbd_obj_request_put(obj_request);