aboutsummaryrefslogtreecommitdiffstats
path: root/net/ceph/osd_client.c
diff options
context:
space:
mode:
authorAlex Elder <elder@inktank.com>2013-05-22 21:54:25 -0400
committerSage Weil <sage@inktank.com>2013-07-03 18:32:37 -0400
commit96e4dac66f69d28af2b736e723364efbbdf9fdee (patch)
treecc21efe7b885bf5ac276650e4d554aa705079412 /net/ceph/osd_client.c
parent6af8652849a15e407b458a271ef9154e472f6dd4 (diff)
libceph: add lingering request reference when registered
When an osd request is set to linger, the osd client holds onto the request so it can be re-submitted following certain osd map changes. The osd client holds a reference to the request until it is unregistered. This is used by rbd for watch requests. Currently, the reference is taken when the request is marked with the linger flag. This means that if an error occurs after that time but before the the request completes successfully, that reference is leaked. There's really no reason to take the reference until the request is registered in the the osd client's list of lingering requests, and that only happens when the lingering (watch) request completes successfully. So take that reference only when it gets registered following succesful completion, and drop it (as before) when the request gets unregistered. This avoids the reference problem on error in rbd. Rearrange ceph_osdc_unregister_linger_request() to avoid using the request pointer after it may have been freed. And hold an extra reference in kick_requests() while handling a linger request that has not yet been registered, to ensure it doesn't go away. This resolves: http://tracker.ceph.com/issues/3859 Signed-off-by: Alex Elder <elder@inktank.com> Reviewed-by: Josh Durgin <josh.durgin@inktank.com>
Diffstat (limited to 'net/ceph/osd_client.c')
-rw-r--r--net/ceph/osd_client.c12
1 files changed, 5 insertions, 7 deletions
diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c
index 3a246a6cab47..e0abb83b520e 100644
--- a/net/ceph/osd_client.c
+++ b/net/ceph/osd_client.c
@@ -1174,6 +1174,7 @@ static void __register_linger_request(struct ceph_osd_client *osdc,
1174 struct ceph_osd_request *req) 1174 struct ceph_osd_request *req)
1175{ 1175{
1176 dout("__register_linger_request %p\n", req); 1176 dout("__register_linger_request %p\n", req);
1177 ceph_osdc_get_request(req);
1177 list_add_tail(&req->r_linger_item, &osdc->req_linger); 1178 list_add_tail(&req->r_linger_item, &osdc->req_linger);
1178 if (req->r_osd) 1179 if (req->r_osd)
1179 list_add_tail(&req->r_linger_osd, 1180 list_add_tail(&req->r_linger_osd,
@@ -1196,6 +1197,7 @@ static void __unregister_linger_request(struct ceph_osd_client *osdc,
1196 if (list_empty(&req->r_osd_item)) 1197 if (list_empty(&req->r_osd_item))
1197 req->r_osd = NULL; 1198 req->r_osd = NULL;
1198 } 1199 }
1200 ceph_osdc_put_request(req);
1199} 1201}
1200 1202
1201void ceph_osdc_unregister_linger_request(struct ceph_osd_client *osdc, 1203void ceph_osdc_unregister_linger_request(struct ceph_osd_client *osdc,
@@ -1203,9 +1205,8 @@ void ceph_osdc_unregister_linger_request(struct ceph_osd_client *osdc,
1203{ 1205{
1204 mutex_lock(&osdc->request_mutex); 1206 mutex_lock(&osdc->request_mutex);
1205 if (req->r_linger) { 1207 if (req->r_linger) {
1206 __unregister_linger_request(osdc, req);
1207 req->r_linger = 0; 1208 req->r_linger = 0;
1208 ceph_osdc_put_request(req); 1209 __unregister_linger_request(osdc, req);
1209 } 1210 }
1210 mutex_unlock(&osdc->request_mutex); 1211 mutex_unlock(&osdc->request_mutex);
1211} 1212}
@@ -1217,11 +1218,6 @@ void ceph_osdc_set_request_linger(struct ceph_osd_client *osdc,
1217 if (!req->r_linger) { 1218 if (!req->r_linger) {
1218 dout("set_request_linger %p\n", req); 1219 dout("set_request_linger %p\n", req);
1219 req->r_linger = 1; 1220 req->r_linger = 1;
1220 /*
1221 * caller is now responsible for calling
1222 * unregister_linger_request
1223 */
1224 ceph_osdc_get_request(req);
1225 } 1221 }
1226} 1222}
1227EXPORT_SYMBOL(ceph_osdc_set_request_linger); 1223EXPORT_SYMBOL(ceph_osdc_set_request_linger);
@@ -1633,8 +1629,10 @@ static void kick_requests(struct ceph_osd_client *osdc, int force_resend)
1633 dout("%p tid %llu restart on osd%d\n", 1629 dout("%p tid %llu restart on osd%d\n",
1634 req, req->r_tid, 1630 req, req->r_tid,
1635 req->r_osd ? req->r_osd->o_osd : -1); 1631 req->r_osd ? req->r_osd->o_osd : -1);
1632 ceph_osdc_get_request(req);
1636 __unregister_request(osdc, req); 1633 __unregister_request(osdc, req);
1637 __register_linger_request(osdc, req); 1634 __register_linger_request(osdc, req);
1635 ceph_osdc_put_request(req);
1638 continue; 1636 continue;
1639 } 1637 }
1640 1638