Whamcloud - gitweb
LU-4198 clio: AIO support for direct IO
[fs/lustre-release.git] / lustre / llite / file.c
index e340c71..d3cdc6f 100644 (file)
@@ -42,9 +42,7 @@
 #include <linux/file.h>
 #include <linux/sched.h>
 #include <linux/user_namespace.h>
-#ifdef HAVE_UIDGID_HEADER
-# include <linux/uidgid.h>
-#endif
+#include <linux/uidgid.h>
 
 #include <uapi/linux/lustre/lustre_ioctl.h>
 #include <lustre_swab.h>
@@ -61,6 +59,7 @@ struct split_param {
 struct pcc_param {
        __u64   pa_data_version;
        __u32   pa_archive_id;
+       __u32   pa_layout_gen;
 };
 
 static int
@@ -162,6 +161,7 @@ static int ll_close_inode_openhandle(struct inode *inode,
                op_data->op_attr_blocks += ((struct inode *)data)->i_blocks;
                op_data->op_attr.ia_valid |= ATTR_SIZE;
                op_data->op_xvalid |= OP_XVALID_BLOCKS;
+               /* fallthrough */
        case MDS_CLOSE_LAYOUT_SPLIT:
        case MDS_CLOSE_LAYOUT_SWAP: {
                struct split_param *sp = data;
@@ -237,6 +237,12 @@ static int ll_close_inode_openhandle(struct inode *inode,
                body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY);
                if (!(body->mbo_valid & OBD_MD_CLOSE_INTENT_EXECED))
                        rc = -EBUSY;
+
+               if (bias & MDS_PCC_ATTACH) {
+                       struct pcc_param *param = data;
+
+                       param->pa_layout_gen = body->mbo_layout_gen;
+               }
        }
 
        ll_finish_md_op_data(op_data);
@@ -346,7 +352,9 @@ static int ll_md_close(struct inode *inode, struct file *file)
        }
        mutex_unlock(&lli->lli_och_mutex);
 
-       if (!md_lock_match(ll_i2mdexp(inode), flags, ll_inode2fid(inode),
+       /* LU-4398: do not cache write open lock if the file has exec bit */
+       if ((lockmode == LCK_CW && inode->i_mode & S_IXUGO) ||
+           !md_lock_match(ll_i2mdexp(inode), flags, ll_inode2fid(inode),
                           LDLM_IBITS, &policy, lockmode, &lockh))
                rc = ll_md_real_close(inode, fd->fd_omode);
 
@@ -364,19 +372,19 @@ out:
  */
 int ll_file_release(struct inode *inode, struct file *file)
 {
-        struct ll_file_data *fd;
-        struct ll_sb_info *sbi = ll_i2sbi(inode);
-        struct ll_inode_info *lli = ll_i2info(inode);
-        int rc;
-        ENTRY;
+       struct ll_file_data *fd;
+       struct ll_sb_info *sbi = ll_i2sbi(inode);
+       struct ll_inode_info *lli = ll_i2info(inode);
+       ktime_t kstart = ktime_get();
+       int rc;
+
+       ENTRY;
 
        CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p)\n",
               PFID(ll_inode2fid(inode)), inode);
 
-       if (inode->i_sb->s_root != file_dentry(file))
-                ll_stats_ops_tally(sbi, LPROC_LL_RELEASE, 1);
-        fd = LUSTRE_FPRIVATE(file);
-        LASSERT(fd != NULL);
+       fd = LUSTRE_FPRIVATE(file);
+       LASSERT(fd != NULL);
 
        /* The last ref on @file, maybe not the the owner pid of statahead,
         * because parent and child process can share the same file handle. */
@@ -386,7 +394,7 @@ int ll_file_release(struct inode *inode, struct file *file)
        if (inode->i_sb->s_root == file_dentry(file)) {
                LUSTRE_FPRIVATE(file) = NULL;
                ll_file_data_put(fd);
-               RETURN(0);
+               GOTO(out, rc = 0);
        }
 
        pcc_file_release(inode, file);
@@ -402,6 +410,10 @@ int ll_file_release(struct inode *inode, struct file *file)
        if (CFS_FAIL_TIMEOUT_MS(OBD_FAIL_PTLRPC_DUMP_LOG, cfs_fail_val))
                libcfs_debug_dumplog();
 
+out:
+       if (!rc && inode->i_sb->s_root != file_dentry(file))
+               ll_stats_ops_tally(sbi, LPROC_LL_RELEASE,
+                                  ktime_us_delta(ktime_get(), kstart));
        RETURN(rc);
 }
 
@@ -431,6 +443,7 @@ void ll_dom_finish_open(struct inode *inode, struct ptlrpc_request *req,
        struct address_space *mapping = inode->i_mapping;
        struct page *vmpage;
        struct niobuf_remote *rnb;
+       struct mdt_body *body;
        char *data;
        unsigned long index, start;
        struct niobuf_local lnb;
@@ -440,8 +453,8 @@ void ll_dom_finish_open(struct inode *inode, struct ptlrpc_request *req,
        if (obj == NULL)
                RETURN_EXIT;
 
-       if (!req_capsule_has_field(&req->rq_pill, &RMF_NIOBUF_INLINE,
-                                  RCL_SERVER))
+       if (!req_capsule_field_present(&req->rq_pill, &RMF_NIOBUF_INLINE,
+                                      RCL_SERVER))
                RETURN_EXIT;
 
        rnb = req_capsule_server_get(&req->rq_pill, &RMF_NIOBUF_INLINE);
@@ -453,28 +466,29 @@ void ll_dom_finish_open(struct inode *inode, struct ptlrpc_request *req,
         * client PAGE_SIZE to be used on that client, if server's PAGE_SIZE is
         * smaller then offset may be not aligned and that data is just ignored.
         */
-       if (rnb->rnb_offset % PAGE_SIZE)
+       if (rnb->rnb_offset & ~PAGE_MASK)
                RETURN_EXIT;
 
-       /* Server returns whole file or just file tail if it fills in
-        * reply buffer, in both cases total size should be inode size.
+       /* Server returns whole file or just file tail if it fills in reply
+        * buffer, in both cases total size should be equal to the file size.
         */
-       if (rnb->rnb_offset + rnb->rnb_len < i_size_read(inode)) {
-               CERROR("%s: server returns off/len %llu/%u < i_size %llu\n",
+       body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY);
+       if (rnb->rnb_offset + rnb->rnb_len != body->mbo_dom_size) {
+               CERROR("%s: server returns off/len %llu/%u but size %llu\n",
                       ll_i2sbi(inode)->ll_fsname, rnb->rnb_offset,
-                      rnb->rnb_len, i_size_read(inode));
+                      rnb->rnb_len, body->mbo_dom_size);
                RETURN_EXIT;
        }
 
-       CDEBUG(D_INFO, "Get data along with open at %llu len %i, i_size %llu\n",
-              rnb->rnb_offset, rnb->rnb_len, i_size_read(inode));
+       CDEBUG(D_INFO, "Get data along with open at %llu len %i, size %llu\n",
+              rnb->rnb_offset, rnb->rnb_len, body->mbo_dom_size);
 
        data = (char *)rnb + sizeof(*rnb);
 
        lnb.lnb_file_offset = rnb->rnb_offset;
-       start = lnb.lnb_file_offset / PAGE_SIZE;
+       start = lnb.lnb_file_offset >> PAGE_SHIFT;
        index = 0;
-       LASSERT(lnb.lnb_file_offset % PAGE_SIZE == 0);
+       LASSERT((lnb.lnb_file_offset & ~PAGE_MASK) == 0);
        lnb.lnb_page_offset = 0;
        do {
                lnb.lnb_data = data + (index << PAGE_SHIFT);
@@ -681,6 +695,7 @@ int ll_file_open(struct inode *inode, struct file *file)
        struct obd_client_handle **och_p = NULL;
        __u64 *och_usecount = NULL;
        struct ll_file_data *fd;
+       ktime_t kstart = ktime_get();
        int rc = 0;
        ENTRY;
 
@@ -770,7 +785,9 @@ restart:
         } else {
                 LASSERT(*och_usecount == 0);
                if (!it->it_disposition) {
-                       struct ll_dentry_data *ldd = ll_d2d(file->f_path.dentry);
+                       struct dentry *dentry = file_dentry(file);
+                       struct ll_dentry_data *ldd;
+
                         /* We cannot just request lock handle now, new ELC code
                            means that one of other OPEN locks for this file
                            could be cancelled, and since blocking ast handler
@@ -792,18 +809,21 @@ restart:
                         *  lookup path only, since ll_iget_for_nfs always calls
                         *  ll_d_init().
                         */
+                       ldd = ll_d2d(dentry);
                        if (ldd && ldd->lld_nfs_dentry) {
                                ldd->lld_nfs_dentry = 0;
-                               it->it_flags |= MDS_OPEN_LOCK;
+                               if (!filename_is_volatile(dentry->d_name.name,
+                                                         dentry->d_name.len,
+                                                         NULL))
+                                       it->it_flags |= MDS_OPEN_LOCK;
                        }
 
-                        /*
+                       /*
                         * Always specify MDS_OPEN_BY_FID because we don't want
                         * to get file with different fid.
                         */
                        it->it_flags |= MDS_OPEN_BY_FID;
-                       rc = ll_intent_file_open(file_dentry(file), NULL, 0,
-                                                it);
+                       rc = ll_intent_file_open(dentry, NULL, 0, it);
                         if (rc)
                                 GOTO(out_openerr, rc);
 
@@ -832,19 +852,23 @@ restart:
                if (rc)
                        GOTO(out_och_free, rc);
        }
+
        rc = pcc_file_open(inode, file);
        if (rc)
                GOTO(out_och_free, rc);
 
        mutex_unlock(&lli->lli_och_mutex);
-        fd = NULL;
 
-        /* Must do this outside lli_och_mutex lock to prevent deadlock where
-           different kind of OPEN lock for this same inode gets cancelled
-           by ldlm_cancel_lru */
-        if (!S_ISREG(inode->i_mode))
-                GOTO(out_och_free, rc);
+       /* lockless for direct IO so that it can do IO in parallel */
+       if (file->f_flags & O_DIRECT)
+               fd->fd_flags |= LL_FILE_LOCKLESS_IO;
+       fd = NULL;
 
+       /* Must do this outside lli_och_mutex lock to prevent deadlock where
+          different kind of OPEN lock for this same inode gets cancelled
+          by ldlm_cancel_lru */
+       if (!S_ISREG(inode->i_mode))
+               GOTO(out_och_free, rc);
        cl_lov_delay_create_clear(&file->f_flags);
        GOTO(out_och_free, rc);
 
@@ -863,9 +887,10 @@ out_openerr:
 
                if (fd != NULL)
                        ll_file_data_put(fd);
-        } else {
-                ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_OPEN, 1);
-        }
+       } else {
+               ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_OPEN,
+                                  ktime_us_delta(ktime_get(), kstart));
+       }
 
 out_nofiledata:
        if (it && it_disposition(it, DISP_ENQ_OPEN_REF)) {
@@ -873,7 +898,7 @@ out_nofiledata:
                it_clear_disposition(it, DISP_ENQ_OPEN_REF);
        }
 
-        return rc;
+       return rc;
 }
 
 static int ll_md_blocking_lease_ast(struct ldlm_lock *lock,
@@ -1053,7 +1078,9 @@ ll_lease_open(struct inode *inode, struct file *file, fmode_t fmode,
                GOTO(out_release_it, rc);
 
        LASSERT(it_disposition(&it, DISP_ENQ_OPEN_REF));
-       ll_och_fill(sbi->ll_md_exp, &it, och);
+       rc = ll_och_fill(sbi->ll_md_exp, &it, och);
+       if (rc)
+               GOTO(out_release_it, rc);
 
        if (!it_disposition(&it, DISP_OPEN_LEASE)) /* old server? */
                GOTO(out_close, rc = -EOPNOTSUPP);
@@ -1268,11 +1295,10 @@ int ll_merge_attr(const struct lu_env *env, struct inode *inode)
         * POSIX. Solving this problem needs to send an RPC to MDT for each
         * read, this will hurt performance.
         */
-       if (inode->i_atime.tv_sec < lli->lli_atime ||
-           lli->lli_update_atime) {
+       if (ll_file_test_and_clear_flag(lli, LLIF_UPDATE_ATIME) ||
+           inode->i_atime.tv_sec < lli->lli_atime)
                inode->i_atime.tv_sec = lli->lli_atime;
-               lli->lli_update_atime = 0;
-       }
+
        inode->i_mtime.tv_sec = lli->lli_mtime;
        inode->i_ctime.tv_sec = lli->lli_ctime;
 
@@ -1362,13 +1388,14 @@ static bool file_is_noatime(const struct file *file)
        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))
