Whamcloud - gitweb
LU-4669 lmv: remove unused lmv_adjust_dirpages()
[fs/lustre-release.git] / lustre / llite / dir.c
index 0f811aa..3fcaa6b 100644 (file)
  * 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);
 }
 
 #ifdef HAVE_DIR_CONTEXT
-int ll_dir_read(struct inode *inode, struct md_op_data *op_data,
+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, struct md_op_data *op_data,
+int ll_dir_read(struct inode *inode, __u64 *ppos, struct md_op_data *op_data,
                void *cookie, filldir_t filldir)
 {
 #endif
-       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;
+       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);
+       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;
+               }
 
+               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
-               /* 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 = !dir_emit(ctx, ent->lde_name, namelen, ino, type);
+                       ctx->pos = lhash;
+                       done = !dir_emit(ctx, ent->lde_name, namelen, ino,
+                                        type);
 #else
-               done = filldir(cookie, ent->lde_name, namelen, lhash,
-                              ino, type);
+                       done = filldir(cookie, ent->lde_name, namelen, lhash,
+                                      ino, type);
 #endif
+               }
+
                if (done) {
-                       if (op_data->op_hash_offset != MDS_DIR_END_OFF)
-                               op_data->op_hash_offset = last_hash;
+                       pos = hash;
+                       ll_release_page(inode, page, false);
                        break;
-               } else {
-                       last_hash = hash;
                }
-       }
 
-       if (IS_ERR(ent))
-               rc = PTR_ERR(ent);
-
-       if (page != NULL) {
-               kunmap(page);
-               page_cache_release(page);
+               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);
 }
@@ -315,17 +328,39 @@ 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;
+       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, op_data, ctx);
+       rc = ll_dir_read(inode, &pos, op_data, ctx);
        pos = ctx->pos;
 #else
-       rc = ll_dir_read(inode, op_data, cookie, filldir);
+       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)
@@ -334,9 +369,7 @@ static int ll_readdir(struct file *filp, void *cookie, filldir_t filldir)
                        pos = LL_DIR_END_OFF;
        } else {
                if (api32 && hash64)
-                       pos = op_data->op_hash_offset >> 32;
-               else
-                       pos = op_data->op_hash_offset;
+                       pos = pos >> 32;
        }
 #ifdef HAVE_DIR_CONTEXT
        ctx->pos = pos;
@@ -362,7 +395,7 @@ static 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)
@@ -372,13 +405,23 @@ static 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;
 
@@ -387,15 +430,17 @@ static int ll_dir_setdirstripe(struct inode *dir, struct lmv_user_md *lump,
 
        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));
@@ -564,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);
        }
@@ -590,9 +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:
-       case LMV_MAGIC_MIGRATE:
-               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:
@@ -1071,6 +1115,7 @@ out_free:
                char            *filename;
                int              namelen = 0;
                int              lumlen = 0;
+               umode_t          mode;
                int              len;
                int              rc;
 
@@ -1100,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);
@@ -1184,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 */
@@ -1201,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++;
                }
 
@@ -1334,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);
                 }
@@ -1617,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)
@@ -1632,6 +1669,8 @@ out_rmdir:
                /* Compute the whole struct size */
                totalsize = hur_len(hur);
                OBD_FREE_PTR(hur);
+               if (totalsize < 0)
+                       RETURN(-E2BIG);
 
                /* Final size will be more than double totalsize */
                if (totalsize >= MDS_MAXREQSIZE / 3)