Whamcloud - gitweb
Revert "LU-3544 nfs: writing to new files will return ENOENT"
[fs/lustre-release.git] / lustre / llite / file.c
index 83476bd..869998f 100644 (file)
@@ -344,17 +344,17 @@ int ll_file_release(struct inode *inode, struct file *file)
                inode->i_generation, inode);
 
 #ifdef CONFIG_FS_POSIX_ACL
-        if (sbi->ll_flags & LL_SBI_RMT_CLIENT &&
-            inode == inode->i_sb->s_root->d_inode) {
-                struct ll_file_data *fd = LUSTRE_FPRIVATE(file);
-
-                LASSERT(fd != NULL);
-                if (unlikely(fd->fd_flags & LL_FILE_RMTACL)) {
-                        fd->fd_flags &= ~LL_FILE_RMTACL;
-                        rct_del(&sbi->ll_rct, cfs_curproc_pid());
-                        et_search_free(&sbi->ll_et, cfs_curproc_pid());
-                }
-        }
+       if (sbi->ll_flags & LL_SBI_RMT_CLIENT &&
+           inode == inode->i_sb->s_root->d_inode) {
+               struct ll_file_data *fd = LUSTRE_FPRIVATE(file);
+
+               LASSERT(fd != NULL);
+               if (unlikely(fd->fd_flags & LL_FILE_RMTACL)) {
+                       fd->fd_flags &= ~LL_FILE_RMTACL;
+                       rct_del(&sbi->ll_rct, current_pid());
+                       et_search_free(&sbi->ll_et, current_pid());
+               }
+       }
 #endif
 
         if (inode->i_sb->s_root != file->f_dentry)
