Whamcloud - gitweb
LU-4669 lmv: remove unused lmv_adjust_dirpages()
[fs/lustre-release.git] / lustre / llite / dir.c
index c579304..3fcaa6b 100644 (file)
@@ -51,8 +51,8 @@
 #include <lustre/lustre_idl.h>
 #include <obd_support.h>
 #include <obd_class.h>
+#include <lustre_ioctl.h>
 #include <lustre_lib.h>
-#include <lustre/lustre_idl.h>
 #include <lustre_lite.h>
 #include <lustre_dlm.h>
 #include <lustre_fid.h>
  * After client receives reply, several pages will be integrated into dir page
  * in PAGE_CACHE_SIZE (if PAGE_CACHE_SIZE greater than LU_PAGE_SIZE), and the
  * lu_dirpage for this integrated page will be adjusted. See
- * lmv_adjust_dirpages().
+ * mdc_adjust_dirpages().
  *
  */
-/**
- * The following three APIs will be used by llite to iterate directory
- * entries from MDC dir page caches.
- *
- * ll_dir_entry_start(next) will lookup(return) entry by op_hash_offset.
- * To avoid extra memory allocation, the @entry will be pointed to
- * the dir entries in MDC page directly, so these pages can not be released
- * until the entry has been accessed in ll_readdir(or statahead).
- *
- * The iterate process will be
- *
- * ll_dir_entry_start: locate the page in MDC, and return the first entry.
- *                    hold the page.
- *
- * ll_dir_entry_next: return the next entry in the current page, if it reaches
- *                   to the end, release current page.
- *
- * ll_dir_entry_end: release the last page.
- **/
-struct lu_dirent *ll_dir_entry_start(struct inode *dir,
-                                    struct md_op_data *op_data,
-                                    struct page **ppage)
+struct page *ll_get_dir_page(struct inode *dir, struct md_op_data *op_data,
+                            __u64 offset, struct ll_dir_chain *chain)
 {
-       struct lu_dirent *entry;
-       struct md_callback cb_op;
-       int rc;
+       struct md_callback      cb_op;
+       struct page             *page;
+       int                     rc;
 
-       LASSERT(*ppage == NULL);
        cb_op.md_blocking_ast = ll_md_blocking_ast;
-       rc = md_read_entry(ll_i2mdexp(dir), op_data, &cb_op, &entry, ppage);
+       rc = md_read_page(ll_i2mdexp(dir), op_data, &cb_op, offset, &page);
        if (rc != 0)
-               entry = ERR_PTR(rc);
-       return entry;
+               return ERR_PTR(rc);
+
+       return page;
 }
 
-struct lu_dirent *ll_dir_entry_next(struct inode *dir,
-                                   struct md_op_data *op_data,
-                                   struct lu_dirent *ent,
-                                   struct page **ppage)
+void ll_release_page(struct inode *inode, struct page *page,
+                    bool remove)
 {
-       struct lu_dirent *entry;
-       struct md_callback cb_op;
-       int rc;
+       kunmap(page);
+
+       /* Always remove the page for striped dir, because the page is
+        * built from temporarily in LMV layer */
+       if (inode != NULL && S_ISDIR(inode->i_mode) &&
+           ll_i2info(inode)->lli_lsm_md != NULL) {
+               __free_page(page);
+               return;
+       }
 
-       LASSERT(*ppage != NULL);
-       cb_op.md_blocking_ast = ll_md_blocking_ast;
-       op_data->op_hash_offset = le64_to_cpu(ent->lde_hash);
-       kunmap(*ppage);
-       page_cache_release(*ppage);
-       *ppage = NULL;
-       rc = md_read_entry(ll_i2mdexp(dir), op_data, &cb_op, &entry, ppage);
-       if (rc != 0)
-               entry = ERR_PTR(rc);
-       return entry;
+       if (remove) {
+               lock_page(page);
+               if (likely(page->mapping != NULL))
+                       truncate_complete_page(page->mapping, page);
+               unlock_page(page);
+       }
+       page_cache_release(page);
 }
 
