diff --git a/nfs-utils-1.1.5-nfsstat-update.patch b/nfs-utils-1.1.5-nfsstat-update.patch new file mode 100644 index 0000000..961b2b3 --- /dev/null +++ b/nfs-utils-1.1.5-nfsstat-update.patch @@ -0,0 +1,709 @@ +commit fa5352f78533c7ad1d8603c1a4ba08fa82768e6b +Author: Steve Dickson +Date: Wed Apr 8 10:26:26 2009 -0400 + + The --list option does not work on server stats. + + The print_stats_list() routine was using the client's + stats to decide whether to display any stats. This did + not work when there was only server stats. + + This patch breaks up print_stats_list into two different + routines allowing both server and clients stats to be + listed. + + Signed-off-by: Steve Dickson + +commit 500fab45f73c0ba1bc442157ef3d7744f20e6b2a +Author: Steve Dickson +Date: Wed Apr 8 09:48:58 2009 -0400 + + The server stats were not being updated with the + -Z options causing the stats to be incorrect. + + Signed-off-by: Steve Dickson + +commit cb81340660112f9296205901b09c0668a480bc47 +Author: Steve Dickson +Date: Wed Apr 8 09:28:22 2009 -0400 + + Eliminate the displaying zero stats when the explicit protocol + is specified (-2, -3, -4) the -Z and or --list options. + + When a particular protocol is specified and either + the -Z or --list options are used, zeros or blank lines + are echoed to the screen when there is not any NFS traffic. + This cause any useful data to be scroll off the screen. + + With this patch only non-zero stats will be shown, which + makes the output of these options more condensed and + in turn more useful. + + Signed-off-by: Steve Dickson + +commit ca8eb17798fb9b4936a38cc58fe379e9e8d379f9 +Author: Kevin Constantine +Date: Sat Apr 4 07:18:26 2009 -0400 + + nfsstat: Add --list flag + + nfsstat.c: Adds the --list flag to print information in a list format + instead of the standard multi-column format + nfsstat.man: Updates the manpage to include the --list flag. + + Signed-off-by: Kevin Constantine + Signed-off-by: Steve Dickson + +commit 524cdc4eb1663e5c10d12160e48c45dc81852568 +Author: Steve Dickson +Date: Sat Apr 4 06:46:09 2009 -0400 + + Keep the interval output quite when there is no NFS traffic. + + The 'nfsstat -Z5' command continually outputs the following + when there is no NFS traffic. + + Client rpc stats: + calls retrans authrefrsh + 0 0 0 + + This patch adds code that will keep the interval output + quite so real results will not be scrolled of the screen + + Signed-off-by: Steve Dickson + +commit d2319b9cabc67d999b16aea2077a4a3c642ec28d +Author: Kevin Constantine +Date: Sat Apr 4 06:29:01 2009 -0400 + + nfsstat: Print diff stats every N seconds + + nfsstat.c: Implements an optional "interval" argument to --sleep + nfsstat.man: Explains the use of --sleep[interval] + + Reviewed-By: Greg Banks + Signed-off-by: Kevin Constantine + Signed-off-by: Steve Dickson +___________________________________________________________ +diff --git a/utils/nfsstat/nfsstat.c b/utils/nfsstat/nfsstat.c +index 1517414..7e9f327 100644 +--- a/utils/nfsstat/nfsstat.c ++++ b/utils/nfsstat/nfsstat.c +@@ -167,10 +167,16 @@ DECLARE_SRV(srvinfo, _old); + DECLARE_CLT(cltinfo); + DECLARE_CLT(cltinfo, _old); + ++static void print_all_stats(int, int, int); ++static void print_server_stats(int, int); ++static void print_client_stats(int, int); ++static void print_stats_list(int, int, int); + static void print_numbers(const char *, unsigned int *, + unsigned int); + static void print_callstats(const char *, const char **, + unsigned int *, unsigned int); ++static void print_callstats_list(const char *, const char **, ++ unsigned int *, unsigned int); + static int parse_raw_statfile(const char *, struct statinfo *); + static int parse_pretty_statfile(const char *, struct statinfo *); + +@@ -181,8 +187,10 @@ static int mounts(const char *); + static void get_stats(const char *, struct statinfo *, int *, int, + int); + static int has_stats(const unsigned int *); ++static int has_rpcstats(const unsigned int *, int); + static void diff_stats(struct statinfo *, struct statinfo *, int); + static void unpause(int); ++static void update_old_counters(struct statinfo *, struct statinfo *); + + static time_t starttime; + +@@ -207,26 +215,30 @@ void usage(char *name) + { + printf("Usage: %s [OPTION]...\n\ + \n\ +- -m, --mounts\t\tShow statistics on mounted NFS filesystems\n\ +- -c, --client\t\tShow NFS client statistics\n\ +- -s, --server\t\tShow NFS server statistics\n\ +- -2\t\t\tShow NFS version 2 statistics\n\ +- -3\t\t\tShow NFS version 3 statistics\n\ +- -4\t\t\tShow NFS version 4 statistics\n\ +- -o [facility]\t\tShow statistics on particular facilities.\n\ +- nfs\tNFS protocol information\n\ +- rpc\tGeneral RPC information\n\ +- net\tNetwork layer statistics\n\ +- fh\t\tUsage information on the server's file handle cache\n\ +- rc\t\tUsage information on the server's request reply cache\n\ +- all\tSelect all of the above\n\ +- -v, --verbose, --all\tSame as '-o all'\n\ +- -r, --rpc\t\tShow RPC statistics\n\ +- -n, --nfs\t\tShow NFS statistics\n\ +- -Z, --sleep\t\tSaves stats, pauses, diffs current and saved\n\ +- -S, --since file\tShows difference between current stats and those in 'file'\n\ +- --version\t\tShow program version\n\ +- --help\t\tWhat you just did\n\ ++ -m, --mounts Show statistics on mounted NFS filesystems\n\ ++ -c, --client Show NFS client statistics\n\ ++ -s, --server Show NFS server statistics\n\ ++ -2 Show NFS version 2 statistics\n\ ++ -3 Show NFS version 3 statistics\n\ ++ -4 Show NFS version 4 statistics\n\ ++ -o [facility] Show statistics on particular facilities.\n\ ++ nfs NFS protocol information\n\ ++ rpc General RPC information\n\ ++ net Network layer statistics\n\ ++ fh Usage information on the server's file handle cache\n\ ++ rc Usage information on the server's request reply cache\n\ ++ all Select all of the above\n\ ++ -v, --verbose, --all Same as '-o all'\n\ ++ -r, --rpc Show RPC statistics\n\ ++ -n, --nfs Show NFS statistics\n\ ++ -Z[#], --sleep[=#] Collects stats until interrupted.\n\ ++ Cumulative stats are then printed\n\ ++ If # is provided, stats will be output every\n\ ++ # seconds.\n\ ++ -S, --since file Shows difference between current stats and those in 'file'\n\ ++ -l, --list Prints stats in list format\n\ ++ --version Show program version\n\ ++ --help What you just did\n\ + \n", name); + exit(0); + } +@@ -245,10 +257,12 @@ static struct option longopts[] = + { "zero", 0, 0, 'z' }, + { "help", 0, 0, '\1' }, + { "version", 0, 0, '\2' }, +- { "sleep", 0, 0, 'Z' }, ++ { "sleep", 2, 0, 'Z' }, + { "since", 1, 0, 'S' }, ++ { "list", 0, 0, 'l' }, + { NULL, 0, 0, 0 } + }; ++int opt_sleep; + + int + main(int argc, char **argv) +@@ -257,7 +271,8 @@ main(int argc, char **argv) + opt_srv = 0, + opt_clt = 0, + opt_prt = 0, +- opt_sleep = 0, ++ sleep_time = 0, ++ opt_list =0, + opt_since = 0; + int c; + char *progname, +@@ -279,7 +294,7 @@ main(int argc, char **argv) + else + progname = argv[0]; + +- while ((c = getopt_long(argc, argv, "234acmno:ZS:vrsz\1\2", longopts, NULL)) != EOF) { ++ while ((c = getopt_long(argc, argv, "234acmno:Z::S:vrslz\1\2", longopts, NULL)) != EOF) { + switch (c) { + case 'a': + fprintf(stderr, "nfsstat: nfs acls are not yet supported.\n"); +@@ -311,6 +326,9 @@ main(int argc, char **argv) + break; + case 'Z': + opt_sleep = 1; ++ if (optarg) { ++ sleep_time = atoi(optarg); ++ } + break; + case 'S': + opt_since = 1; +@@ -334,6 +352,9 @@ main(int argc, char **argv) + case 's': + opt_srv = 1; + break; ++ case 'l': ++ opt_list = 1; ++ break; + case 'z': + fprintf(stderr, "nfsstat: zeroing of nfs statistics " + "not yet supported\n"); +@@ -384,7 +405,7 @@ main(int argc, char **argv) + if (opt_clt) + get_stats(clientfile, clientinfo, &opt_clt, opt_srv, 0); + +- if (opt_sleep) { ++ if (opt_sleep && !sleep_time) { + starttime = time(NULL); + printf("Collecting statistics; press CTRL-C to view results from interval (i.e., from pause to CTRL-C).\n"); + if (sigaction(SIGINT, &act, NULL) != 0) { +@@ -404,119 +425,288 @@ main(int argc, char **argv) + diff_stats(clientinfo_tmp, clientinfo, 0); + } + } ++ if(sleep_time) { ++ while(1) { ++ if (opt_srv) { ++ get_stats(NFSSRVSTAT, serverinfo_tmp , &opt_srv, opt_clt, 1); ++ diff_stats(serverinfo_tmp, serverinfo, 1); ++ } ++ if (opt_clt) { ++ get_stats(NFSCLTSTAT, clientinfo_tmp, &opt_clt, opt_srv, 0); ++ diff_stats(clientinfo_tmp, clientinfo, 0); ++ } ++ if (opt_list) { ++ print_stats_list(opt_srv, opt_clt, opt_prt); ++ } else { ++ print_all_stats(opt_srv, opt_clt, opt_prt); ++ } ++ fflush(stdout); ++ ++ if (opt_srv) ++ update_old_counters(serverinfo_tmp, serverinfo); ++ if (opt_clt) ++ update_old_counters(clientinfo_tmp, clientinfo); ++ ++ sleep(sleep_time); ++ } ++ } else { ++ if (opt_list) { ++ print_stats_list(opt_srv, opt_clt, opt_prt); ++ } else { ++ print_all_stats(opt_srv, opt_clt, opt_prt); ++ } ++ } + +- if (opt_srv) { +- if (opt_prt & PRNT_NET) { +- print_numbers( +- LABEL_srvnet +- "packets udp tcp tcpconn\n", +- srvnetinfo, 4 +- ); ++ return 0; ++} ++ ++static void ++print_all_stats (int opt_srv, int opt_clt, int opt_prt) ++{ ++ print_server_stats(opt_srv, opt_prt); ++ print_client_stats(opt_clt, opt_prt); ++} ++ ++static void ++print_server_stats(int opt_srv, int opt_prt) ++{ ++ if (!opt_srv) ++ return; ++ ++ if (opt_prt & PRNT_NET) { ++ if (opt_sleep && !has_rpcstats(srvnetinfo, 4)) { ++ } else { ++ print_numbers( LABEL_srvnet ++ "packets udp tcp tcpconn\n", ++ srvnetinfo, 4); + printf("\n"); + } +- if (opt_prt & PRNT_RPC) { +- print_numbers( +- LABEL_srvrpc +- "calls badcalls badauth badclnt xdrcall\n", +- srvrpcinfo, 5 +- ); ++ } ++ if (opt_prt & PRNT_RPC) { ++ if (opt_sleep && !has_rpcstats(srvrpcinfo, 5)) { ++ ; ++ } else { ++ print_numbers(LABEL_srvrpc ++ "calls badcalls badauth badclnt xdrcall\n", ++ srvrpcinfo, 5); + printf("\n"); + } +- if (opt_prt & PRNT_RC) { +- print_numbers( +- LABEL_srvrc +- "hits misses nocache\n", +- srvrcinfo, 3 +- ); ++ } ++ if (opt_prt & PRNT_RC) { ++ if (opt_sleep && !has_rpcstats(srvrcinfo, 3)) { ++ ; ++ } else { ++ print_numbers(LABEL_srvrc ++ "hits misses nocache\n", ++ srvrcinfo, 3); + printf("\n"); + } ++ } + +- /* +- * 2.2 puts all fh-related info after the 'rc' header +- * 2.4 puts all fh-related info after the 'fh' header, but relocates +- * 'stale' to the start and swaps dir and nondir :-( +- * We preseve the 2.2 order +- */ +- if (opt_prt & PRNT_FH) { +- if (get_stat_info("fh", srvinfo)) { /* >= 2.4 */ +- int t = srvfhinfo[3]; +- srvfhinfo[3]=srvfhinfo[4]; +- srvfhinfo[4]=t; +- +- srvfhinfo[5]=srvfhinfo[0]; /* relocate 'stale' */ +- +- print_numbers( +- LABEL_srvfh +- "lookup anon ncachedir ncachedir stale\n", +- srvfhinfo + 1, 5); +- } else /* < 2.4 */ +- print_numbers( +- LABEL_srvfh +- "lookup anon ncachedir ncachedir stale\n", +- srvrcinfo + 3, 5); +- printf("\n"); ++ /* ++ * 2.2 puts all fh-related info after the 'rc' header ++ * 2.4 puts all fh-related info after the 'fh' header, but relocates ++ * 'stale' to the start and swaps dir and nondir :-( ++ * We preseve the 2.2 order ++ */ ++ if (opt_prt & PRNT_FH) { ++ if (get_stat_info("fh", srvinfo)) { /* >= 2.4 */ ++ int t = srvfhinfo[3]; ++ srvfhinfo[3]=srvfhinfo[4]; ++ srvfhinfo[4]=t; ++ ++ srvfhinfo[5]=srvfhinfo[0]; /* relocate 'stale' */ ++ ++ print_numbers( ++ LABEL_srvfh ++ "lookup anon ncachedir ncachedir stale\n", ++ srvfhinfo + 1, 5); ++ } else /* < 2.4 */ ++ print_numbers( ++ LABEL_srvfh ++ "lookup anon ncachedir ncachedir stale\n", ++ srvrcinfo + 3, 5); ++ printf("\n"); ++ } ++ if (opt_prt & PRNT_CALLS) { ++ if ((opt_prt & PRNT_V2) || ++ ((opt_prt & PRNT_AUTO) && has_stats(srvproc2info))) { ++ if (opt_sleep && !has_stats(srvproc2info)) { ++ ; ++ } else { ++ print_callstats(LABEL_srvproc2, ++ nfsv2name, srvproc2info + 1, ++ sizeof(nfsv2name)/sizeof(char *)); ++ } ++ } ++ if ((opt_prt & PRNT_V3) || ++ ((opt_prt & PRNT_AUTO) && has_stats(srvproc3info))) { ++ if (opt_sleep && !has_stats(srvproc3info)) { ++ ; ++ } else { ++ print_callstats(LABEL_srvproc3, ++ nfsv3name, srvproc3info + 1, ++ sizeof(nfsv3name)/sizeof(char *)); ++ } + } +- if (opt_prt & PRNT_CALLS) { +- if ((opt_prt & PRNT_V2) || ((opt_prt & PRNT_AUTO) && has_stats(srvproc2info))) +- print_callstats( +- LABEL_srvproc2, +- nfsv2name, srvproc2info + 1, sizeof(nfsv2name)/sizeof(char *) +- ); +- if ((opt_prt & PRNT_V3) || ((opt_prt & PRNT_AUTO) && has_stats(srvproc3info))) +- print_callstats( +- LABEL_srvproc3, +- nfsv3name, srvproc3info + 1, sizeof(nfsv3name)/sizeof(char *) +- ); +- if ((opt_prt & PRNT_V4) || ((opt_prt & PRNT_AUTO) && has_stats(srvproc4info))) { +- print_callstats( +- LABEL_srvproc4, +- nfssrvproc4name, srvproc4info + 1, sizeof(nfssrvproc4name)/sizeof(char *) +- ); +- print_callstats( +- LABEL_srvproc4ops, +- nfssrvproc4opname, srvproc4opsinfo + 1, sizeof(nfssrvproc4opname)/sizeof(char *) +- ); ++ if ((opt_prt & PRNT_V4) || ++ ((opt_prt & PRNT_AUTO) && has_stats(srvproc4info))) { ++ if (opt_sleep && !has_stats(srvproc4info)) { ++ ; ++ } else { ++ print_callstats( LABEL_srvproc4, ++ nfssrvproc4name, srvproc4info + 1, ++ sizeof(nfssrvproc4name)/sizeof(char *)); ++ print_callstats(LABEL_srvproc4ops, ++ nfssrvproc4opname, srvproc4opsinfo + 1, ++ sizeof(nfssrvproc4opname)/sizeof(char *)); + } + } + } +- +- if (opt_clt) { +- if (opt_prt & PRNT_NET) { +- print_numbers( +- LABEL_cltnet +- "packets udp tcp tcpconn\n", +- cltnetinfo, 4 +- ); ++} ++static void ++print_client_stats(int opt_clt, int opt_prt) ++{ ++ if (!opt_clt) ++ return; ++ ++ if (opt_prt & PRNT_NET) { ++ if (opt_sleep && !has_rpcstats(cltnetinfo, 4)) { ++ ; ++ } else { ++ print_numbers(LABEL_cltnet ++ "packets udp tcp tcpconn\n", ++ cltnetinfo, 4); + printf("\n"); + } +- if (opt_prt & PRNT_RPC) { +- print_numbers( +- LABEL_cltrpc +- "calls retrans authrefrsh\n", +- cltrpcinfo, 3 +- ); ++ } ++ if (opt_prt & PRNT_RPC) { ++ if (opt_sleep && !has_rpcstats(cltrpcinfo, 3)) { ++ ; ++ } else { ++ print_numbers(LABEL_cltrpc ++ "calls retrans authrefrsh\n", ++ cltrpcinfo, 3); + printf("\n"); + } +- if (opt_prt & PRNT_CALLS) { +- if ((opt_prt & PRNT_V2) || ((opt_prt & PRNT_AUTO) && has_stats(cltproc2info))) +- print_callstats( +- LABEL_cltproc2, +- nfsv2name, cltproc2info + 1, sizeof(nfsv2name)/sizeof(char *) +- ); +- if ((opt_prt & PRNT_V3) || ((opt_prt & PRNT_AUTO) && has_stats(cltproc3info))) +- print_callstats( +- LABEL_cltproc3, +- nfsv3name, cltproc3info + 1, sizeof(nfsv3name)/sizeof(char *) +- ); +- if ((opt_prt & PRNT_V4) || ((opt_prt & PRNT_AUTO) && has_stats(cltproc4info))) +- print_callstats( +- LABEL_cltproc4, +- nfscltproc4name, cltproc4info + 1, sizeof(nfscltproc4name)/sizeof(char *) +- ); ++ } ++ if (opt_prt & PRNT_CALLS) { ++ if ((opt_prt & PRNT_V2) || ++ ((opt_prt & PRNT_AUTO) && has_stats(cltproc2info))) { ++ if (opt_sleep && !has_stats(cltproc2info)) { ++ ; ++ } else { ++ print_callstats(LABEL_cltproc2, ++ nfsv2name, cltproc2info + 1, ++ sizeof(nfsv2name)/sizeof(char *)); ++ } ++ } ++ if ((opt_prt & PRNT_V3) || ++ ((opt_prt & PRNT_AUTO) && has_stats(cltproc3info))) { ++ if (opt_sleep && !has_stats(cltproc3info)) { ++ ; ++ } else { ++ print_callstats(LABEL_cltproc3, ++ nfsv3name, cltproc3info + 1, ++ sizeof(nfsv3name)/sizeof(char *)); ++ } ++ } ++ if ((opt_prt & PRNT_V4) || ++ ((opt_prt & PRNT_AUTO) && has_stats(cltproc4info))) { ++ if (opt_sleep && !has_stats(cltproc4info)) { ++ ; ++ } else { ++ print_callstats(LABEL_cltproc4, ++ nfscltproc4name, cltproc4info + 1, ++ sizeof(nfscltproc4name)/sizeof(char *)); ++ } + } + } ++} + +- return 0; ++static void ++print_clnt_list(int opt_prt) ++{ ++ if (opt_prt & PRNT_CALLS) { ++ if ((opt_prt & PRNT_V2) || ++ ((opt_prt & PRNT_AUTO) && has_stats(cltproc2info))) { ++ if (opt_sleep && !has_stats(cltproc2info)) { ++ ; ++ } else { ++ print_callstats_list("nfs v2 client", ++ nfsv2name, cltproc2info + 1, ++ sizeof(nfsv2name)/sizeof(char *)); ++ } ++ } ++ if ((opt_prt & PRNT_V3) || ++ ((opt_prt & PRNT_AUTO) && has_stats(cltproc3info))) { ++ if (opt_sleep && !has_stats(cltproc3info)) { ++ ; ++ } else { ++ print_callstats_list("nfs v3 client", ++ nfsv3name, cltproc3info + 1, ++ sizeof(nfsv3name)/sizeof(char *)); ++ } ++ } ++ if ((opt_prt & PRNT_V4) || ++ ((opt_prt & PRNT_AUTO) && has_stats(cltproc4info))) { ++ if (opt_sleep && !has_stats(cltproc4info)) { ++ ; ++ } else { ++ print_callstats_list("nfs v4 ops", ++ nfssrvproc4opname, srvproc4opsinfo + 1, ++ sizeof(nfssrvproc4opname)/sizeof(char *)); ++ print_callstats_list("nfs v4 client", ++ nfscltproc4name, cltproc4info + 1, ++ sizeof(nfscltproc4name)/sizeof(char *)); ++ } ++ } ++ } ++} ++static void ++print_serv_list(int opt_prt) ++{ ++ if (opt_prt & PRNT_CALLS) { ++ if ((opt_prt & PRNT_V2) || ++ ((opt_prt & PRNT_AUTO) && has_stats(srvproc2info))) { ++ if (opt_sleep && !has_stats(srvproc2info)) { ++ ; ++ } else { ++ print_callstats_list("nfs v2 server", ++ nfsv2name, srvproc2info + 1, ++ sizeof(nfsv2name)/sizeof(char *)); ++ } ++ } ++ if ((opt_prt & PRNT_V3) || ++ ((opt_prt & PRNT_AUTO) && has_stats(srvproc3info))) { ++ if (opt_sleep && !has_stats(srvproc3info)) { ++ ; ++ } else { ++ print_callstats_list("nfs v3 server", ++ nfsv3name, srvproc3info + 1, ++ sizeof(nfsv3name)/sizeof(char *)); ++ } ++ } ++ if ((opt_prt & PRNT_V4) || ++ ((opt_prt & PRNT_AUTO) && has_stats(srvproc4opsinfo))) { ++ if (opt_sleep && !has_stats(srvproc4info)) { ++ ; ++ } else { ++ print_callstats_list("nfs v4 ops", ++ nfssrvproc4opname, srvproc4opsinfo + 1, ++ sizeof(nfssrvproc4opname)/sizeof(char *)); ++ } ++ } ++ } ++} ++static void ++print_stats_list(int opt_srv, int opt_clt, int opt_prt) ++{ ++ if (opt_srv) ++ print_serv_list(opt_prt); ++ ++ if (opt_clt) ++ print_clnt_list(opt_prt); + } + + static statinfo * +@@ -569,6 +759,29 @@ print_callstats(const char *hdr, const char **names, + printf("\n"); + } + ++static void ++print_callstats_list(const char *hdr, const char **names, ++ unsigned int *callinfo, unsigned int nr) ++{ ++ unsigned long long calltotal; ++ int i; ++ ++ for (i = 0, calltotal = 0; i < nr; i++) { ++ calltotal += callinfo[i]; ++ } ++ if (!calltotal) ++ return; ++ printf("%13s %13s %8llu \n", hdr, "total:", calltotal); ++ printf("------------- ------------- --------\n"); ++ for (i = 0; i < nr; i++) { ++ if (callinfo[i]) ++ printf("%13s %12s: %8u \n", hdr, names[i], callinfo[i]); ++ } ++ printf("\n"); ++ ++} ++ ++ + /* returns 0 on success, 1 otherwise */ + static int + parse_raw_statfile(const char *name, struct statinfo *statp) +@@ -792,6 +1005,15 @@ has_stats(const unsigned int *info) + { + return (info[0] && info[info[0] + 1] > info[0]); + } ++static int ++has_rpcstats(const unsigned int *info, int size) ++{ ++ int i, cnt; ++ ++ for (i=0, cnt=0; i < size; i++) ++ cnt += info[i]; ++ return cnt; ++} + + /* + * take the difference of each individual stat value in 'new' and 'old' +@@ -846,3 +1068,13 @@ unpause(int sig) + seconds = (int)time_diff % 60; + printf("Signal received; displaying (only) statistics gathered over the last %d minutes, %d seconds:\n\n", minutes, seconds); + } ++ ++static void ++update_old_counters(struct statinfo *new, struct statinfo *old) ++{ ++ int z, i; ++ for (z = 0; old[z].tag; z++) ++ for (i = 0; i <= old[z].nrvals; i++) ++ old[z].valptr[i] += new[z].valptr[i]; ++ ++} +diff --git a/utils/nfsstat/nfsstat.man b/utils/nfsstat/nfsstat.man +index cb5f89f..52215a9 100644 +--- a/utils/nfsstat/nfsstat.man ++++ b/utils/nfsstat/nfsstat.man +@@ -72,6 +72,9 @@ Display all of the above facilities. + .B \-v, \-\-verbose + This is equivalent to \fB\-o all\fR. + .TP ++.B \-l, \-\-list ++Print information in list form. ++.TP + .BI "\-S, \-\-since " file + Instead of printing current statistics, + .B nfsstat +@@ -91,7 +94,7 @@ output + .I file + are treated as zeroes. + .TP +-.B \-Z, \-\-sleep ++.B \-Z[interval], \-\-sleep=[interval] + Instead of printing current statistics and immediately exiting, + .B nfsstat + takes a snapshot of the current statistics and pauses until it receives +@@ -100,6 +103,10 @@ takes a snapshot of the current statistics and pauses until it receives + .BR Ctrl-C ), + at which point it takes another snapshot and displays the difference + between the two. ++If \fIinterval\fR is specified, ++.B nfsstat ++will print the number of \fBNFS\fR calls made since the previous report. ++Stats will be printed repeatedly every \fIinterval\fR seconds. + .\" --------------------- EXAMPLES ------------------------------- + .SH EXAMPLES + .TP diff --git a/nfs-utils-1.1.5-umount-privport.patch b/nfs-utils-1.1.5-umount-privport.patch new file mode 100644 index 0000000..7a6648c --- /dev/null +++ b/nfs-utils-1.1.5-umount-privport.patch @@ -0,0 +1,391 @@ +commit c062f45deebc20dae5eb8cdb50fb03fb1c252b47 +Author: Chuck Lever +Date: Sat Apr 18 09:45:46 2009 -0400 + + umount.nfs: Fix return value of nfs_mount_protocol() + + Fix a copy-paste error introduced in nfs_mount_protocol(). It should + return an IPPROTO_ number, not an NFS version number. + + Signed-off-by: Chuck Lever + Signed-off-by: Steve Dickson + +commit 879a9b1b2bdd1160571896023d06291a611c4315 +Author: Chuck Lever +Date: Sat Apr 18 09:44:56 2009 -0400 + + umount.nfs: Use a privileged port when sending UMNT requests + + Turns out we do actually need to use a privileged port for UMNT. The + Linux rpc.mountd complains if an ephemeral source port is used: + + Apr 17 15:52:19 ingres mountd[2061]: refused unmount request from + 192.168.0.59 for /export (/export): illegal port 60932 + + Signed-off-by: Chuck Lever + Signed-off-by: Steve Dickson + +commit 8c94296bc84f3a204f2061c0391a1d2350e4f37e +Author: Chuck Lever +Date: Sat Apr 18 09:43:58 2009 -0400 + + support: Provide an API for creating a privileged RPC client + + We needed to guarantee that some RPC programs, such as PMAP, got an + unprivileged port, to prevent exhausting the local privileged port + space sending RPC requests that don't need such privileges. + nfs_get_rpcclient() provides that feature. + + However, some RPC programs, such as MNT and UMNT, require a privileged + port. So, let's provide an additional API for this that also supports + IPv6 and setting a destination port. + + Signed-off-by: Chuck Lever + Signed-off-by: Steve Dickson + +commit 41eb279c2f46ca020bc3b8d17811555f74b99d2e +Author: Benny Halevy +Date: Wed Apr 15 14:16:08 2009 -0400 + + utils/nfsd: fix -N optarg error printout + + as currently printed c is the version number, not a string char, + therefore is should be printed as %d not %c. That said, just print + optarg as %s since it might be non-numeric. + + Signed-off-by: Benny Halevy + Signed-off-by: Steve Dickson + +commit d4008af910ba1d527f00f8207fb3f8f5709e943d +Author: Chuck Lever +Date: Wed Apr 15 12:52:48 2009 -0400 + + getport.c: fix non-standard C + + Squelch a compiler warning in getport.c: + + getport.c:65: warning: ¿static¿ is not at beginning of declaration + + Signed-off-by: Chuck Lever + Signed-off-by: Steve Dickson + +commit c51d826a201095fb3a7c68c3666e2b795a2b687d +Author: Chuck Lever +Date: Wed Apr 15 12:38:40 2009 -0400 + + nfs-utils: reverse order of librpcsecgss and libgssglue checks + + The check that validates the version of librpcsecgss also needs to + have libgssglue installed. Without libgssglue, ./configure complains + that it can't find rpcsecgss, even though it's installed. + + It also turns out that the error message generated by pkg-config is + more complete than the one we have in aclocal/rpcsec_vers.m4, so just + let those PKG_CHECK_MODULES m4 macros use the default error message. + + Signed-off-by: Chuck Lever + Signed-off-by: Steve Dickson +--------------------------------------------------------------- +diff --git a/aclocal/rpcsec_vers.m4 b/aclocal/rpcsec_vers.m4 +index e59c0aa..25902ca 100644 +--- a/aclocal/rpcsec_vers.m4 ++++ b/aclocal/rpcsec_vers.m4 +@@ -1,12 +1,11 @@ + dnl Checks librpcsec version + AC_DEFUN([AC_RPCSEC_VERSION], [ + +- dnl TI-RPC replaces librpcsecgss, but we still need libgssglue ++ PKG_CHECK_MODULES([GSSGLUE], [libgssglue >= 0.1]) ++ ++ dnl TI-RPC replaces librpcsecgss + if test "$enable_tirpc" = no; then +- PKG_CHECK_MODULES([RPCSECGSS], [librpcsecgss >= 0.16], , +- [AC_MSG_ERROR([Unable to locate information required to use librpcsecgss. If you have pkgconfig installed, you might try setting environment variable PKG_CONFIG_PATH to /usr/local/lib/pkgconfig])]) +- else +- PKG_CHECK_MODULES([GSSGLUE], [libgssglue >= 0.1]) ++ PKG_CHECK_MODULES([RPCSECGSS], [librpcsecgss >= 0.16]) + fi + + ])dnl +diff --git a/support/include/nfsrpc.h b/support/include/nfsrpc.h +index 097debb..543c35b 100644 +--- a/support/include/nfsrpc.h ++++ b/support/include/nfsrpc.h +@@ -24,6 +24,7 @@ + #define __NFS_UTILS_NFSRPC_H + + #include ++#include + + /* + * Conventional RPC program numbers +@@ -54,7 +55,7 @@ + extern rpcprog_t nfs_getrpcbyname(const rpcprog_t, const char *table[]); + + /* +- * Acquire an RPC CLIENT * ++ * Acquire an RPC CLIENT * with an ephemeral source port + */ + extern CLIENT *nfs_get_rpcclient(const struct sockaddr *, + const socklen_t, const unsigned short, +@@ -62,6 +63,14 @@ extern CLIENT *nfs_get_rpcclient(const struct sockaddr *, + struct timeval *); + + /* ++ * Acquire an RPC CLIENT * with a privileged source port ++ */ ++extern CLIENT *nfs_get_priv_rpcclient( const struct sockaddr *, ++ const socklen_t, const unsigned short, ++ const rpcprog_t, const rpcvers_t, ++ struct timeval *); ++ ++/* + * Convert a socket address to a universal address + */ + extern char *nfs_sockaddr2universal(const struct sockaddr *, +diff --git a/support/nfs/getport.c b/support/nfs/getport.c +index 734d21a..cf1677e 100644 +--- a/support/nfs/getport.c ++++ b/support/nfs/getport.c +@@ -60,9 +60,9 @@ + #endif /* !HAVE_LIBTIRPC */ + + #ifdef HAVE_LIBTIRPC +-const static rpcvers_t default_rpcb_version = RPCBVERS_4; ++static const rpcvers_t default_rpcb_version = RPCBVERS_4; + #else /* !HAVE_LIBTIRPC */ +-const static rpcvers_t default_rpcb_version = PMAPVERS; ++static const rpcvers_t default_rpcb_version = PMAPVERS; + #endif /* !HAVE_LIBTIRPC */ + + #ifdef HAVE_DECL_AI_ADDRCONFIG +diff --git a/support/nfs/rpc_socket.c b/support/nfs/rpc_socket.c +index 2b11e35..85e6064 100644 +--- a/support/nfs/rpc_socket.c ++++ b/support/nfs/rpc_socket.c +@@ -132,6 +132,58 @@ static int nfs_bind(const int sock, const sa_family_t family) + return -1; + } + ++#ifdef IPV6_SUPPORT ++ ++/* ++ * Bind a socket using an unused privileged source port. ++ * ++ * Returns zero on success, or returns -1 on error. errno is ++ * set to reflect the nature of the error. ++ */ ++static int nfs_bindresvport(const int sock, const sa_family_t family) ++{ ++ struct sockaddr_in sin = { ++ .sin_family = AF_INET, ++ .sin_addr.s_addr = htonl(INADDR_ANY), ++ }; ++ struct sockaddr_in6 sin6 = { ++ .sin6_family = AF_INET6, ++ .sin6_addr = IN6ADDR_ANY_INIT, ++ }; ++ ++ switch (family) { ++ case AF_INET: ++ return bindresvport_sa(sock, (struct sockaddr *)&sin, ++ (socklen_t)sizeof(sin)); ++ case AF_INET6: ++ return bindresvport_sa(sock, (struct sockaddr *)&sin6, ++ (socklen_t)sizeof(sin6)); ++ } ++ ++ errno = EAFNOSUPPORT; ++ return -1; ++} ++ ++#else /* !IPV6_SUPPORT */ ++ ++/* ++ * Bind a socket using an unused privileged source port. ++ * ++ * Returns zero on success, or returns -1 on error. errno is ++ * set to reflect the nature of the error. ++ */ ++static int nfs_bindresvport(const int sock, const sa_family_t family) ++{ ++ if (family != AF_INET) { ++ errno = EAFNOSUPPORT; ++ return -1; ++ } ++ ++ return bindresvport(sock, NULL); ++} ++ ++#endif /* !IPV6_SUPPORT */ ++ + /* + * Perform a non-blocking connect on the socket fd. + * +@@ -218,7 +270,8 @@ static CLIENT *nfs_get_udpclient(const struct sockaddr *sap, + const socklen_t salen, + const rpcprog_t program, + const rpcvers_t version, +- struct timeval *timeout) ++ struct timeval *timeout, ++ const int resvport) + { + CLIENT *client; + int ret, sock; +@@ -245,7 +298,10 @@ static CLIENT *nfs_get_udpclient(const struct sockaddr *sap, + return NULL; + } + +- ret = nfs_bind(sock, sap->sa_family); ++ if (resvport) ++ ret = nfs_bindresvport(sock, sap->sa_family); ++ else ++ ret = nfs_bind(sock, sap->sa_family); + if (ret < 0) { + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = errno; +@@ -294,7 +350,8 @@ static CLIENT *nfs_get_tcpclient(const struct sockaddr *sap, + const socklen_t salen, + const rpcprog_t program, + const rpcvers_t version, +- struct timeval *timeout) ++ struct timeval *timeout, ++ const int resvport) + { + CLIENT *client; + int ret, sock; +@@ -321,7 +378,10 @@ static CLIENT *nfs_get_tcpclient(const struct sockaddr *sap, + return NULL; + } + +- ret = nfs_bind(sock, sap->sa_family); ++ if (resvport) ++ ret = nfs_bindresvport(sock, sap->sa_family); ++ else ++ ret = nfs_bind(sock, sap->sa_family); + if (ret < 0) { + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = errno; +@@ -365,7 +425,8 @@ static CLIENT *nfs_get_tcpclient(const struct sockaddr *sap, + * @timeout: pointer to request timeout (must not be NULL) + * + * Set up an RPC client for communicating with an RPC program @program +- * and @version on the server @sap over @transport. ++ * and @version on the server @sap over @transport. An unprivileged ++ * source port is used. + * + * Returns a pointer to a prepared RPC client if successful, and + * @timeout is initialized; caller must destroy a non-NULL returned RPC +@@ -405,10 +466,75 @@ CLIENT *nfs_get_rpcclient(const struct sockaddr *sap, + + switch (transport) { + case IPPROTO_TCP: +- return nfs_get_tcpclient(sap, salen, program, version, timeout); ++ return nfs_get_tcpclient(sap, salen, program, version, ++ timeout, 0); ++ case 0: ++ case IPPROTO_UDP: ++ return nfs_get_udpclient(sap, salen, program, version, ++ timeout, 0); ++ } ++ ++ rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; ++ return NULL; ++} ++ ++/** ++ * nfs_get_priv_rpcclient - acquire an RPC client ++ * @sap: pointer to socket address of RPC server ++ * @salen: length of socket address ++ * @transport: IPPROTO_ value of transport protocol to use ++ * @program: RPC program number ++ * @version: RPC version number ++ * @timeout: pointer to request timeout (must not be NULL) ++ * ++ * Set up an RPC client for communicating with an RPC program @program ++ * and @version on the server @sap over @transport. A privileged ++ * source port is used. ++ * ++ * Returns a pointer to a prepared RPC client if successful, and ++ * @timeout is initialized; caller must destroy a non-NULL returned RPC ++ * client. Otherwise returns NULL, and rpc_createerr.cf_stat is set to ++ * reflect the error. ++ */ ++CLIENT *nfs_get_priv_rpcclient(const struct sockaddr *sap, ++ const socklen_t salen, ++ const unsigned short transport, ++ const rpcprog_t program, ++ const rpcvers_t version, ++ struct timeval *timeout) ++{ ++ struct sockaddr_in *sin = (struct sockaddr_in *)sap; ++ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap; ++ ++ switch (sap->sa_family) { ++ case AF_LOCAL: ++ return nfs_get_localclient(sap, salen, program, ++ version, timeout); ++ case AF_INET: ++ if (sin->sin_port == 0) { ++ rpc_createerr.cf_stat = RPC_UNKNOWNADDR; ++ return NULL; ++ } ++ break; ++ case AF_INET6: ++ if (sin6->sin6_port == 0) { ++ rpc_createerr.cf_stat = RPC_UNKNOWNADDR; ++ return NULL; ++ } ++ break; ++ default: ++ rpc_createerr.cf_stat = RPC_UNKNOWNHOST; ++ return NULL; ++ } ++ ++ switch (transport) { ++ case IPPROTO_TCP: ++ return nfs_get_tcpclient(sap, salen, program, version, ++ timeout, 1); + case 0: + case IPPROTO_UDP: +- return nfs_get_udpclient(sap, salen, program, version, timeout); ++ return nfs_get_udpclient(sap, salen, program, version, ++ timeout, 1); + } + + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; +diff --git a/utils/mount/network.c b/utils/mount/network.c +index bcd0c0f..72f4b84 100644 +--- a/utils/mount/network.c ++++ b/utils/mount/network.c +@@ -869,7 +869,7 @@ int nfs_advise_umount(const struct sockaddr *sap, const socklen_t salen, + memcpy(saddr, sap, salen); + nfs_set_port(saddr, mnt_pmap.pm_port); + +- client = nfs_get_rpcclient(saddr, salen, mnt_pmap.pm_prot, ++ client = nfs_get_priv_rpcclient(saddr, salen, mnt_pmap.pm_prot, + mnt_pmap.pm_prog, mnt_pmap.pm_vers, + &timeout); + if (client == NULL) +@@ -1337,7 +1337,7 @@ static unsigned short nfs_mount_protocol(struct mount_options *options) + return IPPROTO_UDP; + } + +- return nfs_nfs_version(options); ++ return nfs_nfs_protocol(options); + } + + /* +diff --git a/utils/nfsd/nfsd.c b/utils/nfsd/nfsd.c +index aaf8d29..c97c81f 100644 +--- a/utils/nfsd/nfsd.c ++++ b/utils/nfsd/nfsd.c +@@ -86,7 +86,7 @@ main(int argc, char **argv) + NFSCTL_VERUNSET(versbits, c); + break; + default: +- fprintf(stderr, "%c: Unsupported version\n", c); ++ fprintf(stderr, "%s: Unsupported version\n", optarg); + exit(1); + } + break; diff --git a/nfs-utils.spec b/nfs-utils.spec index 9093c86..bc48686 100644 --- a/nfs-utils.spec +++ b/nfs-utils.spec @@ -2,7 +2,7 @@ Summary: NFS utilities and supporting clients and daemons for the kernel NFS ser Name: nfs-utils URL: http://sourceforge.net/projects/nfs Version: 1.1.5 -Release: 4%{?dist} +Release: 5%{?dist} Epoch: 1 # group all 32bit related archs @@ -29,6 +29,8 @@ Patch02: nfs-utils-1.1.0-exp-subtree-warn-off.patch Patch100: nfs-utils-1.1.5-tcpwrap-externs.patch Patch101: nfs-utils-1-1-6-rc2.patch Patch102: nfs-utils-1-1-6-rc3.patch +Patch103: nfs-utils-1.1.5-nfsstat-update.patch +Patch104: nfs-utils-1.1.5-umount-privport.patch %if %{enablefscache} Patch90: nfs-utils-1.1.0-mount-fsc.patch @@ -86,6 +88,8 @@ This package also contains the mount.nfs and umount.nfs program. %patch100 -p1 %patch101 -p1 %patch102 -p1 +%patch103 -p1 +%patch104 -p1 %if %{enablefscache} %patch90 -p1 @@ -249,6 +253,10 @@ fi %attr(4755,root,root) /sbin/umount.nfs4 %changelog +* Mon Apr 20 2009 Steve Dickson 1.1.5-5 +- Update nfsstat with --sleep and --list options +- Fixed umount from using non-privilege ports (bz 492598) + * Mon Mar 23 2009 Steve Dickson 1.1.5-4 - Added upstream rc3 patch - gssd: initialize fakeseed in prepare_krb5_rfc1964_buffer