@@ -393,6 +393,8 @@ static int ll_intent_file_open(struct file *file, void *lmm,
 {
         struct ll_sb_info *sbi = ll_i2sbi(file->f_dentry->d_inode);
         struct dentry *parent = file->f_dentry->d_parent;
+        const char *name = file->f_dentry->d_name.name;
+        const int len = file->f_dentry->d_name.len;
         struct md_op_data *op_data;
         struct ptlrpc_request *req;
         __u32 opc = LUSTRE_OPC_ANY;
@@ -417,10 +419,9 @@ static int ll_intent_file_open(struct file *file, void *lmm,
                         opc = LUSTRE_OPC_CREATE;
         }
 
-       op_data  = ll_prep_md_op_data(NULL, parent->d_inode,
-                                     file->f_dentry->d_inode, NULL, 0,
-                                     O_RDWR, opc, NULL);
-
+        op_data  = ll_prep_md_op_data(NULL, parent->d_inode,
+                                      file->f_dentry->d_inode, name, len,
+                                      O_RDWR, opc, NULL);
         if (IS_ERR(op_data))
                 RETURN(PTR_ERR(op_data));
 
@@ -562,7 +563,7 @@ int ll_file_open(struct inode *inode, struct file *file)
                if (lli->lli_opendir_key == NULL && lli->lli_sai == NULL &&
                    lli->lli_opendir_pid == 0) {
                        lli->lli_opendir_key = fd;
-                       lli->lli_opendir_pid = cfs_curproc_pid();
+                       lli->lli_opendir_pid = current_pid();
                        opendir_set = 1;
                }
                spin_unlock(&lli->lli_sa_lock);
@@ -864,20 +865,24 @@ struct obd_client_handle *ll_lease_open(struct inode *inode, struct file *file,
        RETURN(och);
 
 out_close:
-       rc2 = ll_close_inode_openhandle(sbi->ll_md_exp, inode, och, NULL);
-       if (rc2)
-               CERROR("Close openhandle returned %d\n", rc2);
-
-       /* cancel open lock */
+       /* Cancel open lock */
        if (it.d.lustre.it_lock_mode != 0) {
                ldlm_lock_decref_and_cancel(&och->och_lease_handle,
-                                               it.d.lustre.it_lock_mode);
+                                           it.d.lustre.it_lock_mode);
                it.d.lustre.it_lock_mode = 0;
+               och->och_lease_handle.cookie = 0ULL;
        }
+       rc2 = ll_close_inode_openhandle(sbi->ll_md_exp, inode, och, NULL);
+       if (rc2 < 0)
+               CERROR("%s: error closing file "DFID": %d\n",
+                      ll_get_fsname(inode->i_sb, NULL, 0),
+                      PFID(&ll_i2info(inode)->lli_fid), rc2);
+       och = NULL; /* och has been freed in ll_close_inode_openhandle() */
 out_release_it:
        ll_intent_release(&it);
 out:
-       OBD_FREE_PTR(och);
+       if (och != NULL)
+               OBD_FREE_PTR(och);
        RETURN(ERR_PTR(rc));
 }
 EXPORT_SYMBOL(ll_lease_open);
@@ -899,7 +904,7 @@ int ll_lease_close(struct obd_client_handle *och, struct inode *inode,
                lock_res_and_lock(lock);
                cancelled = ldlm_is_cancel(lock);
                unlock_res_and_lock(lock);
-               ldlm_lock_put(lock);
+               LDLM_LOCK_PUT(lock);
        }
 
        CDEBUG(D_INODE, "lease for "DFID" broken? %d\n",
@@ -918,8 +923,8 @@ EXPORT_SYMBOL(ll_lease_close);
 
 /* 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 sync)
+                         struct obd_capa *capa, struct obdo *obdo,
+                         __u64 ioepoch, int dv_flags)
 {
         struct ptlrpc_request_set *set;
         struct obd_info            oinfo = { { { 0 } } };
@@ -941,10 +946,12 @@ static int ll_lsm_getattr(struct lov_stripe_md *lsm, struct obd_export *exp,
                                OBD_MD_FLGROUP | OBD_MD_FLEPOCH |
                                OBD_MD_FLDATAVERSION;
         oinfo.oi_capa = capa;
-        if (sync) {
-                oinfo.oi_oa->o_valid |= OBD_MD_FLFLAGS;
-                oinfo.oi_oa->o_flags |= OBD_FL_SRVLOCK;
-        }
+       if (dv_flags & (LL_DV_WR_FLUSH | LL_DV_RD_FLUSH)) {
+               oinfo.oi_oa->o_valid |= OBD_MD_FLFLAGS;
+               oinfo.oi_oa->o_flags |= OBD_FL_SRVLOCK;
+               if (dv_flags & LL_DV_WR_FLUSH)
+                       oinfo.oi_oa->o_flags |= OBD_FL_FLUSH;
+       }
 
         set = ptlrpc_prep_set();
         if (set == NULL) {
@@ -956,12 +963,17 @@ static int ll_lsm_getattr(struct lov_stripe_md *lsm, struct obd_export *exp,
                         rc = ptlrpc_set_wait(set);
                 ptlrpc_set_destroy(set);
         }
-        if (rc == 0)
-                oinfo.oi_oa->o_valid &= (OBD_MD_FLBLOCKS | OBD_MD_FLBLKSZ |
-                                         OBD_MD_FLATIME | OBD_MD_FLMTIME |
-                                         OBD_MD_FLCTIME | OBD_MD_FLSIZE |
-                                         OBD_MD_FLDATAVERSION);
-        RETURN(rc);
+       if (rc == 0) {
+               oinfo.oi_oa->o_valid &= (OBD_MD_FLBLOCKS | OBD_MD_FLBLKSZ |
+                                        OBD_MD_FLATIME | OBD_MD_FLMTIME |
+                                        OBD_MD_FLCTIME | OBD_MD_FLSIZE |
+                                        OBD_MD_FLDATAVERSION | OBD_MD_FLFLAGS);
+               if (dv_flags & LL_DV_WR_FLUSH &&
+                   !(oinfo.oi_oa->o_valid & OBD_MD_FLFLAGS &&
+                     oinfo.oi_oa->o_flags & OBD_FL_FLUSH))
+                       RETURN(-ENOTSUPP);
+       }
+       RETURN(rc);
 }
 
 /**
@@ -978,7 +990,7 @@ int ll_inode_getattr(struct inode *inode, struct obdo *obdo,
 
        lsm = ccc_inode_lsm_get(inode);
        rc = ll_lsm_getattr(lsm, ll_i2dtexp(inode),
-                           capa, obdo, ioepoch, sync);
+                               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;
@@ -1055,6 +1067,33 @@ int ll_glimpse_ioctl(struct ll_sb_info *sbi, struct lov_stripe_md *lsm,
         return rc;
 }
 
+static bool file_is_noatime(const struct file *file)
+{
+       const struct vfsmount *mnt = file->f_path.mnt;
+       const struct inode *inode = file->f_path.dentry->d_inode;
+
+       /* Adapted from file_accessed() and touch_atime().*/
+       if (file->f_flags & O_NOATIME)
+               return true;
+
+       if (inode->i_flags & S_NOATIME)
+               return true;
+
+       if (IS_NOATIME(inode))
+               return true;
+
+       if (mnt->mnt_flags & (MNT_NOATIME | MNT_READONLY))
+               return true;
+
+       if ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode))
+               return true;
+
+       if ((inode->i_sb->s_flags & MS_NODIRATIME) && S_ISDIR(inode->i_mode))
+               return true;
+
+       return false;
+}
+
 void ll_io_init(struct cl_io *io, const struct file *file, int write)
 {
         struct inode *inode = file->f_dentry->d_inode;
@@ -1074,6 +1113,8 @@ void ll_io_init(struct cl_io *io, const struct file *file, int write)
         } else if (file->f_flags & O_APPEND) {
                 io->ci_lockreq = CILR_MANDATORY;
         }