+       if ((inode->i_sb->s_flags & SB_NODIRATIME) && S_ISDIR(inode->i_mode))
                return true;
 
        return false;
 }
 
-static void ll_io_init(struct cl_io *io, struct file *file, enum cl_io_type iot)
+void ll_io_init(struct cl_io *io, struct file *file, enum cl_io_type iot,
+               struct vvp_io_args *args)
 {
        struct inode *inode = file_inode(file);
        struct ll_file_data *fd  = LUSTRE_FPRIVATE(file);
@@ -1381,7 +1408,13 @@ static void ll_io_init(struct cl_io *io, struct file *file, enum cl_io_type iot)
                io->u.ci_wr.wr_sync   = !!(file->f_flags & O_SYNC ||
                                           file->f_flags & O_DIRECT ||
                                           IS_SYNC(inode));
+#ifdef HAVE_GENERIC_WRITE_SYNC_2ARGS
+               io->u.ci_wr.wr_sync  |= !!(args &&
+                                          args->via_io_subtype == IO_NORMAL &&
+                                          args->u.normal.via_iocb->ki_flags & IOCB_DSYNC);
+#endif
        }
+
        io->ci_obj = ll_i2info(inode)->lli_clob;
        io->ci_lockreq = CILR_MAYBE;
        if (ll_file_nolock(file)) {
@@ -1391,6 +1424,7 @@ static void ll_io_init(struct cl_io *io, struct file *file, enum cl_io_type iot)
                io->ci_lockreq = CILR_MANDATORY;
        }
        io->ci_noatime = file_is_noatime(file);
