diff options
author | Ilya Dryomov <ilya.dryomov@inktank.com> | 2014-06-20 10:29:20 -0400 |
---|---|---|
committer | Ilya Dryomov <ilya.dryomov@inktank.com> | 2014-07-08 07:08:44 -0400 |
commit | af59306455587143615517ade1ffce2e8f4fda48 (patch) | |
tree | c97beeb35bf52009d633a1c034452124bb0e0a77 /net/ceph/osd_client.c | |
parent | 7c6e6fc53e7335570ed82f77656cedce1502744e (diff) |
libceph: unregister only registered linger requests
Linger requests that have not yet been registered should not be
unregistered by __unregister_linger_request(). This messes up ref
count and leads to use-after-free.
Signed-off-by: Ilya Dryomov <ilya.dryomov@inktank.com>
Reviewed-by: Alex Elder <elder@linaro.org>
Diffstat (limited to 'net/ceph/osd_client.c')
-rw-r--r-- | net/ceph/osd_client.c | 19 |
1 files changed, 14 insertions, 5 deletions
diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index a9b7ea7bfdc6..943dba916ab1 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c | |||
@@ -1248,7 +1248,9 @@ static void __cancel_request(struct ceph_osd_request *req) | |||
1248 | static void __register_linger_request(struct ceph_osd_client *osdc, | 1248 | static void __register_linger_request(struct ceph_osd_client *osdc, |
1249 | struct ceph_osd_request *req) | 1249 | struct ceph_osd_request *req) |
1250 | { | 1250 | { |
1251 | dout("__register_linger_request %p\n", req); | 1251 | dout("%s %p tid %llu\n", __func__, req, req->r_tid); |
1252 | WARN_ON(!req->r_linger); | ||
1253 | |||
1252 | ceph_osdc_get_request(req); | 1254 | ceph_osdc_get_request(req); |
1253 | list_add_tail(&req->r_linger_item, &osdc->req_linger); | 1255 | list_add_tail(&req->r_linger_item, &osdc->req_linger); |
1254 | if (req->r_osd) | 1256 | if (req->r_osd) |
@@ -1259,8 +1261,17 @@ static void __register_linger_request(struct ceph_osd_client *osdc, | |||
1259 | static void __unregister_linger_request(struct ceph_osd_client *osdc, | 1261 | static void __unregister_linger_request(struct ceph_osd_client *osdc, |
1260 | struct ceph_osd_request *req) | 1262 | struct ceph_osd_request *req) |
1261 | { | 1263 | { |
1262 | dout("__unregister_linger_request %p\n", req); | 1264 | WARN_ON(!req->r_linger); |
1265 | |||
1266 | if (list_empty(&req->r_linger_item)) { | ||
1267 | dout("%s %p tid %llu not registered\n", __func__, req, | ||
1268 | req->r_tid); | ||
1269 | return; | ||
1270 | } | ||
1271 | |||
1272 | dout("%s %p tid %llu\n", __func__, req, req->r_tid); | ||
1263 | list_del_init(&req->r_linger_item); | 1273 | list_del_init(&req->r_linger_item); |
1274 | |||
1264 | if (req->r_osd) { | 1275 | if (req->r_osd) { |
1265 | list_del_init(&req->r_linger_osd_item); | 1276 | list_del_init(&req->r_linger_osd_item); |
1266 | maybe_move_osd_to_lru(osdc, req->r_osd); | 1277 | maybe_move_osd_to_lru(osdc, req->r_osd); |
@@ -1274,10 +1285,8 @@ void ceph_osdc_unregister_linger_request(struct ceph_osd_client *osdc, | |||
1274 | struct ceph_osd_request *req) | 1285 | struct ceph_osd_request *req) |
1275 | { | 1286 | { |
1276 | mutex_lock(&osdc->request_mutex); | 1287 | mutex_lock(&osdc->request_mutex); |
1277 | if (req->r_linger) { | 1288 | if (req->r_linger) |
1278 | req->r_linger = 0; | ||
1279 | __unregister_linger_request(osdc, req); | 1289 | __unregister_linger_request(osdc, req); |
1280 | } | ||
1281 | mutex_unlock(&osdc->request_mutex); | 1290 | mutex_unlock(&osdc->request_mutex); |
1282 | } | 1291 | } |
1283 | EXPORT_SYMBOL(ceph_osdc_unregister_linger_request); | 1292 | EXPORT_SYMBOL(ceph_osdc_unregister_linger_request); |