Whamcloud - gitweb
LU-18082 utils: fid2path support for path exceeding PATH_MAX 97/55897/4
authorSebastien Buisson <sbuisson@ddn.com>
Wed, 31 Jul 2024 14:03:52 +0000 (16:03 +0200)
committerOleg Drokin <green@whamcloud.com>
Fri, 23 Aug 2024 22:01:03 +0000 (22:01 +0000)
PATH_MAX affects the path length of a single pathname, but it is
possible to exceed this by eg. creating a subdirectory tree, then cd
into it, then create a deep tree below this using a relative pathname.

So fix ll_fid2path and lfs_fid2path to not limit the output buffer to
PATH_MAX.

Add sanity test_154i to exercise this.

Signed-off-by: Sebastien Buisson <sbuisson@ddn.com>
Change-Id: Ic3a0e3ac1e806e45eb4c72c571f33404c60d0df5
Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/55897
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Stephane Thiell <sthiell@stanford.edu>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
lustre/llite/file.c
lustre/lmv/lmv_obd.c
lustre/mdt/mdt_handler.c
lustre/tests/sanity.sh
lustre/utils/lfs.c

index 45e0564..3e97ed9 100644 (file)
@@ -3378,8 +3378,6 @@ int ll_fid2path(struct inode *inode, void __user *arg)
        if (get_user(pathlen, &gfin->gf_pathlen))
                RETURN(-EFAULT);
 
-       if (pathlen > PATH_MAX)
-               RETURN(-EINVAL);
        pathlen_orig = pathlen;
 
 gf_alloc:
index 99b7360..79918db 100644 (file)
@@ -630,6 +630,7 @@ static int lmv_fid2path(struct obd_export *exp, int len, void *karg,
        int remote_gf_size = 0;
        int currentisenc = 0;
        int globalisenc = 0;
+       int excess;
        int rc;
 
        gf = karg;
@@ -689,10 +690,11 @@ repeat_fid2path:
                }
        }
 
-       CDEBUG(D_INFO, "%s: get path %s "DFID" rec: %llu ln: %u\n",
+       excess = gf->gf_pathlen > 3072 ? gf->gf_pathlen - 3072 : 0;
+       CDEBUG(D_INFO, "%s: get path %.*s "DFID" rec: %llu ln: %u\n",
               tgt->ltd_exp->exp_obd->obd_name,
-              gf->gf_u.gf_path, PFID(&gf->gf_fid), gf->gf_recno,
-              gf->gf_linkno);
+              gf->gf_pathlen - excess, gf->gf_u.gf_path + excess,
+              PFID(&gf->gf_fid), gf->gf_recno, gf->gf_linkno);
 
        if (rc == 0)
                GOTO(out_fid2path, rc);