-int ll_dir_read(struct inode *inode, struct md_op_data *op_data,
+#ifdef HAVE_DIR_CONTEXT
+int ll_dir_read(struct inode *inode, __u64 *ppos, struct md_op_data *op_data,
+               struct dir_context *ctx)
+{
+#else
+int ll_dir_read(struct inode *inode, __u64 *ppos, struct md_op_data *op_data,
                void *cookie, filldir_t filldir)
 {
-       struct ll_sb_info       *sbi = ll_i2sbi(inode);
-       struct ll_dir_chain     chain;
-       struct lu_dirent        *ent;
-       int                     api32 = ll_need_32bit_api(sbi);
-       int                     hash64 = sbi->ll_flags & LL_SBI_64BIT_HASH;
-       int                     done = 0;
-       int                     rc = 0;
-       __u64                   hash = MDS_DIR_END_OFF;
-       __u64                   last_hash = MDS_DIR_END_OFF;
-       struct page             *page = NULL;
+#endif
+       struct ll_sb_info    *sbi        = ll_i2sbi(inode);
+       __u64                 pos        = *ppos;
+       bool                  is_api32 = ll_need_32bit_api(sbi);
+       bool                  is_hash64 = sbi->ll_flags & LL_SBI_64BIT_HASH;
+       struct page          *page;
+       struct ll_dir_chain   chain;
+       bool                  done = false;
+       int                   rc = 0;
        ENTRY;
 
-        ll_dir_chain_init(&chain);
-       for (ent = ll_dir_entry_start(inode, op_data, &page);
-            ent != NULL && !IS_ERR(ent) && !done;
-            ent = ll_dir_entry_next(inode, op_data, ent, &page)) {
-               __u16          type;
-               int            namelen;
-               struct lu_fid  fid;
-               __u64          lhash;
-               __u64          ino;
-
-               hash = le64_to_cpu(ent->lde_hash);
-               if (hash < op_data->op_hash_offset)
-                       /*
-                        * Skip until we find target hash
-                        * value.
-                        */
-                       continue;
-               namelen = le16_to_cpu(ent->lde_namelen);
-               if (namelen == 0)
-                       /*
-                        * Skip dummy record.
-                        */
-                       continue;
+       ll_dir_chain_init(&chain);
 
-               if (api32 && hash64)
-                       lhash = hash >> 32;
-               else
-                       lhash = hash;
-               fid_le_to_cpu(&fid, &ent->lde_fid);
-               ino = cl_fid_build_ino(&fid, api32);
-               type = ll_dirent_type_get(ent);
-               /* For 'll_nfs_get_name_filldir()', it will try
-                * to access the 'ent' through its 'lde_name',
-                * so the parameter 'name' for 'filldir()' must
-                * be part of the 'ent'. */
-               done = filldir(cookie, ent->lde_name, namelen, lhash,
-                              ino, type);
-               if (done) {
-                       if (op_data->op_hash_offset != MDS_DIR_END_OFF)
-                               op_data->op_hash_offset = last_hash;
+       page = ll_get_dir_page(inode, op_data, pos, &chain);
+
+       while (rc == 0 && !done) {
+               struct lu_dirpage *dp;
+               struct lu_dirent  *ent;
+               __u64 hash;
+               __u64 next;
+
+               if (IS_ERR(page)) {
+                       rc = PTR_ERR(page);
                        break;
-               } else {
-                       last_hash = hash;
                }
-       }
 
-       if (IS_ERR(ent))
-               rc = PTR_ERR(ent);
+               hash = MDS_DIR_END_OFF;
+               dp = page_address(page);
+               for (ent = lu_dirent_start(dp); ent != NULL && !done;
+                    ent = lu_dirent_next(ent)) {
+                       __u16          type;
+                       int            namelen;
+                       struct lu_fid  fid;
+                       __u64          lhash;
+                       __u64          ino;
+
+                       hash = le64_to_cpu(ent->lde_hash);
+                       if (hash < pos)
+                               /*
+                                * Skip until we find target hash
+                                * value.
+                                */
+                               continue;
+
+                       namelen = le16_to_cpu(ent->lde_namelen);
+                       if (namelen == 0)
+                               /*
+                                * Skip dummy record.
+                                */
+                               continue;
+
+                       if (is_api32 && is_hash64)
+                               lhash = hash >> 32;
+                       else
+                               lhash = hash;
+                       fid_le_to_cpu(&fid, &ent->lde_fid);
+                       ino = cl_fid_build_ino(&fid, is_api32);
+                       type = ll_dirent_type_get(ent);
+                       /* For 'll_nfs_get_name_filldir()', it will try
+                        * to access the 'ent' through its 'lde_name',
+                        * so the parameter 'name' for 'filldir()' must
+                        * be part of the 'ent'. */
+#ifdef HAVE_DIR_CONTEXT
+                       ctx->pos = lhash;
+                       done = !dir_emit(ctx, ent->lde_name, namelen, ino,
+                                        type);
+#else
+                       done = filldir(cookie, ent->lde_name, namelen, lhash,
+                                      ino, type);
+#endif
+               }
 
-       if (page != NULL) {
-               kunmap(page);
-               page_cache_release(page);
-       }
+               if (done) {
+                       pos = hash;
+                       ll_release_page(inode, page, false);
+                       break;
+               }
 
+               next = le64_to_cpu(dp->ldp_hash_end);
+               pos = next;
+               if (pos == MDS_DIR_END_OFF) {
+                       /*
+                        * End of directory reached.
+                        */
+                       done = 1;
+                       ll_release_page(inode, page, false);
+               } else {
+                       /*
+                        * Normal case: continue to the next
+                        * page.
+                        */
+                       ll_release_page(inode, page,
+                                       le32_to_cpu(dp->ldp_flags) &
+                                       LDF_COLLIDE);
+                       next = pos;
+                       page = ll_get_dir_page(inode, op_data, pos,
+                                              &chain);
+               }
+       }
+#ifdef HAVE_DIR_CONTEXT
+       ctx->pos = pos;
+#else
+       *ppos = pos;
+#endif
        ll_dir_chain_fini(&chain);
        RETURN(rc);
 }
 
+#ifdef HAVE_DIR_CONTEXT
+static int ll_iterate(struct file *filp, struct dir_context *ctx)
+#else
 static int ll_readdir(struct file *filp, void *cookie, filldir_t filldir)
+#endif
 {
        struct inode            *inode  = filp->f_dentry->d_inode;
        struct ll_file_data     *lfd    = LUSTRE_FPRIVATE(filp);
        struct ll_sb_info       *sbi    = ll_i2sbi(inode);
-       __u64                   pos     = lfd->lfd_pos;
        int                     hash64  = sbi->ll_flags & LL_SBI_64BIT_HASH;
        int                     api32   = ll_need_32bit_api(sbi);
        struct md_op_data       *op_data;
+       __u64                   pos;
        int                     rc;
-#ifdef HAVE_TOUCH_ATIME_1ARG
-       struct path             path;
-#endif
        ENTRY;
 
        if (lfd != NULL)
@@ -303,37 +328,56 @@ static int ll_readdir(struct file *filp, void *cookie, filldir_t filldir)
        if (IS_ERR(op_data))
                GOTO(out, rc = PTR_ERR(op_data));
 
-       op_data->op_hash_offset = pos;
-       op_data->op_max_pages = sbi->ll_md_brw_size >> PAGE_CACHE_SHIFT;
-       rc = ll_dir_read(inode, op_data, cookie, filldir);
+       if (unlikely(op_data->op_mea1 != NULL)) {
+               /* This is only needed for striped dir to fill ..,
+                * see lmv_read_entry */
+               if (filp->f_dentry->d_parent != NULL &&
+                   filp->f_dentry->d_parent->d_inode != NULL) {
+                       __u64 ibits = MDS_INODELOCK_UPDATE;
+                       struct inode *parent =
+                               filp->f_dentry->d_parent->d_inode;
+
+                       if (ll_have_md_lock(parent, &ibits, LCK_MINMODE))
+                               op_data->op_fid3 = *ll_inode2fid(parent);
+               }
+
+               /* If it can not find in cache, do lookup .. on the master
+                * object */
+               if (fid_is_zero(&op_data->op_fid3)) {
+                       rc = ll_dir_get_parent_fid(inode, &op_data->op_fid3);
+                       if (rc != 0) {
+                               ll_finish_md_op_data(op_data);
+                               RETURN(rc);
+                       }
+               }
+       }
+       op_data->op_max_pages = sbi->ll_md_brw_pages;
+#ifdef HAVE_DIR_CONTEXT
+       ctx->pos = pos;
+       rc = ll_dir_read(inode, &pos, op_data, ctx);
+       pos = ctx->pos;
+#else
+       rc = ll_dir_read(inode, &pos, op_data, cookie, filldir);
+#endif
        if (lfd != NULL)
-               lfd->lfd_pos = op_data->op_hash_offset;
+               lfd->lfd_pos = pos;
 
        if (pos == MDS_DIR_END_OFF) {
                if (api32)
-                       filp->f_pos = LL_DIR_END_OFF_32BIT;
+                       pos = LL_DIR_END_OFF_32BIT;
                else
-                       filp->f_pos = LL_DIR_END_OFF;
+                       pos = LL_DIR_END_OFF;
        } else {
                if (api32 && hash64)
-                       filp->f_pos = op_data->op_hash_offset >> 32;
-               else
-                       filp->f_pos = op_data->op_hash_offset;
+                       pos = pos >> 32;
        }
-
-       ll_finish_md_op_data(op_data);
-       filp->f_version = inode->i_version;
-#ifdef HAVE_TOUCH_ATIME_1ARG
-#ifdef HAVE_F_PATH_MNT
-       path.mnt = filp->f_path.mnt;
-#else
-       path.mnt = filp->f_vfsmnt;
-#endif
-       path.dentry = filp->f_dentry;
-       touch_atime(&path);
+#ifdef HAVE_DIR_CONTEXT
+       ctx->pos = pos;
 #else
-       touch_atime(filp->f_vfsmnt, filp->f_dentry);
+       filp->f_pos = pos;
 #endif
+       ll_finish_md_op_data(op_data);
+       filp->f_version = inode->i_version;
 
 out:
        if (!rc)
@@ -342,7 +386,7 @@ out:
        RETURN(rc);
 }
 
-int ll_send_mgc_param(struct obd_export *mgc, char *string)
+static int ll_send_mgc_param(struct obd_export *mgc, char *string)
 {
         struct mgs_send_param *msp;
         int rc = 0;
@@ -351,7 +395,7 @@ int ll_send_mgc_param(struct obd_export *mgc, char *string)
         if (!msp)
                 return -ENOMEM;
 
-        strncpy(msp->mgs_param, string, MGS_PARAM_MAXLEN);
+       strlcpy(msp->mgs_param, string, sizeof(msp->mgs_param));
         rc = obd_set_info_async(NULL, mgc, sizeof(KEY_SET_INFO), KEY_SET_INFO,
                                 sizeof(struct mgs_send_param), msp, NULL);
         if (rc)
@@ -361,47 +405,50 @@ int ll_send_mgc_param(struct obd_export *mgc, char *string)
         return rc;
 }
 
-static int ll_dir_setdirstripe(struct inode *dir, struct lmv_user_md *lump,
-                              const char *filename)
+/**
+ * Create striped directory with specified stripe(@lump)
+ *
+ * param[in]parent     the parent of the directory.
+ * param[in]lump       the specified stripes.
+ * param[in]dirname    the name of the directory.
+ * param[in]mode       the specified mode of the directory.
+ *
+ * retval              =0 if striped directory is being created successfully.
+ *                      <0 if the creation is failed.
+ */
+static int ll_dir_setdirstripe(struct inode *parent, struct lmv_user_md *lump,
+                              const char *dirname, umode_t mode)
 {
        struct ptlrpc_request *request = NULL;
        struct md_op_data *op_data;
-       struct ll_sb_info *sbi = ll_i2sbi(dir);
-       int mode;
+       struct ll_sb_info *sbi = ll_i2sbi(parent);
        int err;
        ENTRY;
 
        if (unlikely(lump->lum_magic != LMV_USER_MAGIC))
                RETURN(-EINVAL);
 
-       if (lump->lum_stripe_offset == (__u32)-1) {
-               int mdtidx;
-
-               mdtidx = ll_get_mdt_idx(dir);
-               if (mdtidx < 0)
-                       RETURN(mdtidx);
-
-               lump->lum_stripe_offset = mdtidx;
-       }
-
        CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p) name %s"
               "stripe_offset %d, stripe_count: %u\n",
-              PFID(ll_inode2fid(dir)), dir, filename,
+              PFID(ll_inode2fid(parent)), parent, dirname,
               (int)lump->lum_stripe_offset, lump->lum_stripe_count);
 
        if (lump->lum_magic != cpu_to_le32(LMV_USER_MAGIC))
                lustre_swab_lmv_user_md(lump);
 
-       mode = (0755 & (S_IRWXUGO|S_ISVTX) & ~current->fs->umask) | S_IFDIR;
-       op_data = ll_prep_md_op_data(NULL, dir, NULL, filename,
-                                    strlen(filename), mode, LUSTRE_OPC_MKDIR,
+       if (!IS_POSIXACL(parent) || !exp_connect_umask(ll_i2mdexp(parent)))
+               mode &= ~current_umask();
+       mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR;
+       op_data = ll_prep_md_op_data(NULL, parent, NULL, dirname,
+                                    strlen(dirname), mode, LUSTRE_OPC_MKDIR,
                                     lump);
        if (IS_ERR(op_data))
                GOTO(err_exit, err = PTR_ERR(op_data));
 
        op_data->op_cli_flags |= CLI_SET_MEA;
        err = md_create(sbi->ll_md_exp, op_data, lump, sizeof(*lump), mode,
-                       current_fsuid(), current_fsgid(),
+                       from_kuid(&init_user_ns, current_fsuid()),
+                       from_kgid(&init_user_ns, current_fsgid()),
                        cfs_curproc_cap_pack(), 0, &request);
        ll_finish_md_op_data(op_data);
        if (err)
@@ -540,7 +587,7 @@ int ll_dir_getstripe(struct inode *inode, void **plmm, int *plmm_size,
        struct md_op_data *op_data;
        ENTRY;
 
-       rc = ll_get_max_mdsize(sbi, &lmm_size);
+       rc = ll_get_default_mdsize(sbi, &lmm_size);
        if (rc)
                RETURN(rc);
 
@@ -562,9 +609,9 @@ int ll_dir_getstripe(struct inode *inode, void **plmm, int *plmm_size,
        body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY);
        LASSERT(body != NULL);
 
-       lmm_size = body->eadatasize;
+       lmm_size = body->mbo_eadatasize;
 
-       if (!(body->valid & (OBD_MD_FLEASIZE | OBD_MD_FLDIREA)) ||
+       if (!(body->mbo_valid & (OBD_MD_FLEASIZE | OBD_MD_FLDIREA)) ||
            lmm_size == 0) {
                GOTO(out, rc = -ENODATA);
        }
@@ -588,8 +635,8 @@ int ll_dir_getstripe(struct inode *inode, void **plmm, int *plmm_size,
                if (LOV_MAGIC != cpu_to_le32(LOV_MAGIC))
                        lustre_swab_lov_user_md_v3((struct lov_user_md_v3 *)lmm);
                break;
-       case LMV_MAGIC:
-               if (LOV_MAGIC != cpu_to_le32(LOV_MAGIC))
+       case LMV_MAGIC_V1:
+               if (LMV_MAGIC != cpu_to_le32(LMV_MAGIC))
                        lustre_swab_lmv_mds_md((union lmv_mds_md *)lmm);
                break;
        case LMV_USER_MAGIC:
@@ -607,8 +654,7 @@ out:
        return rc;
 }
 
-static int ll_get_mdt_idx_by_fid(struct ll_sb_info *sbi,
-                                const struct lu_fid *fid)
+int ll_get_mdt_idx_by_fid(struct ll_sb_info *sbi, const struct lu_fid *fid)
 {
        struct md_op_data       *op_data;
        int                     rc;
@@ -853,8 +899,10 @@ static int quotactl_ioctl(struct ll_sb_info *sbi, struct if_quotactl *qctl)
                         RETURN(-EPERM);
                 break;
        case Q_GETQUOTA:
-               if (((type == USRQUOTA && current_euid() != id) ||
-                    (type == GRPQUOTA && !in_egroup_p(id))) &&
+               if (((type == USRQUOTA &&
+                     !uid_eq(current_euid(), make_kuid(&init_user_ns, id))) ||
+                    (type == GRPQUOTA &&
+                     !in_egroup_p(make_kgid(&init_user_ns, id)))) &&
                    (!cfs_capable(CFS_CAP_SYS_ADMIN) ||
                     sbi->ll_flags & LL_SBI_RMT_CLIENT))
                        RETURN(-EPERM);
@@ -1034,39 +1082,29 @@ static long ll_dir_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                 return 0;
         }
         case IOC_MDC_LOOKUP: {
-                struct ptlrpc_request *request = NULL;
-                int namelen, len = 0;
-                char *buf = NULL;
-                char *filename;
-                struct md_op_data *op_data;
-
-                rc = obd_ioctl_getdata(&buf, &len, (void *)arg);
-                if (rc)
-                        RETURN(rc);
-                data = (void *)buf;
+               int namelen, len = 0;
+               char *buf = NULL;
+               char *filename;
 
-                filename = data->ioc_inlbuf1;
-                namelen = strlen(filename);
-
-                if (namelen < 1) {
-                        CDEBUG(D_INFO, "IOC_MDC_LOOKUP missing filename\n");
-                        GOTO(out_free, rc = -EINVAL);
-                }
+               rc = obd_ioctl_getdata(&buf, &len, (void *)arg);
+               if (rc != 0)
+                       RETURN(rc);
+               data = (void *)buf;
 
-                op_data = ll_prep_md_op_data(NULL, inode, NULL, filename, namelen,
-                                             0, LUSTRE_OPC_ANY, NULL);
-                if (IS_ERR(op_data))
-                        GOTO(out_free, rc = PTR_ERR(op_data));
+               filename = data->ioc_inlbuf1;
+               namelen = strlen(filename);
+               if (namelen < 1) {
+                       CDEBUG(D_INFO, "IOC_MDC_LOOKUP missing filename\n");
+                       GOTO(out_free, rc = -EINVAL);
+               }
 
-                op_data->op_valid = OBD_MD_FLID;
-                rc = md_getattr_name(sbi->ll_md_exp, op_data, &request);
-                ll_finish_md_op_data(op_data);
-                if (rc < 0) {
-                        CDEBUG(D_INFO, "md_getattr_name: %d\n", rc);
-                        GOTO(out_free, rc);
-                }
-                ptlrpc_req_finished(request);
-                EXIT;
+               rc = ll_get_fid_by_name(inode, filename, namelen, NULL);
+               if (rc < 0) {
+                       CERROR("%s: lookup %.*s failed: rc = %d\n",
+                              ll_get_fsname(inode->i_sb, NULL, 0), namelen,
+                              filename, rc);
+                       GOTO(out_free, rc);
+               }
 out_free:
                 obd_ioctl_freedata(buf, len);
                 return rc;
@@ -1077,6 +1115,7 @@ out_free:
                char            *filename;
                int              namelen = 0;
                int              lumlen = 0;
+               umode_t          mode;
                int              len;
                int              rc;
 
@@ -1106,11 +1145,12 @@ out_free:
                        GOTO(lmv_out_free, rc = -EINVAL);
                }
 
-               /**
-                * ll_dir_setdirstripe will be used to set dir stripe
-                *  mdc_create--->mdt_reint_create (with dirstripe)
-                */
-               rc = ll_dir_setdirstripe(inode, lum, filename);
+#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 50, 0)
+               mode = data->ioc_type != 0 ? data->ioc_type : S_IRWXUGO;
+#else
+               mode = data->ioc_type;
+#endif
+               rc = ll_dir_setdirstripe(inode, lum, filename, mode);
 lmv_out_free:
                obd_ioctl_freedata(buf, len);
                RETURN(rc);
@@ -1190,7 +1230,7 @@ lmv_out_free:
 
                rc = ll_dir_getstripe(inode, (void **)&lmm, &lmmsize, &request,
                                      valid);
-               if (rc != 0 && rc != -ENODATA)
+               if (rc != 0)
                        GOTO(finish_req, rc);
 
                /* Get default LMV EA */
@@ -1207,38 +1247,29 @@ lmv_out_free:
                        GOTO(finish_req, rc);
                }
 
-               /* Get normal LMV EA */
-               if (rc == -ENODATA) {
-                       stripe_count = 1;
-               } else {
-                       LASSERT(lmm != NULL);
-                       stripe_count = lmv_mds_md_stripe_count_get(lmm);
-               }
-
+               stripe_count = lmv_mds_md_stripe_count_get(lmm);
                lum_size = lmv_user_md_size(stripe_count, LMV_MAGIC_V1);
                OBD_ALLOC(tmp, lum_size);
                if (tmp == NULL)
                        GOTO(finish_req, rc = -ENOMEM);
 
-               tmp->lum_magic = LMV_MAGIC_V1;
-               tmp->lum_stripe_count = 1;
                mdt_index = ll_get_mdt_idx(inode);
                if (mdt_index < 0)
                        GOTO(out_tmp, rc = -ENOMEM);
+
+               tmp->lum_magic = LMV_MAGIC_V1;
+               tmp->lum_stripe_count = 0;
                tmp->lum_stripe_offset = mdt_index;
-               tmp->lum_objects[0].lum_mds = mdt_index;
-               tmp->lum_objects[0].lum_fid = *ll_inode2fid(inode);
-               for (i = 1; i < stripe_count; i++) {
-                       struct lmv_mds_md_v1 *lmm1;
-
-                       lmm1 = &lmm->lmv_md_v1;
-                       mdt_index = ll_get_mdt_idx_by_fid(sbi,
-                                                    &lmm1->lmv_stripe_fids[i]);
+               for (i = 0; i < stripe_count; i++) {
+                       struct lu_fid   *fid;
+
+                       fid = &lmm->lmv_md_v1.lmv_stripe_fids[i];
+                       mdt_index = ll_get_mdt_idx_by_fid(sbi, fid);
                        if (mdt_index < 0)
                                GOTO(out_tmp, rc = mdt_index);
 
                        tmp->lum_objects[i].lum_mds = mdt_index;
-                       tmp->lum_objects[i].lum_fid = lmm1->lmv_stripe_fids[i];
+                       tmp->lum_objects[i].lum_fid = *fid;
                        tmp->lum_stripe_count++;
                }
 
@@ -1280,8 +1311,8 @@ out_rmdir:
        }
        case LL_IOC_LOV_SWAP_LAYOUTS:
                RETURN(-EPERM);
-        case LL_IOC_OBD_STATFS:
-                RETURN(ll_obd_statfs(inode, (void *)arg));
+       case IOC_OBD_STATFS:
+               RETURN(ll_obd_statfs(inode, (void *)arg));
         case LL_IOC_LOV_GETSTRIPE:
         case LL_IOC_MDC_GETINFO:
         case IOC_MDC_GETFILEINFO:
@@ -1340,21 +1371,21 @@ out_rmdir:
                         struct lov_user_mds_data *lmdp;
                         lstat_t st = { 0 };
 
-                        st.st_dev     = inode->i_sb->s_dev;
-                        st.st_mode    = body->mode;
-                        st.st_nlink   = body->nlink;
-                        st.st_uid     = body->uid;
-                        st.st_gid     = body->gid;
-                        st.st_rdev    = body->rdev;
-                        st.st_size    = body->size;
-                       st.st_blksize = PAGE_CACHE_SIZE;
-                        st.st_blocks  = body->blocks;
-                        st.st_atime   = body->atime;
-                        st.st_mtime   = body->mtime;
-                        st.st_ctime   = body->ctime;
-                        st.st_ino     = inode->i_ino;
-
-                        lmdp = (struct lov_user_mds_data *)arg;
+                       st.st_dev       = inode->i_sb->s_dev;
+                       st.st_mode      = body->mbo_mode;
+                       st.st_nlink     = body->mbo_nlink;
+                       st.st_uid       = body->mbo_uid;
+                       st.st_gid       = body->mbo_gid;
+                       st.st_rdev      = body->mbo_rdev;
+                       st.st_size      = body->mbo_size;
+                       st.st_blksize   = PAGE_CACHE_SIZE;
+                       st.st_blocks    = body->mbo_blocks;
+                       st.st_atime     = body->mbo_atime;
+                       st.st_mtime     = body->mbo_mtime;
+                       st.st_ctime     = body->mbo_ctime;
+                       st.st_ino       = inode->i_ino;
+
+                       lmdp = (struct lov_user_mds_data *)arg;
                        if (copy_to_user(&lmdp->lmd_st, &st, sizeof(st)))
                                 GOTO(out_req, rc = -EFAULT);
                 }
@@ -1432,10 +1463,7 @@ out_rmdir:
                 OBD_FREE_LARGE(lmm, lmmsize);
                 return rc;
         }
-        case OBD_IOC_LLOG_CATINFO: {
-               RETURN(-EOPNOTSUPP);
-        }
-        case OBD_IOC_QUOTACHECK: {
+       case OBD_IOC_QUOTACHECK: {
                 struct obd_quotactl *oqctl;
                 int error = 0;
 
@@ -1460,7 +1488,7 @@ out_rmdir:
                 OBD_FREE_PTR(oqctl);
                 return error ?: rc;
         }
-        case OBD_IOC_POLL_QUOTACHECK: {
+       case OBD_IOC_POLL_QUOTACHECK: {
                 struct if_quotacheck *check;
 
                 if (!cfs_capable(CFS_CAP_SYS_ADMIN) ||
@@ -1548,7 +1576,7 @@ out_rmdir:
 #else
 #warning "remove old LL_IOC_QUOTACTL_18 compatibility code"
 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 7, 50, 0) */
-        case LL_IOC_QUOTACTL: {
+       case OBD_IOC_QUOTACTL: {
                 struct if_quotactl *qctl;
 
                 OBD_ALLOC_PTR(qctl);
@@ -1626,7 +1654,7 @@ out_rmdir:
                RETURN(ll_fid2path(inode, (void *)arg));
        case LL_IOC_HSM_REQUEST: {
                struct hsm_user_request *hur;
-               int                      totalsize;
+               ssize_t                  totalsize;
 
                OBD_ALLOC_PTR(hur);
                if (hur == NULL)
@@ -1641,9 +1669,11 @@ out_rmdir:
                /* Compute the whole struct size */
                totalsize = hur_len(hur);
                OBD_FREE_PTR(hur);
+               if (totalsize < 0)
+                       RETURN(-E2BIG);
 
-               /* Make sure the size is reasonable */
-               if (totalsize >= MDS_MAXREQSIZE)
+               /* Final size will be more than double totalsize */
+               if (totalsize >= MDS_MAXREQSIZE / 3)
                        RETURN(-E2BIG);
 
                OBD_ALLOC_LARGE(hur, totalsize);
@@ -1749,6 +1779,39 @@ out_rmdir:
                OBD_FREE_PTR(copy);
                RETURN(rc);
        }
+       case LL_IOC_MIGRATE: {
+               char            *buf = NULL;
+               const char      *filename;
+               int             namelen = 0;
+               int             len;
+               int             rc;
+               int             mdtidx;
+
+               rc = obd_ioctl_getdata(&buf, &len, (void __user *)arg);
+               if (rc < 0)
+                       RETURN(rc);
+
+               data = (struct obd_ioctl_data *)buf;
+               if (data->ioc_inlbuf1 == NULL || data->ioc_inlbuf2 == NULL ||
+                   data->ioc_inllen1 == 0 || data->ioc_inllen2 == 0)
+                       GOTO(migrate_free, rc = -EINVAL);
+
+               filename = data->ioc_inlbuf1;
+               namelen = data->ioc_inllen1;
+               /* \0 is packed at the end of filename */
+               if (namelen < 1 || namelen != strlen(filename) + 1)
+                       GOTO(migrate_free, rc = -EINVAL);
+
+               if (data->ioc_inllen2 != sizeof(mdtidx))
+                       GOTO(migrate_free, rc = -EINVAL);
+               mdtidx = *(int *)data->ioc_inlbuf2;
+
+               rc = ll_migrate(inode, file, mdtidx, filename, namelen - 1);
+migrate_free:
+               obd_ioctl_freedata(buf, len);
+
+               RETURN(rc);
+       }
        default:
                RETURN(obd_iocontrol(cmd, sbi->ll_dt_exp, 0, NULL,
                                     (void *)arg));
@@ -1806,24 +1869,28 @@ out:
         return ret;
 }
 
-int ll_dir_open(struct inode *inode, struct file *file)
+static int ll_dir_open(struct inode *inode, struct file *file)
 {
         ENTRY;
         RETURN(ll_file_open(inode, file));
 }
 
-int ll_dir_release(struct inode *inode, struct file *file)
+static int ll_dir_release(struct inode *inode, struct file *file)
 {
         ENTRY;
         RETURN(ll_file_release(inode, file));
 }
 
-struct file_operations ll_dir_operations = {
-        .llseek   = ll_dir_seek,
-        .open     = ll_dir_open,
-        .release  = ll_dir_release,
-        .read     = generic_read_dir,
-        .readdir  = ll_readdir,
-        .unlocked_ioctl   = ll_dir_ioctl,
-        .fsync    = ll_fsync,
+const struct file_operations ll_dir_operations = {
+       .llseek         = ll_dir_seek,
+       .open           = ll_dir_open,
+       .release        = ll_dir_release,
+       .read           = generic_read_dir,
+#ifdef HAVE_DIR_CONTEXT
+       .iterate        = ll_iterate,
+#else
+       .readdir        = ll_readdir,
+#endif
+       .unlocked_ioctl = ll_dir_ioctl,
+       .fsync          = ll_fsync,
 };