Whamcloud - gitweb
Revert "LU-3544 nfs: writing to new files will return ENOENT"
[fs/lustre-release.git] / lustre / llite / file.c
index 85c3944..869998f 100644 (file)
@@ -54,7 +54,7 @@ struct ll_file_data *ll_file_data_get(void)
 {
        struct ll_file_data *fd;
 
-       OBD_SLAB_ALLOC_PTR_GFP(fd, ll_file_data_slab, CFS_ALLOC_IO);
+       OBD_SLAB_ALLOC_PTR_GFP(fd, ll_file_data_slab, __GFP_IO);
        if (fd == NULL)
                return NULL;
 
@@ -119,8 +119,9 @@ out:
 }
 
 static int ll_close_inode_openhandle(struct obd_export *md_exp,
-                                     struct inode *inode,
-                                     struct obd_client_handle *och)
+                                    struct inode *inode,
+                                    struct obd_client_handle *och,
+                                    const __u64 *data_version)
 {
         struct obd_export *exp = ll_i2mdexp(inode);
         struct md_op_data *op_data;
@@ -144,7 +145,14 @@ static int ll_close_inode_openhandle(struct obd_export *md_exp,
         if (op_data == NULL)
                 GOTO(out, rc = -ENOMEM); // XXX We leak openhandle and request here.
 
-        ll_prepare_close(inode, op_data, och);
+       ll_prepare_close(inode, op_data, och);
+       if (data_version != NULL) {
+               /* Pass in data_version implies release. */
+               op_data->op_bias |= MDS_HSM_RELEASE;
+               op_data->op_data_version = *data_version;
+               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) {
@@ -173,8 +181,6 @@ static int ll_close_inode_openhandle(struct obd_export *md_exp,
                spin_unlock(&lli->lli_lock);
        }
 
-        ll_finish_md_op_data(op_data);
-
         if (rc == 0) {
                 rc = ll_objects_destroy(req, inode);
                 if (rc)
@@ -182,6 +188,14 @@ static int ll_close_inode_openhandle(struct obd_export *md_exp,
                                inode->i_ino, rc);
         }
 
+       if (rc == 0 && op_data->op_bias & MDS_HSM_RELEASE) {
+               struct mdt_body *body;
+               body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY);
+               if (!(body->valid & OBD_MD_FLRELEASED))
+                       rc = -EBUSY;
+       }
+
+        ll_finish_md_op_data(op_data);
         EXIT;
 out:
 
@@ -233,7 +247,7 @@ int ll_md_real_close(struct inode *inode, int flags)
         if (och) { /* There might be a race and somebody have freed this och
                       already */
                 rc = ll_close_inode_openhandle(ll_i2sbi(inode)->ll_md_exp,
-                                               inode, och);
+                                              inode, och, NULL);
         }
 
         RETURN(rc);
@@ -251,6 +265,24 @@ int ll_md_close(struct obd_export *md_exp, struct inode *inode,
         if (unlikely(fd->fd_flags & LL_FILE_GROUP_LOCKED))
                 ll_put_grouplock(inode, file, fd->fd_grouplock.cg_gid);
 
+       if (fd->fd_lease_och != NULL) {
+               bool lease_broken;
+
+               /* Usually the lease is not released when the
+                * application crashed, we need to release here. */
+               rc = ll_lease_close(fd->fd_lease_och, inode, &lease_broken);
+               CDEBUG(rc ? D_ERROR : D_INODE, "Clean up lease "DFID" %d/%d\n",
+                       PFID(&lli->lli_fid), rc, lease_broken);
+
+               fd->fd_lease_och = NULL;
+       }
+
+       if (fd->fd_och != NULL) {
+               rc = ll_close_inode_openhandle(md_exp, inode, fd->fd_och, NULL);
+               fd->fd_och = NULL;
+               GOTO(out, rc);
+       }
+
         /* Let's see if we have good enough OPEN lock on the file and if
            we can skip talking to MDS */
         if (file->f_dentry->d_inode) { /* Can this ever be false? */
@@ -287,11 +319,12 @@ int ll_md_close(struct obd_export *md_exp, struct inode *inode,
                        file, file->f_dentry, file->f_dentry->d_name.name);
         }
 
-        LUSTRE_FPRIVATE(file) = NULL;
-        ll_file_data_put(fd);
-        ll_capa_close(inode);
+out:
+       LUSTRE_FPRIVATE(file) = NULL;
+       ll_file_data_put(fd);
+       ll_capa_close(inode);
 
-        RETURN(rc);
+       RETURN(rc);
 }
 
 /* While this returns an error code, fput() the caller does not, so we need
@@ -311,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)
@@ -443,24 +476,20 @@ void ll_ioepoch_open(struct ll_inode_info *lli, __u64 ioepoch)
         }
 }
 
-static int ll_och_fill(struct obd_export *md_exp, struct ll_inode_info *lli,
-                       struct lookup_intent *it, struct obd_client_handle *och)
+static int ll_och_fill(struct obd_export *md_exp, struct lookup_intent *it,
+                      struct obd_client_handle *och)
 {
-        struct ptlrpc_request *req = it->d.lustre.it_data;
-        struct mdt_body *body;
-
-        LASSERT(och);
-
-        body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY);
-        LASSERT(body != NULL);                      /* reply already checked out */
+       struct ptlrpc_request *req = it->d.lustre.it_data;
+       struct mdt_body *body;
 
-        memcpy(&och->och_fh, &body->handle, sizeof(body->handle));
-        och->och_magic = OBD_CLIENT_HANDLE_MAGIC;
-        och->och_fid = lli->lli_fid;
-        och->och_flags = it->it_flags;
-        ll_ioepoch_open(lli, body->ioepoch);
+       body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY);
+       och->och_fh = body->handle;
+       och->och_fid = body->fid1;
+       och->och_lease_handle.cookie = it->d.lustre.it_lock_handle;
+       och->och_magic = OBD_CLIENT_HANDLE_MAGIC;
+       och->och_flags = it->it_flags;
 
