X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=blobdiff_plain;f=lustre%2Fllite%2Fdir.c;h=3fcaa6b99f4935fa3894cbe13734099a2f53836c;hp=04c1da6a194fc587f91c7a5f7dc03a4f61083331;hb=c15a14fbeb566705a2cdd6a471da1155c7b8b444;hpb=482b5e7f76b3fdb48c987de2f221bdcae8b4f5e2 diff --git a/lustre/llite/dir.c b/lustre/llite/dir.c index 04c1da6..3fcaa6b 100644 --- a/lustre/llite/dir.c +++ b/lustre/llite/dir.c @@ -136,145 +136,158 @@ * 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; + 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); } @@ -1070,6 +1115,7 @@ out_free: char *filename; int namelen = 0; int lumlen = 0; + umode_t mode; int len; int rc; @@ -1099,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); @@ -1324,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); } @@ -1607,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) @@ -1622,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)