+
+       io->ci_noatime = file_is_noatime(file);
 }
 
 static ssize_t
@@ -1432,7 +1473,8 @@ static int ll_lov_recreate_fid(struct inode *inode, unsigned long arg)
 }
 
 int ll_lov_setstripe_ea_info(struct inode *inode, struct file *file,
-                             int flags, struct lov_user_md *lum, int lum_size)
+                             __u64  flags, struct lov_user_md *lum,
+                            int lum_size)
 {
        struct lov_stripe_md *lsm = NULL;
        struct lookup_intent oit = {.it_op = IT_OPEN, .it_flags = flags};
@@ -1554,7 +1596,7 @@ out:
 static int ll_lov_setea(struct inode *inode, struct file *file,
                             unsigned long arg)
 {
-       int                      flags = MDS_OPEN_HAS_OBJS | FMODE_WRITE;
+       __u64                    flags = MDS_OPEN_HAS_OBJS | FMODE_WRITE;
        struct lov_user_md      *lump;
        int                      lum_size = sizeof(struct lov_user_md) +
                                            sizeof(struct lov_user_ost_data);
@@ -1587,7 +1629,7 @@ static int ll_lov_setstripe(struct inode *inode, struct file *file,
        struct lov_user_md_v1   *lumv1p = (struct lov_user_md_v1 *)arg;
        struct lov_user_md_v3   *lumv3p = (struct lov_user_md_v3 *)arg;
        int                      lum_size, rc;
-       int                      flags = FMODE_WRITE;
+       __u64                    flags = FMODE_WRITE;
        ENTRY;
 
        /* first try with v1 which is smaller than v3 */
@@ -1911,11 +1953,12 @@ error:
  * This value is computed using stripe object version on OST.
  * Version is computed using server side locking.
  *
- * @param extent_lock  Take extent lock. Not needed if a process is already
- *                    holding the OST object group locks.
+ * @param sync 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 extent_lock)
+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);
@@ -1935,7 +1978,7 @@ int ll_data_version(struct inode *inode, __u64 *data_version,
        if (obdo == NULL)
                GOTO(out, rc = -ENOMEM);
 
-       rc = ll_lsm_getattr(lsm, sbi->ll_dt_exp, NULL, obdo, 0, extent_lock);
+       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;
@@ -1971,7 +2014,7 @@ int ll_hsm_release(struct inode *inode)
                GOTO(out, rc = PTR_ERR(och));
 
        /* Grab latest data_version and [am]time values */
-       rc = ll_data_version(inode, &data_version, 1);
+       rc = ll_data_version(inode, &data_version, LL_DV_WR_FLUSH);
        if (rc != 0)
                GOTO(out, rc);
 
@@ -2158,6 +2201,86 @@ free:
        RETURN(rc);
 }
 
+static int ll_hsm_state_set(struct inode *inode, struct hsm_state_set *hss)
+{
+       struct md_op_data       *op_data;
+       int                      rc;
+
+       /* Non-root users are forbidden to set or clear flags which are
+        * NOT defined in HSM_USER_MASK. */
+       if (((hss->hss_setmask | hss->hss_clearmask) & ~HSM_USER_MASK) &&
+           !cfs_capable(CFS_CAP_SYS_ADMIN))
+               RETURN(-EPERM);
+
+       op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, 0,
+                                    LUSTRE_OPC_ANY, hss);
+       if (IS_ERR(op_data))
+               RETURN(PTR_ERR(op_data));
+
+       rc = obd_iocontrol(LL_IOC_HSM_STATE_SET, ll_i2mdexp(inode),
+                          sizeof(*op_data), op_data, NULL);
+
+       ll_finish_md_op_data(op_data);
+
+       RETURN(rc);
+}
+
+static int ll_hsm_import(struct inode *inode, struct file *file,
+                        struct hsm_user_import *hui)
+{
+       struct hsm_state_set    *hss = NULL;
+       struct iattr            *attr = NULL;
+       int                      rc;
+       ENTRY;
+
+       if (!S_ISREG(inode->i_mode))
+               RETURN(-EINVAL);
+
+       /* set HSM flags */
+       OBD_ALLOC_PTR(hss);
+       if (hss == NULL)
+               GOTO(out, rc = -ENOMEM);
+
+       hss->hss_valid = HSS_SETMASK | HSS_ARCHIVE_ID;
+       hss->hss_archive_id = hui->hui_archive_id;
+       hss->hss_setmask = HS_ARCHIVED | HS_EXISTS | HS_RELEASED;
+       rc = ll_hsm_state_set(inode, hss);
+       if (rc != 0)
+               GOTO(out, rc);
+
+       OBD_ALLOC_PTR(attr);
+       if (attr == NULL)
+               GOTO(out, rc = -ENOMEM);
+
+       attr->ia_mode = hui->hui_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
+       attr->ia_mode |= S_IFREG;
+       attr->ia_uid = hui->hui_uid;
+       attr->ia_gid = hui->hui_gid;
+       attr->ia_size = hui->hui_size;
+       attr->ia_mtime.tv_sec = hui->hui_mtime;
+       attr->ia_mtime.tv_nsec = hui->hui_mtime_ns;
+       attr->ia_atime.tv_sec = hui->hui_atime;
+       attr->ia_atime.tv_nsec = hui->hui_atime_ns;
+
+       attr->ia_valid = ATTR_SIZE | ATTR_MODE | ATTR_FORCE |
+                        ATTR_UID | ATTR_GID |
+                        ATTR_MTIME | ATTR_MTIME_SET |
+                        ATTR_ATIME | ATTR_ATIME_SET;
+
+       rc = ll_setattr_raw(file->f_dentry, attr, true);
+       if (rc == -ENODATA)
+               rc = 0;
+
+out:
+       if (hss != NULL)
+               OBD_FREE_PTR(hss);
+
+       if (attr != NULL)
+               OBD_FREE_PTR(attr);
+
+       RETURN(rc);
+}
+
 long ll_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
        struct inode            *inode = file->f_dentry->d_inode;
