Whamcloud - gitweb
LU-5823 clio: add coo_obd_info_get and coo_data_version
[fs/lustre-release.git] / lustre / llite / file.c
index 230a41f..f835a85 100644 (file)
@@ -91,7 +91,6 @@ void ll_pack_inode2opdata(struct inode *inode, struct md_op_data *op_data,
         op_data->op_attr.ia_size = i_size_read(inode);
         op_data->op_attr_blocks = inode->i_blocks;
        op_data->op_attr_flags = ll_inode_to_ext_flags(inode->i_flags);
-        op_data->op_ioepoch = ll_i2info(inode)->lli_ioepoch;
         if (fh)
                 op_data->op_handle = *fh;
         op_data->op_capa1 = ll_mdscapa_get(inode);
@@ -101,8 +100,7 @@ void ll_pack_inode2opdata(struct inode *inode, struct md_op_data *op_data,
 }
 
 /**
- * Closes the IO epoch and packs all the attributes into @op_data for
- * the CLOSE rpc.
+ * Packs all the attributes into @op_data for the CLOSE rpc.
  */
 static void ll_prepare_close(struct inode *inode, struct md_op_data *op_data,
                              struct obd_client_handle *och)
@@ -116,10 +114,7 @@ static void ll_prepare_close(struct inode *inode, struct md_op_data *op_data,
         if (!(och->och_flags & FMODE_WRITE))
                 goto out;
 
-        if (!exp_connect_som(ll_i2mdexp(inode)) || !S_ISREG(inode->i_mode))
-                op_data->op_attr.ia_valid |= ATTR_SIZE | ATTR_BLOCKS;
-        else
-                ll_ioepoch_close(inode, op_data, &och, 0);
+       op_data->op_attr.ia_valid |= ATTR_SIZE | ATTR_BLOCKS;
 
 out:
         ll_pack_inode2opdata(inode, op_data, &och->och_fh);
@@ -137,7 +132,6 @@ static int ll_close_inode_openhandle(struct obd_export *md_exp,
         struct md_op_data *op_data;
         struct ptlrpc_request *req = NULL;
         struct obd_device *obd = class_exp2obd(exp);
-        int epoch_close = 1;
         int rc;
         ENTRY;
 
@@ -163,22 +157,9 @@ static int ll_close_inode_openhandle(struct obd_export *md_exp,
                op_data->op_lease_handle = och->och_lease_handle;
                op_data->op_attr.ia_valid |= ATTR_SIZE | ATTR_BLOCKS;
        }
-        epoch_close = (op_data->op_flags & MF_EPOCH_CLOSE);
+
         rc = md_close(md_exp, op_data, och->och_mod, &req);
-        if (rc == -EAGAIN) {
-                /* This close must have the epoch closed. */
-                LASSERT(epoch_close);
-                /* MDS has instructed us to obtain Size-on-MDS attribute from
-                 * OSTs and send setattr to back to MDS. */
-                rc = ll_som_update(inode, op_data);
-                if (rc) {
-                       CERROR("%s: inode "DFID" mdc Size-on-MDS update"
-                              " failed: rc = %d\n",
-                              ll_i2mdexp(inode)->exp_obd->obd_name,
-                              PFID(ll_inode2fid(inode)), rc);
-                       rc = 0;
-               }
-       } else if (rc) {
+       if (rc) {
                CERROR("%s: inode "DFID" mdc close failed: rc = %d\n",
                       ll_i2mdexp(inode)->exp_obd->obd_name,
                       PFID(ll_inode2fid(inode)), rc);
@@ -205,15 +186,10 @@ static int ll_close_inode_openhandle(struct obd_export *md_exp,
         EXIT;
 out:
 
-        if (exp_connect_som(exp) && !epoch_close &&
-            S_ISREG(inode->i_mode) && (och->och_flags & FMODE_WRITE)) {
-                ll_queue_done_writing(inode, LLIF_DONE_WRITING);
-        } else {
-                md_clear_open_replay_data(md_exp, och);
-                /* Free @och if it is not waiting for DONE_WRITING. */
-                och->och_fh.cookie = DEAD_HANDLE_MAGIC;
-                OBD_FREE_PTR(och);
-        }
+       md_clear_open_replay_data(md_exp, och);
+       och->och_fh.cookie = DEAD_HANDLE_MAGIC;
+       OBD_FREE_PTR(och);
+
         if (req) /* This is close request */
                 ptlrpc_req_finished(req);
         return rc;
@@ -462,20 +438,6 @@ out:
        RETURN(rc);
 }
 
-/**
- * Assign an obtained @ioepoch to client's inode. No lock is needed, MDS does
- * not believe attributes if a few ioepoch holders exist. Attributes for
- * previous ioepoch if new one is opened are also skipped by MDS.
- */
-void ll_ioepoch_open(struct ll_inode_info *lli, __u64 ioepoch)
-{
-        if (ioepoch && lli->lli_ioepoch != ioepoch) {
-                lli->lli_ioepoch = ioepoch;
-                CDEBUG(D_INODE, "Epoch "LPU64" opened on "DFID"\n",
-                       ioepoch, PFID(&lli->lli_fid));
-        }
-}
-
 static int ll_och_fill(struct obd_export *md_exp, struct lookup_intent *it,
                       struct obd_client_handle *och)
 {
@@ -495,25 +457,19 @@ static int ll_och_fill(struct obd_export *md_exp, struct lookup_intent *it,
 static int ll_local_open(struct file *file, struct lookup_intent *it,
                         struct ll_file_data *fd, struct obd_client_handle *och)
 {
-        struct inode *inode = file->f_dentry->d_inode;
-        struct ll_inode_info *lli = ll_i2info(inode);
-        ENTRY;
+       struct inode *inode = file->f_dentry->d_inode;
+       ENTRY;
 
-        LASSERT(!LUSTRE_FPRIVATE(file));
+       LASSERT(!LUSTRE_FPRIVATE(file));
 
-        LASSERT(fd != NULL);
+       LASSERT(fd != NULL);
 
-        if (och) {
-                struct ptlrpc_request *req = it->d.lustre.it_data;
-                struct mdt_body *body;
-                int rc;
+       if (och) {
+               int rc;
 
                rc = ll_och_fill(ll_i2sbi(inode)->ll_md_exp, it, och);
                if (rc != 0)
                        RETURN(rc);
-
-               body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY);
-               ll_ioepoch_open(lli, body->mbo_ioepoch);
        }
 
        LUSTRE_FPRIVATE(file) = fd;
@@ -928,7 +884,7 @@ static int ll_lease_close(struct obd_client_handle *och, struct inode *inode,
 /* Fills the obdo with the attributes for the lsm */
 static int ll_lsm_getattr(struct lov_stripe_md *lsm, struct obd_export *exp,
                          struct obd_capa *capa, struct obdo *obdo,
-                         __u64 ioepoch, int dv_flags)
+                         int dv_flags)
 {
         struct ptlrpc_request_set *set;
         struct obd_info            oinfo = { { { 0 } } };
@@ -942,13 +898,11 @@ static int ll_lsm_getattr(struct lov_stripe_md *lsm, struct obd_export *exp,
         oinfo.oi_oa = obdo;
        oinfo.oi_oa->o_oi = lsm->lsm_oi;
         oinfo.oi_oa->o_mode = S_IFREG;
-        oinfo.oi_oa->o_ioepoch = ioepoch;
         oinfo.oi_oa->o_valid = OBD_MD_FLID | OBD_MD_FLTYPE |
                                OBD_MD_FLSIZE | OBD_MD_FLBLOCKS |
                                OBD_MD_FLBLKSZ | OBD_MD_FLATIME |
                                OBD_MD_FLMTIME | OBD_MD_FLCTIME |
-                               OBD_MD_FLGROUP | OBD_MD_FLEPOCH |
-                               OBD_MD_FLDATAVERSION;
+                              OBD_MD_FLGROUP | OBD_MD_FLDATAVERSION;
         oinfo.oi_capa = capa;
        if (dv_flags & (LL_DV_WR_FLUSH | LL_DV_RD_FLUSH)) {
                oinfo.oi_oa->o_valid |= OBD_MD_FLFLAGS;
@@ -980,35 +934,6 @@ static int ll_lsm_getattr(struct lov_stripe_md *lsm, struct obd_export *exp,
        RETURN(rc);
 }
 
-/**
-  * Performs the getattr on the inode and updates its fields.
-  * If @sync != 0, perform the getattr under the server-side lock.
-  */
-int ll_inode_getattr(struct inode *inode, struct obdo *obdo,
-                     __u64 ioepoch, int sync)
-{
-       struct obd_capa      *capa = ll_mdscapa_get(inode);
-       struct lov_stripe_md *lsm;
-       int rc;
-       ENTRY;
-
-       lsm = ccc_inode_lsm_get(inode);
-       rc = ll_lsm_getattr(lsm, ll_i2dtexp(inode),
-                               capa, obdo, ioepoch, sync ? LL_DV_RD_FLUSH : 0);
-       capa_put(capa);
-       if (rc == 0) {
-               struct ost_id *oi = lsm ? &lsm->lsm_oi : &obdo->o_oi;
-
-               obdo_refresh_inode(inode, obdo, obdo->o_valid);
-               CDEBUG(D_INODE, "objid "DOSTID" size %llu, blocks %llu,"
-                      " blksize %lu\n", POSTID(oi), i_size_read(inode),
-                      (unsigned long long)inode->i_blocks,
-                      1UL << inode->i_blkbits);
-       }
-       ccc_inode_lsm_put(inode, lsm);
-       RETURN(rc);
-}
-
 int ll_merge_attr(const struct lu_env *env, struct inode *inode)
 {
        struct ll_inode_info *lli = ll_i2info(inode);
@@ -1071,7 +996,7 @@ int ll_glimpse_ioctl(struct ll_sb_info *sbi, struct lov_stripe_md *lsm,
         struct obdo obdo = { 0 };
         int rc;
 
-        rc = ll_lsm_getattr(lsm, sbi->ll_dt_exp, NULL, &obdo, 0, 0);
+       rc = ll_lsm_getattr(lsm, sbi->ll_dt_exp, NULL, &obdo, 0);
         if (rc == 0) {
                 st->st_size   = obdo.o_size;
                 st->st_blocks = obdo.o_blocks;
@@ -1137,7 +1062,9 @@ ll_file_io_generic(const struct lu_env *env, struct vvp_io_args *args,
                   struct file *file, enum cl_io_type iot,
                   loff_t *ppos, size_t count)
 {
-       struct ll_inode_info *lli = ll_i2info(file->f_dentry->d_inode);
+       struct inode *inode = file->f_dentry->d_inode;
+       struct ll_inode_info *lli = ll_i2info(inode);
+       loff_t               end;
        struct ll_file_data  *fd  = LUSTRE_FPRIVATE(file);
        struct cl_io         *io;
        ssize_t               result;
@@ -1151,6 +1078,19 @@ restart:
         io = ccc_env_thread_io(env);
         ll_io_init(io, file, iot == CIT_WRITE);
 
+       /* The maximum Lustre file size is variable, based on the
+        * OST maximum object size and number of stripes.  This
+        * needs another check in addition to the VFS checks earlier. */
+       end = (io->u.ci_wr.wr_append ? i_size_read(inode) : *ppos) + count;
+       if (end > ll_file_maxbytes(inode)) {
+               result = -EFBIG;
+               CDEBUG(D_INODE, "%s: file "DFID" offset %llu > maxbytes "LPU64
+                      ": rc = %zd\n", ll_get_fsname(inode->i_sb, NULL, 0),
+                      PFID(&lli->lli_fid), end, ll_file_maxbytes(inode),
+                      result);
+               RETURN(result);
+       }
+
         if (cl_io_rw_init(env, io, iot, *ppos, count) == 0) {
                struct vvp_io *vio = vvp_env_io(env);
                bool range_locked = false;
@@ -1756,43 +1696,34 @@ out:
 /**
  * Get size for inode for which FIEMAP mapping is requested.
  * Make the FIEMAP get_info call and returns the result.
+ * \param fiemap       kernel buffer to hold extens
+ * \param num_bytes    kernel buffer size
  */
-static int ll_do_fiemap(struct inode *inode, struct ll_user_fiemap *fiemap,
+static int ll_do_fiemap(struct inode *inode, struct fiemap *fiemap,
                        size_t num_bytes)
 {
-       struct obd_export *exp = ll_i2dtexp(inode);
-       struct lov_stripe_md *lsm = NULL;
-        struct ll_fiemap_info_key fm_key = { .name = KEY_FIEMAP, };
-       __u32 vallen = num_bytes;
-        int rc;
-        ENTRY;
-
-        /* Checks for fiemap flags */
-        if (fiemap->fm_flags & ~LUSTRE_FIEMAP_FLAGS_COMPAT) {
-                fiemap->fm_flags &= ~LUSTRE_FIEMAP_FLAGS_COMPAT;
-                return -EBADR;
-        }
-
-        /* Check for FIEMAP_FLAG_SYNC */
-        if (fiemap->fm_flags & FIEMAP_FLAG_SYNC) {
-                rc = filemap_fdatawrite(inode->i_mapping);
-                if (rc)
-                        return rc;
-        }
+       struct lu_env                   *env;
+       int                             refcheck;
+       int                             rc = 0;
+       struct ll_fiemap_info_key       fmkey = { .name = KEY_FIEMAP, };
+       ENTRY;
 
-       lsm = ccc_inode_lsm_get(inode);
-       if (lsm == NULL)
-               return -ENOENT;
+       /* Checks for fiemap flags */
+       if (fiemap->fm_flags & ~LUSTRE_FIEMAP_FLAGS_COMPAT) {
+               fiemap->fm_flags &= ~LUSTRE_FIEMAP_FLAGS_COMPAT;
+               return -EBADR;
+       }
 
-       /* If the stripe_count > 1 and the application does not understand
-        * DEVICE_ORDER flag, then it cannot interpret the extents correctly.
-        */
-       if (lsm->lsm_stripe_count > 1 &&
-           !(fiemap->fm_flags & FIEMAP_FLAG_DEVICE_ORDER))
-               GOTO(out, rc = -EOPNOTSUPP);
+       /* Check for FIEMAP_FLAG_SYNC */
+       if (fiemap->fm_flags & FIEMAP_FLAG_SYNC) {
+               rc = filemap_fdatawrite(inode->i_mapping);
+               if (rc)
+                       return rc;
+       }
 
-       fm_key.oa.o_oi = lsm->lsm_oi;
-        fm_key.oa.o_valid = OBD_MD_FLID | OBD_MD_FLGROUP;
+       env = cl_env_get(&refcheck);
+       if (IS_ERR(env))
+               RETURN(PTR_ERR(env));
 
        if (i_size_read(inode) == 0) {
                rc = ll_glimpse_size(inode);
@@ -1800,23 +1731,22 @@ static int ll_do_fiemap(struct inode *inode, struct ll_user_fiemap *fiemap,
                        GOTO(out, rc);
        }
 
-        obdo_from_inode(&fm_key.oa, inode, OBD_MD_FLSIZE);
-        obdo_set_parent_fid(&fm_key.oa, &ll_i2info(inode)->lli_fid);
-        /* If filesize is 0, then there would be no objects for mapping */
-        if (fm_key.oa.o_size == 0) {
-                fiemap->fm_mapped_extents = 0;
-               GOTO(out, rc = 0);
-        }
+       fmkey.oa.o_valid = OBD_MD_FLID | OBD_MD_FLGROUP;
+       obdo_from_inode(&fmkey.oa, inode, OBD_MD_FLSIZE);
+       obdo_set_parent_fid(&fmkey.oa, &ll_i2info(inode)->lli_fid);
 
-        memcpy(&fm_key.fiemap, fiemap, sizeof(*fiemap));
+       /* If filesize is 0, then there would be no objects for mapping */
+       if (fmkey.oa.o_size == 0) {
+               fiemap->fm_mapped_extents = 0;
+               GOTO(out, rc = 0);
+       }
 
-        rc = obd_get_info(NULL, exp, sizeof(fm_key), &fm_key, &vallen,
-                          fiemap, lsm);
-        if (rc)
-                CERROR("obd_get_info failed: rc = %d\n", rc);
+       fmkey.fiemap = *fiemap;
 
+       rc = cl_object_fiemap(env, ll_i2info(inode)->lli_clob,
+                             &fmkey, fiemap, &num_bytes);
 out:
-       ccc_inode_lsm_put(inode, lsm);
+       cl_env_put(env, &refcheck);
        RETURN(rc);
 }
 
@@ -1863,60 +1793,59 @@ gf_free:
        RETURN(rc);
 }
 
-static int ll_ioctl_fiemap(struct inode *inode, unsigned long arg)
+static int ll_ioctl_fiemap(struct inode *inode, struct fiemap __user *arg)
 {
-        struct ll_user_fiemap *fiemap_s;
-        size_t num_bytes, ret_bytes;
-        unsigned int extent_count;
-        int rc = 0;
+       struct fiemap   *fiemap;
+       size_t          num_bytes;
+       size_t          ret_bytes;
+       __u32           extent_count;
+       int             rc = 0;
 
-        /* Get the extent count so we can calculate the size of
-         * required fiemap buffer */
-        if (get_user(extent_count,
-            &((struct ll_user_fiemap __user *)arg)->fm_extent_count))
-                RETURN(-EFAULT);
+       /* Get the extent count so we can calculate the size of
+        * required fiemap buffer */
+       if (get_user(extent_count, &arg->fm_extent_count))
+               RETURN(-EFAULT);
 
        if (extent_count >=
-           (SIZE_MAX - sizeof(*fiemap_s)) / sizeof(struct ll_fiemap_extent))
+           (SIZE_MAX - sizeof(*fiemap)) / sizeof(struct ll_fiemap_extent))
                RETURN(-EINVAL);
-        num_bytes = sizeof(*fiemap_s) + (extent_count *
-                                         sizeof(struct ll_fiemap_extent));
+       num_bytes = sizeof(*fiemap) + (extent_count *
+                                      sizeof(struct ll_fiemap_extent));
 
-        OBD_ALLOC_LARGE(fiemap_s, num_bytes);
-        if (fiemap_s == NULL)
-                RETURN(-ENOMEM);
+       OBD_ALLOC_LARGE(fiemap, num_bytes);
+       if (fiemap == NULL)
+               RETURN(-ENOMEM);
 
        /* get the fiemap value */
-       if (copy_from_user(fiemap_s, (struct ll_user_fiemap __user *)arg,
-                          sizeof(*fiemap_s)))
+       if (copy_from_user(fiemap, arg, sizeof(*fiemap)))
                GOTO(error, rc = -EFAULT);
 
-        /* If fm_extent_count is non-zero, read the first extent since
-         * it is used to calculate end_offset and device from previous
-         * fiemap call. */
-        if (extent_count) {
-                if (copy_from_user(&fiemap_s->fm_extents[0],
-                    (char __user *)arg + sizeof(*fiemap_s),
-                    sizeof(struct ll_fiemap_extent)))
-                        GOTO(error, rc = -EFAULT);
-        }
+       /* If fm_extent_count is non-zero, read the first extent since
+        * it is used to calculate end_offset and device from previous
+        * fiemap call. */
+       if (extent_count != 0) {
+               if (copy_from_user(&fiemap->fm_extents[0],
+                                  (char __user *)arg + sizeof(*fiemap),
+                                  sizeof(struct ll_fiemap_extent)))
+                       GOTO(error, rc = -EFAULT);
+       }
 
-        rc = ll_do_fiemap(inode, fiemap_s, num_bytes);
-        if (rc)
-                GOTO(error, rc);
+       rc = ll_do_fiemap(inode, fiemap, num_bytes);
+       if (rc)
+               GOTO(error, rc);
 
-        ret_bytes = sizeof(struct ll_user_fiemap);
+       ret_bytes = sizeof(struct fiemap);
 
-        if (extent_count != 0)
-                ret_bytes += (fiemap_s->fm_mapped_extents *
-                                 sizeof(struct ll_fiemap_extent));
+       if (extent_count != 0)
+               ret_bytes += (fiemap->fm_mapped_extents *
+                                sizeof(struct ll_fiemap_extent));
 
-       if (copy_to_user((void __user *)arg, fiemap_s, ret_bytes))
+       if (copy_to_user((void __user *)arg, fiemap, ret_bytes))
                rc = -EFAULT;
 
 error:
-        OBD_FREE_LARGE(fiemap_s, num_bytes);
-        RETURN(rc);
+       OBD_FREE_LARGE(fiemap, num_bytes);
+       RETURN(rc);
 }
 
 /*
@@ -1925,43 +1854,31 @@ error:
  * This value is computed using stripe object version on OST.
  * Version is computed using server side locking.
  *
- * @param sync if do sync on the OST side;
+ * @param flags if do sync on the OST side;
  *             0: no sync
  *             LL_DV_RD_FLUSH: flush dirty pages, LCK_PR on OSTs
  *             LL_DV_WR_FLUSH: drop all caching pages, LCK_PW on OSTs
  */
 int ll_data_version(struct inode *inode, __u64 *data_version, int flags)
 {
-       struct lov_stripe_md    *lsm = NULL;
-       struct ll_sb_info       *sbi = ll_i2sbi(inode);
-       struct obdo             *obdo = NULL;
-       int                      rc;
+       struct lu_env   *env;
+       int             refcheck;
+       int             rc;
        ENTRY;
 
-       /* If no stripe, we consider version is 0. */
-       lsm = ccc_inode_lsm_get(inode);
-       if (!lsm_has_objects(lsm)) {
+       /* If no file object initialized, we consider its version is 0. */
+       if (ll_i2info(inode)->lli_clob == NULL) {
                *data_version = 0;
-               CDEBUG(D_INODE, "No object for inode\n");
-               GOTO(out, rc = 0);
+               RETURN(0);
        }
 
-       OBD_ALLOC_PTR(obdo);
-       if (obdo == NULL)
-               GOTO(out, rc = -ENOMEM);
-
-       rc = ll_lsm_getattr(lsm, sbi->ll_dt_exp, NULL, obdo, 0, flags);
-       if (rc == 0) {
-               if (!(obdo->o_valid & OBD_MD_FLDATAVERSION))
-                       rc = -EOPNOTSUPP;
-               else
-                       *data_version = obdo->o_data_version;
-       }
+       env = cl_env_get(&refcheck);
+       if (IS_ERR(env))
+               RETURN(PTR_ERR(env));
 
-       OBD_FREE_PTR(obdo);
-       EXIT;
-out:
-       ccc_inode_lsm_put(inode, lsm);
+       rc = cl_object_data_version(env, ll_i2info(inode)->lli_clob,
+                                   data_version, flags);
+       cl_env_put(env, &refcheck);
        RETURN(rc);
 }
 
@@ -2177,6 +2094,11 @@ static int ll_hsm_state_set(struct inode *inode, struct hsm_state_set *hss)
 {
        struct md_op_data       *op_data;
        int                      rc;
+       ENTRY;
+
+       /* Detect out-of range masks */
+       if ((hss->hss_setmask | hss->hss_clearmask) & ~HSM_FLAGS_MASK)
+               RETURN(-EINVAL);
 
        /* Non-root users are forbidden to set or clear flags which are
         * NOT defined in HSM_USER_MASK. */
@@ -2184,6 +2106,11 @@ static int ll_hsm_state_set(struct inode *inode, struct hsm_state_set *hss)
            !cfs_capable(CFS_CAP_SYS_ADMIN))
                RETURN(-EPERM);
 
+       /* Detect out-of range archive id */
+       if ((hss->hss_valid & HSS_ARCHIVE_ID) &&
+           (hss->hss_archive_id > LL_HSM_MAX_ARCHIVE))
+               RETURN(-EINVAL);
+
        op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, 0,
                                     LUSTRE_OPC_ANY, hss);
        if (IS_ERR(op_data))
@@ -2333,8 +2260,8 @@ ll_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        case LL_IOC_LOV_GETSTRIPE:
                RETURN(ll_file_getstripe(inode,
                                         (struct lov_user_md __user *)arg));
-        case FSFILT_IOC_FIEMAP:
-                RETURN(ll_ioctl_fiemap(inode, arg));
+       case FSFILT_IOC_FIEMAP:
+               RETURN(ll_ioctl_fiemap(inode, (struct fiemap __user *)arg));
         case FSFILT_IOC_GETFLAGS:
         case FSFILT_IOC_SETFLAGS:
                 RETURN(ll_iocontrol(inode, file, cmd, arg));
@@ -3030,11 +2957,14 @@ int ll_migrate(struct inode *parent, struct file *file, int mdtidx,
        qstr.name = name;
        qstr.len = namelen;
        dchild = d_lookup(file->f_dentry, &qstr);
-       if (dchild != NULL && dchild->d_inode != NULL) {
-               op_data->op_fid3 = *ll_inode2fid(dchild->d_inode);
+       if (dchild != NULL) {
                if (dchild->d_inode != NULL) {
                        child_inode = igrab(dchild->d_inode);
-                       ll_invalidate_aliases(child_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 {
@@ -3075,6 +3005,7 @@ int ll_migrate(struct inode *parent, struct file *file, int mdtidx,
 out_free:
        if (child_inode != NULL) {
                clear_nlink(child_inode);
+               mutex_unlock(&child_inode->i_mutex);
                iput(child_inode);
        }