+       io->ci_async_readahead = false;
 
        /* FLR: only use non-delay I/O for read as there is only one
         * avaliable mirror for write. */
@@ -1444,7 +1478,7 @@ ll_file_io_generic(const struct lu_env *env, struct vvp_io_args *args,
        ssize_t                 result = 0;
        int                     rc = 0;
        unsigned                retried = 0;
-       bool                    restarted = false;
+       unsigned                ignore_lockless = 0;
 
        ENTRY;
 
@@ -1454,7 +1488,8 @@ ll_file_io_generic(const struct lu_env *env, struct vvp_io_args *args,
 
 restart:
        io = vvp_env_thread_io(env);
-       ll_io_init(io, file, iot);
+       ll_io_init(io, file, iot, args);
+       io->ci_ignore_lockless = ignore_lockless;
        io->ci_ndelay_tried = retried;
 
        if (cl_io_rw_init(env, io, iot, *ppos, count) == 0) {
@@ -1527,7 +1562,8 @@ out:
               file->f_path.dentry->d_name.name,
               iot, rc, result, io->ci_need_restart);
 
-       if ((rc == 0 || rc == -ENODATA) && count > 0 && io->ci_need_restart) {
+       if ((rc == 0 || rc == -ENODATA || rc == -ENOLCK) &&
+           count > 0 && io->ci_need_restart) {
                CDEBUG(D_VFSTRACE,
                       "%s: restart %s from %lld, count: %zu, ret: %zd, rc: %d\n",
                       file_dentry(file)->d_name.name,
@@ -1535,7 +1571,7 @@ out:
                       *ppos, count, result, rc);
                /* preserve the tried count for FLR */
                retried = io->ci_ndelay_tried;
-               restarted = true;
+               ignore_lockless = io->ci_ignore_lockless;
                goto restart;
        }
 
@@ -1625,7 +1661,7 @@ ll_do_fast_read(struct kiocb *iocb, struct iov_iter *iter)
        if (result > 0) {
                ll_heat_add(file_inode(iocb->ki_filp), CIT_READ, result);
                ll_stats_ops_tally(ll_i2sbi(file_inode(iocb->ki_filp)),
-                               LPROC_LL_READ_BYTES, result);
+                                  LPROC_LL_READ_BYTES, result);
        }
 
        return result;
@@ -1638,10 +1674,15 @@ static ssize_t ll_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
 {
        struct lu_env *env;
        struct vvp_io_args *args;
+       struct file *file = iocb->ki_filp;
        ssize_t result;
        ssize_t rc2;
        __u16 refcheck;
-       bool cached = false;
+       ktime_t kstart = ktime_get();
+       bool cached;
+
+       if (!iov_iter_count(to))
+               return 0;
 
        /**
         * Currently when PCC read failed, we do not fall back to the
@@ -1656,9 +1697,9 @@ static ssize_t ll_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
         */
        result = pcc_file_read_iter(iocb, to, &cached);
        if (cached)
-               return result;
+               GOTO(out, result);
 
-       ll_ras_enter(iocb->ki_filp);
+       ll_ras_enter(file, iocb->ki_pos, iov_iter_count(to));
 
        result = ll_do_fast_read(iocb, to);
        if (result < 0 || iov_iter_count(to) == 0)
@@ -1672,7 +1713,7 @@ static ssize_t ll_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
        args->u.normal.via_iter = to;
        args->u.normal.via_iocb = iocb;
 
-       rc2 = ll_file_io_generic(env, args, iocb->ki_filp, CIT_READ,
+       rc2 = ll_file_io_generic(env, args, file, CIT_READ,
                                 &iocb->ki_pos, iov_iter_count(to));
        if (rc2 > 0)
                result += rc2;
@@ -1681,6 +1722,14 @@ static ssize_t ll_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
 
        cl_env_put(env, &refcheck);
 out:
+       if (result > 0) {
+               ll_rw_stats_tally(ll_i2sbi(file_inode(file)), current->pid,
+                                 LUSTRE_FPRIVATE(file), iocb->ki_pos, result,
+                                 READ);
+               ll_stats_ops_tally(ll_i2sbi(file_inode(file)), LPROC_LL_READ,
+                                  ktime_us_delta(ktime_get(), kstart));
+       }
+
        return result;
 }
 
@@ -1751,32 +1800,38 @@ static ssize_t ll_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
        struct vvp_io_args *args;
        struct lu_env *env;
        ssize_t rc_tiny = 0, rc_normal;
+       struct file *file = iocb->ki_filp;
        __u16 refcheck;
-       bool cached = false;
+       bool cached;
+       ktime_t kstart = ktime_get();
        int result;
 
        ENTRY;
 
+       if (!iov_iter_count(from))
+               GOTO(out, rc_normal = 0);
+
        /**
-        * When PCC write failed, we do not fall back to the normal
-        * write path, just return the error. The reason is that:
-        * PCC is actually a HSM device, and HSM does not handle the
-        * failure especially -ENOSPC due to space used out; Moreover,
-        * the fallback to normal I/O path for ENOSPC failure, needs
-        * to restore the file data to OSTs first and redo the write
-        * again, making the logic of PCC very complex.
+        * When PCC write failed, we usually do not fall back to the normal
+        * write path, just return the error. But there is a special case when
+        * returned error code is -ENOSPC due to running out of space on PCC HSM
+        * bakcend. At this time, it will fall back to normal I/O path and
+        * retry the I/O. As the file is in HSM released state, it will restore
+        * the file data to OSTs first and redo the write again. And the
+        * restore process will revoke the layout lock and detach the file
+        * from PCC cache automatically.
         */
        result = pcc_file_write_iter(iocb, from, &cached);
-       if (cached)
-               return result;
+       if (cached && result != -ENOSPC && result != -EDQUOT)
+               GOTO(out, rc_normal = result);
 
        /* NB: we can't do direct IO for tiny writes because they use the page
         * cache, we can't do sync writes because tiny writes can't flush
         * pages, and we can't do append writes because we can't guarantee the
         * required DLM locks are held to protect file size.
         */
-       if (ll_sbi_has_tiny_write(ll_i2sbi(file_inode(iocb->ki_filp))) &&
-           !(iocb->ki_filp->f_flags & (O_DIRECT | O_SYNC | O_APPEND)))
+       if (ll_sbi_has_tiny_write(ll_i2sbi(file_inode(file))) &&
+           !(file->f_flags & (O_DIRECT | O_SYNC | O_APPEND)))
                rc_tiny = ll_do_tiny_write(iocb, from);
 
        /* In case of error, go on and try normal write - Only stop if tiny
@@ -1793,8 +1848,8 @@ static ssize_t ll_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
        args->u.normal.via_iter = from;
        args->u.normal.via_iocb = iocb;
 
-       rc_normal = ll_file_io_generic(env, args, iocb->ki_filp, CIT_WRITE,
-                                   &iocb->ki_pos, iov_iter_count(from));
+       rc_normal = ll_file_io_generic(env, args, file, CIT_WRITE,
+                                      &iocb->ki_pos, iov_iter_count(from));
 
        /* On success, combine bytes written. */
        if (rc_tiny >= 0 && rc_normal > 0)
@@ -1807,6 +1862,14 @@ static ssize_t ll_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
 
        cl_env_put(env, &refcheck);
 out:
+       if (rc_normal > 0) {
+               ll_rw_stats_tally(ll_i2sbi(file_inode(file)), current->pid,
+                                 LUSTRE_FPRIVATE(file), iocb->ki_pos,
+                                 rc_normal, WRITE);
+               ll_stats_ops_tally(ll_i2sbi(file_inode(file)), LPROC_LL_WRITE,
+                                  ktime_us_delta(ktime_get(), kstart));
+       }
+
        RETURN(rc_normal);
 }
 
@@ -1854,6 +1917,9 @@ static ssize_t ll_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
        if (result)
                RETURN(result);
 
+       if (!iov_count)
+               RETURN(0);
+
 # ifdef HAVE_IOV_ITER_INIT_DIRECTION
        iov_iter_init(&to, READ, iov, nr_segs, iov_count);
 # else /* !HAVE_IOV_ITER_INIT_DIRECTION */
@@ -1871,8 +1937,12 @@ static ssize_t ll_file_read(struct file *file, char __user *buf, size_t count,
        struct iovec   iov = { .iov_base = buf, .iov_len = count };
        struct kiocb   kiocb;
        ssize_t        result;
+
        ENTRY;
 
+       if (!count)
+               RETURN(0);
+
        init_sync_kiocb(&kiocb, file);
        kiocb.ki_pos = *ppos;
 #ifdef HAVE_KIOCB_KI_LEFT
@@ -1903,6 +1973,9 @@ static ssize_t ll_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
        if (result)
                RETURN(result);
 
+       if (!iov_count)
+               RETURN(0);
+
 # ifdef HAVE_IOV_ITER_INIT_DIRECTION
        iov_iter_init(&from, WRITE, iov, nr_segs, iov_count);
 # else /* !HAVE_IOV_ITER_INIT_DIRECTION */
@@ -1924,6 +1997,9 @@ static ssize_t ll_file_write(struct file *file, const char __user *buf,
 
        ENTRY;
 
+       if (!count)
+               RETURN(0);
+
        init_sync_kiocb(&kiocb, file);
        kiocb.ki_pos = *ppos;
 #ifdef HAVE_KIOCB_KI_LEFT
@@ -1946,23 +2022,22 @@ static ssize_t ll_file_splice_read(struct file *in_file, loff_t *ppos,
                                    struct pipe_inode_info *pipe, size_t count,
                                    unsigned int flags)
 {
-        struct lu_env      *env;
-        struct vvp_io_args *args;
-        ssize_t             result;
-       __u16               refcheck;
-       struct ll_file_data *fd = LUSTRE_FPRIVATE(in_file);
-       struct file *pcc_file = fd->fd_pcc_file.pccf_file;
+       struct lu_env *env;
+       struct vvp_io_args *args;
+       ssize_t result;
+       __u16 refcheck;
+       bool cached;
 
         ENTRY;
 
-       /* pcc cache path */
-       if (pcc_file && file_inode(pcc_file)->i_fop->splice_read)
-               return file_inode(pcc_file)->i_fop->splice_read(pcc_file,
-                                               ppos, pipe, count, flags);
+       result = pcc_file_splice_read(in_file, ppos, pipe,
+                                     count, flags, &cached);
+       if (cached)
+               RETURN(result);
 
-       ll_ras_enter(in_file);
+       ll_ras_enter(in_file, *ppos, count);
 
-        env = cl_env_get(&refcheck);
+       env = cl_env_get(&refcheck);
         if (IS_ERR(env))
                 RETURN(PTR_ERR(env));
 
@@ -1972,6 +2047,11 @@ static ssize_t ll_file_splice_read(struct file *in_file, loff_t *ppos,
 
         result = ll_file_io_generic(env, args, in_file, CIT_READ, ppos, count);
         cl_env_put(env, &refcheck);
+
+       if (result > 0)
+               ll_rw_stats_tally(ll_i2sbi(file_inode(in_file)), current->pid,
+                                 LUSTRE_FPRIVATE(in_file), *ppos, result,
+                                 READ);
         RETURN(result);
 }
 
@@ -1985,6 +2065,12 @@ int ll_lov_setstripe_ea_info(struct inode *inode, struct dentry *dentry,
        int rc;
        ENTRY;
 
+       if ((__swab32(lum->lmm_magic) & le32_to_cpu(LOV_MAGIC_MASK)) ==
+           le32_to_cpu(LOV_MAGIC_MAGIC)) {
+               /* this code will only exist for big-endian systems */
+               lustre_swab_lov_user_md(lum, 0);
+       }
+
        ll_inode_size_lock(inode);
        rc = ll_intent_file_open(dentry, lum, lum_size, &oit);
        if (rc < 0)
@@ -2048,13 +2134,14 @@ int ll_lov_getstripe_ea_info(struct inode *inode, const char *filename,
            lmm->lmm_magic != cpu_to_le32(LOV_MAGIC_FOREIGN))
                GOTO(out, rc = -EPROTO);
 
-        /*
-         * This is coming from the MDS, so is probably in
-         * little endian.  We convert it to host endian before
-         * passing it to userspace.
-         */
-        if (LOV_MAGIC != cpu_to_le32(LOV_MAGIC)) {
-               int stripe_count;
+       /*
+        * This is coming from the MDS, so is probably in
+        * little endian.  We convert it to host endian before
+        * passing it to userspace.
+        */
+       if ((lmm->lmm_magic & __swab32(LOV_MAGIC_MAGIC)) ==
+           __swab32(LOV_MAGIC_MAGIC)) {
+               int stripe_count = 0;
 
                if (lmm->lmm_magic == cpu_to_le32(LOV_MAGIC_V1) ||
                    lmm->lmm_magic == cpu_to_le32(LOV_MAGIC_V3)) {
@@ -2064,36 +2151,19 @@ int ll_lov_getstripe_ea_info(struct inode *inode, const char *filename,
                                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)) {
-                       lustre_swab_lov_user_md_v1(
-                                       (struct lov_user_md_v1 *)lmm);
-                       if (S_ISREG(body->mbo_mode))
-                               lustre_swab_lov_user_md_objects(
-                                   ((struct lov_user_md_v1 *)lmm)->lmm_objects,
-                                   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->mbo_mode))
-                               lustre_swab_lov_user_md_objects(
-                                   ((struct lov_user_md_v3 *)lmm)->lmm_objects,
-                                   stripe_count);
-               } else if (lmm->lmm_magic ==
-                          cpu_to_le32(LOV_MAGIC_COMP_V1)) {
-                       lustre_swab_lov_comp_md_v1(
-                                       (struct lov_comp_md_v1 *)lmm);
-               } else if (lmm->lmm_magic ==
-                          cpu_to_le32(LOV_MAGIC_FOREIGN)) {
-                       struct lov_foreign_md *lfm;
-
-                       lfm = (struct lov_foreign_md *)lmm;
-                       __swab32s(&lfm->lfm_magic);
-                       __swab32s(&lfm->lfm_length);
-                       __swab32s(&lfm->lfm_type);
-                       __swab32s(&lfm->lfm_flags);
-               }
+               lustre_swab_lov_user_md((struct lov_user_md *)lmm, 0);
+
+               /* if function called for directory - we should
+                * avoid swab not existent lsm objects */
+               if (lmm->lmm_magic == LOV_MAGIC_V1 && S_ISREG(body->mbo_mode))
+                       lustre_swab_lov_user_md_objects(
+                               ((struct lov_user_md_v1 *)lmm)->lmm_objects,
+                               stripe_count);
+               else if (lmm->lmm_magic == LOV_MAGIC_V3 &&
+                        S_ISREG(body->mbo_mode))
+                       lustre_swab_lov_user_md_objects(
+                               ((struct lov_user_md_v3 *)lmm)->lmm_objects,
+                               stripe_count);
        }
 
 out:
@@ -2180,10 +2250,11 @@ static int ll_lov_setstripe(struct inode *inode, struct file *file,
        cl_lov_delay_create_clear(&file->f_flags);
 
 out:
-       OBD_FREE(klum, lum_size);
+       OBD_FREE_LARGE(klum, lum_size);
        RETURN(rc);
 }
 
+
 static int
 ll_get_grouplock(struct inode *inode, struct file *file, unsigned long arg)
 {
@@ -2199,18 +2270,28 @@ ll_get_grouplock(struct inode *inode, struct file *file, unsigned long arg)
                RETURN(-EINVAL);
        }
 
-        if (ll_file_nolock(file))
-                RETURN(-EOPNOTSUPP);
+       if (ll_file_nolock(file))
+               RETURN(-EOPNOTSUPP);
+retry:
+       if (file->f_flags & O_NONBLOCK) {
+               if (!mutex_trylock(&lli->lli_group_mutex))
+                       RETURN(-EAGAIN);
+       } else
+               mutex_lock(&lli->lli_group_mutex);
 
-       spin_lock(&lli->lli_lock);
        if (fd->fd_flags & LL_FILE_GROUP_LOCKED) {
                CWARN("group lock already existed with gid %lu\n",
                      fd->fd_grouplock.lg_gid);
-               spin_unlock(&lli->lli_lock);
-               RETURN(-EINVAL);
+               GOTO(out, rc = -EINVAL);
+       }
+       if (arg != lli->lli_group_gid && lli->lli_group_users != 0) {
+               if (file->f_flags & O_NONBLOCK)
+                       GOTO(out, rc = -EAGAIN);
+               mutex_unlock(&lli->lli_group_mutex);
+               wait_var_event(&lli->lli_group_users, !lli->lli_group_users);
+               GOTO(retry, rc = 0);
        }
        LASSERT(fd->fd_grouplock.lg_lock == NULL);
-       spin_unlock(&lli->lli_lock);
 
        /**
         * XXX: group lock needs to protect all OST objects while PFL
@@ -2230,7 +2311,7 @@ ll_get_grouplock(struct inode *inode, struct file *file, unsigned long arg)
 
                env = cl_env_get(&refcheck);
                if (IS_ERR(env))
-                       RETURN(PTR_ERR(env));
+                       GOTO(out, rc = PTR_ERR(env));
 
                rc = cl_object_layout_get(env, obj, &cl);
                if (!rc && cl.cl_is_composite)
@@ -2239,28 +2320,26 @@ ll_get_grouplock(struct inode *inode, struct file *file, unsigned long arg)
 
                cl_env_put(env, &refcheck);
                if (rc)
-                       RETURN(rc);
+                       GOTO(out, rc);
        }
 
        rc = cl_get_grouplock(ll_i2info(inode)->lli_clob,
                              arg, (file->f_flags & O_NONBLOCK), &grouplock);
-       if (rc)
-               RETURN(rc);
 
-       spin_lock(&lli->lli_lock);
-       if (fd->fd_flags & LL_FILE_GROUP_LOCKED) {
-               spin_unlock(&lli->lli_lock);
-               CERROR("another thread just won the race\n");
-               cl_put_grouplock(&grouplock);
-               RETURN(-EINVAL);
-       }
+       if (rc)
+               GOTO(out, rc);
 
        fd->fd_flags |= LL_FILE_GROUP_LOCKED;
        fd->fd_grouplock = grouplock;
-       spin_unlock(&lli->lli_lock);
+       if (lli->lli_group_users == 0)
+               lli->lli_group_gid = grouplock.lg_gid;
+       lli->lli_group_users++;
 
        CDEBUG(D_INFO, "group lock %lu obtained\n", arg);
-       RETURN(0);
+out:
+       mutex_unlock(&lli->lli_group_mutex);
+
+       RETURN(rc);
 }
 
 static int ll_put_grouplock(struct inode *inode, struct file *file,
@@ -2269,32 +2348,40 @@ static int ll_put_grouplock(struct inode *inode, struct file *file,
        struct ll_inode_info   *lli = ll_i2info(inode);
        struct ll_file_data    *fd = LUSTRE_FPRIVATE(file);
        struct ll_grouplock     grouplock;
+       int                     rc;
        ENTRY;
 
-       spin_lock(&lli->lli_lock);
+       mutex_lock(&lli->lli_group_mutex);
        if (!(fd->fd_flags & LL_FILE_GROUP_LOCKED)) {
-               spin_unlock(&lli->lli_lock);
-                CWARN("no group lock held\n");
-                RETURN(-EINVAL);
-        }
+               CWARN("no group lock held\n");
+               GOTO(out, rc = -EINVAL);
+       }
 
        LASSERT(fd->fd_grouplock.lg_lock != NULL);
 
        if (fd->fd_grouplock.lg_gid != arg) {
                CWARN("group lock %lu doesn't match current id %lu\n",
                      arg, fd->fd_grouplock.lg_gid);
-               spin_unlock(&lli->lli_lock);
-               RETURN(-EINVAL);
+               GOTO(out, rc = -EINVAL);
        }
 
        grouplock = fd->fd_grouplock;
        memset(&fd->fd_grouplock, 0, sizeof(fd->fd_grouplock));
        fd->fd_flags &= ~LL_FILE_GROUP_LOCKED;
-       spin_unlock(&lli->lli_lock);
 
        cl_put_grouplock(&grouplock);
+
+       lli->lli_group_users--;
+       if (lli->lli_group_users == 0) {
+               lli->lli_group_gid = 0;
+               wake_up_var(&lli->lli_group_users);
+       }
        CDEBUG(D_INFO, "group lock %lu released\n", arg);
-       RETURN(0);
+       GOTO(out, rc = 0);
+out:
+       mutex_unlock(&lli->lli_group_mutex);
+
+       RETURN(rc);
 }
 
 /**
@@ -2329,7 +2416,9 @@ 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, it, och);
+       rc = ll_och_fill(ll_i2sbi(inode)->ll_md_exp, it, och);
+       if (rc)
+               GOTO(out, rc);
 
        rc = ll_close_inode_openhandle(inode, och, 0, NULL);
 out:
@@ -2975,6 +3064,7 @@ static int ll_ladvise_sanity(struct inode *inode,
                               ladvise_names[advice], rc);
                        GOTO(out, rc);
                }
+               /* fallthrough */
        case LU_LADVISE_WILLREAD:
        case LU_LADVISE_DONTNEED:
        default:
@@ -3310,8 +3400,10 @@ out:
        case LL_LEASE_PCC_ATTACH:
                if (!rc)
                        rc = rc2;
-               rc = pcc_readwrite_attach_fini(file, inode, lease_broken,
-                                              rc, attached);
+               rc = pcc_readwrite_attach_fini(file, inode,
+                                              param.pa_layout_gen,
+                                              lease_broken, rc,
+                                              attached);
                break;
        }
 
@@ -3836,6 +3928,29 @@ out_ladvise:
                rc = ll_heat_set(inode, flags);
                RETURN(rc);
        }
+       case LL_IOC_PCC_DETACH: {
+               struct lu_pcc_detach *detach;
+
+               OBD_ALLOC_PTR(detach);
+               if (detach == NULL)
+                       RETURN(-ENOMEM);
+
+               if (copy_from_user(detach,
+                                  (const struct lu_pcc_detach __user *)arg,
+                                  sizeof(*detach)))
+                       GOTO(out_detach_free, rc = -EFAULT);
+
+               if (!S_ISREG(inode->i_mode))
+                       GOTO(out_detach_free, rc = -EINVAL);
+
+               if (!inode_owner_or_capable(inode))
+                       GOTO(out_detach_free, rc = -EPERM);
+
+               rc = pcc_ioctl_detach(inode, detach->pccd_opt);
+out_detach_free:
+               OBD_FREE_PTR(detach);
+               RETURN(rc);
+       }
        case LL_IOC_PCC_STATE: {
                struct lu_pcc_state __user *ustate =
                        (struct lu_pcc_state __user *)arg;
@@ -3848,7 +3963,7 @@ out_ladvise:
                if (copy_from_user(state, ustate, sizeof(*state)))
                        GOTO(out_state, rc = -EFAULT);
 
-               rc = pcc_ioctl_state(inode, state);
+               rc = pcc_ioctl_state(file, inode, state);
                if (rc)
                        GOTO(out_state, rc);
 
@@ -3936,6 +4051,7 @@ static loff_t ll_file_seek(struct file *file, loff_t offset, int origin)
 {
        struct inode *inode = file_inode(file);
        loff_t retval, eof = 0;
+       ktime_t kstart = ktime_get();
 
        ENTRY;
        retval = offset + ((origin == SEEK_END) ? i_size_read(inode) :
@@ -3943,7 +4059,6 @@ static loff_t ll_file_seek(struct file *file, loff_t offset, int origin)
        CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p), to=%llu=%#llx(%d)\n",
               PFID(ll_inode2fid(inode)), inode, retval, retval,
               origin);
-       ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_LLSEEK, 1);
 
        if (origin == SEEK_END || origin == SEEK_HOLE || origin == SEEK_DATA) {
                retval = ll_glimpse_size(inode);
@@ -3953,7 +4068,10 @@ static loff_t ll_file_seek(struct file *file, loff_t offset, int origin)
        }
 
        retval = ll_generic_file_llseek_size(file, offset, origin,
-                                         ll_file_maxbytes(inode), eof);
+                                            ll_file_maxbytes(inode), eof);
+       if (retval >= 0)
+               ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_LLSEEK,
+                                  ktime_us_delta(ktime_get(), kstart));
        RETURN(retval);
 }
 
@@ -4037,55 +4155,25 @@ int cl_sync_file_range(struct inode *inode, loff_t start, loff_t end,
  * file_dentry() as is done otherwise.
  */
 
-#ifdef HAVE_FILE_FSYNC_4ARGS
 int ll_fsync(struct file *file, loff_t start, loff_t end, int datasync)
 {
        struct dentry *dentry = file_dentry(file);
-#elif defined(HAVE_FILE_FSYNC_2ARGS)
-int ll_fsync(struct file *file, int datasync)
-{
-       struct dentry *dentry = file_dentry(file);
-       loff_t start = 0;
-       loff_t end = LLONG_MAX;
-#else
-int ll_fsync(struct file *file, struct dentry *dentry, int datasync)
-{
-       loff_t start = 0;
-       loff_t end = LLONG_MAX;
-#endif
        struct inode *inode = dentry->d_inode;
        struct ll_inode_info *lli = ll_i2info(inode);
-       struct ll_file_data *fd = LUSTRE_FPRIVATE(file);
        struct ptlrpc_request *req;
-       struct file *pcc_file = fd->fd_pcc_file.pccf_file;
+       ktime_t kstart = ktime_get();
        int rc, err;
+
        ENTRY;
 
-       CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p)\n",
-              PFID(ll_inode2fid(inode)), inode);
-       ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_FSYNC, 1);
-
-       /* pcc cache path */
-       if (pcc_file)
-#ifdef HAVE_FILE_FSYNC_4ARGS
-               return file_inode(pcc_file)->i_fop->fsync(pcc_file,
-                                       start, end, datasync);
-#elif defined(HAVE_FILE_FSYNC_2ARGS)
-               return file_inode(pcc_file)->i_fop->fsync(pcc_file,
-                                       datasync);
-#else
-               return file_inode(pcc_file)->i_fop->fsync(pcc_file,
-                                       dentry, datasync);
-#endif
+       CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p), start %lld, end %lld,"
+              "datasync %d\n",
+              PFID(ll_inode2fid(inode)), inode, start, end, datasync);
 
