aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSage Weil <sage@newdream.net>2010-01-25 14:33:08 -0500
committerSage Weil <sage@newdream.net>2010-01-25 14:49:51 -0500
commit5b1daecd59f95eb24dc629407ed80369c9929520 (patch)
tree19b5d4e11427350f48947df8dca453069ed0a0d5
parent3ea25f9441fc0951ada649105f2c57a59536b539 (diff)
ceph: properly handle aborted mds requests
Previously, if the MDS request was interrupted, we would unregister the request and ignore any reply. This could cause the caps or other cache state to become out of sync. (For instance, aborting dbench and doing rm -r on clients would complain about a non-empty directory because the client didn't realize it's aborted file create request completed.) Even we don't unregister, we still can't process the reply normally because we are no longer holding the caller's locks (like the dir i_mutex). So, mark aborted operations with r_aborted, and in the reply handler, be sure to process all the caps. Do not process the namespace changes, though, since we no longer will hold the dir i_mutex. The dentry lease state can also be ignored as it's more forgiving. Signed-off-by: Sage Weil <sage@newdream.net>
-rw-r--r--fs/ceph/inode.c16
-rw-r--r--fs/ceph/mds_client.c28
-rw-r--r--fs/ceph/mds_client.h1
3 files changed, 34 insertions, 11 deletions
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c
index 518beb628f09..71e107fb4dbc 100644
--- a/fs/ceph/inode.c
+++ b/fs/ceph/inode.c
@@ -915,6 +915,16 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req,
915 } 915 }
916 916
917 if (rinfo->head->is_dentry) { 917 if (rinfo->head->is_dentry) {
918 struct inode *dir = req->r_locked_dir;
919
920 err = fill_inode(dir, &rinfo->diri, rinfo->dirfrag,
921 session, req->r_request_started, -1,
922 &req->r_caps_reservation);
923 if (err < 0)
924 return err;
925 }
926
927 if (rinfo->head->is_dentry && !req->r_aborted) {
918 /* 928 /*
919 * lookup link rename : null -> possibly existing inode 929 * lookup link rename : null -> possibly existing inode
920 * mknod symlink mkdir : null -> new inode 930 * mknod symlink mkdir : null -> new inode
@@ -932,12 +942,6 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req,
932 BUG_ON(ceph_snap(dir) != 942 BUG_ON(ceph_snap(dir) !=
933 le64_to_cpu(rinfo->diri.in->snapid)); 943 le64_to_cpu(rinfo->diri.in->snapid));
934 944
935 err = fill_inode(dir, &rinfo->diri, rinfo->dirfrag,
936 session, req->r_request_started, -1,
937 &req->r_caps_reservation);
938 if (err < 0)
939 return err;
940
941 /* do we have a lease on the whole dir? */ 945 /* do we have a lease on the whole dir? */
942 have_dir_cap = 946 have_dir_cap =
943 (le32_to_cpu(rinfo->diri.in->cap.caps) & 947 (le32_to_cpu(rinfo->diri.in->cap.caps) &
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
index 6e08f488a30f..623c67cd484b 100644
--- a/fs/ceph/mds_client.c
+++ b/fs/ceph/mds_client.c
@@ -1624,11 +1624,29 @@ int ceph_mdsc_do_request(struct ceph_mds_client *mdsc,
1624 err = PTR_ERR(req->r_reply); 1624 err = PTR_ERR(req->r_reply);
1625 req->r_reply = NULL; 1625 req->r_reply = NULL;
1626 1626
1627 /* clean up */ 1627 if (err == -ERESTARTSYS) {
1628 __unregister_request(mdsc, req); 1628 /* aborted */
1629 if (!list_empty(&req->r_unsafe_item)) 1629 req->r_aborted = true;
1630 list_del_init(&req->r_unsafe_item); 1630
1631 complete(&req->r_safe_completion); 1631 if (req->r_locked_dir &&
1632 (req->r_op & CEPH_MDS_OP_WRITE)) {
1633 struct ceph_inode_info *ci =
1634 ceph_inode(req->r_locked_dir);
1635
1636 dout("aborted, clearing I_COMPLETE on %p\n",
1637 req->r_locked_dir);
1638 spin_lock(&req->r_locked_dir->i_lock);
1639 ci->i_ceph_flags &= ~CEPH_I_COMPLETE;
1640 ci->i_release_count++;
1641 spin_unlock(&req->r_locked_dir->i_lock);
1642 }
1643 } else {
1644 /* clean up this request */
1645 __unregister_request(mdsc, req);
1646 if (!list_empty(&req->r_unsafe_item))
1647 list_del_init(&req->r_unsafe_item);
1648 complete(&req->r_safe_completion);
1649 }
1632 } else if (req->r_err) { 1650 } else if (req->r_err) {
1633 err = req->r_err; 1651 err = req->r_err;
1634 } else { 1652 } else {
diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h
index b1c2025227c5..ee71495e27c4 100644
--- a/fs/ceph/mds_client.h
+++ b/fs/ceph/mds_client.h
@@ -188,6 +188,7 @@ struct ceph_mds_request {
188 struct ceph_msg *r_reply; 188 struct ceph_msg *r_reply;
189 struct ceph_mds_reply_info_parsed r_reply_info; 189 struct ceph_mds_reply_info_parsed r_reply_info;
190 int r_err; 190 int r_err;
191 bool r_aborted;
191 192
192 unsigned long r_timeout; /* optional. jiffies */ 193 unsigned long r_timeout; /* optional. jiffies */
193 unsigned long r_started; /* start time to measure timeout against */ 194 unsigned long r_started; /* start time to measure timeout against */