Whamcloud - gitweb
LU-18242 utils: allow 'lfs df -m/-o' to specify one MDT/OST 29/58729/8
authorChakshu Kansal <ckansal@ddn.com>
Fri, 13 Jun 2025 09:22:15 +0000 (14:52 +0530)
committerOleg Drokin <green@whamcloud.com>
Thu, 3 Jul 2025 13:20:24 +0000 (13:20 +0000)
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 <ckansal@ddn.com>
Change-Id: I74538b6d8c95c41a7d9030f94103a7c0fd8756db
Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/58729
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
Documentation/man1/lfs-df.1
lustre/tests/sanity.sh
lustre/utils/lfs.c

index 1502a86..02637e6 100644 (file)
@@ -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
index 60fbb47..25852e3 100755 (executable)
@@ -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)) ] ||
index b844c15..c2d8646 100644 (file)
@@ -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;