-        return md_set_open_replay_data(md_exp, och, req);
+       return md_set_open_replay_data(md_exp, och, req);
 }
 
 int ll_local_open(struct file *file, struct lookup_intent *it,
@@ -479,21 +508,19 @@ int ll_local_open(struct file *file, struct lookup_intent *it,
                 struct mdt_body *body;
                 int rc;
 
-                rc = ll_och_fill(ll_i2sbi(inode)->ll_md_exp, lli, it, och);
-                if (rc)
-                        RETURN(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);
-                if ((it->it_flags & FMODE_WRITE) &&
-                    (body->valid & OBD_MD_FLSIZE))
-                        CDEBUG(D_INODE, "Epoch "LPU64" opened on "DFID"\n",
-                               lli->lli_ioepoch, PFID(&lli->lli_fid));
-        }
+               body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY);
+               ll_ioepoch_open(lli, body->ioepoch);
+       }
+
+       LUSTRE_FPRIVATE(file) = fd;
+       ll_readahead_init(inode, &fd->fd_ras);
+       fd->fd_omode = it->it_flags & (FMODE_READ | FMODE_WRITE | FMODE_EXEC);
 
-        LUSTRE_FPRIVATE(file) = fd;
-        ll_readahead_init(inode, &fd->fd_ras);
-        fd->fd_omode = it->it_flags;
-        RETURN(0);
+       RETURN(0);
 }
 
 /* Open a file, and (for the very first open) create objects on the OSTs at
@@ -536,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);
@@ -695,10 +722,209 @@ out_openerr:
         return rc;
 }
 
+static int ll_md_blocking_lease_ast(struct ldlm_lock *lock,
+                       struct ldlm_lock_desc *desc, void *data, int flag)
+{
+       int rc;
+       struct lustre_handle lockh;
+       ENTRY;
+
+       switch (flag) {
+       case LDLM_CB_BLOCKING:
+               ldlm_lock2handle(lock, &lockh);
+               rc = ldlm_cli_cancel(&lockh, LCF_ASYNC);
+               if (rc < 0) {
+                       CDEBUG(D_INODE, "ldlm_cli_cancel: %d\n", rc);
+                       RETURN(rc);
+               }
+               break;
+       case LDLM_CB_CANCELING:
+               /* do nothing */
+               break;
+       }
+       RETURN(0);
+}
+
+/**
+ * Acquire a lease and open the file.
+ */
+struct obd_client_handle *ll_lease_open(struct inode *inode, struct file *file,
+                                       fmode_t fmode, __u64 open_flags)
+{
+       struct lookup_intent it = { .it_op = IT_OPEN };
+       struct ll_sb_info *sbi = ll_i2sbi(inode);
+       struct md_op_data *op_data;
+       struct ptlrpc_request *req;
+       struct lustre_handle old_handle = { 0 };
+       struct obd_client_handle *och = NULL;
+       int rc;
+       int rc2;
+       ENTRY;
+
+       if (fmode != FMODE_WRITE && fmode != FMODE_READ)
+               RETURN(ERR_PTR(-EINVAL));
+
+       if (file != NULL) {
+               struct ll_inode_info *lli = ll_i2info(inode);
+               struct ll_file_data *fd = LUSTRE_FPRIVATE(file);
+               struct obd_client_handle **och_p;
+               __u64 *och_usecount;
+
+               if (!(fmode & file->f_mode) || (file->f_mode & FMODE_EXEC))
+                       RETURN(ERR_PTR(-EPERM));
+
+               /* Get the openhandle of the file */
+               rc = -EBUSY;
+               mutex_lock(&lli->lli_och_mutex);
+               if (fd->fd_lease_och != NULL) {
+                       mutex_unlock(&lli->lli_och_mutex);
+                       RETURN(ERR_PTR(rc));
+               }
+
+               if (fd->fd_och == NULL) {
+                       if (file->f_mode & FMODE_WRITE) {
+                               LASSERT(lli->lli_mds_write_och != NULL);
+                               och_p = &lli->lli_mds_write_och;
+                               och_usecount = &lli->lli_open_fd_write_count;
+                       } else {
+                               LASSERT(lli->lli_mds_read_och != NULL);
+                               och_p = &lli->lli_mds_read_och;
+                               och_usecount = &lli->lli_open_fd_read_count;
+                       }
+                       if (*och_usecount == 1) {
+                               fd->fd_och = *och_p;
+                               *och_p = NULL;
+                               *och_usecount = 0;
+                               rc = 0;
+                       }
+               }
+               mutex_unlock(&lli->lli_och_mutex);
+               if (rc < 0) /* more than 1 opener */
+                       RETURN(ERR_PTR(rc));
+
+               LASSERT(fd->fd_och != NULL);
+               old_handle = fd->fd_och->och_fh;
+       }
+
+       OBD_ALLOC_PTR(och);
+       if (och == NULL)
+               RETURN(ERR_PTR(-ENOMEM));
+
+       op_data = ll_prep_md_op_data(NULL, inode, inode, NULL, 0, 0,
+                                       LUSTRE_OPC_ANY, NULL);
+       if (IS_ERR(op_data))
+               GOTO(out, rc = PTR_ERR(op_data));
+
+       /* To tell the MDT this openhandle is from the same owner */
+       op_data->op_handle = old_handle;
+
+       it.it_flags = fmode | open_flags;
+       it.it_flags |= MDS_OPEN_LOCK | MDS_OPEN_BY_FID | MDS_OPEN_LEASE;
+       rc = md_intent_lock(sbi->ll_md_exp, op_data, NULL, 0, &it, 0, &req,
+                               ll_md_blocking_lease_ast,
+       /* LDLM_FL_NO_LRU: To not put the lease lock into LRU list, otherwise
+        * it can be cancelled which may mislead applications that the lease is
+        * broken;
+        * LDLM_FL_EXCL: Set this flag so that it won't be matched by normal
+        * open in ll_md_blocking_ast(). Otherwise as ll_md_blocking_lease_ast
+        * doesn't deal with openhandle, so normal openhandle will be leaked. */
+                               LDLM_FL_NO_LRU | LDLM_FL_EXCL);
+       ll_finish_md_op_data(op_data);
+       if (req != NULL) {
+               ptlrpc_req_finished(req);
+               it_clear_disposition(&it, DISP_ENQ_COMPLETE);
+       }
+       if (rc < 0)
+               GOTO(out_release_it, rc);
+
+       if (it_disposition(&it, DISP_LOOKUP_NEG))
+               GOTO(out_release_it, rc = -ENOENT);
+
+       rc = it_open_error(DISP_OPEN_OPEN, &it);
+       if (rc)
+               GOTO(out_release_it, rc);
+
+       LASSERT(it_disposition(&it, DISP_ENQ_OPEN_REF));
+       ll_och_fill(sbi->ll_md_exp, &it, och);
+
+       if (!it_disposition(&it, DISP_OPEN_LEASE)) /* old server? */
+               GOTO(out_close, rc = -EOPNOTSUPP);
+
+       /* already get lease, handle lease lock */
+       ll_set_lock_data(sbi->ll_md_exp, inode, &it, NULL);
+       if (it.d.lustre.it_lock_mode == 0 ||
+           it.d.lustre.it_lock_bits != MDS_INODELOCK_OPEN) {
+               /* open lock must return for lease */
+               CERROR(DFID "lease granted but no open lock, %d/%Lu.\n",
+                       PFID(ll_inode2fid(inode)), it.d.lustre.it_lock_mode,
+                       it.d.lustre.it_lock_bits);
+               GOTO(out_close, rc = -EPROTO);
+       }
+
+       ll_intent_release(&it);
+       RETURN(och);
+
+out_close:
+       /* 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 = 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:
+       if (och != NULL)
+               OBD_FREE_PTR(och);
+       RETURN(ERR_PTR(rc));
+}
+EXPORT_SYMBOL(ll_lease_open);
+
+/**
+ * Release lease and close the file.
+ * It will check if the lease has ever broken.
+ */
+int ll_lease_close(struct obd_client_handle *och, struct inode *inode,
+                       bool *lease_broken)
+{
+       struct ldlm_lock *lock;
+       bool cancelled = true;
+       int rc;
+       ENTRY;
+
+       lock = ldlm_handle2lock(&och->och_lease_handle);
+       if (lock != NULL) {
+               lock_res_and_lock(lock);
+               cancelled = ldlm_is_cancel(lock);
+               unlock_res_and_lock(lock);
+               LDLM_LOCK_PUT(lock);
+       }
+
+       CDEBUG(D_INODE, "lease for "DFID" broken? %d\n",
+               PFID(&ll_i2info(inode)->lli_fid), cancelled);
+
+       if (!cancelled)
+               ldlm_cli_cancel(&och->och_lease_handle, 0);
+       if (lease_broken != NULL)
+               *lease_broken = cancelled;
+
+       rc = ll_close_inode_openhandle(ll_i2sbi(inode)->ll_md_exp, inode, och,
+                                      NULL);
+       RETURN(rc);
+}
+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 } } };
@@ -720,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) {
@@ -735,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);
 }
 
 /**
@@ -757,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;
@@ -834,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;
@@ -853,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
@@ -883,9 +1145,7 @@ restart:
                         cio->cui_iov = args->u.normal.via_iov;
                         cio->cui_nrsegs = args->u.normal.via_nrsegs;
                         cio->cui_tot_nrsegs = cio->cui_nrsegs;
-#ifndef HAVE_FILE_WRITEV
                         cio->cui_iocb = args->u.normal.via_iocb;
-#endif
                         if ((iot == CIT_WRITE) &&
                             !(cio->cui_fd->fd_flags & LL_FILE_GROUP_LOCKED)) {
                                if (mutex_lock_interruptible(&lli->
@@ -927,7 +1187,7 @@ out:
         cl_io_fini(env, io);
        /* If any bit been read/written (result != 0), we just return
         * short read/write instead of restart io. */