index 48131ee..f023617 100644 (file)
@@ -7708,7 +7708,8 @@ static int mdt_fid2path(struct mdt_thread_info *info,
 {
        struct mdt_device *mdt = info->mti_mdt;
        struct mdt_object *obj;
-       int    rc;
+       int excess;
+       int rc;
 
        ENTRY;
 
@@ -7761,9 +7762,10 @@ static int mdt_fid2path(struct mdt_thread_info *info,
 
        rc = mdt_path(info, obj, fp, root_fid);
 
-       CDEBUG(D_INFO, "fid "DFID", path %s recno %#llx linkno %u\n",
-              PFID(&fp->gf_fid), fp->gf_u.gf_path,
-              fp->gf_recno, fp->gf_linkno);
+       excess = fp->gf_pathlen > 3072 ? fp->gf_pathlen - 3072 : 0;
+       CDEBUG(D_INFO, "fid "DFID", path %.*s recno %#llx linkno %u\n",
+              PFID(&fp->gf_fid), fp->gf_pathlen - excess,
+              fp->gf_u.gf_path + excess, fp->gf_recno, fp->gf_linkno);
 
        mdt_object_put(info->mti_env, obj);
 
index 31dd8dc..1e76285 100755 (executable)
@@ -18401,6 +18401,33 @@ test_154h()
 }
 run_test 154h "Verify interactive path2fid"
 
+test_154i()
+{
+       local long=thislongpathnameisforaverydeepsubdirthatwewanttotestagainst
+       local depth
+       local path
+       local max
+       local fid
+
+       mkdir -p $DIR/$tdir
+       cd $DIR/$tdir
+
+       # create a directory tree with full path longer than PATH_MAX=4096
+       max=$((4096 / $(wc -c <<< $long) + 5))
+       for (( depth = 0; depth <= max; depth++)); do
+               mkdir -v $long$depth || error "mkdir $long$depth failed"
+               cd $long$depth
+       done
+
+       fid=$($LFS path2fid .) || error "path2fid failed"
+       path=$($LFS fid2path $MOUNT $fid) || error "fid2path failed (1)"
+       echo -e "Path for fid $fid is:\n$path"
+
+       path=$($LFS fid2path $(cd ..; pwd) $fid) || error "fid2path failed (2)"
+       echo -e "Path for fid $fid is:\n$path"
+}
+run_test 154i "fid2path for path longer than PATH_MAX"
+
 test_155_small_load() {
     local temp=$TMP/$tfile
     local file=$DIR/$tfile
index a21746b..b29b349 100755 (executable)
@@ -10426,7 +10426,8 @@ static int lfs_fid2path(int argc, char **argv)
        bool print_link = false;
        bool print_fid = false;
        bool print_mnt_dir;
-       char mnt_dir[PATH_MAX] = "";
+       char *mnt_dir = NULL;
+       int mnt_dir_len = PATH_MAX + 1;
        int mnt_fd = -1;
        char *path_or_fsname;
        long long recno = -1;
@@ -10495,6 +10496,13 @@ static int lfs_fid2path(int argc, char **argv)
        }
 
        path_or_fsname = argv[optind];
+       if (path_or_fsname && strlen(path_or_fsname))
+               mnt_dir_len = strlen(path_or_fsname) + 1;
+       mnt_dir = malloc(mnt_dir_len + 1);
+       if (!mnt_dir) {
+               rc = -ENOMEM;
+               goto out;
+       }
 
        if (*path_or_fsname == '/') {
                print_mnt_dir = true;
@@ -10524,6 +10532,8 @@ static int lfs_fid2path(int argc, char **argv)
 
        for (i = optind + 1; i < argc; i++) {
                const char *fid_str = argv[i];
+               int path_len = PATH_MAX;
+               char *path_buf;
                struct lu_fid fid;
                char *ptr = NULL;
                int rc2;
@@ -10541,15 +10551,35 @@ static int lfs_fid2path(int argc, char **argv)
 
                int linktmp = (linkno >= 0) ? linkno : 0;
 
+               path_buf = malloc(path_len);
+               if (!path_buf) {
+                       if (rc == 0)
+                               rc = -ENOMEM;
+                       continue;
+               }
+
                while (1) {
                        int oldtmp = linktmp;
                        long long rectmp = recno;
-                       char path_buf[PATH_MAX];
 
+fid2path:
                        rc2 = llapi_fid2path_at(mnt_fd, &fid, path_buf,
-                                               sizeof(path_buf), &rectmp,
+                                               path_len, &rectmp,
                                                &linktmp);
                        if (rc2 < 0) {
+                               if (rc2 == -ERANGE) {
+                                       char *tmpbuf;
+
+                                       path_len += PATH_MAX;
+                                       tmpbuf = realloc(path_buf, path_len);
+                                       if (!tmpbuf) {
+                                               if (rc == 0)
+                                                       rc = -ENOMEM;
+                                               break;
+                                       }
+                                       path_buf = tmpbuf;
+                                       goto fid2path;
+                               }
                                fprintf(stderr,
                                        "%s fid2path: cannot find %s %s: %s\n",
                                        progname, path_or_fsname, fid_str,
@@ -10615,10 +10645,12 @@ static int lfs_fid2path(int argc, char **argv)
                                /* no more links */
                                break;
                }
+               free(path_buf);
        }
 out:
        if (!(mnt_fd < 0))
                close(mnt_fd);
+       free(mnt_dir);
 
        return rc;
 }