Whamcloud - gitweb
EX-2455 pcc: get PCC state for a file without opening itself
authorQian Yingjin <qian@ddn.com>
Thu, 25 Feb 2021 12:43:58 +0000 (20:43 +0800)
committerAndreas Dilger <adilger@whamcloud.com>
Fri, 26 Mar 2021 18:02:09 +0000 (18:02 +0000)
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 <qian@ddn.com>
Change-Id: I310a7e73dc6c0f4318dc27df2e02ecf6559ee5b4
Reviewed-on: https://review.whamcloud.com/41927
Tested-by: jenkins <devops@whamcloud.com>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Jian Yu <yujian@whamcloud.com>
Reviewed-by: Li Xi <lixi@ddn.com>
lustre/include/uapi/linux/lustre/lustre_user.h
lustre/llite/dir.c
lustre/llite/file.c
lustre/llite/pcc.c
lustre/tests/sanity-pcc.sh
lustre/utils/liblustreapi.c
lustre/utils/liblustreapi_pcc.c
lustre/utils/lustreapi_internal.h

index ddab641..f367b8b 100644 (file)
@@ -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 {
index 838eccd..0e73a9d 100644 (file)
@@ -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;
index 5551985..d6ddcf7 100644 (file)
@@ -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)))
index d0cd8c1..9f815b6 100644 (file)
@@ -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;
index 23a7e68..5e7934f 100644 (file)
@@ -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
index 2087ae7..db34be3 100644 (file)
@@ -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;
index 1107f23..8cb44fb 100644 (file)
@@ -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;
 }
 
index 367393d..3aa9126 100644 (file)
@@ -36,6 +36,7 @@
 
 #include <limits.h>
 #include <stdint.h>
+#include <dirent.h>
 
 #include <libcfs/util/ioctl.h>
 #include <libcfs/util/param.h>
@@ -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_ */