-       if (result == 0 && io->ci_need_restart) {
+       if ((result == 0 || result == -ENODATA) && io->ci_need_restart) {
                CDEBUG(D_VFSTRACE, "Restart %s on %s from %lld, count:%zd\n",
                       iot == CIT_READ ? "read" : "write",
                       file->f_dentry->d_name.name, *ppos, count);
@@ -984,56 +1244,6 @@ static int ll_file_get_iov_count(const struct iovec *iov,
         return 0;
 }
 
-#ifdef HAVE_FILE_READV
-static ssize_t ll_file_readv(struct file *file, const struct iovec *iov,
-                              unsigned long nr_segs, loff_t *ppos)
-{
-        struct lu_env      *env;
-        struct vvp_io_args *args;
-        size_t              count;
-        ssize_t             result;
-        int                 refcheck;
-        ENTRY;
-
-        result = ll_file_get_iov_count(iov, &nr_segs, &count);
-        if (result)
-                RETURN(result);
-
-        env = cl_env_get(&refcheck);
-        if (IS_ERR(env))
-                RETURN(PTR_ERR(env));
-
-        args = vvp_env_args(env, IO_NORMAL);
-        args->u.normal.via_iov = (struct iovec *)iov;
-        args->u.normal.via_nrsegs = nr_segs;
-
-        result = ll_file_io_generic(env, args, file, CIT_READ, ppos, count);
-        cl_env_put(env, &refcheck);
-        RETURN(result);
-}
-
-static ssize_t ll_file_read(struct file *file, char *buf, size_t count,
-                            loff_t *ppos)
-{
-        struct lu_env *env;
-        struct iovec  *local_iov;
-        ssize_t        result;
-        int            refcheck;
-        ENTRY;
-
-        env = cl_env_get(&refcheck);
-        if (IS_ERR(env))
-                RETURN(PTR_ERR(env));
-
-        local_iov = &vvp_env_info(env)->vti_local_iov;
-        local_iov->iov_base = (void __user *)buf;
-        local_iov->iov_len = count;
-        result = ll_file_readv(file, local_iov, 1, ppos);
-        cl_env_put(env, &refcheck);
-        RETURN(result);
-}
-
-#else
 static ssize_t ll_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
                                 unsigned long nr_segs, loff_t pos)
 {
@@ -1091,62 +1301,11 @@ static ssize_t ll_file_read(struct file *file, char *buf, size_t count,
         cl_env_put(env, &refcheck);
         RETURN(result);
 }
-#endif
 
 /*
  * Write to a file (through the page cache).
+ * AIO stuff
  */
-#ifdef HAVE_FILE_WRITEV
-static ssize_t ll_file_writev(struct file *file, const struct iovec *iov,
-                              unsigned long nr_segs, loff_t *ppos)
-{
-        struct lu_env      *env;
-        struct vvp_io_args *args;
-        size_t              count;
-        ssize_t             result;
-        int                 refcheck;
-        ENTRY;
-
-        result = ll_file_get_iov_count(iov, &nr_segs, &count);
-        if (result)
-                RETURN(result);
-
-        env = cl_env_get(&refcheck);
-        if (IS_ERR(env))
-                RETURN(PTR_ERR(env));
-
-        args = vvp_env_args(env, IO_NORMAL);
-        args->u.normal.via_iov = (struct iovec *)iov;
-        args->u.normal.via_nrsegs = nr_segs;
-
-        result = ll_file_io_generic(env, args, file, CIT_WRITE, ppos, count);
-        cl_env_put(env, &refcheck);
-        RETURN(result);
-}
-
-static ssize_t ll_file_write(struct file *file, const char *buf, size_t count,
-                             loff_t *ppos)
-{
-        struct lu_env    *env;
-        struct iovec     *local_iov;
-        ssize_t           result;
-        int               refcheck;
-        ENTRY;
-
-        env = cl_env_get(&refcheck);
-        if (IS_ERR(env))
-                RETURN(PTR_ERR(env));
-
-        local_iov = &vvp_env_info(env)->vti_local_iov;
-        local_iov->iov_base = (void __user *)buf;
-        local_iov->iov_len = count;
-
-        result = ll_file_writev(file, local_iov, 1, ppos);
-        cl_env_put(env, &refcheck);
-        RETURN(result);
-}
-
-#else /* AIO stuff */
 static ssize_t ll_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
                                  unsigned long nr_segs, loff_t pos)
 {
@@ -1204,37 +1363,7 @@ static ssize_t ll_file_write(struct file *file, const char *buf, size_t count,
         cl_env_put(env, &refcheck);
         RETURN(result);
 }
-#endif
 
-
-#ifdef HAVE_KERNEL_SENDFILE
-/*
- * Send file content (through pagecache) somewhere with helper
- */
-static ssize_t ll_file_sendfile(struct file *in_file, loff_t *ppos,size_t count,
-                                read_actor_t actor, void *target)
-{
-        struct lu_env      *env;
-        struct vvp_io_args *args;
-        ssize_t             result;
-        int                 refcheck;
-        ENTRY;
-
-        env = cl_env_get(&refcheck);
-        if (IS_ERR(env))
-                RETURN(PTR_ERR(env));
-
-        args = vvp_env_args(env, IO_SENDFILE);
-        args->u.sendfile.via_target = target;
-        args->u.sendfile.via_actor = actor;
-
-        result = ll_file_io_generic(env, args, in_file, CIT_READ, ppos, count);
-        cl_env_put(env, &refcheck);
-        RETURN(result);
-}
-#endif
-
-#ifdef HAVE_KERNEL_SPLICE_READ
 /*
  * Send file content (through pagecache) somewhere with helper
  */
@@ -1260,7 +1389,6 @@ static ssize_t ll_file_splice_read(struct file *in_file, loff_t *ppos,
         cl_env_put(env, &refcheck);
         RETURN(result);
 }
-#endif
 
 static int ll_lov_recreate(struct inode *inode, struct ost_id *oi,
                            obd_count ost_idx)
@@ -1278,7 +1406,7 @@ static int ll_lov_recreate(struct inode *inode, struct ost_id *oi,
                RETURN(-ENOMEM);
 
        lsm = ccc_inode_lsm_get(inode);
-        if (lsm == NULL)
+       if (!lsm_has_objects(lsm))
                 GOTO(out, rc = -ENOENT);
 
         lsm_size = sizeof(*lsm) + (sizeof(struct lov_oinfo) *
@@ -1345,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};
@@ -1434,6 +1563,12 @@ int ll_lov_getstripe_ea_info(struct inode *inode, const char *filename,
          * passing it to userspace.
          */
         if (LOV_MAGIC != cpu_to_le32(LOV_MAGIC)) {
+               int stripe_count;
+
+               stripe_count = le16_to_cpu(lmm->lmm_stripe_count);
+               if (le32_to_cpu(lmm->lmm_pattern) & LOV_PATTERN_F_RELEASED)
+                       stripe_count = 0;
+
                 /* if function called for directory - we should
                  * avoid swab not existent lsm objects */
                 if (lmm->lmm_magic == cpu_to_le32(LOV_MAGIC_V1)) {
@@ -1441,13 +1576,13 @@ int ll_lov_getstripe_ea_info(struct inode *inode, const char *filename,
                         if (S_ISREG(body->mode))
                                 lustre_swab_lov_user_md_objects(
                                  ((struct lov_user_md_v1 *)lmm)->lmm_objects,
-                                 ((struct lov_user_md_v1 *)lmm)->lmm_stripe_count);
+                                 stripe_count);
                 } else if (lmm->lmm_magic == cpu_to_le32(LOV_MAGIC_V3)) {
                         lustre_swab_lov_user_md_v3((struct lov_user_md_v3 *)lmm);
                         if (S_ISREG(body->mode))
                                 lustre_swab_lov_user_md_objects(
                                  ((struct lov_user_md_v3 *)lmm)->lmm_objects,
-                                 ((struct lov_user_md_v3 *)lmm)->lmm_stripe_count);
+                                 stripe_count);
                 }
         }
 
@@ -1461,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);
@@ -1494,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 */
@@ -1644,18 +1779,17 @@ int ll_release_openhandle(struct dentry *dentry, struct lookup_intent *it)
         if (!och)
                 GOTO(out, rc = -ENOMEM);
 
-        ll_och_fill(ll_i2sbi(inode)->ll_md_exp,
-                    ll_i2info(inode), it, och);
+       ll_och_fill(ll_i2sbi(inode)->ll_md_exp, it, och);
 
         rc = ll_close_inode_openhandle(ll_i2sbi(inode)->ll_md_exp,
-                                       inode, och);
- out:
-        /* this one is in place of ll_file_open */
-        if (it_disposition(it, DISP_ENQ_OPEN_REF)) {
-                ptlrpc_req_finished(it->d.lustre.it_data);
-                it_clear_disposition(it, DISP_ENQ_OPEN_REF);
-        }
-        RETURN(rc);
+                                      inode, och, NULL);
+out:
+       /* this one is in place of ll_file_open */
+       if (it_disposition(it, DISP_ENQ_OPEN_REF)) {
+               ptlrpc_req_finished(it->d.lustre.it_data);
+               it_clear_disposition(it, DISP_ENQ_OPEN_REF);
+       }
+       RETURN(rc);
 }
 
 /**
@@ -1819,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);
@@ -1833,20 +1968,18 @@ int ll_data_version(struct inode *inode, __u64 *data_version,
 
        /* If no stripe, we consider version is 0. */
        lsm = ccc_inode_lsm_get(inode);