-#ifdef HAVE_FILE_FSYNC_4ARGS
-       rc = filemap_write_and_wait_range(inode->i_mapping, start, end);
-       inode_lock(inode);
-#else
        /* fsync's caller has already called _fdata{sync,write}, we want
         * that IO to finish before calling the osc and mdc sync methods */
-       rc = filemap_fdatawait(inode->i_mapping);
-#endif
+       rc = filemap_write_and_wait_range(inode->i_mapping, start, end);
+       inode_lock(inode);
 
        /* catch async errors that were recorded back when async writeback
         * failed for pages in this mapping. */
@@ -4109,8 +4197,15 @@ int ll_fsync(struct file *file, struct dentry *dentry, int datasync)
 
        if (S_ISREG(inode->i_mode)) {
                struct ll_file_data *fd = LUSTRE_FPRIVATE(file);
+               bool cached;
 
-               err = cl_sync_file_range(inode, start, end, CL_FSYNC_ALL, 0);
+               /* Sync metadata on MDT first, and then sync the cached data
+                * on PCC.
+                */
+               err = pcc_fsync(file, start, end, datasync, &cached);
+               if (!cached)
+                       err = cl_sync_file_range(inode, start, end,
+                                                CL_FSYNC_ALL, 0);
                if (rc == 0 && err < 0)
                        rc = err;
                if (rc < 0)
@@ -4119,9 +4214,11 @@ int ll_fsync(struct file *file, struct dentry *dentry, int datasync)
                        fd->fd_write_failed = false;
        }
 
