From 1276a8f6dac736a63244f7e943cbc6951e518b2d Mon Sep 17 00:00:00 2001 From: Qian Yingjin Date: Thu, 25 Feb 2021 20:43:58 +0800 Subject: [PATCH] EX-2455 pcc: get PCC state for a file without opening itself Originally to get PCC state for a given file, the user needs to open the file and then get the current PCC state of the file via the file handle. After that, close the file. If the file is met the predefined condition of auto prefetching into PCC at the open time, "lfs pcc state" command on the file will attach the file into PCC cache. This may be not the intention of the user. In this patch, we rework the "lfs pcc state" command. It always open the parent directory, and then do the lookup by name/FID without open the file itself to get the PCC state. Test-Parameters: clientcount=3 testlist=sanity-pcc,sanity-pcc,sanity-pcc Signed-off-by: Qian Yingjin Change-Id: I310a7e73dc6c0f4318dc27df2e02ecf6559ee5b4 Reviewed-on: https://review.whamcloud.com/41927 Tested-by: jenkins Reviewed-by: Andreas Dilger Tested-by: Maloo Reviewed-by: Jian Yu Reviewed-by: Li Xi --- lustre/include/uapi/linux/lustre/lustre_user.h | 10 ++-- lustre/llite/dir.c | 75 ++++++++++++++++++++++++++ lustre/llite/file.c | 2 + lustre/llite/pcc.c | 13 +++-- lustre/tests/sanity-pcc.sh | 74 ++++++++++++++++++++++++- lustre/utils/liblustreapi.c | 2 +- lustre/utils/liblustreapi_pcc.c | 34 ++++++++++-- lustre/utils/lustreapi_internal.h | 3 ++ 8 files changed, 197 insertions(+), 16 deletions(-) diff --git a/lustre/include/uapi/linux/lustre/lustre_user.h b/lustre/include/uapi/linux/lustre/lustre_user.h index ddab641..f367b8b 100644 --- a/lustre/include/uapi/linux/lustre/lustre_user.h +++ b/lustre/include/uapi/linux/lustre/lustre_user.h @@ -2733,11 +2733,11 @@ enum lu_pcc_state_flags { }; struct lu_pcc_state { - __u32 pccs_type; /* enum lu_pcc_type */ - __u32 pccs_open_count; - __u32 pccs_flags; /* enum lu_pcc_state_flags */ - __u32 pccs_padding; - char pccs_path[PATH_MAX]; + __u32 pccs_type; /* OUT: enum lu_pcc_type */ + __u32 pccs_open_count; /* OUT: user count */ + __u32 pccs_flags; /* OUT: enum lu_pcc_state_flags */ + __u32 pccs_namelen; /* IN: file name len */ + char pccs_path[PATH_MAX]; /* IN|OUT: file name or path buffer */ }; enum lu_pcc_cleanup_flags { diff --git a/lustre/llite/dir.c b/lustre/llite/dir.c index 838eccd..0e73a9d 100644 --- a/lustre/llite/dir.c +++ b/lustre/llite/dir.c @@ -2127,6 +2127,81 @@ migrate_free: RETURN(ll_ioctl_fsgetxattr(inode, cmd, arg)); case FS_IOC_FSSETXATTR: RETURN(ll_ioctl_fssetxattr(inode, cmd, arg)); + case LL_IOC_PCC_STATE: { + struct lu_pcc_state __user *ustate = + (struct lu_pcc_state __user *)arg; + struct lu_pcc_state *state; + struct dentry *parent = file_dentry(file); + struct dentry *dchild = NULL; + struct inode *child_inode = NULL; + struct qstr qstr; + int namelen = 0; + char *name; + + OBD_ALLOC_PTR(state); + if (state == NULL) + RETURN(-ENOMEM); + + if (copy_from_user(state, ustate, sizeof(*state))) + GOTO(out_free, rc = -EFAULT); + + name = state->pccs_path; + namelen = strlen(name); + if (namelen < 0 || state->pccs_namelen != namelen + 1) { + CDEBUG(D_INFO, "IOC_PCC_STATE missing filename\n"); + GOTO(out_state_free, rc = -EINVAL); + } + + /* Get Child from dcache first. */ + qstr.hash = ll_full_name_hash(parent, name, namelen); + qstr.name = name; + qstr.len = namelen; + dchild = d_lookup(parent, &qstr); + if (dchild) { + if (dchild->d_inode) + child_inode = igrab(dchild->d_inode); + dput(dchild); + } + + if (!child_inode) { + unsigned long ino; + struct lu_fid fid; + + rc = ll_get_fid_by_name(parent->d_inode, name, namelen, + &fid, NULL); + if (rc) + GOTO(out_state_free, rc); + + ino = cl_fid_build_ino(&fid, ll_need_32bit_api(sbi)); + child_inode = ilookup5(inode->i_sb, ino, + ll_test_inode_by_fid, &fid); + } + + if (!child_inode) { + /* + * Target inode is not in inode cache, the + * corresponding PCC file may be already released, + * return immediately. + */ + state->pccs_type = LU_PCC_NONE; + GOTO(out_copy_to, rc = 0); + } + + if (!S_ISREG(child_inode->i_mode)) + GOTO(out_child_iput, rc = -EINVAL); + + rc = pcc_ioctl_state(NULL, child_inode, state); + if (rc) + GOTO(out_child_iput, rc); +out_copy_to: + if (copy_to_user(ustate, state, sizeof(*state))) + GOTO(out_child_iput, rc = -EFAULT); +out_child_iput: + iput(child_inode); +out_state_free: + OBD_FREE_PTR(state); + RETURN(rc); + } case LL_IOC_PCC_DETACH_BY_FID: { struct lu_pcc_detach_fid *detach; struct lu_fid *fid; diff --git a/lustre/llite/file.c b/lustre/llite/file.c index 5551985..d6ddcf7 100644 --- a/lustre/llite/file.c +++ b/lustre/llite/file.c @@ -4054,6 +4054,7 @@ out_detach_free: OBD_FREE_PTR(detach); RETURN(rc); } +#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 18, 53, 0) case LL_IOC_PCC_STATE: { struct lu_pcc_state __user *ustate = (struct lu_pcc_state __user *)arg; @@ -4077,6 +4078,7 @@ out_state: OBD_FREE_PTR(state); RETURN(rc); } +#endif #ifdef HAVE_LUSTRE_CRYPTO case LL_IOC_SET_ENCRYPTION_POLICY: if (!ll_sbi_has_encrypt(ll_i2sbi(inode))) diff --git a/lustre/llite/pcc.c b/lustre/llite/pcc.c index d0cd8c1..9f815b6 100644 --- a/lustre/llite/pcc.c +++ b/lustre/llite/pcc.c @@ -3575,8 +3575,6 @@ int pcc_ioctl_state(struct file *file, struct inode *inode, char *buf; char *path; int buf_len = sizeof(state->pccs_path); - struct ll_file_data *fd = file->private_data; - struct pcc_file *pccf = &fd->fd_pcc_file; struct pcc_inode *pcci; ENTRY; @@ -3604,8 +3602,15 @@ int pcc_ioctl_state(struct file *file, struct inode *inode, if (pcc_inode_has_layout(pcci)) count--; - if (pccf->pccf_file != NULL) - count--; + + if (file) { + struct ll_file_data *fd = file->private_data; + struct pcc_file *pccf = &fd->fd_pcc_file; + + if (pccf->pccf_file != NULL) + count--; + } + state->pccs_type = pcci->pcci_type; state->pccs_open_count = count; state->pccs_flags = ll_i2info(inode)->lli_pcc_state; diff --git a/lustre/tests/sanity-pcc.sh b/lustre/tests/sanity-pcc.sh index 23a7e68..5e7934f 100644 --- a/lustre/tests/sanity-pcc.sh +++ b/lustre/tests/sanity-pcc.sh @@ -2506,12 +2506,14 @@ test_29a() { $LFS project -sp $project_id $file || error "failed to set project for $file" $LFS project -d $file + check_file_data $SINGLEAGT $file "ro_uptodate" check_lpcc_state $file "readonly" check_file_data $SINGLEAGT $file "ro_uptodate" echo -n Update_ro_data > $file2 - check_lpcc_state $file "readonly" + check_lpcc_state $file "none" check_file_data $SINGLEAGT $file "Update_ro_data" + check_lpcc_state $file "readonly" do_facet $SINGLEAGT $LFS pcc detach $file || error "failed to detach $file" @@ -2700,34 +2702,52 @@ test_33() { do_facet $SINGLEAGT $LCTL pcc list $MOUNT touch $file || error "touch $file failed" $TRUNCATE $file $((1048576 * 2)) || error "Truncate $file failed" + do_facet $SINGLEAGT $MULTIOP $file oc || + error "failed to readonly open $file" check_lpcc_state $file "none" do_facet $SINGLEAGT $LFS pcc state $file $TRUNCATE $file $((1048576 / 2)) || error "Truncate $file failed" do_facet $SINGLEAGT $LFS pcc state $file + do_facet $SINGLEAGT $MULTIOP $file oc || + error "failed to readonly open $file" check_lpcc_state $file "readonly" cleanup_pcc_mapping setup_pcc_mapping $SINGLEAGT \ "fname={*.doc}\&size\<{5M}\&size\>{3M}\ roid=5\ ropcc=1" do_facet $SINGLEAGT $LCTL pcc list $MOUNT + do_facet $SINGLEAGT $MULTIOP $file oc || + error "failed to readonly open $file" check_lpcc_state $file "none" $TRUNCATE $file2 $((1048576 * 6)) || error "Truncate $file2 failed" + do_facet $SINGLEAGT $MULTIOP $file oc || + error "failed to readonly open $file" check_lpcc_state $file "none" $TRUNCATE $file2 $((1048576 * 4)) || error "Truncate $file2 failed" + do_facet $SINGLEAGT $MULTIOP $file oc || + error "failed to readonly open $file" check_lpcc_state $file "readonly" cleanup_pcc_mapping setup_pcc_mapping $SINGLEAGT \ "fname={*.doc}\&size={5M\ 3M}\ roid=5\ ropcc=1" do_facet $SINGLEAGT $LCTL pcc list $MOUNT + do_facet $SINGLEAGT $MULTIOP $file oc || + error "failed to readonly open $file" check_lpcc_state $file "none" $TRUNCATE $file $((1048576 * 5)) || error "Truncate $file failed" + do_facet $SINGLEAGT $MULTIOP $file oc || + error "failed to readonly open $file" check_lpcc_state $file "readonly" do_facet $SINGLEAGT $LFS pcc detach $file || error "failed to detach $file" $TRUNCATE $file $((1048576 * 4)) || error "Truncate $file failed" + do_facet $SINGLEAGT $MULTIOP $file oc || + error "failed to readonly open $file" check_lpcc_state $file "none" $TRUNCATE $file $((1048576 * 3)) || error "Truncate $file failed" + do_facet $SINGLEAGT $MULTIOP $file oc || + error "failed to readonly open $file" check_lpcc_state $file "readonly" cleanup_pcc_mapping } @@ -2751,39 +2771,59 @@ test_34() { do_facet $SINGLEAGT $LCTL pcc list $MOUNT do_facet $SINGLEAGT "echo -n QQQQQ > $file" || error "failed to write $file" + do_facet $SINGLEAGT $MULTIOP $file oc || + error "failed to readonly open $file" check_lpcc_state $file "none" $LFS project -p 99 $file || error "failed to set project for $file" $LFS project -d $file + do_facet $SINGLEAGT $MULTIOP $file oc || + error "failed to readonly open $file" check_lpcc_state $file "none" $LFS project -p 101 $file || error "failed to set project for $file" $LFS project -d $file + do_facet $SINGLEAGT $MULTIOP $file oc || + error "failed to readonly open $file" check_lpcc_state $file "readonly" cleanup_pcc_mapping setup_pcc_mapping $SINGLEAGT \ "projid\<{100}\ roid=5\ ropcc=1" do_facet $SINGLEAGT $LCTL pcc list $MOUNT + do_facet $SINGLEAGT $MULTIOP $file oc || + error "failed to readonly open $file" check_lpcc_state $file "none" $LFS project -p 102 $file || error "failed to set project for $file" $LFS project -d $file + do_facet $SINGLEAGT $MULTIOP $file oc || + error "failed to readonly open $file" check_lpcc_state $file "none" $LFS project -p 99 $file || error "failed to set project for $file" $LFS project -d $file + do_facet $SINGLEAGT $MULTIOP $file oc || + error "failed to readonly open $file" check_lpcc_state $file "readonly" cleanup_pcc_mapping setup_pcc_mapping $SINGLEAGT \ "projid\<{120}\&projid\>{110}\ roid=5\ ropcc=1" do_facet $SINGLEAGT $LCTL pcc list $MOUNT + do_facet $SINGLEAGT $MULTIOP $file oc || + error "failed to readonly open $file" check_lpcc_state $file "none" $LFS project -p 105 $file || error "failed to set project for $file" $LFS project -d $file + do_facet $SINGLEAGT $MULTIOP $file oc || + error "failed to readonly open $file" check_lpcc_state $file "none" $LFS project -p 121 $file || error "failed to set project for $file" $LFS project -d $file + do_facet $SINGLEAGT $MULTIOP $file oc || + error "failed to readonly open $file" check_lpcc_state $file "none" $LFS project -p 115 $file || error "failed to set project for $file" $LFS project -d $file + do_facet $SINGLEAGT $MULTIOP $file oc || + error "failed to readonly open $file" check_lpcc_state $file "readonly" cleanup_pcc_mapping } @@ -2902,6 +2942,38 @@ test_37() { } run_test 37 "Multiple readers on a shared file with PCC-RO mode" +test_38() { + local loopfile="$TMP/$tfile" + local mntpt="/mnt/pcc.$tdir" + local hsm_root="$mntpt/$tdir" + local dir=$DIR/$tdir + local file=$dir/$tfile + + ! is_project_quota_supported && + skip "project quota is not supported" + + enable_project_quota + mkdir $dir || error "mkdir $dir failed" + $LFS project -sp 100 $dir || + error "failed to set project for $dir" + echo "QQQQQ" > $file + + setup_loopdev $SINGLEAGT $loopfile $mntpt 50 + do_facet $SINGLEAGT mkdir $hsm_root || error "mkdir $hsm_root failed" + setup_pcc_mapping $SINGLEAGT \ + "projid={100}\ roid=$HSM_ARCHIVE_NUMBER\ ropcc=1" + + do_facet $SINGLEAGT $LFS pcc state $file || + error "failed to get PCC state for $file" + check_lpcc_state $file "none" + do_facet $SINGLEAGT cat $file || error "cat $file failed" + check_lpcc_state $file "readonly" + do_facet $SINGLEAGT $LFS pcc detach $file || + error "failed to detach $file" + check_lpcc_state $file "none" +} +run_test 38 "Verify LFS pcc state does not trigger prefetch for auto PCC-RO" + complete $SECONDS check_and_cleanup_lustre exit_status diff --git a/lustre/utils/liblustreapi.c b/lustre/utils/liblustreapi.c index 2087ae7..db34be3 100644 --- a/lustre/utils/liblustreapi.c +++ b/lustre/utils/liblustreapi.c @@ -1852,7 +1852,7 @@ static int cb_common_fini(char *path, DIR *parent, DIR **dirp, void *data, } /* set errno upon failure */ -static DIR *opendir_parent(const char *path) +DIR *opendir_parent(const char *path) { char *path_copy; char *parent_path; diff --git a/lustre/utils/liblustreapi_pcc.c b/lustre/utils/liblustreapi_pcc.c index 1107f23..8cb44fb 100644 --- a/lustre/utils/liblustreapi_pcc.c +++ b/lustre/utils/liblustreapi_pcc.c @@ -366,7 +366,7 @@ int llapi_pcc_detach_file(const char *path, __u32 flags) /** * Return the current PCC state related to a file. * - * \param fd File handle. + * \param fd File handle for the parent directory. * \param state PCC state info. * * \return 0 on success, an error code otherwise. @@ -389,16 +389,40 @@ int llapi_pcc_state_get_fd(int fd, struct lu_pcc_state *state) */ int llapi_pcc_state_get(const char *path, struct lu_pcc_state *state) { + char *path_copy; + char *filename; + DIR *parent; int fd; int rc; - fd = open(path, O_RDONLY | O_NONBLOCK); - if (fd < 0) - return -errno; + parent = opendir_parent(path); + if (parent == NULL) { + rc = -errno; + llapi_error(LLAPI_MSG_ERROR, rc, "can not open %s", path); + return rc; + } + + fd = dirfd(parent); + path_copy = strdup(path); + if (path_copy == NULL) { + closedir(parent); + return -ENOMEM; + } + + filename = basename(path_copy); + state->pccs_namelen = strlen(filename) + 1; + strncpy(state->pccs_path, filename, sizeof(state->pccs_path)); rc = llapi_pcc_state_get_fd(fd, state); + if (rc != 0) { + rc = -errno; + llapi_error(LLAPI_MSG_ERROR, rc, "Get PCC state on %s failed", + path); + } + + closedir(parent); + free(path_copy); - close(fd); return rc; } diff --git a/lustre/utils/lustreapi_internal.h b/lustre/utils/lustreapi_internal.h index 367393d..3aa9126 100644 --- a/lustre/utils/lustreapi_internal.h +++ b/lustre/utils/lustreapi_internal.h @@ -36,6 +36,7 @@ #include #include +#include #include #include @@ -165,4 +166,6 @@ int get_lmd_info_fd(const char *path, int parentfd, int dirfd, void *lmd_buf, int lmd_len, enum get_lmd_info_type type); int lov_comp_md_size(struct lov_comp_md_v1 *lcm); + +DIR *opendir_parent(const char *path); #endif /* _LUSTREAPI_INTERNAL_H_ */ -- 1.8.3.1