@@ -2264,13 +2387,13 @@ long ll_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                RETURN(ll_fid2path(inode, (void *)arg));
        case LL_IOC_DATA_VERSION: {
                struct ioc_data_version idv;
-               int                     rc;
+               int rc;
 
                if (copy_from_user(&idv, (char *)arg, sizeof(idv)))
                        RETURN(-EFAULT);
 
-               rc = ll_data_version(inode, &idv.idv_version,
-                               !(idv.idv_flags & LL_DV_NOFLUSH));
+               idv.idv_flags &= LL_DV_RD_FLUSH | LL_DV_WR_FLUSH;
+               rc = ll_data_version(inode, &idv.idv_version, idv.idv_flags);
 
                if (rc == 0 && copy_to_user((char *) arg, &idv, sizeof(idv)))
                        RETURN(-EFAULT);
@@ -2320,37 +2443,19 @@ long ll_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                RETURN(rc);
        }
        case LL_IOC_HSM_STATE_SET: {
-               struct md_op_data       *op_data;
                struct hsm_state_set    *hss;
                int                      rc;
 
                OBD_ALLOC_PTR(hss);
                if (hss == NULL)
                        RETURN(-ENOMEM);
+
                if (copy_from_user(hss, (char *)arg, sizeof(*hss))) {
                        OBD_FREE_PTR(hss);
                        RETURN(-EFAULT);
                }
 
-               /* Non-root users are forbidden to set or clear flags which are
-                * NOT defined in HSM_USER_MASK. */
-               if (((hss->hss_setmask | hss->hss_clearmask) & ~HSM_USER_MASK)
-                   && !cfs_capable(CFS_CAP_SYS_ADMIN)) {
-                       OBD_FREE_PTR(hss);
-                       RETURN(-EPERM);
-               }
-
-               op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, 0,
-                                            LUSTRE_OPC_ANY, hss);
-               if (IS_ERR(op_data)) {
-                       OBD_FREE_PTR(hss);
-                       RETURN(PTR_ERR(op_data));
-               }
-
-               rc = obd_iocontrol(cmd, ll_i2mdexp(inode), sizeof(*op_data),
-                                  op_data, NULL);
-
-               ll_finish_md_op_data(op_data);
+               rc = ll_hsm_state_set(inode, hss);
 
                OBD_FREE_PTR(hss);
                RETURN(rc);
