From f5251cb7af4cfae8f2e9e7f69251253c0bc233b6 Mon Sep 17 00:00:00 2001 From: Sebastien Buisson Date: Wed, 31 Jul 2024 16:03:52 +0200 Subject: [PATCH] LU-18082 utils: fid2path support for path exceeding PATH_MAX 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 Change-Id: Ic3a0e3ac1e806e45eb4c72c571f33404c60d0df5 Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/55897 Reviewed-by: Andreas Dilger Reviewed-by: Stephane Thiell Reviewed-by: Oleg Drokin Tested-by: jenkins Tested-by: Maloo --- lustre/llite/file.c | 2 -- lustre/lmv/lmv_obd.c | 8 +++++--- lustre/mdt/mdt_handler.c | 10 ++++++---- lustre/tests/sanity.sh | 27 +++++++++++++++++++++++++++ lustre/utils/lfs.c | 38 +++++++++++++++++++++++++++++++++++--- 5 files changed, 73 insertions(+), 12 deletions(-) diff --git a/lustre/llite/file.c b/lustre/llite/file.c index 45e0564..3e97ed9 100644 --- a/lustre/llite/file.c +++ b/lustre/llite/file.c @@ -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: diff --git a/lustre/lmv/lmv_obd.c b/lustre/lmv/lmv_obd.c index 99b7360..79918db 100644 --- a/lustre/lmv/lmv_obd.c +++ b/lustre/lmv/lmv_obd.c @@ -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); diff --git a/lustre/mdt/mdt_handler.c b/lustre/mdt/mdt_handler.c index 48131ee..f023617 100644 --- a/lustre/mdt/mdt_handler.c +++ b/lustre/mdt/mdt_handler.c @@ -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); diff --git a/lustre/tests/sanity.sh b/lustre/tests/sanity.sh index 31dd8dc..1e76285 100755 --- a/lustre/tests/sanity.sh +++ b/lustre/tests/sanity.sh @@ -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 diff --git a/lustre/utils/lfs.c b/lustre/utils/lfs.c index a21746b..b29b349 100755 --- a/lustre/utils/lfs.c +++ b/lustre/utils/lfs.c @@ -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; } -- 1.8.3.1