-       if (lsm == NULL) {
+       if (!lsm_has_objects(lsm)) {
                *data_version = 0;
                CDEBUG(D_INODE, "No object for inode\n");
-               RETURN(0);
+               GOTO(out, rc = 0);
        }
 
        OBD_ALLOC_PTR(obdo);
-       if (obdo == NULL) {
-               ccc_inode_lsm_put(inode, lsm);
-               RETURN(-ENOMEM);
-       }
+       if (obdo == NULL)
+               GOTO(out, rc = -ENOMEM);
 
-       rc = ll_lsm_getattr(lsm, sbi->ll_dt_exp, NULL, obdo, 0, extent_lock);
-       if (!rc) {
+       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
@@ -1854,11 +1987,59 @@ int ll_data_version(struct inode *inode, __u64 *data_version,
        }
 
        OBD_FREE_PTR(obdo);
+       EXIT;
+out:
        ccc_inode_lsm_put(inode, lsm);
-
        RETURN(rc);
 }
 
+/*
+ * Trigger a HSM release request for the provided inode.
+ */
+int ll_hsm_release(struct inode *inode)
+{
+       struct cl_env_nest nest;
+       struct lu_env *env;
+       struct obd_client_handle *och = NULL;
+       __u64 data_version = 0;
+       int rc;
+       ENTRY;
+
+       CDEBUG(D_INODE, "%s: Releasing file "DFID".\n",
+              ll_get_fsname(inode->i_sb, NULL, 0),
+              PFID(&ll_i2info(inode)->lli_fid));
+
+       och = ll_lease_open(inode, NULL, FMODE_WRITE, MDS_OPEN_RELEASE);
+       if (IS_ERR(och))
+               GOTO(out, rc = PTR_ERR(och));
+
+       /* Grab latest data_version and [am]time values */
+       rc = ll_data_version(inode, &data_version, LL_DV_WR_FLUSH);
+       if (rc != 0)
+               GOTO(out, rc);
+
+       env = cl_env_nested_get(&nest);
+       if (IS_ERR(env))
+               GOTO(out, rc = PTR_ERR(env));
+
+       ll_merge_lvb(env, inode);
+       cl_env_nested_put(&nest, env);
+
+       /* Release the file.
+        * NB: lease lock handle is released in mdc_hsm_release_pack() because
+        * we still need it to pack l_remote_handle to MDT. */
+       rc = ll_close_inode_openhandle(ll_i2sbi(inode)->ll_md_exp, inode, och,
+                                      &data_version);
+       och = NULL;
+
+       EXIT;
+out:
+       if (och != NULL && !IS_ERR(och)) /* close the file */
+               ll_lease_close(och, inode, NULL);
+
+       return rc;
+}
+
 struct ll_swap_stack {
        struct iattr             ia1, ia2;
        __u64                    dv1, dv2;
@@ -1886,8 +2067,8 @@ static int ll_swap_layouts(struct file *file1, struct file *file2,
        if (!S_ISREG(llss->inode2->i_mode))
                GOTO(free, rc = -EINVAL);
 
-       if (ll_permission(llss->inode1, MAY_WRITE, NULL) ||
-           ll_permission(llss->inode2, MAY_WRITE, NULL))
+       if (inode_permission(llss->inode1, MAY_WRITE) ||
+           inode_permission(llss->inode2, MAY_WRITE))
                GOTO(free, rc = -EPERM);
 
        if (llss->inode2->i_sb != llss->inode1->i_sb)
@@ -1967,12 +2148,12 @@ static int ll_swap_layouts(struct file *file1, struct file *file2,
        rc = -ENOMEM;
        op_data = ll_prep_md_op_data(NULL, llss->inode1, llss->inode2, NULL, 0,
                                     0, LUSTRE_OPC_ANY, &msl);
-       if (op_data != NULL) {
-               rc = obd_iocontrol(LL_IOC_LOV_SWAP_LAYOUTS,
-                                  ll_i2mdexp(llss->inode1),
-                                  sizeof(*op_data), op_data, NULL);
-               ll_finish_md_op_data(op_data);
-       }
+       if (IS_ERR(op_data))
+               GOTO(free, rc = PTR_ERR(op_data));
+
+       rc = obd_iocontrol(LL_IOC_LOV_SWAP_LAYOUTS, ll_i2mdexp(llss->inode1),
+                          sizeof(*op_data), op_data, NULL);
+       ll_finish_md_op_data(op_data);
 
 putgl:
        if (gid != 0) {
@@ -2020,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;
@@ -2069,7 +2330,7 @@ long ll_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                struct file *file2;
                struct lustre_swap_layouts lsl;
 
-               if (cfs_copy_from_user(&lsl, (char *)arg,
+               if (copy_from_user(&lsl, (char *)arg,
                                       sizeof(struct lustre_swap_layouts)))
                        RETURN(-EFAULT);
 
@@ -2126,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);
@@ -2166,9 +2427,9 @@ long ll_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 
                op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, 0,
                                             LUSTRE_OPC_ANY, hus);
-               if (op_data == NULL) {
+               if (IS_ERR(op_data)) {
                        OBD_FREE_PTR(hus);
-                       RETURN(-ENOMEM);
+                       RETURN(PTR_ERR(op_data));
                }
 
                rc = obd_iocontrol(cmd, ll_i2mdexp(inode), sizeof(*op_data),
@@ -2182,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 (op_data == NULL) {
-                       OBD_FREE_PTR(hss);
-                       RETURN(-ENOMEM);
-               }
-
-               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);
@@ -2228,21 +2471,121 @@ long ll_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 
                op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, 0,
                                             LUSTRE_OPC_ANY, hca);
-               if (op_data == NULL) {
+               if (IS_ERR(op_data)) {
                        OBD_FREE_PTR(hca);
-                       RETURN(-ENOMEM);
+                       RETURN(PTR_ERR(op_data));
                }
 
                rc = obd_iocontrol(cmd, ll_i2mdexp(inode), sizeof(*op_data),
                                   op_data, NULL);
 
-               if (cfs_copy_to_user((char *)arg, hca, sizeof(*hca)))
+               if (copy_to_user((char *)arg, hca, sizeof(*hca)))
                        rc = -EFAULT;
 
                ll_finish_md_op_data(op_data);
                OBD_FREE_PTR(hca);
                RETURN(rc);
        }
+       case LL_IOC_SET_LEASE: {
+               struct ll_inode_info *lli = ll_i2info(inode);
+               struct obd_client_handle *och = NULL;
+               bool lease_broken;
+               fmode_t mode = 0;
+
+               switch (arg) {
+               case F_WRLCK:
+                       if (!(file->f_mode & FMODE_WRITE))
+                               RETURN(-EPERM);
+                       mode = FMODE_WRITE;
+                       break;
+               case F_RDLCK:
+                       if (!(file->f_mode & FMODE_READ))
+                               RETURN(-EPERM);
+                       mode = FMODE_READ;
+                       break;
+               case F_UNLCK:
+                       mutex_lock(&lli->lli_och_mutex);
+                       if (fd->fd_lease_och != NULL) {
+                               och = fd->fd_lease_och;
+                               fd->fd_lease_och = NULL;
+                       }
+                       mutex_unlock(&lli->lli_och_mutex);
+
+                       if (och != NULL) {
+                               mode = och->och_flags &(FMODE_READ|FMODE_WRITE);
+                               rc = ll_lease_close(och, inode, &lease_broken);
+                               if (rc == 0 && lease_broken)
+                                       mode = 0;
+                       } else {
+                               rc = -ENOLCK;
+                       }
+
+                       /* return the type of lease or error */
+                       RETURN(rc < 0 ? rc : (int)mode);
+               default:
+                       RETURN(-EINVAL);
+               }
+
+               CDEBUG(D_INODE, "Set lease with mode %d\n", mode);
+
+               /* apply for lease */
+               och = ll_lease_open(inode, file, mode, 0);
+               if (IS_ERR(och))
+                       RETURN(PTR_ERR(och));
+
+               rc = 0;
+               mutex_lock(&lli->lli_och_mutex);
+               if (fd->fd_lease_och == NULL) {
+                       fd->fd_lease_och = och;
+                       och = NULL;
+               }
+               mutex_unlock(&lli->lli_och_mutex);
+               if (och != NULL) {
+                       /* impossible now that only excl is supported for now */
+                       ll_lease_close(och, inode, &lease_broken);
+                       rc = -EBUSY;
+               }
+               RETURN(rc);
+       }
+       case LL_IOC_GET_LEASE: {
+               struct ll_inode_info *lli = ll_i2info(inode);
+               struct ldlm_lock *lock = NULL;
+
+               rc = 0;
+               mutex_lock(&lli->lli_och_mutex);
+               if (fd->fd_lease_och != NULL) {
+                       struct obd_client_handle *och = fd->fd_lease_och;
+
+                       lock = ldlm_handle2lock(&och->och_lease_handle);
+                       if (lock != NULL) {
+                               lock_res_and_lock(lock);
+                               if (!ldlm_is_cancel(lock))
+                                       rc = och->och_flags &
+                                               (FMODE_READ | FMODE_WRITE);
+                               unlock_res_and_lock(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: {
                int err;
 
@@ -2477,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;
@@ -2506,18 +2849,20 @@ int ll_fsync(struct file *file, struct dentry *dentry, int datasync)
 
 int ll_file_flock(struct file *file, int cmd, struct file_lock *file_lock)
 {
-        struct inode *inode = file->f_dentry->d_inode;
-        struct ll_sb_info *sbi = ll_i2sbi(inode);
-        struct ldlm_enqueue_info einfo = { .ei_type = LDLM_FLOCK,
-                                           .ei_cb_cp =ldlm_flock_completion_ast,
-                                           .ei_cbdata = file_lock };
-        struct md_op_data *op_data;
-        struct lustre_handle lockh = {0};
-        ldlm_policy_data_t flock = {{0}};
-        int flags = 0;
-        int rc;
+       struct inode *inode = file->f_dentry->d_inode;
+       struct ll_sb_info *sbi = ll_i2sbi(inode);
+       struct ldlm_enqueue_info einfo = {
+               .ei_type        = LDLM_FLOCK,
+               .ei_cb_cp       = ldlm_flock_completion_ast,
+               .ei_cbdata      = file_lock,
+       };
+       struct md_op_data *op_data;
+       struct lustre_handle lockh = {0};
+       ldlm_policy_data_t flock = {{0}};
+       int flags = 0;
+       int rc;
        int rc2 = 0;
-        ENTRY;
+       ENTRY;
 
         CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu file_lock=%p\n",
                inode->i_ino, file_lock);
@@ -2691,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;
@@ -2701,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)
@@ -2824,13 +3170,13 @@ out:
 }
 
 int ll_inode_revalidate_it(struct dentry *dentry, struct lookup_intent *it,
-                           __u64 ibits)
+                          __u64 ibits)
 {
-        struct inode *inode = dentry->d_inode;
-        int rc;
-        ENTRY;
+       struct inode    *inode = dentry->d_inode;
+       int              rc;
+       ENTRY;
 
-        rc = __ll_inode_revalidate_it(dentry, it, ibits);
+       rc = __ll_inode_revalidate_it(dentry, it, ibits);
        if (rc != 0)
                RETURN(rc);
 
@@ -2840,9 +3186,17 @@ int ll_inode_revalidate_it(struct dentry *dentry, struct lookup_intent *it,
                LTIME_S(inode->i_mtime) = ll_i2info(inode)->lli_lvb.lvb_mtime;
                LTIME_S(inode->i_ctime) = ll_i2info(inode)->lli_lvb.lvb_ctime;
        } else {
-               rc = ll_glimpse_size(inode);
+               /* In case of restore, the MDT has the right size and has
+                * already send it back without granting the layout lock,
+                * inode is up-to-date so glimpse is useless.
+                * Also to glimpse we need the layout, in case of a running
+                * restore the MDT holds the layout lock so the glimpse will
+                * block up to the end of restore (getattr will block)
+                */
+               if (!(ll_i2info(inode)->lli_flags & LLIF_FILE_RESTORING))
+                       rc = ll_glimpse_size(inode);
        }
-        RETURN(rc);
+       RETURN(rc);
 }
 
 int ll_getattr_it(struct vfsmount *mnt, struct dentry *de,
@@ -2887,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)
 {
@@ -2920,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)
 {
@@ -3013,55 +3365,33 @@ int ll_inode_permission(struct inode *inode, int mask, struct nameidata *nd)
        RETURN(rc);
 }
 
-#ifdef HAVE_FILE_READV
-#define READ_METHOD readv
-#define READ_FUNCTION ll_file_readv
-#define WRITE_METHOD writev
-#define WRITE_FUNCTION ll_file_writev
-#else
-#define READ_METHOD aio_read
-#define READ_FUNCTION ll_file_aio_read
-#define WRITE_METHOD aio_write
-#define WRITE_FUNCTION ll_file_aio_write
-#endif
-
 /* -o localflock - only provides locally consistent flock locks */
 struct file_operations ll_file_operations = {
         .read           = ll_file_read,
-        .READ_METHOD    = READ_FUNCTION,
+       .aio_read    = ll_file_aio_read,
         .write          = ll_file_write,
-        .WRITE_METHOD   = WRITE_FUNCTION,
+       .aio_write   = ll_file_aio_write,
         .unlocked_ioctl = ll_file_ioctl,
         .open           = ll_file_open,
         .release        = ll_file_release,
         .mmap           = ll_file_mmap,
         .llseek         = ll_file_seek,
-#ifdef HAVE_KERNEL_SENDFILE
-        .sendfile       = ll_file_sendfile,
-#endif
-#ifdef HAVE_KERNEL_SPLICE_READ
         .splice_read    = ll_file_splice_read,
-#endif
         .fsync          = ll_fsync,
         .flush          = ll_flush
 };
 
 struct file_operations ll_file_operations_flock = {
         .read           = ll_file_read,
-        .READ_METHOD    = READ_FUNCTION,
+       .aio_read    = ll_file_aio_read,
         .write          = ll_file_write,
-        .WRITE_METHOD   = WRITE_FUNCTION,
+       .aio_write   = ll_file_aio_write,
         .unlocked_ioctl = ll_file_ioctl,
         .open           = ll_file_open,
         .release        = ll_file_release,
         .mmap           = ll_file_mmap,
         .llseek         = ll_file_seek,
-#ifdef HAVE_KERNEL_SENDFILE
-        .sendfile       = ll_file_sendfile,
-#endif
-#ifdef HAVE_KERNEL_SPLICE_READ
         .splice_read    = ll_file_splice_read,
-#endif
         .fsync          = ll_fsync,
         .flush          = ll_flush,
         .flock          = ll_file_flock,
@@ -3071,20 +3401,15 @@ struct file_operations ll_file_operations_flock = {
 /* These are for -o noflock - to return ENOSYS on flock calls */
 struct file_operations ll_file_operations_noflock = {
         .read           = ll_file_read,
-        .READ_METHOD    = READ_FUNCTION,
+       .aio_read    = ll_file_aio_read,
         .write          = ll_file_write,
-        .WRITE_METHOD   = WRITE_FUNCTION,
+       .aio_write   = ll_file_aio_write,
         .unlocked_ioctl = ll_file_ioctl,
         .open           = ll_file_open,
         .release        = ll_file_release,
         .mmap           = ll_file_mmap,
         .llseek         = ll_file_seek,
-#ifdef HAVE_KERNEL_SENDFILE
-        .sendfile       = ll_file_sendfile,
-#endif
-#ifdef HAVE_KERNEL_SPLICE_READ
         .splice_read    = ll_file_splice_read,
-#endif
         .fsync          = ll_fsync,
         .flush          = ll_flush,
         .flock          = ll_file_noflock,
@@ -3099,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
@@ -3255,7 +3578,11 @@ static int ll_layout_fetch(struct inode *inode, struct ldlm_lock *lock)
        int rc;
        ENTRY;
 
-       if (lock->l_lvb_data != NULL)
+       CDEBUG(D_INODE, DFID" LVB_READY=%d l_lvb_data=%p l_lvb_len=%d\n",
+              PFID(ll_inode2fid(inode)), !!(lock->l_flags & LDLM_FL_LVB_READY),
+              lock->l_lvb_data, lock->l_lvb_len);
+
+       if ((lock->l_lvb_data != NULL) && (lock->l_flags & LDLM_FL_LVB_READY))
                RETURN(0);
 
        /* if layout lock was granted right away, the layout is returned
@@ -3291,15 +3618,13 @@ static int ll_layout_fetch(struct inode *inode, struct ldlm_lock *lock)
 
        memcpy(lvbdata, lmm, lmmsize);
        lock_res_and_lock(lock);
-       if (lock->l_lvb_data == NULL) {
-               lock->l_lvb_data = lvbdata;
-               lock->l_lvb_len = lmmsize;
-               lvbdata = NULL;
-       }
+       if (lock->l_lvb_data != NULL)
+               OBD_FREE_LARGE(lock->l_lvb_data, lock->l_lvb_len);
+
+       lock->l_lvb_data = lvbdata;
+       lock->l_lvb_len = lmmsize;
        unlock_res_and_lock(lock);
 
-       if (lvbdata != NULL)
-               OBD_FREE_LARGE(lvbdata, lmmsize);
        EXIT;
 
 out:
@@ -3331,7 +3656,7 @@ static int ll_layout_lock_set(struct lustre_handle *lockh, ldlm_mode_t mode,
        LASSERT(ldlm_has_layout(lock));
 
        LDLM_DEBUG(lock, "File %p/"DFID" being reconfigured: %d.\n",
-               inode, PFID(&lli->lli_fid), reconf);
+                  inode, PFID(&lli->lli_fid), reconf);
 
        /* in case this is a caching lock and reinstate with new inode */
        md_set_lock_data(sbi->ll_md_exp, &lockh->cookie, inode, NULL);
@@ -3341,6 +3666,7 @@ static int ll_layout_lock_set(struct lustre_handle *lockh, ldlm_mode_t mode,
        unlock_res_and_lock(lock);
        /* checking lvb_ready is racy but this is okay. The worst case is
         * that multi processes may configure the file on the same time. */
+
        if (lvb_ready || !reconf) {
                rc = -ENODATA;
                if (lvb_ready) {
@@ -3437,11 +3763,12 @@ int ll_layout_refresh(struct inode *inode, __u32 *gen)
        struct lookup_intent   it;
        struct lustre_handle   lockh;
        ldlm_mode_t            mode;
-       struct ldlm_enqueue_info einfo = { .ei_type = LDLM_IBITS,
-                                          .ei_mode = LCK_CR,
-                                          .ei_cb_bl = ll_md_blocking_ast,
-                                          .ei_cb_cp = ldlm_completion_ast,
-                                          .ei_cbdata = NULL };
+       struct ldlm_enqueue_info einfo = {
+               .ei_type = LDLM_IBITS,
+               .ei_mode = LCK_CR,
+               .ei_cb_bl = ll_md_blocking_ast,
+               .ei_cb_cp = ldlm_completion_ast,
+       };
        int rc;
        ENTRY;
 
@@ -3455,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)
@@ -3470,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)
@@ -3519,3 +3848,33 @@ again:
 
        RETURN(rc);
 }
+
+/**
+ *  This function send a restore request to the MDT
+ */
+int ll_layout_restore(struct inode *inode, loff_t offset, __u64 length)
+{
+       struct hsm_user_request *hur;
+       int                      len, rc;
+       ENTRY;
+
+       len = sizeof(struct hsm_user_request) +
+             sizeof(struct hsm_user_item);
+       OBD_ALLOC(hur, len);
+       if (hur == NULL)
+               RETURN(-ENOMEM);
+
+       hur->hur_request.hr_action = HUA_RESTORE;
+       hur->hur_request.hr_archive_id = 0;
+       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.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);
+       OBD_FREE(hur, len);
+       RETURN(rc);
+}
+