Whamcloud - gitweb
LU-15536 utils: add lfs somsync utility 98/49498/5
authorJian Yu <yujian@whamcloud.com>
Tue, 24 Sep 2024 07:29:19 +0000 (00:29 -0700)
committerOleg Drokin <green@whamcloud.com>
Sun, 24 Nov 2024 06:03:25 +0000 (06:03 +0000)
This patch adds lfs somsync utility to synchronize
SOM xattr(s) for given FILE(s) or FID(s).

lfs somsync FILE ...
lfs somsync --by-fid MOUNT FID ...

Test-Parameters: trivial env=ONLY=807 testlist=sanity

Change-Id: Ie9ee39625d56ec026c89dcc0f27025904ca354e3
Signed-off-by: Jian Yu <yujian@whamcloud.com>
Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/49498
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Alex Zhuravlev <bzzz@whamcloud.com>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
lustre/doc/lfs-somsync.1 [new file with mode: 0644]
lustre/doc/llapi_fsync.3 [new file with mode: 0644]
lustre/include/lustre/lustreapi.h
lustre/tests/sanity.sh
lustre/utils/lfs.c
lustre/utils/liblustreapi.c

diff --git a/lustre/doc/lfs-somsync.1 b/lustre/doc/lfs-somsync.1
new file mode 100644 (file)
index 0000000..ae16c28
--- /dev/null
@@ -0,0 +1,53 @@
+.TH LFS-SOMSYNC 1 2024-09-24 "Lustre" "Lustre User Utilities"
+.SH NAME
+lfs-somsync \- synchronize SOM xattr for given file or FID
+.SH SYNOPSIS
+.SY lfs
+.B somsync
+.IR FILE " ..."
+.SY lfs
+.B somsync
+--by-fid
+.I MOUNT
+.IR FID " ..."
+.YS
+.SH DESCRIPTION
+This command synchronizes SOM xattr(s) for given
+.I FILE\c
+(s) or
+.I FID\c
+(s).
+.br
+The
+.I MOUNT
+specifies a mountpoint of Lustre filesystem where given
+.I FID\c
+(s) are stored.
+.I FID\c
+(s) can be wrapped with square brackets.
+.SH EXAMPLES
+Synchronize SOM xattr for file /mnt/lustre/file:
+.RS
+.EX
+.B # lfs somsync /mnt/lustre/file
+.EE
+.RE
+.PP
+Synchronize SOM xattrs for FIDs [0x200000400:0x1:0x0]
+and [0x200000402:0x20:0x0]:
+.RS
+.EX
+.B # lfs somsync --by-fid /mnt/lustre [0x200000400:0x1:0x0] [0x200000402:0x20:0x0]
+.EE
+.RE
+.SH AVAILABILITY
+The
+.B lfs somsync
+command is part of the
+.BR lustre (7)
+filesystem package since release 2.16.0.
+.\" Added in commit v2_15_91-1-gefaa7f561220
+.SH SEE ALSO
+.BR lfs (1),
+.BR lfs-path2fid (1),
+.BR lustre (7)
diff --git a/lustre/doc/llapi_fsync.3 b/lustre/doc/llapi_fsync.3
new file mode 100644 (file)
index 0000000..720269b
--- /dev/null
@@ -0,0 +1,37 @@
+.TH LLAPI_FSYNC 3 2024-09-24 "Lustre User API" "Lustre Library Functions"
+.SH NAME
+llapi_fsync \- flush dirty pages from all Lustre clients
+.SH SYNOPSIS
+.nf
+.B #include <lustre/lustreapi.h>
+.sp
+.BI "int llapi_fsync(int " fd ");"
+.YS
+.fi
+.SH DESCRIPTION
+.B llapi_fsync()
+flushes dirty pages from all of the clients for a given file descriptor.
+.TP
+.I fd
+file descriptor
+.SH RETURN VALUES
+.B llapi_fsync()
+returns:
+.TP
+0
+on success
+.TP
+<0
+a negative errno value on failure
+.SH EXAMPLES
+An example can be found in lfs.c source file.
+.SH AVAILABILITY
+The
+.B llapi_fsync
+API is part of the
+.BR lustre (7)
+user application interface library since release 2.16.0.
+.\" Added in commit v2_15_91-1-g425b9f75225d
+.SH SEE ALSO
+.BR lustre (7),
+.BR lustreapi (7)
index c056d0f..9791584 100644 (file)
@@ -545,6 +545,7 @@ int llapi_get_version(char *buffer, int buffer_size, char **version)
        __attribute__((deprecated));
 int llapi_get_data_version(int fd, __u64 *data_version, __u64 flags);
 int llapi_file_flush(int fd);