-#ifdef HAVE_FILE_FSYNC_4ARGS
        inode_unlock(inode);
-#endif
+
+       if (!rc)
+               ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_FSYNC,
+                                  ktime_us_delta(ktime_get(), kstart));
        RETURN(rc);
 }
 
@@ -4139,6 +4236,7 @@ ll_file_flock(struct file *file, int cmd, struct file_lock *file_lock)
        struct lustre_handle lockh = { 0 };
        union ldlm_policy_data flock = { { 0 } };
        int fl_type = file_lock->fl_type;
+       ktime_t kstart = ktime_get();
        __u64 flags = 0;
        int rc;
        int rc2 = 0;
@@ -4147,23 +4245,22 @@ ll_file_flock(struct file *file, int cmd, struct file_lock *file_lock)
        CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID" file_lock=%p\n",
               PFID(ll_inode2fid(inode)), file_lock);
 
-        ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_FLOCK, 1);
-
-        if (file_lock->fl_flags & FL_FLOCK) {
-                LASSERT((cmd == F_SETLKW) || (cmd == F_SETLK));
-                /* flocks are whole-file locks */
-                flock.l_flock.end = OFFSET_MAX;
-                /* For flocks owner is determined by the local file desctiptor*/
-                flock.l_flock.owner = (unsigned long)file_lock->fl_file;
-        } else if (file_lock->fl_flags & FL_POSIX) {
-                flock.l_flock.owner = (unsigned long)file_lock->fl_owner;
-                flock.l_flock.start = file_lock->fl_start;
-                flock.l_flock.end = file_lock->fl_end;
-        } else {
-                RETURN(-EINVAL);
-        }
-        flock.l_flock.pid = file_lock->fl_pid;
+       if (file_lock->fl_flags & FL_FLOCK) {
+               LASSERT((cmd == F_SETLKW) || (cmd == F_SETLK));
+               /* flocks are whole-file locks */
+               flock.l_flock.end = OFFSET_MAX;
+               /* For flocks owner is determined by the local file desctiptor*/
+               flock.l_flock.owner = (unsigned long)file_lock->fl_file;
+       } else if (file_lock->fl_flags & FL_POSIX) {
+               flock.l_flock.owner = (unsigned long)file_lock->fl_owner;
+               flock.l_flock.start = file_lock->fl_start;
+               flock.l_flock.end = file_lock->fl_end;
+       } else {
+               RETURN(-EINVAL);
+       }
+       flock.l_flock.pid = file_lock->fl_pid;
 
