summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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,
}
if (rinfo->head->is_dentry) {
+ struct inode *dir = req->r_locked_dir;
+
+ err = fill_inode(dir, &rinfo->diri, rinfo->dirfrag,
+ session, req->r_request_started, -1,
+ &req->r_caps_reservation);
+ if (err < 0)
+ return err;
+ }
+
+ if (rinfo->head->is_dentry && !req->r_aborted) {
/*
* lookup link rename : null -> possibly existing inode
* mknod symlink mkdir : null -> new inode
@@ -932,12 +942,6 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req,
BUG_ON(ceph_snap(dir) !=
le64_to_cpu(rinfo->diri.in->snapid));
- err = fill_inode(dir, &rinfo->diri, rinfo->dirfrag,
- session, req->r_request_started, -1,
- &req->r_caps_reservation);
- if (err < 0)
- return err;
-
/* do we have a lease on the whole dir? */
have_dir_cap =
(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,
err = PTR_ERR(req->r_reply);
req->r_reply = NULL;
- /* clean up */
- __unregister_request(mdsc, req);
- if (!list_empty(&req->r_unsafe_item))
- list_del_init(&req->r_unsafe_item);
- complete(&req->r_safe_completion);
+ if (err == -ERESTARTSYS) {
+ /* aborted */
+ req->r_aborted = true;
+
+ if (req->r_locked_dir &&
+ (req->r_op & CEPH_MDS_OP_WRITE)) {
+ struct ceph_inode_info *ci =
+ ceph_inode(req->r_locked_dir);
+
+ dout("aborted, clearing I_COMPLETE on %p\n",
+ req->r_locked_dir);
+ spin_lock(&req->r_locked_dir->i_lock);
+ ci->i_ceph_flags &= ~CEPH_I_COMPLETE;
+ ci->i_release_count++;
+ spin_unlock(&req->r_locked_dir->i_lock);
+ }
+ } else {
+ /* clean up this request */
+ __unregister_request(mdsc, req);
+ if (!list_empty(&req->r_unsafe_item))
+ list_del_init(&req->r_unsafe_item);
+ complete(&req->r_safe_completion);
+ }
} else if (req->r_err) {
err = req->r_err;
} 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 {
struct ceph_msg *r_reply;
struct ceph_mds_reply_info_parsed r_reply_info;
int r_err;
+ bool r_aborted;
unsigned long r_timeout; /* optional. jiffies */
unsigned long r_started; /* start time to measure timeout against */