@@ -2458,11 +2563,27 @@ long ll_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                                        rc = och->och_flags &
                                                (FMODE_READ | FMODE_WRITE);
                                unlock_res_and_lock(lock);
-                               ldlm_lock_put(lock);
+                               LDLM_LOCK_PUT(lock);
                        }
                }
                mutex_unlock(&lli->lli_och_mutex);
+               RETURN(rc);
+       }
+       case LL_IOC_HSM_IMPORT: {
+               struct hsm_user_import *hui;
 
+               OBD_ALLOC_PTR(hui);
+               if (hui == NULL)
+                       RETURN(-ENOMEM);
+
+               if (copy_from_user(hui, (void *)arg, sizeof(*hui))) {
+                       OBD_FREE_PTR(hui);
+                       RETURN(-EFAULT);
+               }
+
+               rc = ll_hsm_import(inode, file, hui);
+
+               OBD_FREE_PTR(hui);
                RETURN(rc);
        }
        default: {
@@ -2699,8 +2820,8 @@ int ll_fsync(struct file *file, struct dentry *dentry, int datasync)
         }
 
         oc = ll_mdscapa_get(inode);
-        err = md_sync(ll_i2sbi(inode)->ll_md_exp, ll_inode2fid(inode), oc,
-                      &req);
+       err = md_fsync(ll_i2sbi(inode)->ll_md_exp, ll_inode2fid(inode), oc,
+                      &req);
         capa_put(oc);
         if (!rc)
                 rc = err;