+int llapi_fsync(int fd);
 extern int llapi_get_ost_layout_version(int fd, __u32 *layout_version);
 int llapi_hsm_data_version_set(int fd, __u64 data_version);
 int llapi_hsm_state_get_fd(int fd, struct hsm_user_state *hus);
index 6b0833b..7c47980 100755 (executable)
@@ -32913,16 +32913,27 @@ test_806() {
 }
 run_test 806 "Verify Lazy Size on MDS"
 
-test_807() {
-       [ -n "$FILESET" ] && skip "Not functional for FILESET set"
-       [ $MDS1_VERSION -lt $(version_code 2.11.52) ] &&
+verify_som_sync_utility() {
+       local utility=$1
+       local use_llsom_sync=false
+
+       [[ -z "$FILESET" ]] || skip "Not functional for FILESET set"
+       [[ $MDS1_VERSION -ge $(version_code 2.11.52) ]] ||
                skip "Need MDS version at least 2.11.52"
 
-       # Registration step
-       changelog_register || error "changelog_register failed"
-       local cl_user="${CL_USERS[$SINGLEMDS]%% *}"
-       changelog_users $SINGLEMDS | grep -q $cl_user ||
-               error "User $cl_user not found in changelog_users"
+       case $utility in
+               llsom_sync ) use_llsom_sync=true ;;
+               somsync ) use_llsom_sync=false ;;
+               *) error "invalid utility $utility" ;;
+       esac
+
+       if $use_llsom_sync; then
+               # Registration step
+               changelog_register || error "changelog_register failed"
+               local cl_user="${CL_USERS[$SINGLEMDS]%% *}"
+               changelog_users $SINGLEMDS | grep -q $cl_user ||
+                       error "User $cl_user not found in changelog_users"
+       fi
 
        rm -rf $DIR/$tdir || error "rm $tdir failed"
        mkdir_on_mdt0 $DIR/$tdir || error "mkdir $tdir failed"
