ceph: fix race between aborted requests and fill_trace
authorSage Weil <sage@newdream.net>
Thu, 13 May 2010 19:01:13 +0000 (12:01 -0700)
committerSage Weil <sage@newdream.net>
Mon, 17 May 2010 17:25:45 +0000 (10:25 -0700)
When we abort requests we need to prevent fill_trace et al from doing
anything that relies on locks held by the VFS caller.  This fixes a race
between the reply handler and the abort code, ensuring that continue
holding the dir mutex until the reply handler completes.

Signed-off-by: Sage Weil <sage@newdream.net>
fs/ceph/mds_client.c
fs/ceph/mds_client.h

index b3b19f05b821406bb623eb064ef1dbb21a72bf46..c0568fe3c0badb6874b27a0b6aba2deab9219702 100644 (file)
@@ -1181,6 +1181,7 @@ ceph_mdsc_create_request(struct ceph_mds_client *mdsc, int op, int mode)
        if (!req)
                return ERR_PTR(-ENOMEM);
 
+       mutex_init(&req->r_fill_mutex);
        req->r_started = jiffies;
        req->r_resend_mds = -1;
        INIT_LIST_HEAD(&req->r_unsafe_dir_item);
@@ -1715,8 +1716,16 @@ int ceph_mdsc_do_request(struct ceph_mds_client *mdsc,
                err = le32_to_cpu(req->r_reply_info.head->result);
        } else if (err < 0) {
                dout("aborted request %lld with %d\n", req->r_tid, err);
+
+               /*
+                * ensure we aren't running concurrently with
+                * ceph_fill_trace or ceph_readdir_prepopulate, which
+                * rely on locks (dir mutex) held by our caller.
+                */
+               mutex_lock(&req->r_fill_mutex);
                req->r_err = err;
                req->r_aborted = true;
+               mutex_unlock(&req->r_fill_mutex);
 
                if (req->r_locked_dir &&
                    (req->r_op & CEPH_MDS_OP_WRITE)) {
@@ -1861,12 +1870,14 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg)
        }
 
        /* insert trace into our cache */
+       mutex_lock(&req->r_fill_mutex);
        err = ceph_fill_trace(mdsc->client->sb, req, req->r_session);
        if (err == 0) {
                if (result == 0 && rinfo->dir_nr)
                        ceph_readdir_prepopulate(req, req->r_session);
                ceph_unreserve_caps(&req->r_caps_reservation);
        }
+       mutex_unlock(&req->r_fill_mutex);
 
        up_read(&mdsc->snap_rwsem);
 out_err:
index 0b1dd10be39aec2bb29412b905d914ef6ce03adb..141a265bda750f5bec2c5e002af6444bf01fd538 100644 (file)
@@ -165,6 +165,8 @@ struct ceph_mds_request {
        struct inode *r_locked_dir; /* dir (if any) i_mutex locked by vfs */
        struct inode *r_target_inode;       /* resulting inode */
 
+       struct mutex r_fill_mutex;
+
        union ceph_mds_request_args r_args;
        int r_fmode;        /* file mode, if expecting cap */