From afeb1331a5ba09f1040d472a20d3195fe367d5a9 Mon Sep 17 00:00:00 2001 From: "John L. Hammond" Date: Thu, 26 Aug 2021 10:26:04 -0500 Subject: [PATCH] EX-3658 pumount: refine exit statuses 0 Unmount succeeded and no processes using FS remained. 1 Unmount succeeded but one or more processes using FS remained. 2 Unmount failed or some other major error occurred. 3 An invalid option or argument was supplied. Add sanity-pumount 57a-c to verify. Test-Parameters: trivial testlist=sanity-pumount clientextra_install_params="--packages pumount" Signed-off-by: John L. Hammond Change-Id: I7d0d67129af08d5c56ab5e676d4d92b3a14f2d9d Reviewed-on: https://review.whamcloud.com/44758 Tested-by: jenkins Tested-by: Maloo Reviewed-on: https://review.whamcloud.com/44958 Reviewed-by: Andreas Dilger --- lustre/tests/sanity-pumount.sh | 29 ++++++++++++- pumount/pumount.c | 99 ++++++++++++++++++++++++------------------ 2 files changed, 84 insertions(+), 44 deletions(-) diff --git a/lustre/tests/sanity-pumount.sh b/lustre/tests/sanity-pumount.sh index 1519758..75a1003 100755 --- a/lustre/tests/sanity-pumount.sh +++ b/lustre/tests/sanity-pumount.sh @@ -708,6 +708,7 @@ test_57a() { local file=$DIR/$tfile local fd local pid + local status init_pumount_env @@ -716,12 +717,36 @@ test_57a() { pid=$! exec {fd}>&- - ! pumount --signal=$SIGCHLD "$MOUNT1" || error "pumount should fail" + status=0 + pumount --signal=$SIGCHLD "$MOUNT1" || status=$? + ((status == 1)) || error "pumount exited with status $status, expected 1" + ! mountpoint --quiet "$MOUNT1" || error "'$MOUNT1' still in mountinfo" kill_wait_signaled $pid $SIGTERM $SIGTERM check_unmount_complete "$MOUNT1" } -run_test 57a "pumount fails when processes remain" +run_test 57a "pumount fails with status 1 when processes remain" + +test_57b() { + local status + + init_pumount_env + umount_client "$MOUNT2" + + status=0 + pumount "$MOUNT2" || status=$? + ((status == 2)) || error "pumount exited with status $status, expected 2" +} +run_test 57b "pumount fails with status 2 when umount fails" + +test_57c() { + local status + + status=0 + pumount || status=$? + ((status == 3)) || error "pumount exited with status $status, expected 3" +} +run_test 57c "pumount fails with status 3 on invalid usage" log "cleanup: ======================================================" diff --git a/pumount/pumount.c b/pumount/pumount.c index 0d39430..bba34af 100644 --- a/pumount/pumount.c +++ b/pumount/pumount.c @@ -19,6 +19,10 @@ #include #include +#ifndef ARRAY_SIZE +# define ARRAY_SIZE(a) ((sizeof(a)) / (sizeof((a)[0]))) +#endif + #ifdef VERSION # define PU_VERSION VERSION #else @@ -29,7 +33,28 @@ static const char pu_program_name[] = "pumount"; static const char pu_version[] = PU_VERSION; static bool pu_debug; -#define ARRAY_SIZE(a) ((sizeof(a)) / (sizeof((a)[0]))) +enum { + PU_DEF_SCAN_COUNT_MAX = 10, + PU_DEF_SIGNAL = SIGKILL, /* XXX Hard coded in help message. */ + PU_EXIT_SUCCESS = 0, /* See the help message. */ + PU_EXIT_PROCESSES_REMAINED = 1, + PU_EXIT_FAILURE = 2, + PU_EXIT_TRY_HELP = 3, + PU_FILEID_LUSTRE = 0x97, /* From linux/exportfs.h */ + PU_FILEID_INVALID = 0xff, /* ... */ + PU_MOUNT_ID_FAKE = INT_MAX, +}; + +struct pu_fid { + __u64 f_seq; + __u32 f_oid; + __u32 f_ver; +}; + +struct pu_lustre_nfs_fid { + struct pu_fid lnf_child; + struct pu_fid lnf_parent; +}; #define PU_DEBUG(fmt, args...) \ do { \ @@ -49,8 +74,8 @@ static bool pu_debug; #define PU_FATAL(fmt, args...) \ do { \ - PU_ERROR("fatal: "fmt, ##args); \ - exit(EXIT_FAILURE); \ + PU_ERROR("fatal: "fmt, ##args); \ + exit(PU_EXIT_FAILURE); \ } while (0) #define OOM() \ @@ -60,8 +85,8 @@ static bool pu_debug; do { \ fprintf(stderr, \ "Try '%s --help' for more information.\n", \ - pu_program_name); \ - exit(2); \ + pu_program_name); \ + exit(PU_EXIT_TRY_HELP); \ } while (0) #define TRY_HELP(fmt, args...) \ @@ -402,23 +427,6 @@ out: return rc; } -struct pu_fid { - __u64 f_seq; - __u32 f_oid; - __u32 f_ver; -}; - -struct pu_lustre_nfs_fid { - struct pu_fid lnf_child; - struct pu_fid lnf_parent; -}; - -enum { - PU_MOUNT_ID_FAKE = INT_MAX, - PU_FILEID_LUSTRE = 0x97, /* From linux/exportfs.h */ - PU_FILEID_INVALID = 0xff, /* ... */ -}; - static int pu_name_to_handle(int dirfd, const char *path, struct file_handle **phandle, int *mount_id, int flags) { struct file_handle *handle = NULL; @@ -753,7 +761,7 @@ static struct option options[] = { { NULL }, }; -void usage(void) +static void print_help(void) { printf( "Usage pumount [OPTION]... DIRECTORY\n" @@ -768,9 +776,9 @@ void usage(void) " --no-open do not open DIRECTORY\n" " --no-signal do not send signals\n" " --no-umount do not unmount FS\n" -" -p, --print print users of FS\n" -" --scan-count=COUNT scan for users at most COUNT times\n" /* ... (default %d) */ -" --signal=SIG send SIG to users of FS (default SIGKILL)\n" +" -p, --print print uses of FS\n" +" --scan-count=COUNT scan for processes at most COUNT times (default %d)\n" +" --signal=SIG send SIG to processes using FS (default SIGKILL)\n" /* XXX */ " --version print version information and exit\n" "\n" "Operation:\n" @@ -829,10 +837,16 @@ void usage(void) "python 8942 0 lustre [0x200000404:0x3:0x0] /lustre/fs0a12/client/projects/EGGS\\040V7\\040FINAL.xls\n" "\n" "Exit status:\n" -" 0 Unmount succeeded and no users remained.\n" -" 1 Unmount failed or users remained or other error.\n" -" 2 An invalid option or argument was supplied.\n"); -/* TODO (maybe) add more statuses about users remaining, minor errors. ... */ +" %d Unmount succeeded and no processes using FS remained.\n" +" %d Unmount succeeded but one or more processes using FS remained.\n" +" %d Unmount failed or some other major error occurred.\n" +" %d An invalid option or argument was supplied.\n", +PU_DEF_SCAN_COUNT_MAX, +PU_EXIT_SUCCESS, +PU_EXIT_PROCESSES_REMAINED, +PU_EXIT_FAILURE, +PU_EXIT_TRY_HELP +); } int main(int argc, char *argv[]) @@ -849,10 +863,10 @@ int main(int argc, char *argv[]) bool do_print = false; bool do_signal = true; bool do_umount = true; - int sig = SIGKILL; + int sig = PU_DEF_SIGNAL; int umount2_flags = MNT_DETACH; int proc_count; - int scan_count_max = 4; + int scan_count_max = PU_DEF_SCAN_COUNT_MAX; int scan_count; int use_count = 0; int err_count = 0; @@ -875,8 +889,8 @@ int main(int argc, char *argv[]) umount2_flags |= MNT_FORCE; break; case 'h': - usage(); - exit(EXIT_SUCCESS); + print_help(); + exit(PU_EXIT_SUCCESS); case 'l': /* Already implied. */ break; @@ -895,25 +909,24 @@ int main(int argc, char *argv[]) case PU_OPT_SCAN_COUNT: rc = pu_strtoi(optarg, &scan_count_max, 0, INT_MAX); if (rc < 0) - PU_FATAL("invalid scan-count '%s'\n", optarg); + TRY_HELP("invalid scan-count '%s'\n", optarg); break; case PU_OPT_SIGNAL: rc = pu_str_to_signal(optarg, &sig); if (rc < 0) - PU_FATAL("invalid signal '%s'\n", optarg); + TRY_HELP("invalid signal '%s'\n", optarg); break; case PU_OPT_VERSION: printf("%s %s\n", pu_program_name, pu_version); - exit(EXIT_SUCCESS); + exit(PU_EXIT_SUCCESS); case '?': TRY_HELP_1(); } } - if (optind + 1 != argc) { + if (optind + 1 != argc) TRY_HELP("usage: %s [OPTION]... DIRECTORY\n", pu_program_name); - } mount_point = argv[optind]; @@ -1039,7 +1052,7 @@ int main(int argc, char *argv[]) if (puc->puc_use_count == 0) goto next; - PU_DEBUG("found process %d, comm '%s' with %d usesN of mount %d\n", + PU_DEBUG("found process %d, comm '%s' with %d uses of mount %d\n", pid, puc_comm(puc), puc->puc_use_count, mount_id); proc_count += 1; @@ -1074,11 +1087,13 @@ int main(int argc, char *argv[]) proc_count, proc_count == 1 ? "" : "es", mount_point, mount_id, scan_count, scan_count == 1 ? "" : "s"); - status = EXIT_FAILURE; + status = PU_EXIT_PROCESSES_REMAINED; } else { - status = EXIT_SUCCESS; + status = PU_EXIT_SUCCESS; } + PU_DEBUG_D(status); + /* If there are no other users of FS then the real umount * should happen in the close of mount_dirfd. */ pu_close(&mount_dirfd); -- 1.8.3.1