ceph: prepopulate inodes only when request is aborted
authorSage Weil <sage@inktank.com>
Tue, 29 Jan 2013 07:55:31 +0000 (02:55 -0500)
committerAl Viro <viro@zeniv.linux.org.uk>
Tue, 26 Feb 2013 07:46:08 +0000 (02:46 -0500)
If r_aborted is true, we do not hold the dir i_mutex, and cannot touch
the dcache.  However, we still need to update the inodes with the state
returned by the MDS.

Reported-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Sage Weil <sage@inktank.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/ceph/inode.c

index 2971eaa65cdce9b3b31edca64ea979eeb814ab7a..4bc086a72475e514a1db0c89357174073ee2c615 100644 (file)
@@ -1130,8 +1130,8 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req,
                                            req->r_request_started);
                dout(" final dn %p\n", dn);
                i++;
-       } else if (req->r_op == CEPH_MDS_OP_LOOKUPSNAP ||
-                  req->r_op == CEPH_MDS_OP_MKSNAP) {
+       } else if ((req->r_op == CEPH_MDS_OP_LOOKUPSNAP ||
+                  req->r_op == CEPH_MDS_OP_MKSNAP) && !req->r_aborted) {
                struct dentry *dn = req->r_dentry;
 
                /* fill out a snapdir LOOKUPSNAP dentry */
@@ -1195,6 +1195,39 @@ done:
 /*
  * Prepopulate our cache with readdir results, leases, etc.
  */
+static int readdir_prepopulate_inodes_only(struct ceph_mds_request *req,
+                                          struct ceph_mds_session *session)
+{
+       struct ceph_mds_reply_info_parsed *rinfo = &req->r_reply_info;
+       int i, err = 0;
+
+       for (i = 0; i < rinfo->dir_nr; i++) {
+               struct ceph_vino vino;
+               struct inode *in;
+               int rc;
+
+               vino.ino = le64_to_cpu(rinfo->dir_in[i].in->ino);
+               vino.snap = le64_to_cpu(rinfo->dir_in[i].in->snapid);
+
+               in = ceph_get_inode(req->r_dentry->d_sb, vino);
+               if (IS_ERR(in)) {
+                       err = PTR_ERR(in);
+                       dout("new_inode badness got %d\n", err);
+                       continue;
+               }
+               rc = fill_inode(in, &rinfo->dir_in[i], NULL, session,
+                               req->r_request_started, -1,
+                               &req->r_caps_reservation);
+               if (rc < 0) {
+                       pr_err("fill_inode badness on %p got %d\n", in, rc);
+                       err = rc;
+                       continue;
+               }
+       }
+
+       return err;
+}
+
 int ceph_readdir_prepopulate(struct ceph_mds_request *req,
                             struct ceph_mds_session *session)
 {
@@ -1209,6 +1242,9 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req,
        u64 frag = le32_to_cpu(rhead->args.readdir.frag);
        struct ceph_dentry_info *di;
 
+       if (req->r_aborted)
+               return readdir_prepopulate_inodes_only(req, session);
+
        if (le32_to_cpu(rinfo->head->op) == CEPH_MDS_OP_LSSNAP) {
                snapdir = ceph_get_snapdir(parent->d_inode);
                parent = d_find_alias(snapdir);