@@ -2915,7 +3036,8 @@ int ll_have_md_lock(struct inode *inode, __u64 *bits,  ldlm_mode_t l_req_mode)
 }
 
 ldlm_mode_t ll_take_md_lock(struct inode *inode, __u64 bits,
-                            struct lustre_handle *lockh, __u64 flags)
+                           struct lustre_handle *lockh, __u64 flags,
+                           ldlm_mode_t mode)
 {
         ldlm_policy_data_t policy = { .l_inodebits = {bits}};
         struct lu_fid *fid;
@@ -2925,10 +3047,10 @@ ldlm_mode_t ll_take_md_lock(struct inode *inode, __u64 bits,
         fid = &ll_i2info(inode)->lli_fid;
         CDEBUG(D_INFO, "trying to match res "DFID"\n", PFID(fid));
 
-        rc = md_lock_match(ll_i2mdexp(inode), LDLM_FL_BLOCK_GRANTED|flags,
-                          fid, LDLM_IBITS, &policy,
-                           LCK_CR|LCK_CW|LCK_PR|LCK_PW, lockh);
-        RETURN(rc);
+       rc = md_lock_match(ll_i2mdexp(inode), LDLM_FL_BLOCK_GRANTED|flags,
+                          fid, LDLM_IBITS, &policy, mode, lockh);
+
+       RETURN(rc);
 }
 
 static int ll_inode_revalidate_fini(struct inode *inode, int rc)
@@ -3119,7 +3241,6 @@ int ll_getattr(struct vfsmount *mnt, struct dentry *de, struct kstat *stat)
         return ll_getattr_it(mnt, de, &it, stat);
 }
 
-#ifdef HAVE_LINUX_FIEMAP_H
 int ll_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                 __u64 start, __u64 len)
 {
@@ -3152,7 +3273,6 @@ int ll_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
         OBD_FREE_LARGE(fiemap, num_bytes);
         return rc;
 }
-#endif
 
 struct posix_acl * ll_get_acl(struct inode *inode, int type)
 {
@@ -3304,9 +3424,7 @@ struct inode_operations ll_file_inode_operations = {
        .getxattr       = ll_getxattr,
        .listxattr      = ll_listxattr,
        .removexattr    = ll_removexattr,
-#ifdef  HAVE_LINUX_FIEMAP_H
        .fiemap         = ll_fiemap,
-#endif
 #ifdef HAVE_IOP_GET_ACL
        .get_acl        = ll_get_acl,
 #endif
@@ -3664,7 +3782,8 @@ int ll_layout_refresh(struct inode *inode, __u32 *gen)
 
        /* mostly layout lock is caching on the local side, so try to match
         * it before grabbing layout lock mutex. */
-       mode = ll_take_md_lock(inode, MDS_INODELOCK_LAYOUT, &lockh, 0);
+       mode = ll_take_md_lock(inode, MDS_INODELOCK_LAYOUT, &lockh, 0,
+                              LCK_CR | LCK_CW | LCK_PR | LCK_PW);
        if (mode != 0) { /* hit cached lock */
                rc = ll_layout_lock_set(&lockh, mode, inode, gen, false);
                if (rc == 0)
@@ -3679,7 +3798,8 @@ int ll_layout_refresh(struct inode *inode, __u32 *gen)
 
 again:
        /* try again. Maybe somebody else has done this. */
-       mode = ll_take_md_lock(inode, MDS_INODELOCK_LAYOUT, &lockh, 0);
+       mode = ll_take_md_lock(inode, MDS_INODELOCK_LAYOUT, &lockh, 0,
+                              LCK_CR | LCK_CW | LCK_PR | LCK_PW);
        if (mode != 0) { /* hit cached lock */
                rc = ll_layout_lock_set(&lockh, mode, inode, gen, true);
                if (rc == -EAGAIN)
@@ -3732,7 +3852,7 @@ again:
 /**
  *  This function send a restore request to the MDT
  */
-int ll_layout_restore(struct inode *inode)
+int ll_layout_restore(struct inode *inode, loff_t offset, __u64 length)
 {
        struct hsm_user_request *hur;
        int                      len, rc;
@@ -3749,7 +3869,8 @@ int ll_layout_restore(struct inode *inode)
        hur->hur_request.hr_flags = 0;
        memcpy(&hur->hur_user_item[0].hui_fid, &ll_i2info(inode)->lli_fid,
               sizeof(hur->hur_user_item[0].hui_fid));
-       hur->hur_user_item[0].hui_extent.length = -1;
+       hur->hur_user_item[0].hui_extent.offset = offset;
+       hur->hur_user_item[0].hui_extent.length = length;
        hur->hur_request.hr_itemcount = 1;
        rc = obd_iocontrol(LL_IOC_HSM_REQUEST, cl_i2sbi(inode)->ll_md_exp,
                           len, hur, NULL);