From 1b1ac423ea40cbca9a1da7c2208a7d6b41804b47 Mon Sep 17 00:00:00 2001 From: Jian Yu Date: Tue, 24 Sep 2024 00:29:19 -0700 Subject: [PATCH] LU-15536 utils: add lfs somsync utility 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 Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/49498 Tested-by: jenkins Tested-by: Maloo Reviewed-by: Alex Zhuravlev Reviewed-by: Andreas Dilger Reviewed-by: Oleg Drokin --- lustre/doc/lfs-somsync.1 | 53 ++++++++++++ lustre/doc/llapi_fsync.3 | 37 +++++++++ lustre/include/lustre/lustreapi.h | 1 + lustre/tests/sanity.sh | 65 +++++++++++---- lustre/utils/lfs.c | 168 ++++++++++++++++++++++++++++++++++++++ lustre/utils/liblustreapi.c | 17 ++++ 6 files changed, 323 insertions(+), 18 deletions(-) create mode 100644 lustre/doc/lfs-somsync.1 create mode 100644 lustre/doc/llapi_fsync.3 diff --git a/lustre/doc/lfs-somsync.1 b/lustre/doc/lfs-somsync.1 new file mode 100644 index 0000000..ae16c28 --- /dev/null +++ b/lustre/doc/lfs-somsync.1 @@ -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 index 0000000..720269b --- /dev/null +++ b/lustre/doc/llapi_fsync.3 @@ -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 +.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) diff --git a/lustre/include/lustre/lustreapi.h b/lustre/include/lustre/lustreapi.h index c056d0f..9791584 100644 --- a/lustre/include/lustre/lustreapi.h +++ b/lustre/include/lustre/lustreapi.h @@ -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); diff --git a/lustre/tests/sanity.sh b/lustre/tests/sanity.sh index 6b0833b..7c47980 100755 --- a/lustre/tests/sanity.sh +++ b/lustre/tests/sanity.sh @@ -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() { diff --git a/lustre/utils/lfs.c b/lustre/utils/lfs.c index fa45994..2e73933 100755 --- a/lustre/utils/lfs.c +++ b/lustre/utils/lfs.c @@ -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 ...\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 diff --git a/lustre/utils/liblustreapi.c b/lustre/utils/liblustreapi.c index 5b68248..d27589e 100644 --- a/lustre/utils/liblustreapi.c +++ b/lustre/utils/liblustreapi.c @@ -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); +} -- 1.8.3.1