@@ -32940,33 +32951,51 @@ test_807() {
        # multi-client wirtes
        local num=$(get_node_count ${CLIENTS//,/ })
        local offset=0
-       local i=0
+       local -a pids
 
        echo "Test SOM for multi-client ($num) writes"
        touch $DIR/$tfile || error "touch $tfile failed"
        $TRUNCATE $DIR/$tfile 0
        for client in ${CLIENTS//,/ }; do
                do_node $client $MULTIOP $DIR/$tfile Oz${offset}w${bs}c &
-               local pids[$i]=$!
-               i=$((i + 1))
-               offset=$((offset + $bs))
-       done
-       for (( i=0; i < $num; i++ )); do
-               wait ${pids[$i]}
+               pids+=( $! )
+               offset=$((offset + bs))
        done
+       wait ${pids[@]}
 
        do_rpc_nodes "$CLIENTS" cancel_lru_locks osc
        do_nodes "$CLIENTS" "sync ; sleep 5 ; sync"
-       $LSOM_SYNC -u $cl_user -m $FSNAME-MDT0000 $MOUNT
+
+       if $use_llsom_sync; then
+               $LSOM_SYNC -u $cl_user -m $FSNAME-MDT0000 $MOUNT ||
+                       error "$LSOM_SYNC failed"
+       else
+               $LFS somsync $DIR/$tfile ||
+                       error "$LFS somsync $DIR/$tfile failed"
+               find $DIR/$tdir -type f | xargs $LFS path2fid |
+                       awk '{print $2}' | xargs $LFS somsync --by-fid $DIR ||
+                               error "$LFS somsync --by-fid $DIR failed"
+       fi
+
        check_lsom_data $DIR/$tdir/trunc "(0)"
        check_lsom_data $DIR/$tdir/single_dd "(1)"
        check_lsom_data $DIR/$tfile "(2)"
 
        rm -rf $DIR/$tdir
        # Deregistration step
-       changelog_deregister || error "changelog_deregister failed"
+       ! $use_llsom_sync || changelog_deregister ||
+               error "changelog_deregister failed"
+}
+
+test_807a() {
+       verify_som_sync_utility llsom_sync
+}
+run_test 807a "verify LSOM syncing tool"
+
+test_807b() {
+       verify_som_sync_utility somsync
 }
-run_test 807 "verify LSOM syncing tool"
+run_test 807b "verify lfs somsync utility"
 
 check_som_nologged()
 {
index fa45994..2e73933 100755 (executable)
@@ -133,6 +133,7 @@ static int lfs_swap_layouts(int argc, char **argv);
 static int lfs_mv(int argc, char **argv);
 static int lfs_ladvise(int argc, char **argv);
 static int lfs_getsom(int argc, char **argv);
+static int lfs_somsync(int argc, char **argv);
 static int lfs_heat_get(int argc, char **argv);
 static int lfs_heat_set(int argc, char **argv);
 static int lfs_mirror(int argc, char **argv);
@@ -579,6 +580,10 @@ command_t cmdlist[] = {
         "\t-s: Only show the size value of the SOM data for a given file\n"
         "\t-b: Only show the blocks value of the SOM data for a given file\n"
         "\t-f: Only show the flags value of the SOM data for a given file\n"},
+       {"somsync", lfs_somsync, 0,
+        "Synchronize SOM xattr(s) for given file(s) or FID(s).\n"
+        "usage: somsync FILE ...\n"
+        "       somsync --by-fid MOUNT FID ...\n"},
        {"heat_get", lfs_heat_get, 0,
         "To get heat of files.\n"
         "usage: heat_get <file> ...\n"},
@@ -12359,6 +12364,169 @@ static inline int verify_mirror_id_by_fd(int fd, __u16 mirror_id)
        return 0;
 }
 
+static inline int lfs_somsync_by_fd(int fd)
+{
+       struct stat st;
+       int rc = 0;
+
+       /* flush dirty pages from clients */
+       rc = llapi_fsync(fd);
+       if (rc < 0)
+               goto out;
+
+       rc = fstat(fd, &st);
+       if (rc < 0)
+               rc = -errno;
+
+       /*
+        * After call fstat(), it already gets OST attrs to the client,
+        * when close the file, MDS will update the LSOM data itself
+        * according the size and blocks information from the client.
+        */
+out:
+       close(fd);
+       return rc;
+}
+
+static inline int lfs_somsync_by_path(const char *fname)
+{
+       int fd;
+       int rc = 0;
+
+       fd = open(fname, O_RDONLY | O_NOATIME);
+       if (fd < 0) {
+               rc = -errno;
+               fprintf(stderr,
+                       "%s somsync: cannot open '%s': %s\n",
+                       progname, fname, strerror(errno));
+               return rc;
+       }
+
+       rc = lfs_somsync_by_fd(fd);
+       if (rc < 0) {
+               fprintf(stderr,
+                       "%s somsync: cannot synchronize SOM data of '%s': %s\n",
+                       progname, fname, strerror(-rc));
+               return rc;
+       }
+
+       return 0;
+}
+
+static inline int lfs_somsync_by_fid(const char *lustre_dir,
+                                    const struct lu_fid *fid)
+{
+       int fd = -1;
+       char fidstr[FID_LEN];
+       int rc = 0;
+
+       snprintf(fidstr, sizeof(fidstr), DFID, PFID(fid));
+       fd = llapi_open_by_fid(lustre_dir, fid, O_RDONLY | O_NOATIME);
+       if (fd < 0) {
+               rc = -errno;
+               fprintf(stderr,
+                       "%s somsync: cannot open '%s': %s\n",
+                       progname, fidstr, strerror(-rc));
+               return rc;
+       }
+
+       rc = lfs_somsync_by_fd(fd);
+       if (rc < 0) {
+               fprintf(stderr,
+                       "%s somsync: cannot synchronize SOM data of '%s': %s\n",
+                       progname, fidstr, strerror(-rc));
+               return rc;
+       }
+
+       return 0;
+}
+
+enum {
+       LFS_SOMSYNC_CLIENT_MOUNT = 1,
+};
+
+static int lfs_somsync(int argc, char **argv)
+{
+       struct option long_opts[] = {
+               { "by-fid", required_argument, NULL, LFS_SOMSYNC_CLIENT_MOUNT },
+               { NULL },
+       };
+       const char *client_mount = NULL;
+       int c;
+       int rc = 0, rc1;
+
+       while ((c = getopt_long(argc, argv, "", long_opts, NULL)) != -1) {
+               switch (c) {
+               case LFS_SOMSYNC_CLIENT_MOUNT:
+                       client_mount = optarg;
+                       break;
+               default:
+                       fprintf(stderr,
+                               "%s somsync: unrecognized option '%s'\n",
+                               progname, argv[optind - 1]);
+                       return CMD_HELP;
+               }
+       }
+
+       if (client_mount != NULL) {
+               /* lfs somsync --by-fid MOUNT FID ... */
+               char mntdir[PATH_MAX];
+               struct lu_fid fid;
+               char *fidstr;
+               int found;
+
+               if (argc == optind) {
+                       fprintf(stderr, "%s somsync: missing FID\n", progname);
+                       return CMD_HELP;
+               }
+
+               rc = llapi_search_mounts(client_mount, 0, mntdir, NULL);
+               if (rc < 0) {
+                       fprintf(stderr,
+                               "%s somsync: invalid MOUNT '%s': %s\n",
+                               progname, client_mount, strerror(-rc));
+                       return rc;
+               }
+
+               rc = 0;
+               while (optind < argc) {
+                       found = 0;
+
+                       fidstr = argv[optind++];
+                       while (*fidstr == '[')
+                               fidstr++;
+                       found = sscanf(fidstr, SFID, RFID(&fid));
+                       if (found != 3) {
+                               fprintf(stderr,
+                                       "%s somsync: unrecognized FID: %s\n",
+                                       progname, argv[optind - 1]);
+                               return -EINVAL;
+                       }
+
+                       rc1 = lfs_somsync_by_fid(mntdir, &fid);
+                       if (rc1 && !rc)
+                               rc = rc1;
+               }
+
+               return rc;
+       }
+
+       /* lfs somsync FILE ... */
+       if (argc == optind) {
+               fprintf(stderr, "%s somsync: missing FILE\n", progname);
+               return CMD_HELP;
+       }
+
+       rc = 0;
+       while (optind < argc) {
+               rc1 = lfs_somsync_by_path(argv[optind++]);
+               if (rc1 && !rc)
+                       rc = rc1;
+       }
+
+       return rc;
+}
+
 /**
  * Check whether two files are the same file
  * \retval     0  same file
index 5b68248..d27589e 100644 (file)
@@ -7183,3 +7183,20 @@ int llapi_file_flush(int fd)
 
        return llapi_get_data_version(fd, &dv, LL_DV_WR_FLUSH);
 }
+
+/**
+ * Flush dirty pages from all clients.
+ *
+ * OSTs will take LCK_PR to flush dirty pages from clients.
+ *
+ * \param[in]  fd      File descriptor
+ *
+ * \retval 0 on success.
+ * \retval -errno on error.
+ */
+int llapi_fsync(int fd)
+{
+       __u64 dv;
+
+       return llapi_get_data_version(fd, &dv, LL_DV_RD_FLUSH);
+}