From a889daac1e9a862fdcc44ed4bf5ceac7ccd960bc Mon Sep 17 00:00:00 2001 From: Chakshu Kansal Date: Fri, 13 Jun 2025 14:52:15 +0530 Subject: [PATCH] LU-18242 utils: allow 'lfs df -m/-o' to specify one MDT/OST Extend the 'lfs df' command to allow specifying a single MDT or OST index with the -m and -o options. This allows users to easily check the space usage of a specific target without having to use grep. For example: lfs df -m0 /mnt/lustre # Show only MDT0 lfs df -o1 /mnt/lustre # Show only OST1 This is useful in test scripts and for end users who want to check the space usage of a specific target. Signed-off-by: Chakshu Kansal Change-Id: I74538b6d8c95c41a7d9030f94103a7c0fd8756db Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/58729 Tested-by: jenkins Tested-by: Maloo Reviewed-by: Andreas Dilger Reviewed-by: Oleg Drokin --- Documentation/man1/lfs-df.1 | 27 +++++++++++++++++---- lustre/tests/sanity.sh | 29 ++++++++++++----------- lustre/utils/lfs.c | 57 ++++++++++++++++++++++++++++++++++++++------- 3 files changed, 85 insertions(+), 28 deletions(-) diff --git a/Documentation/man1/lfs-df.1 b/Documentation/man1/lfs-df.1 index 1502a86..02637e6 100644 --- a/Documentation/man1/lfs-df.1 +++ b/Documentation/man1/lfs-df.1 @@ -139,17 +139,25 @@ the client. This avoids blocking the output if a target is offline or unreachable, and only returns the space on OSTs that can currently be accessed. .TP -.BR -m ", " --mdt +.BR -m ", " --mdt "[="\fIINDEX\fR] Filter output to show information on .B MDT -devices. Can be used with +devices. If +.I INDEX +is specified, it must be attached to the option without a space, like "-m\fIINDEX\fR" or "--mdt=\fIINDEX\fR". +For example: "-m0" or "--mdt=0". +Can be used with .BR -o to show both types of devices, which is equivalent to having neither option. .TP -.BR -o ", " --ost +.BR -o ", " --ost "[="\fIINDEX\fR] Filter output to show information on -.B OSTc -devices. Can be used with +.B OST +devices. If +.I INDEX +is specified, it must be attached to the option without a space, like "-o\fIINDEX\fR" or "--ost=\fIINDEX\fR". +For example: "-o0" or "--ost=0". +Can be used with .BR -m to show both types of devices, which is equivalent to having neither option. .TP @@ -251,6 +259,15 @@ filesystem, even if not currently connected: .B # lfs df -v /mnt/testfs .EE .RE +.PP +List space usage for only OST index 1 of the +.B testfs +filesystem: +.RS +.EX +.B # lfs df -o1 /mnt/testfs +.EE +.RE .SH AVAILABILITY .B lfs df is part of the diff --git a/lustre/tests/sanity.sh b/lustre/tests/sanity.sh index 60fbb47..25852e3 100755 --- a/lustre/tests/sanity.sh +++ b/lustre/tests/sanity.sh @@ -5938,7 +5938,7 @@ test_44a() { local stride=$($LFS getstripe -S -d $DIR) if [[ $nstripe -eq 0 || $nstripe -eq -1 ]]; then - nstripe=$($LFS df $DIR | grep OST: | wc -l) + nstripe=$($LFS df -o $DIR | wc -l) fi OFFSETS="0 $((stride/2)) $((stride-1))" @@ -6595,7 +6595,7 @@ test_51f() { local ulimit_old=$(ulimit -n) local spare=20 # number of spare fd's for scripts/libraries, etc. local mdt=$($LFS getstripe -m $DIR/$tdir) - local numfree=$($LFS df -i $DIR/$tdir | awk '/MDT:'$mdt'/ { print $4 }') + local numfree=$($LFS df -i --mdt=$mdt $DIR/$tdir | awk '{ print $4 }') echo "MDT$mdt numfree=$numfree, max=$max" [[ $numfree -gt $max ]] && numfree=$max || numfree=$((numfree * 7 / 8)) @@ -7146,15 +7146,16 @@ test_56ca() { run_test 56ca "'lfs df -v' correctly reports 'R' flag when OST set as Readonly" test_56d() { - local mdts=$($LFS df -v $MOUNT | grep -c MDT) - local osts=$($LFS df -v $MOUNT | grep -c OST) + local mdts=$($LFS df -v -m $MOUNT | wc -l) + local osts=$($LFS df -v -o $MOUNT | wc -l) $LFS df $MOUNT - (( mdts == MDSCOUNT )) || - error "lfs df -v showed $mdts MDTs, not $MDSCOUNT" - (( osts == OSTCOUNT )) || - error "lfs df -v showed $osts OSTs, not $OSTCOUNT" + # Subtract 4 for the header line and summary information + (( mdts - 4 == MDSCOUNT )) || + error "lfs df -v -m showed $((mdts - 4)) MDTs, not $MDSCOUNT" + (( osts - 4 == OSTCOUNT )) || + error "lfs df -v -o showed $((osts - 4)) OSTs, not $OSTCOUNT" } run_test 56d "'lfs df -v' prints only configured devices" @@ -12313,8 +12314,8 @@ test_78() { # bug 10901 [[ $F78SIZE -gt $MEMTOTAL ]] && F78SIZE=$MEMTOTAL [[ $F78SIZE -gt 512 ]] && F78SIZE=512 [[ $F78SIZE -gt $((MAXFREE / 1024)) ]] && F78SIZE=$((MAXFREE / 1024)) - SMALLESTOST=$($LFS df $DIR | grep OST | awk '{ print $4 }' | sort -n | - head -n1) + SMALLESTOST=$($LFS df -o $DIR | awk '{ print $4 }' | sort -n | + head -n1) echo "Smallest OST: $SMALLESTOST" [[ $SMALLESTOST -lt 10240 ]] && skip "too small OSTSIZE, useless to run large O_DIRECT test" @@ -23435,7 +23436,7 @@ test_220() { #LU-325 # create on MDT0000 so the last_id and next_id are correct mkdir_on_mdt0 $DIR/$tdir - local OST=$($LFS df $DIR | awk '/OST:'$OSTIDX'/ { print $1 }') + local OST=$($LFS df --ost=$OSTIDX $DIR | awk '{ print $1 }') OST=${OST%_UUID} # on the mdt's osc @@ -33758,7 +33759,7 @@ test_803a() { sleep 3 echo "before create:" $LFS df -i $MOUNT - local before_used=$($LFS df -i | grep MDT0000_UUID | awk '{print $3}') + local before_used=$($LFS df -i -m0 | awk '{print $3}') for i in {1..10}; do $LFS mkdir -c 1 -i 1 $DIR/$tdir/foo$i || @@ -33770,7 +33771,7 @@ test_803a() { sleep 3 echo "after create:" $LFS df -i $MOUNT - local after_used=$($LFS df -i | grep MDT0000_UUID | awk '{print $3}') + local after_used=$($LFS df -i -m0 | awk '{print $3}') # allow for an llog to be cleaned up during the test [ $after_used -ge $((before_used + 10 - 1)) ] || @@ -33787,7 +33788,7 @@ test_803a() { sleep 3 # avoid MDT return cached statfs echo "after unlink:" $LFS df -i $MOUNT - after_used=$($LFS df -i | grep MDT0000_UUID | awk '{print $3}') + after_used=$($LFS df -i -m0 | awk '{print $3}') # allow for an llog to be created during the test [ $after_used -le $((before_used + 1)) ] || diff --git a/lustre/utils/lfs.c b/lustre/utils/lfs.c index b844c15..c2d8646 100644 --- a/lustre/utils/lfs.c +++ b/lustre/utils/lfs.c @@ -524,7 +524,7 @@ command_t cmdlist[] = { "report filesystem disk space usage or inodes usage " "of each MDS and all OSDs or a batch belonging to a specific pool.\n" "Usage: df [--inodes|-i] [--human-readable|-h] [--lazy|-l]\n" - "[--mdt|-m] [--ost|-o]\n" + "[--mdt|-m[INDEX]] [--ost|-o[INDEX]]\n" "[--pool|-p FSNAME[.POOL]] [PATH]"}, {"getname", lfs_getname, 0, "list instances and specified mount points [for specified path only]\n" @@ -7446,7 +7446,7 @@ struct ll_statfs_buf { }; static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags, - int ops, struct ll_statfs_buf *lsb) + int ops, struct ll_statfs_buf *lsb, int mdt_idx, int ost_idx) { struct obd_statfs stat_buf, sum = { .os_bsize = 1 }; struct obd_uuid uuid_buf; @@ -7484,7 +7484,7 @@ static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags, return rc; } - if (flags & MNTDF_SHOW) { + if (flags & MNTDF_SHOW && (ost_idx == -1 && mdt_idx == -1)) { if (flags & MNTDF_INODES) printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n", "UUID", "Inodes", "IUsed", "IFree", @@ -7504,6 +7504,15 @@ static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags, for (index = 0; index < LOV_ALL_STRIPES && (!lsb || lsb->sb_count < LL_STATFS_MAX); index++) { + /* Skip indices that don't match the requested one */ + if (tp->st_op == LL_STATFS_LMV && mdt_idx >= 0 && + index != mdt_idx) + continue; + + if (tp->st_op == LL_STATFS_LOV && ost_idx >= 0 && + index != ost_idx) + continue; + memset(&stat_buf, 0, sizeof(struct obd_statfs)); memset(&uuid_buf, 0, sizeof(struct obd_uuid)); type = flags & MNTDF_LAZY ? @@ -7592,7 +7601,7 @@ static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags, sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree; sum.os_ffree = ost_ffree; } - if (flags & MNTDF_SHOW) { + if (flags & MNTDF_SHOW && ost_idx == -1 && mdt_idx == -1) { printf("\n"); showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0); printf("\n"); @@ -8193,18 +8202,20 @@ static int lfs_df(int argc, char **argv) int ops = 0; int c, rc = 0, rc1 = 0, index = 0, arg_idx = 0; char fsname[PATH_MAX] = "", *pool_name = NULL; + int mdt_idx = -1; + int ost_idx = -1; struct option long_opts[] = { { .val = 'h', .name = "human-readable", .has_arg = no_argument }, { .val = 'H', .name = "si", .has_arg = no_argument }, { .val = 'i', .name = "inodes", .has_arg = no_argument }, { .val = 'l', .name = "lazy", .has_arg = no_argument }, + { .val = 'm', .name = "mdt", .has_arg = optional_argument }, + { .val = 'o', .name = "ost", .has_arg = optional_argument }, { .val = 'p', .name = "pool", .has_arg = required_argument }, { .val = 'v', .name = "verbose", .has_arg = no_argument }, - { .val = 'm', .name = "mdt", .has_arg = no_argument }, - { .val = 'o', .name = "ost", .has_arg = no_argument }, { .name = NULL} }; - while ((c = getopt_long(argc, argv, "hHilmop:v", + while ((c = getopt_long(argc, argv, "hHilm::o::p:v", long_opts, NULL)) != -1) { switch (c) { case 'h': @@ -8221,9 +8232,35 @@ static int lfs_df(int argc, char **argv) break; case 'm': ops |= LL_STATFS_LMV; + if (optarg) { + char *end; + errno = 0; + + mdt_idx = strtol(optarg, &end, 0); + if (errno != 0 || *end != '\0' || mdt_idx < 0 || + mdt_idx > LOV_V1_INSANE_STRIPE_INDEX) { + fprintf(stderr, + "%s: invalid MDT index '%s'\n", + progname, optarg); + return CMD_HELP; + } + } break; case 'o': ops |= LL_STATFS_LOV; + if (optarg) { + char *end; + errno = 0; + + ost_idx = strtol(optarg, &end, 0); + if (errno != 0 || *end != '\0' || ost_idx < 0 || + ost_idx > LOV_V1_INSANE_STRIPE_INDEX) { + fprintf(stderr, + "%s: invalid OST index '%s'\n", + progname, optarg); + return CMD_HELP; + } + } break; case 'p': pool_name = optarg; @@ -8249,7 +8286,8 @@ static int lfs_df(int argc, char **argv) if (mntdir[0] == '\0') continue; - rc = mntdf(mntdir, fsname, pool_name, flags, ops, NULL); + rc = mntdf(mntdir, fsname, pool_name, flags, ops, NULL, + mdt_idx, ost_idx); if (rc || path[0] != '\0') break; @@ -8288,7 +8326,8 @@ static int lfs_df(int argc, char **argv) if (mntdir[0] == '\0') continue; - rc = mntdf(mntdir, fsname, pool_name, flags, ops, NULL); + rc = mntdf(mntdir, fsname, pool_name, flags, ops, NULL, + mdt_idx, ost_idx); if (rc || path[0] != '\0') { valid = true; -- 1.8.3.1