Whamcloud - gitweb
LU-6475 mdt: race between open and migrate
[fs/lustre-release.git] / lustre / llite / file.c
index 97ad193..f71cfb2 100644 (file)
@@ -2901,7 +2901,8 @@ ll_file_flock(struct file *file, int cmd, struct file_lock *file_lock)
 }
 
 int ll_get_fid_by_name(struct inode *parent, const char *name,
-                      int namelen, struct lu_fid *fid)
+                      int namelen, struct lu_fid *fid,
+                      struct inode **inode)
 {
        struct md_op_data       *op_data = NULL;
        struct mdt_body         *body;
@@ -2914,7 +2915,7 @@ int ll_get_fid_by_name(struct inode *parent, const char *name,
        if (IS_ERR(op_data))
                RETURN(PTR_ERR(op_data));
 
-       op_data->op_valid = OBD_MD_FLID;
+       op_data->op_valid = OBD_MD_FLID | OBD_MD_FLTYPE;
        rc = md_getattr_name(ll_i2sbi(parent)->ll_md_exp, op_data, &req);
        ll_finish_md_op_data(op_data);
        if (rc < 0)
@@ -2925,6 +2926,9 @@ int ll_get_fid_by_name(struct inode *parent, const char *name,
                GOTO(out_req, rc = -EFAULT);
        if (fid != NULL)
                *fid = body->mbo_fid1;
+
+       if (inode != NULL)
+               rc = ll_prep_inode(inode, req, parent->i_sb, NULL);
 out_req:
        ptlrpc_req_finished(req);
        RETURN(rc);
@@ -2937,8 +2941,11 @@ int ll_migrate(struct inode *parent, struct file *file, int mdtidx,
        struct inode          *child_inode = NULL;
        struct md_op_data     *op_data;
        struct ptlrpc_request *request = NULL;
+       struct obd_client_handle *och = NULL;
        struct qstr           qstr;
+       struct mdt_body         *body;
        int                    rc;
+       __u64                   data_version = 0;
        ENTRY;
 
        CDEBUG(D_VFSTRACE, "migrate %s under "DFID" to MDT%04x\n",
@@ -2955,22 +2962,23 @@ int ll_migrate(struct inode *parent, struct file *file, int mdtidx,
        qstr.len = namelen;
        dchild = d_lookup(file->f_path.dentry, &qstr);
        if (dchild != NULL) {
-               if (dchild->d_inode != NULL) {
+               if (dchild->d_inode != NULL)
                        child_inode = igrab(dchild->d_inode);
-                       if (child_inode != NULL) {
-                               mutex_lock(&child_inode->i_mutex);
-                               op_data->op_fid3 = *ll_inode2fid(child_inode);
-                               ll_invalidate_aliases(child_inode);
-                       }
-               }
                dput(dchild);
-       } else {
+       }
+
+       if (child_inode == NULL) {
                rc = ll_get_fid_by_name(parent, name, namelen,
-                                       &op_data->op_fid3);
+                                       &op_data->op_fid3, &child_inode);
                if (rc != 0)
                        GOTO(out_free, rc);
        }
 
+       if (child_inode == NULL)
+               GOTO(out_free, rc = -EINVAL);
+
+       mutex_lock(&child_inode->i_mutex);
+       op_data->op_fid3 = *ll_inode2fid(child_inode);
        if (!fid_is_sane(&op_data->op_fid3)) {
                CERROR("%s: migrate %s , but fid "DFID" is insane\n",
                       ll_get_fsname(parent->i_sb, NULL, 0), name,
@@ -2987,6 +2995,26 @@ int ll_migrate(struct inode *parent, struct file *file, int mdtidx,
                       PFID(&op_data->op_fid3), mdtidx);
                GOTO(out_free, rc = 0);
        }
+again:
+       if (S_ISREG(child_inode->i_mode)) {
+               och = ll_lease_open(child_inode, NULL, FMODE_WRITE, 0);
+               if (IS_ERR(och)) {
+                       rc = PTR_ERR(och);
+                       och = NULL;
+                       GOTO(out_free, rc);
+               }
+
+               rc = ll_data_version(child_inode, &data_version,
+                                    LL_DV_WR_FLUSH);
+               if (rc != 0)
+                       GOTO(out_free, rc);
+
+               op_data->op_handle = och->och_fh;
+               op_data->op_data = och->och_mod;
+               op_data->op_data_version = data_version;
+               op_data->op_lease_handle = och->och_lease_handle;
+               op_data->op_bias |= MDS_RENAME_MIGRATE;
+       }
 
        op_data->op_mds = mdtidx;
        op_data->op_cli_flags = CLI_MIGRATE;
@@ -2995,12 +3023,28 @@ int ll_migrate(struct inode *parent, struct file *file, int mdtidx,
        if (rc == 0)
                ll_update_times(request, parent);
 
-       ptlrpc_req_finished(request);
-       if (rc != 0)
-               GOTO(out_free, rc);
+       body = req_capsule_server_get(&request->rq_pill, &RMF_MDT_BODY);
+       if (body == NULL)
+               GOTO(out_free, rc = -EPROTO);
+
+       /* If the server does release layout lock, then we cleanup
+        * the client och here, otherwise release it in out_free: */
+       if (och != NULL && body->mbo_valid & OBD_MD_CLOSE_INTENT_EXECED) {
+               obd_mod_put(och->och_mod);
+               md_clear_open_replay_data(ll_i2sbi(parent)->ll_md_exp, och);
+               och->och_fh.cookie = DEAD_HANDLE_MAGIC;
+               OBD_FREE_PTR(och);
+               och = NULL;
+       }
 
+       ptlrpc_req_finished(request);
+       /* Try again if the file layout has changed. */
+       if (rc == -EAGAIN && S_ISREG(child_inode->i_mode))
+               goto again;
 out_free:
        if (child_inode != NULL) {
+               if (och != NULL) /* close the file */
+                       ll_lease_close(och, child_inode, NULL);
                clear_nlink(child_inode);
                mutex_unlock(&child_inode->i_mutex);
                iput(child_inode);