+#if defined(HAVE_LM_COMPARE_OWNER) || defined(lm_compare_owner)
        /* Somewhat ugly workaround for svc lockd.
         * lockd installs custom fl_lmops->lm_compare_owner that checks
         * for the fl_owner to be the same (which it always is on local node
@@ -4173,6 +4270,7 @@ ll_file_flock(struct file *file, int cmd, struct file_lock *file_lock)
         * pointer space for current->files are not intersecting */
        if (file_lock->fl_lmops && file_lock->fl_lmops->lm_compare_owner)
                flock.l_flock.owner = (unsigned long)file_lock->fl_pid;
+#endif
 
        switch (fl_type) {
         case F_RDLCK:
@@ -4265,7 +4363,10 @@ ll_file_flock(struct file *file, int cmd, struct file_lock *file_lock)
 
        ll_finish_md_op_data(op_data);
 
-        RETURN(rc);
+       if (!rc)
+               ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_FLOCK,
+                                  ktime_us_delta(ktime_get(), kstart));
+       RETURN(rc);
 }
 
 int ll_get_fid_by_name(struct inode *parent, const char *name,
@@ -4350,7 +4451,7 @@ int ll_migrate(struct inode *parent, struct file *file, struct lmv_user_md *lum,
        if (!(exp_connect_flags2(ll_i2sbi(parent)->ll_md_exp) &
              OBD_CONNECT2_DIR_MIGRATE)) {
                if (le32_to_cpu(lum->lum_stripe_count) > 1 ||
-                   ll_i2info(child_inode)->lli_lsm_md) {
+                   ll_dir_striped(child_inode)) {
                        CERROR("%s: MDT doesn't support stripe directory "
                               "migration!\n", ll_i2sbi(parent)->ll_fsname);
                        GOTO(out_iput, rc = -EOPNOTSUPP);
@@ -4455,9 +4556,20 @@ out_iput:
 static int
 ll_file_noflock(struct file *file, int cmd, struct file_lock *file_lock)
 {
-        ENTRY;
+       struct ll_file_data *fd = LUSTRE_FPRIVATE(file);
+       ENTRY;
 
-        RETURN(-ENOSYS);
+       /*
+        * In order to avoid flood of warning messages, only print one message
+        * for one file. And the entire message rate on the client is limited
+        * by CDEBUG_LIMIT too.
+        */
+       if (!(fd->fd_flags & LL_FILE_FLOCK_WARNING)) {
+               fd->fd_flags |= LL_FILE_FLOCK_WARNING;
+               CDEBUG_LIMIT(D_TTY | D_CONSOLE,
+                            "flock disabled, mount with '-o [local]flock' to enable\r\n");
+       }
+       RETURN(-ENOSYS);
 }
 
 /**
@@ -4489,7 +4601,7 @@ int ll_have_md_lock(struct inode *inode, __u64 *bits, enum ldlm_mode l_req_mode)
                ldlm_lockname[mode]);
 
        flags = LDLM_FL_BLOCK_GRANTED | LDLM_FL_CBPENDING | LDLM_FL_TEST_LOCK;
-       for (i = 0; i <= MDS_INODELOCK_MAXSHIFT && *bits != 0; i++) {
+       for (i = 0; i < MDS_INODELOCK_NUMBITS && *bits != 0; i++) {
                policy.l_inodebits.bits = *bits & (1 << i);
                if (policy.l_inodebits.bits == 0)
                        continue;
@@ -4537,8 +4649,7 @@ static int ll_inode_revalidate_fini(struct inode *inode, int rc)
                /* If it is striped directory, and there is bad stripe
                 * Let's revalidate the dentry again, instead of returning
                 * error */
-               if (S_ISDIR(inode->i_mode) &&
-                   ll_i2info(inode)->lli_lsm_md != NULL)
+               if (ll_dir_striped(inode))
                        return 0;
 
                /* This path cannot be hit for regular files unless in
@@ -4595,9 +4706,9 @@ static int ll_inode_revalidate(struct dentry *dentry, enum ldlm_intent_flags op)
         * here to preserve get_cwd functionality on 2.6.
         * Bug 10503 */
        if (!dentry->d_inode->i_nlink) {
-               ll_lock_dcache(inode);
+               spin_lock(&inode->i_lock);
                d_lustre_invalidate(dentry, 0);
-               ll_unlock_dcache(inode);
+               spin_unlock(&inode->i_lock);
        }
 
        ll_lookup_finish_locks(&oit, dentry);
@@ -4615,8 +4726,7 @@ static int ll_merge_md_attr(struct inode *inode)
 
        LASSERT(lli->lli_lsm_md != NULL);
 
-       /* foreign dir is not striped dir */
-       if (lli->lli_lsm_md->lsm_md_magic == LMV_MAGIC_FOREIGN)
+       if (!lmv_dir_striped(lli->lli_lsm_md))
                RETURN(0);
 
        down_read(&lli->lli_lsm_sem);
@@ -4642,20 +4752,20 @@ int ll_getattr_dentry(struct dentry *de, struct kstat *stat)
        struct inode *inode = de->d_inode;
        struct ll_sb_info *sbi = ll_i2sbi(inode);
        struct ll_inode_info *lli = ll_i2info(inode);
+       ktime_t kstart = ktime_get();
        int rc;
 
-       ll_stats_ops_tally(sbi, LPROC_LL_GETATTR, 1);
-
        rc = ll_inode_revalidate(de, IT_GETATTR);
        if (rc < 0)
                RETURN(rc);
 
        if (S_ISREG(inode->i_mode)) {
-               bool cached = false;
+               bool cached;
 
                rc = pcc_inode_getattr(inode, &cached);
                if (cached && rc < 0)
                        RETURN(rc);
+
                /* 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.
@@ -4670,8 +4780,7 @@ int ll_getattr_dentry(struct dentry *de, struct kstat *stat)
                }
        } else {
                /* If object isn't regular a file then don't validate size. */
-               if (S_ISDIR(inode->i_mode) &&
-                   lli->lli_lsm_md != NULL) {
+               if (ll_dir_striped(inode)) {
                        rc = ll_merge_md_attr(inode);
                        if (rc < 0)
                                RETURN(rc);
@@ -4706,7 +4815,10 @@ int ll_getattr_dentry(struct dentry *de, struct kstat *stat)
        stat->size = i_size_read(inode);
        stat->blocks = inode->i_blocks;
 
-        return 0;
+       ll_stats_ops_tally(sbi, LPROC_LL_GETATTR,
+                          ktime_us_delta(ktime_get(), kstart));
+
+       return 0;
 }
 
 #ifdef HAVE_INODEOPS_ENHANCED_GETATTR
@@ -4774,7 +4886,7 @@ struct posix_acl *ll_get_acl(struct inode *inode, int type)
 }
 
 #ifdef HAVE_IOP_SET_ACL
-#ifdef CONFIG_FS_POSIX_ACL
+#ifdef CONFIG_LUSTRE_FS_POSIX_ACL
 int ll_set_acl(struct inode *inode, struct posix_acl *acl, int type)
 {
        struct ll_sb_info *sbi = ll_i2sbi(inode);
@@ -4830,50 +4942,10 @@ out:
                set_cached_acl(inode, type, acl);
        RETURN(rc);
 }
-#endif /* CONFIG_FS_POSIX_ACL */
+#endif /* CONFIG_LUSTRE_FS_POSIX_ACL */
 #endif /* HAVE_IOP_SET_ACL */
 
-#ifndef HAVE_GENERIC_PERMISSION_2ARGS
-static int
-# ifdef HAVE_GENERIC_PERMISSION_4ARGS
-ll_check_acl(struct inode *inode, int mask, unsigned int flags)
-# else
-ll_check_acl(struct inode *inode, int mask)
-# endif
-{
-# ifdef CONFIG_FS_POSIX_ACL
-       struct posix_acl *acl;
-       int rc;
-       ENTRY;
-
-#  ifdef HAVE_GENERIC_PERMISSION_4ARGS
-       if (flags & IPERM_FLAG_RCU)
-               return -ECHILD;
-#  endif
-       acl = ll_get_acl(inode, ACL_TYPE_ACCESS);
-
-       if (!acl)
-               RETURN(-EAGAIN);
-
-       rc = posix_acl_permission(inode, acl, mask);
-       posix_acl_release(acl);
-
-       RETURN(rc);
-# else /* !CONFIG_FS_POSIX_ACL */
-       return -EAGAIN;
-# endif /* CONFIG_FS_POSIX_ACL */
-}
-#endif /* HAVE_GENERIC_PERMISSION_2ARGS */
-
-#ifdef HAVE_GENERIC_PERMISSION_4ARGS
-int ll_inode_permission(struct inode *inode, int mask, unsigned int flags)
-#else
-# ifdef HAVE_INODE_PERMISION_2ARGS
 int ll_inode_permission(struct inode *inode, int mask)
-# else
-int ll_inode_permission(struct inode *inode, int mask, struct nameidata *nd)
-# endif
-#endif
 {
        int rc = 0;
        struct ll_sb_info *sbi;
@@ -4882,15 +4954,11 @@ int ll_inode_permission(struct inode *inode, int mask, struct nameidata *nd)
        const struct cred *old_cred = NULL;
        cfs_cap_t cap;
        bool squash_id = false;
+       ktime_t kstart = ktime_get();
        ENTRY;
 
-#ifdef MAY_NOT_BLOCK
        if (mask & MAY_NOT_BLOCK)
                return -ECHILD;
-#elif defined(HAVE_GENERIC_PERMISSION_4ARGS)
-       if (flags & IPERM_FLAG_RCU)
-               return -ECHILD;
-#endif
 
        /* as root inode are NOT getting validated in lookup operation,
         * need to do it before permission check. */
@@ -4932,14 +5000,17 @@ int ll_inode_permission(struct inode *inode, int mask, struct nameidata *nd)
                old_cred = override_creds(cred);
        }
 
-       ll_stats_ops_tally(sbi, LPROC_LL_INODE_PERM, 1);
-       rc = ll_generic_permission(inode, mask, flags, ll_check_acl);
+       rc = generic_permission(inode, mask);
        /* restore current process's credentials and FS capability */
        if (squash_id) {
                revert_creds(old_cred);
                put_cred(cred);
        }
 
+       if (!rc)
+               ll_stats_ops_tally(sbi, LPROC_LL_INODE_PERM,
+                                  ktime_us_delta(ktime_get(), kstart));
+
        RETURN(rc);
 }
 
@@ -5334,7 +5405,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,
-                                      LCK_CR | LCK_CW | LCK_PR | LCK_PW);
+                                      LCK_CR | LCK_CW | LCK_PR |
+                                      LCK_PW | LCK_EX);
                if (mode != 0) { /* hit cached lock */
                        rc = ll_layout_lock_set(&lockh, mode, inode);
                        if (rc == -EAGAIN)