aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSage Weil <sage@newdream.net>2009-10-08 16:55:47 -0700
committerSage Weil <sage@newdream.net>2009-10-09 11:58:03 -0700
commitc1ea8823be69ebebaface912142190e910711984 (patch)
treed834392aebd65a1d538e23b54b63172ca427f29c
parent0656d11ba6ffa3dee0e8916a1903f96185651217 (diff)
ceph: fix osd request submission race
The osd request submission path registers the request, drops and retakes the request_mutex, then sends it to the OSD. A racing kick_requests could sent it during that interval, causing the same msg to be sent twice and BUGing in the msgr. Fix by only sending the message if it hasn't been touched by other threads. Signed-off-by: Sage Weil <sage@newdream.net>
-rw-r--r--fs/ceph/osd_client.c30
1 files changed, 19 insertions, 11 deletions
diff --git a/fs/ceph/osd_client.c b/fs/ceph/osd_client.c
index 978593a4f46..d14019dd686 100644
--- a/fs/ceph/osd_client.c
+++ b/fs/ceph/osd_client.c
@@ -837,7 +837,8 @@ static void kick_requests(struct ceph_osd_client *osdc,
}
kick:
- dout("kicking tid %llu osd%d\n", req->r_tid, req->r_osd->o_osd);
+ dout("kicking %p tid %llu osd%d\n", req, req->r_tid,
+ req->r_osd->o_osd);
req->r_flags |= CEPH_OSD_FLAG_RETRY;
err = __send_request(osdc, req);
if (err) {
@@ -1016,7 +1017,7 @@ int ceph_osdc_start_request(struct ceph_osd_client *osdc,
struct ceph_osd_request *req,
bool nofail)
{
- int rc;
+ int rc = 0;
req->r_request->pages = req->r_pages;
req->r_request->nr_pages = req->r_num_pages;
@@ -1025,15 +1026,22 @@ int ceph_osdc_start_request(struct ceph_osd_client *osdc,
down_read(&osdc->map_sem);
mutex_lock(&osdc->request_mutex);
- rc = __send_request(osdc, req);
- if (rc) {
- if (nofail) {
- dout("osdc_start_request failed send, marking %lld\n",
- req->r_tid);
- req->r_resend = true;
- rc = 0;
- } else {
- __unregister_request(osdc, req);
+ /*
+ * a racing kick_requests() may have sent the message for us
+ * while we dropped request_mutex above, so only send now if
+ * the request still han't been touched yet.
+ */
+ if (req->r_sent == 0) {
+ rc = __send_request(osdc, req);
+ if (rc) {
+ if (nofail) {
+ dout("osdc_start_request failed send, "
+ " marking %lld\n", req->r_tid);
+ req->r_resend = true;
+ rc = 0;
+ } else {
+ __unregister_request(osdc, req);
+ }
}
}
mutex_unlock(&osdc->request_mutex);