Updated to latest upstream version: 1.1.3

This commit is contained in:
Steve Dickson 2008-07-28 08:17:50 +00:00
parent 433c940a7f
commit 8bea6d77d5
31 changed files with 9 additions and 3013 deletions

View File

@ -12,3 +12,4 @@ nfs-utils-1.0.12.tar.bz2
nfs-utils-1.1.0.tar.bz2
nfs-utils-1.1.1.tar.bz2
nfs-utils-1.1.2.tar.bz2
nfs-utils-1.1.3.tar.bz2

View File

@ -1,31 +0,0 @@
--- nfs-utils-1.0.6/utils/gssd/gssd_proc.c.gssd 2006-03-02 14:36:10.000000000 -0500
+++ nfs-utils-1.0.6/utils/gssd/gssd_proc.c 2006-03-02 14:38:47.000000000 -0500
@@ -53,6 +53,7 @@
#include <pwd.h>
#include <grp.h>
#include <string.h>
+#include <ctype.h>
#include <dirent.h>
#include <poll.h>
#include <fcntl.h>
@@ -115,6 +116,7 @@ read_service_info(char *info_file_name,
int fd = -1;
struct hostent *ent = NULL;
int numfields;
+ char *s;
*servicename = *servername = *protocol = NULL;
@@ -155,6 +157,12 @@ read_service_info(char *info_file_name,
printerr(0, "ERROR: can't resolve server %s name\n", address);
goto fail;
}
+
+ /* don't allow mixed-case names to rain on our parade */
+ for (s = ent->h_name; s && *s; s++) {
+ *s = tolower((int)*s);
+ }
+
if (!(*servername = calloc(strlen(ent->h_name) + 1, 1)))
goto fail;
memcpy(*servername, ent->h_name, strlen(ent->h_name));

View File

@ -1,31 +0,0 @@
#
# Make sure check_new_cache() is looking in the right place
#
--- src/support/nfs/cacheio.c.org 2003-08-04 00:12:16.000000000 -0400
+++ src/support/nfs/cacheio.c 2004-03-22 18:12:55.163534208 -0500
@@ -223,12 +223,23 @@ int readline(int fd, char **buf, int *le
* This succeeds iff the "nfsd" filesystem is mounted on
* /proc/fs/nfs
*/
+static char *cachelist[] = {
+ { "auth.unix.ip" }, { "nfsd.export" }, { "nfsd.fh" },
+ { NULL, NULL }
+};
int
check_new_cache(void)
{
struct stat stb;
- return (stat("/proc/fs/nfs/filehandle", &stb) == 0) ||
- (stat("/proc/fs/nfsd/filehandle", &stb) == 0);
+ char path[64];
+ int i;
+
+ for (i=0; cachelist[i]; i++ ){
+ sprintf(path, "/proc/net/rpc/%s/channel", cachelist[i]);
+ if (stat(path, &stb) < 0)
+ return 0;
+ }
+ return 1;
}

View File

@ -1,94 +0,0 @@
commit fa29d7a9a3d8a72b79924d28813eef7e55a25bc9
Author: Steve Dickson <steved@redhat.com>
Date: Tue Mar 18 09:33:44 2008 -0400
Updated exportfs man to talk about /var/lib/nfs/etab
instead of /var/lib/nfs/xtab
Signed-off-by: Steve Dickson <steved@redhat.com>
diff --git a/utils/exportfs/exportfs.man b/utils/exportfs/exportfs.man
index 59789cc..a8fdb05 100644
--- a/utils/exportfs/exportfs.man
+++ b/utils/exportfs/exportfs.man
@@ -22,14 +22,14 @@ The
.B exportfs
command is used to maintain the current table of exported file systems for
NFS. This list is kept in a separate file named
-.BR /var/lib/nfs/xtab
+.BR /var/lib/nfs/etab
which is read by
.B mountd
when a remote host requests access to mount a file tree, and parts of
the list which are active are kept in the kernel's export table.
.P
Normally this
-.B xtab
+.B etab
file is initialized with the list of all file systems named in
.B /etc/exports
by invoking
@@ -59,7 +59,7 @@ In the new mode,
does not give any information to the kernel but only provides it to
.B mountd
through the
-.B /var/lib/nfs/xtab
+.B /var/lib/nfs/etab
file.
.B mountd
will listen to requests from the kernel and will provide information
@@ -69,7 +69,7 @@ In the legacy mode,
any export requests which identify a specific host (rather than a
subnet or netgroup etc) are entered directly into the kernel's export
table as well as being written to
-.BR /var/lib/nfs/xtab .
+.BR /var/lib/nfs/etab .
Further, any mount points listed in
.B /var/lib/nfs/rmtab
which match a non host-specific export request will cause an
@@ -93,8 +93,8 @@ file, so that only default options and options given on the command
line are used.
.TP
.B -r
-Reexport all directories. It synchronizes /var/lib/nfs/xtab
-with /etc/exports. It removes entries in /var/lib/nfs/xtab
+Reexport all directories. It synchronizes /var/lib/nfs/etab
+with /etc/exports. It removes entries in /var/lib/nfs/etab
which are deleted from /etc/exports, and remove any entries from the
kernel export table which are no longer valid.
.TP
@@ -120,7 +120,7 @@ entries to the export table. When using
all directories in
.B exports(5)
are added to
-.B xtab
+.B etab
and the resulting list is pushed into the kernel.
.P
The
@@ -152,7 +152,7 @@ directory.
Modifications of the kernel export table used by
.B nfsd(8)
take place immediately after parsing the command line and updating the
-.B xtab
+.B etab
file.
.P
The default export options are
@@ -163,14 +163,14 @@ The third synopsis shows how to unexported a currently exported directory.
When using
.BR "exportfs -ua" ,
all entries listed in
-.B xtab
+.B etab
are removed from the kernel export tables, and the file is cleared. This
effectively shuts down all NFS activity.
.P
To remove an export to a host, specify a
.I host:/path
pair. This deletes the specified entry from
-.B xtab
+.B etab
and removes the corresponding kernel entry (if any).
To remove one or more exports to several hosts, use
.BR "exportfs -ua" .

View File

@ -1,24 +0,0 @@
diff -up nfs-utils-1.1.1/support/nfs/xio.c.save nfs-utils-1.1.1/support/nfs/xio.c
--- nfs-utils-1.1.1/support/nfs/xio.c.save 2007-10-18 23:07:28.000000000 -0400
+++ nfs-utils-1.1.1/support/nfs/xio.c 2008-01-05 08:27:35.000000000 -0500
@@ -54,13 +54,19 @@ xflock(char *fname, char *type)
{
struct sigaction sa, oldsa;
int readonly = !strcmp(type, "r");
+ mode_t mode = (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
struct flock fl = { readonly? F_RDLCK : F_WRLCK, SEEK_SET, 0, 0, 0 };
int fd;
- if ((fd = open(fname, readonly? O_RDONLY : (O_RDWR|O_CREAT), 0644)) < 0) {
+ if (readonly)
+ fd = open(fname, O_RDONLY);
+ else
+ fd = open(fname, (O_RDWR|O_CREAT), mode);
+ if (fd < 0) {
xlog(L_WARNING, "could not open %s for locking", fname);
return -1;
}
+
sa.sa_handler = doalarm;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);

View File

@ -1,20 +0,0 @@
--- nfs-utils-1.1.0/utils/showmount/showmount.c.orig 2007-05-10 23:40:57.000000000 -0400
+++ nfs-utils-1.1.0/utils/showmount/showmount.c 2007-07-16 13:02:42.000000000 -0400
@@ -242,6 +242,8 @@ static unsigned short getport(struct soc
rpc_createerr.cf_stat = status;
clnt_destroy(client);
return 0;
+ } else if (port == 0) {
+ rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
}
clnt_destroy(client);
@@ -368,7 +370,7 @@ char **argv;
server_addr.sin_port = getport(&server_addr,
MOUNTPROG, MOUNTVERS, IPPROTO_UDP);
if (!server_addr.sin_port) {
- clnt_pcreateerror("portmap getport");
+ clnt_pcreateerror("showmount");
exit(1);
}
msock = RPC_ANYSOCK;

View File

@ -1,21 +0,0 @@
commit 7ef076fb98233783843d6019b2edbb48e2d18914
Author: Oren Held <oren@held.org.il>
Date: Thu May 8 05:23:10 2008 -0400
Fixed smail typo in exportfs man page
Signed-off-by: Steve Dickson <steved@redhat.com>
diff --git a/utils/exportfs/exportfs.man b/utils/exportfs/exportfs.man
index a8fdb05..c7b230a 100644
--- a/utils/exportfs/exportfs.man
+++ b/utils/exportfs/exportfs.man
@@ -198,7 +198,7 @@ and pushes the resulting export entries into the kernel:
To export the
.B /usr/tmp
directory to host
-.BR djando ,
+.BR django ,
allowing asynchronous writes, one would do this:
.P
.nf

View File

@ -1,235 +0,0 @@
commit 25cd5f9101b8969f9e1f9d7d486f11c215d0eeb4
Author: Vince Busam <vbusam@google.com>
Date: Wed May 7 15:24:53 2008 -0400
Kerberos credentials may be stored in multiple places. Make it
possible to search several directories for valid credentials when
making NFS requests.
Original patch from Vince Busam <vbusam@google.com>
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>.
Signed-off-by: Steve Dickson <steved@redhat.com>
diff --git a/utils/gssd/gssd.c b/utils/gssd/gssd.c
index bbcad20..e8612a5 100644
--- a/utils/gssd/gssd.c
+++ b/utils/gssd/gssd.c
@@ -57,6 +57,7 @@ char pipefs_dir[PATH_MAX] = GSSD_PIPEFS_DIR;
char pipefs_nfsdir[PATH_MAX] = GSSD_PIPEFS_DIR;
char keytabfile[PATH_MAX] = GSSD_DEFAULT_KEYTAB_FILE;
char ccachedir[PATH_MAX] = GSSD_DEFAULT_CRED_DIR;
+char *ccachesearch[GSSD_MAX_CCACHE_SEARCH + 1];
int use_memcache = 0;
int root_uses_machine_creds = 1;
@@ -93,9 +94,11 @@ main(int argc, char *argv[])
int verbosity = 0;
int rpc_verbosity = 0;
int opt;
+ int i;
extern char *optarg;
char *progname;
+ memset(ccachesearch, 0, sizeof(ccachesearch));
while ((opt = getopt(argc, argv, "fvrmnMp:k:d:")) != -1) {
switch (opt) {
case 'f':
@@ -136,6 +139,13 @@ main(int argc, char *argv[])
break;
}
}
+
+ i = 0;
+ ccachesearch[i++] = strtok(ccachedir, ":");
+ do {
+ ccachesearch[i++] = strtok(NULL, ":");
+ } while (ccachesearch[i-1] != NULL && i < GSSD_MAX_CCACHE_SEARCH);
+
snprintf(pipefs_nfsdir, sizeof(pipefs_nfsdir), "%s/%s",
pipefs_dir, GSSD_SERVICE_NAME);
if (pipefs_nfsdir[sizeof(pipefs_nfsdir)-1] != '\0')
diff --git a/utils/gssd/gssd.h b/utils/gssd/gssd.h
index 6f14c34..0f9f428 100644
--- a/utils/gssd/gssd.h
+++ b/utils/gssd/gssd.h
@@ -50,6 +50,7 @@
#define GSSD_DEFAULT_KEYTAB_FILE "/etc/krb5.keytab"
#define GSSD_SERVICE_NAME "nfs"
#define GSSD_SERVICE_NAME_LEN 3
+#define GSSD_MAX_CCACHE_SEARCH 16
/*
* The gss mechanisms that we can handle
@@ -61,7 +62,7 @@ enum {AUTHTYPE_KRB5, AUTHTYPE_SPKM3, AUTHTYPE_LIPKEY};
extern char pipefs_dir[PATH_MAX];
extern char pipefs_nfsdir[PATH_MAX];
extern char keytabfile[PATH_MAX];
-extern char ccachedir[PATH_MAX];
+extern char *ccachesearch[];
extern int use_memcache;
extern int root_uses_machine_creds;
diff --git a/utils/gssd/gssd.man b/utils/gssd/gssd.man
index 2fa749e..8fa4f4a 100644
--- a/utils/gssd/gssd.man
+++ b/utils/gssd/gssd.man
@@ -74,7 +74,11 @@ where to look for the rpc_pipefs filesystem. The default value is
.B -d directory
Tells
.B rpc.gssd
-where to look for kerberos credential files. The default value is "/tmp".
+where to look for Kerberos credential files. The default value is "/tmp".
+This can also be a colon separated list of directories to be searched
+for Kerberos credential files. Note that if machine credentials are being
+stored in files, then the first directory on this list is where the
+machine credentials are stored.
.TP
.B -v
Increases the verbosity of the output (can be specified multiple times).
diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c
index bac7295..be6f440 100644
--- a/utils/gssd/gssd_proc.c
+++ b/utils/gssd/gssd_proc.c
@@ -685,6 +685,7 @@ handle_krb5_upcall(struct clnt_info *clp)
gss_buffer_desc token;
char **credlist = NULL;
char **ccname;
+ char **dirname;
int create_resp = -1;
printerr(1, "handling krb5 upcall\n");
@@ -701,10 +702,14 @@ handle_krb5_upcall(struct clnt_info *clp)
if (uid != 0 || (uid == 0 && root_uses_machine_creds == 0)) {
/* Tell krb5 gss which credentials cache to use */
- gssd_setup_krb5_user_gss_ccache(uid, clp->servername);
+ for (dirname = ccachesearch; *dirname != NULL; dirname++) {
+ gssd_setup_krb5_user_gss_ccache(uid, clp->servername, *dirname);
- create_resp = create_auth_rpc_client(clp, &rpc_clnt, &auth, uid,
- AUTHTYPE_KRB5);
+ create_resp = create_auth_rpc_client(clp, &rpc_clnt, &auth, uid,
+ AUTHTYPE_KRB5);
+ if (create_resp == 0)
+ break;
+ }
}
if (create_resp != 0) {
if (uid == 0 && root_uses_machine_creds == 1) {
diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c
index 0589cd8..512c1cf 100644
--- a/utils/gssd/krb5_util.c
+++ b/utils/gssd/krb5_util.c
@@ -131,7 +131,8 @@ struct gssd_k5_kt_princ *gssd_k5_kt_princ_list = NULL;
/*==========================*/
static int select_krb5_ccache(const struct dirent *d);
-static int gssd_find_existing_krb5_ccache(uid_t uid, struct dirent **d);
+static int gssd_find_existing_krb5_ccache(uid_t uid, char *dirname,
+ struct dirent **d);
static int gssd_get_single_krb5_cred(krb5_context context,
krb5_keytab kt, struct gssd_k5_kt_princ *ple);
@@ -159,7 +160,7 @@ select_krb5_ccache(const struct dirent *d)
}
/*
- * Look in the ccachedir for files that look like they
+ * Look in directory "dirname" for files that look like they
* are Kerberos Credential Cache files for a given UID. Return
* non-zero and the dirent pointer for the entry most likely to be
* what we want. Otherwise, return zero and no dirent pointer.
@@ -170,7 +171,7 @@ select_krb5_ccache(const struct dirent *d)
* 1 => found an existing entry
*/
static int
-gssd_find_existing_krb5_ccache(uid_t uid, struct dirent **d)
+gssd_find_existing_krb5_ccache(uid_t uid, char *dirname, struct dirent **d)
{
struct dirent **namelist;
int n;
@@ -181,9 +182,10 @@ gssd_find_existing_krb5_ccache(uid_t uid, struct dirent **d)
memset(&best_match_stat, 0, sizeof(best_match_stat));
*d = NULL;
- n = scandir(ccachedir, &namelist, select_krb5_ccache, 0);
+ n = scandir(dirname, &namelist, select_krb5_ccache, 0);
if (n < 0) {
- perror("scandir looking for krb5 credentials caches");
+ printerr(1, "Error doing scandir on directory '%s': %s\n",
+ dirname, strerror(errno));
}
else if (n > 0) {
char statname[1024];
@@ -191,7 +193,7 @@ gssd_find_existing_krb5_ccache(uid_t uid, struct dirent **d)
printerr(3, "CC file '%s' being considered\n",
namelist[i]->d_name);
snprintf(statname, sizeof(statname),
- "%s/%s", ccachedir, namelist[i]->d_name);
+ "%s/%s", dirname, namelist[i]->d_name);
if (lstat(statname, &tmp_stat)) {
printerr(0, "Error doing stat on file '%s'\n",
statname);
@@ -291,8 +293,9 @@ limit_krb5_enctypes(struct rpc_gss_sec *sec, uid_t uid)
&credh, NULL, NULL);
if (maj_stat != GSS_S_COMPLETE) {
- pgsserr("gss_acquire_cred",
- maj_stat, min_stat, &krb5oid);
+ if (get_verbosity() > 0)
+ pgsserr("gss_acquire_cred",
+ maj_stat, min_stat, &krb5oid);
return -1;
}
@@ -406,7 +409,7 @@ gssd_get_single_krb5_cred(krb5_context context,
cache_type = "FILE";
snprintf(cc_name, sizeof(cc_name), "%s:%s/%s%s_%s",
cache_type,
- ccachedir, GSSD_DEFAULT_CRED_PREFIX,
+ ccachesearch[0], GSSD_DEFAULT_CRED_PREFIX,
GSSD_DEFAULT_MACHINE_CRED_SUFFIX, ple->realm);
ple->endtime = my_creds.times.endtime;
if (ple->ccname != NULL)
@@ -894,7 +897,7 @@ out:
* void
*/
void
-gssd_setup_krb5_user_gss_ccache(uid_t uid, char *servername)
+gssd_setup_krb5_user_gss_ccache(uid_t uid, char *servername, char *dirname)
{
char buf[MAX_NETOBJ_SZ];
struct dirent *d;
@@ -902,14 +905,13 @@ gssd_setup_krb5_user_gss_ccache(uid_t uid, char *servername)
printerr(2, "getting credentials for client with uid %u for "
"server %s\n", uid, servername);
memset(buf, 0, sizeof(buf));
- if (gssd_find_existing_krb5_ccache(uid, &d)) {
- snprintf(buf, sizeof(buf), "FILE:%s/%s",
- ccachedir, d->d_name);
+ if (gssd_find_existing_krb5_ccache(uid, dirname, &d)) {
+ snprintf(buf, sizeof(buf), "FILE:%s/%s", dirname, d->d_name);
free(d);
}
else
snprintf(buf, sizeof(buf), "FILE:%s/%s%u",
- ccachedir, GSSD_DEFAULT_CRED_PREFIX, uid);
+ dirname, GSSD_DEFAULT_CRED_PREFIX, uid);
printerr(2, "using %s as credentials cache for client with "
"uid %u for server %s\n", buf, uid, servername);
gssd_set_krb5_ccache_name(buf);
diff --git a/utils/gssd/krb5_util.h b/utils/gssd/krb5_util.h
index 78ad45c..431fdaf 100644
--- a/utils/gssd/krb5_util.h
+++ b/utils/gssd/krb5_util.h
@@ -17,7 +17,8 @@ struct gssd_k5_kt_princ {
};
-void gssd_setup_krb5_user_gss_ccache(uid_t uid, char *servername);
+void gssd_setup_krb5_user_gss_ccache(uid_t uid, char *servername,
+ char *dirname);
int gssd_get_krb5_machine_cred_list(char ***list);
void gssd_free_krb5_machine_cred_list(char **list);
void gssd_setup_krb5_machine_gss_ccache(char *servername);

View File

@ -1,25 +0,0 @@
commit 313ab396c04afe160ee6764e28b5e61ce19c46d9
Author: Kevin Coffman <kwc@citi.umich.edu>
Date: Wed May 7 14:32:45 2008 -0400
Add the other two DES encryption types to the default list of
Kerberos encryption types that may be negotiated.
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
Signed-off-by: Steve Dickson <steved@redhat.com>
diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c
index 3cf27ca..0589cd8 100644
--- a/utils/gssd/krb5_util.c
+++ b/utils/gssd/krb5_util.c
@@ -277,7 +277,9 @@ limit_krb5_enctypes(struct rpc_gss_sec *sec, uid_t uid)
u_int maj_stat, min_stat;
gss_cred_id_t credh;
gss_OID_set_desc desired_mechs;
- krb5_enctype enctypes[] = { ENCTYPE_DES_CBC_CRC };
+ krb5_enctype enctypes[] = { ENCTYPE_DES_CBC_CRC,
+ ENCTYPE_DES_CBC_MD5,
+ ENCTYPE_DES_CBC_MD4 };
int num_enctypes = sizeof(enctypes) / sizeof(enctypes[0]);
/* We only care about getting a krb5 cred */

View File

@ -1,84 +0,0 @@
commit a04f8b5a3ea94b7a9d96d339b6ccde5f2e67a2d1
Author: Olga Kornievskaia <aglo@citi.umich.edu>
Date: Wed May 7 10:54:51 2008 -0400
Check the info file nfs/rpc_pipefs/nfs/clnt?/info to
see if a port number was supplied. If so, use it rather
than the default port number.
Signed-off-by: Olga Kornievskaia <aglo@citi.umich.edu>
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
Signed-off-by: Steve Dickson <steved@redhat.com>
diff --git a/utils/gssd/gssd.h b/utils/gssd/gssd.h
index e17edde..6f14c34 100644
--- a/utils/gssd/gssd.h
+++ b/utils/gssd/gssd.h
@@ -80,6 +80,7 @@ struct clnt_info {
int krb5_poll_index;
int spkm3_fd;
int spkm3_poll_index;
+ int port;
};
void init_client_list(void);
diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c
index 6860cc8..bac7295 100644
--- a/utils/gssd/gssd_proc.c
+++ b/utils/gssd/gssd_proc.c
@@ -102,7 +102,7 @@ int pollsize; /* the size of pollaray (in pollfd's) */
/* XXX buffer problems: */
static int
read_service_info(char *info_file_name, char **servicename, char **servername,
- int *prog, int *vers, char **protocol) {
+ int *prog, int *vers, char **protocol, int *port) {
#define INFOBUFLEN 256
char buf[INFOBUFLEN];
static char dummy[128];
@@ -112,6 +112,8 @@ read_service_info(char *info_file_name, char **servicename, char **servername,
char program[16];
char version[16];
char protoname[16];
+ char cb_port[128];
+ char *p;
in_addr_t inaddr;
int fd = -1;
struct hostent *ent = NULL;
@@ -143,6 +145,10 @@ read_service_info(char *info_file_name, char **servicename, char **servername,
goto fail;
}
+ cb_port[0] = '\0';
+ if ((p = strstr(buf, "port")) != NULL)
+ sscanf(p, "port: %127s\n", cb_port);
+
/* check service, program, and version */
if(memcmp(service, "nfs", 3)) return -1;
*prog = atoi(program + 1); /* skip open paren */
@@ -163,6 +169,8 @@ read_service_info(char *info_file_name, char **servicename, char **servername,
if (!(*servicename = calloc(strlen(buf) + 1, 1)))
goto fail;
memcpy(*servicename, buf, strlen(buf));
+ if (cb_port[0] != '\0')
+ *port = atoi(cb_port);
if (!(*protocol = strdup(protoname)))
goto fail;
@@ -238,7 +246,7 @@ process_clnt_dir_files(struct clnt_info * clp)
if ((clp->servicename == NULL) &&
read_service_info(info_file_name, &clp->servicename,
&clp->servername, &clp->prog, &clp->vers,
- &clp->protocol))
+ &clp->protocol, &clp->port))
return -1;
return 0;
}
@@ -587,6 +595,8 @@ int create_auth_rpc_client(struct clnt_info *clp,
clp->servername, uid);
goto out_fail;
}
+ if (clp->port)
+ ((struct sockaddr_in *)a->ai_addr)->sin_port = htons(clp->port);
if (a->ai_protocol == IPPROTO_TCP) {
if ((rpc_clnt = clnttcp_create(
(struct sockaddr_in *) a->ai_addr,

View File

@ -1,35 +0,0 @@
commit 73f9b4402ec6625618967f947c99e6e417322d36
Author: Kevin Coffman <kwc@citi.umich.edu>
Date: Wed May 7 14:38:47 2008 -0400
Add a new function to retrieve the current verbosity level
so that some messages that would otherwise always print may
be silenced.
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
Signed-off-by: Steve Dickson <steved@redhat.com>
diff --git a/utils/gssd/err_util.c b/utils/gssd/err_util.c
index 5644db6..2583e06 100644
--- a/utils/gssd/err_util.c
+++ b/utils/gssd/err_util.c
@@ -60,3 +60,8 @@ void printerr(int priority, char *format, ...)
xlog_backend(L_ERROR, format, args);
va_end(args);
}
+
+int get_verbosity(void)
+{
+ return verbosity;
+}
diff --git a/utils/gssd/err_util.h b/utils/gssd/err_util.h
index 5e5af48..c4df32d 100644
--- a/utils/gssd/err_util.h
+++ b/utils/gssd/err_util.h
@@ -33,5 +33,6 @@
void initerr(char *progname, int verbosity, int fg);
void printerr(int priority, char *format, ...);
+int get_verbosity(void);
#endif /* _ERR_UTIL_H_ */

View File

@ -1,42 +0,0 @@
commit 281ca299724f24e7b19c1eca04bba03410e2a306
Author: Jeff Layton <jlaton@redhat.com>
Date: Wed May 7 10:35:30 2008 -0400
The bg option is essentially ignored with nfs4 currently. nfs4mount()
will never exit with EX_BG, so the mount will never be backgrounded.
Fix it so that when bg is specified that we error out with EX_BG as
soon as possible after the first failed mount attempt.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve Dickson <steved@redhat.com>
diff --git a/utils/mount/nfs4mount.c b/utils/mount/nfs4mount.c
index af70551..2b0fe2e 100644
--- a/utils/mount/nfs4mount.c
+++ b/utils/mount/nfs4mount.c
@@ -188,10 +188,9 @@ int nfs4mount(const char *spec, const char *node, int flags,
int bg, soft, intr;
int nocto, noac, unshared;
int retry;
- int retval;
+ int retval = EX_FAIL;
time_t timeout, t;
- retval = EX_FAIL;
if (strlen(spec) >= sizeof(hostdir)) {
nfs_error(_("%s: excessively long host:dir argument\n"),
progname);
@@ -443,6 +442,13 @@ int nfs4mount(const char *spec, const char *node, int flags,
rpc_mount_errors(hostname, 0, bg);
goto fail;
}
+
+ if (bg && !running_bg) {
+ if (retry > 0)
+ retval = EX_BG;
+ goto fail;
+ }
+
t = time(NULL);
if (t >= timeout) {
rpc_mount_errors(hostname, 0, bg);

View File

@ -1,30 +0,0 @@
commit 0930b25ee3a1eb28b957cdc70c9a1958812d895f
Author: NeilBrown <neilb@suse.de>
Date: Thu May 8 05:18:25 2008 -0400
If mount.nfs is not installed setuid, an attempt to perform a "user"
or "users" mount will fail with a fairly obscure error message,
typically about getting "permission denied" from the server.
This patch gives a more helpful message in that case.
Signed-off-by: NeilBrown <neilb@suse.de>
Signed-off-by: Steve Dickson <steved@redhat.com>
diff --git a/utils/mount/mount.c b/utils/mount/mount.c
index 5076468..d7271a1 100644
--- a/utils/mount/mount.c
+++ b/utils/mount/mount.c
@@ -539,6 +539,12 @@ int main(int argc, char *argv[])
mnt_err = EX_USAGE;
goto out;
}
+
+ if (geteuid() != 0) {
+ nfs_error(_("%s: not installed setuid - "
+ "\"user\" NFS mounts not supported."), progname);
+ exit(EX_FAIL);
+ }
}
if (chk_mountpoint(mount_point)) {

View File

@ -1,458 +0,0 @@
commit c641800eb0fcaa819199e58e5c4c8d1c2a9dab5d
Author: Chuck Lever <chuck.lever@oracle.com>
Date: Fri Jun 6 15:06:21 2008 -0400
Clean up: instead of passing so many arguments to all the helpers, have
nfsmount_string build a data structure that contains all the arguments, and
pass a pointer to that instead.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Steve Dickson <steved@redhat.com>
diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c
index ad5bdee..3564f15 100644
--- a/utils/mount/stropts.c
+++ b/utils/mount/stropts.c
@@ -77,12 +77,26 @@ extern int nfs_mount_data_version;
extern char *progname;
extern int verbose;
-static int parse_devname(const char *spec, char **hostname)
+struct nfsmount_info {
+ const char *spec, /* server:/path */
+ *node, /* mounted-on dir */
+ *type; /* "nfs" or "nfs4" */
+ char *hostname; /* server's hostname */
+
+ struct mount_options *options; /* parsed mount options */
+ char **extra_opts; /* string for /etc/mtab */
+
+ int flags, /* MS_ flags */
+ fake, /* actually do the mount? */
+ child; /* forked bg child? */
+};
+
+static int nfs_parse_devname(struct nfsmount_info *mi)
{
int ret = 0;
char *dev, *pathname, *s;
- dev = xstrdup(spec);
+ dev = xstrdup(mi->spec);
if (!(pathname = strchr(dev, ':'))) {
nfs_error(_("%s: remote share not in 'host:dir' format"),
@@ -113,11 +127,12 @@ static int parse_devname(const char *spec, char **hostname)
nfs_error(_("%s: ignoring hostnames that follow the first one"),
progname);
}
- *hostname = xstrdup(dev);
- if (strlen(*hostname) > NFS_MAXHOSTNAME) {
+ mi->hostname = xstrdup(dev);
+ if (strlen(mi->hostname) > NFS_MAXHOSTNAME) {
nfs_error(_("%s: server hostname is too long"),
progname);
- free(*hostname);
+ free(mi->hostname);
+ mi->hostname = NULL;
goto out;
}
@@ -273,28 +288,30 @@ static int verify_lock_option(struct mount_options *options)
}
/*
- * Set up mandatory mount options.
+ * Set up mandatory NFS mount options.
*
* Returns 1 if successful; otherwise zero.
*/
-static int validate_options(const char *type,
- struct sockaddr_in *saddr,
- struct mount_options *options,
- int fake)
+static int nfs_validate_options(struct nfsmount_info *mi)
{
- if (!append_addr_option(saddr, options))
+ struct sockaddr_in saddr;
+
+ if (!fill_ipv4_sockaddr(mi->hostname, &saddr))
return 0;
- if (strncmp(type, "nfs4", 4) == 0) {
- if (!append_clientaddr_option(saddr, options))
+ if (strncmp(mi->type, "nfs4", 4) == 0) {
+ if (!append_clientaddr_option(&saddr, mi->options))
return 0;
} else {
- if (!fix_mounthost_option(options))
+ if (!fix_mounthost_option(mi->options))
return 0;
- if (!fake && !verify_lock_option(options))
+ if (!mi->fake && !verify_lock_option(mi->options))
return 0;
}
+ if (!append_addr_option(&saddr, mi->options))
+ return 0;
+
return 1;
}
@@ -443,6 +460,27 @@ err:
}
/*
+ * Do the mount(2) system call.
+ *
+ * Returns 1 if successful, otherwise zero.
+ * "errno" is set to reflect the individual error.
+ */
+static int nfs_sys_mount(const struct nfsmount_info *mi, const char *type,
+ const char *options)
+{
+ int result;
+
+ result = mount(mi->spec, mi->node, type,
+ mi->flags & ~(MS_USER|MS_USERS), options);
+ if (verbose && result) {
+ int save = errno;
+ nfs_error(_("%s: mount(2): %s"), progname, strerror(save));
+ errno = save;
+ }
+ return !result;
+}
+
+/*
* Retry an NFS mount that failed because the requested service isn't
* available on the server.
*
@@ -453,12 +491,11 @@ err:
* 'extra_opts' are updated to reflect the mount options that worked.
* If the retry fails, 'options' and 'extra_opts' are left unchanged.
*/
-static int retry_nfsmount(const char *spec, const char *node,
- int flags, struct mount_options *options,
- int fake, char **extra_opts)
+static int nfs_retry_nfs23mount(struct nfsmount_info *mi)
{
struct mount_options *retry_options;
char *retry_str = NULL;
+ char **extra_opts = mi->extra_opts;
retry_options = rewrite_mount_options(*extra_opts);
if (!retry_options) {
@@ -476,17 +513,16 @@ static int retry_nfsmount(const char *spec, const char *node,
printf(_("%s: text-based options (retry): '%s'\n"),
progname, retry_str);
- if (!mount(spec, node, "nfs",
- flags & ~(MS_USER|MS_USERS), retry_str)) {
- free(*extra_opts);
- *extra_opts = retry_str;
- po_replace(options, retry_options);
- return 1;
+ if (!nfs_sys_mount(mi, "nfs", retry_str)) {
+ po_destroy(retry_options);
+ free(retry_str);
+ return 0;
}
- po_destroy(retry_options);
- free(retry_str);
- return 0;
+ free(*extra_opts);
+ *extra_opts = retry_str;
+ po_replace(mi->options, retry_options);
+ return 1;
}
/*
@@ -502,11 +538,11 @@ static int retry_nfsmount(const char *spec, const char *node,
* 'extra_opts' are updated to reflect the mount options that worked.
* If the retry fails, 'options' and 'extra_opts' are left unchanged.
*/
-static int try_nfs23mount(const char *spec, const char *node,
- int flags, struct mount_options *options,
- int fake, char **extra_opts)
+static int nfs_try_nfs23mount(struct nfsmount_info *mi)
{
- if (po_join(options, extra_opts) == PO_FAILED) {
+ char **extra_opts = mi->extra_opts;
+
+ if (po_join(mi->options, extra_opts) == PO_FAILED) {
errno = EIO;
return 0;
}
@@ -515,11 +551,10 @@ static int try_nfs23mount(const char *spec, const char *node,
printf(_("%s: text-based options: '%s'\n"),
progname, *extra_opts);
- if (fake)
+ if (mi->fake)
return 1;
- if (!mount(spec, node, "nfs",
- flags & ~(MS_USER|MS_USERS), *extra_opts))
+ if (nfs_sys_mount(mi, "nfs", *extra_opts))
return 1;
/*
@@ -529,7 +564,7 @@ static int try_nfs23mount(const char *spec, const char *node,
if (errno != EOPNOTSUPP && errno != EPROTONOSUPPORT)
return 0;
- return retry_nfsmount(spec, node, flags, options, fake, extra_opts);
+ return nfs_retry_nfs23mount(mi);
}
/*
@@ -538,11 +573,11 @@ static int try_nfs23mount(const char *spec, const char *node,
* Returns 1 if successful. Otherwise, returns zero.
* "errno" is set to reflect the individual error.
*/
-static int try_nfs4mount(const char *spec, const char *node,
- int flags, struct mount_options *options,
- int fake, char **extra_opts)
+static int nfs_try_nfs4mount(struct nfsmount_info *mi)
{
- if (po_join(options, extra_opts) == PO_FAILED) {
+ char **extra_opts = mi->extra_opts;
+
+ if (po_join(mi->options, extra_opts) == PO_FAILED) {
errno = EIO;
return 0;
}
@@ -551,31 +586,24 @@ static int try_nfs4mount(const char *spec, const char *node,
printf(_("%s: text-based options: '%s'\n"),
progname, *extra_opts);
- if (fake)
+ if (mi->fake)
return 1;
- if (!mount(spec, node, "nfs4",
- flags & ~(MS_USER|MS_USERS), *extra_opts))
- return 1;
- return 0;
+ return nfs_sys_mount(mi, "nfs4", *extra_opts);
}
/*
- * Try the mount(2) system call.
+ * Perform either an NFSv2/3 mount, or an NFSv4 mount system call.
*
* Returns 1 if successful. Otherwise, returns zero.
* "errno" is set to reflect the individual error.
*/
-static int try_mount(const char *spec, const char *node, const char *type,
- int flags, struct mount_options *options, int fake,
- char **extra_opts)
+static int nfs_try_mount(struct nfsmount_info *mi)
{
- if (strncmp(type, "nfs4", 4) == 0)
- return try_nfs4mount(spec, node, flags,
- options, fake, extra_opts);
+ if (strncmp(mi->type, "nfs4", 4) == 0)
+ return nfs_try_nfs4mount(mi);
else
- return try_nfs23mount(spec, node, flags,
- options, fake, extra_opts);
+ return nfs_try_nfs23mount(mi);
}
/*
@@ -585,22 +613,19 @@ static int try_mount(const char *spec, const char *node, const char *type,
*
* Returns a valid mount command exit code.
*/
-static int nfsmount_fg(const char *spec, const char *node,
- const char *type, int flags,
- struct mount_options *options, int fake,
- char **extra_opts)
+static int nfsmount_fg(struct nfsmount_info *mi)
{
unsigned int secs = 1;
time_t timeout;
- timeout = nfs_parse_retry_option(options, NFS_DEF_FG_TIMEOUT_MINUTES);
+ timeout = nfs_parse_retry_option(mi->options,
+ NFS_DEF_FG_TIMEOUT_MINUTES);
if (verbose)
printf(_("%s: timeout set for %s"),
progname, ctime(&timeout));
for (;;) {
- if (try_mount(spec, node, type, flags,
- options, fake, extra_opts))
+ if (nfs_try_mount(mi))
return EX_SUCCESS;
if (is_permanent_error(errno))
@@ -620,7 +645,7 @@ static int nfsmount_fg(const char *spec, const char *node,
}
};
- mount_error(spec, node, errno);
+ mount_error(mi->spec, mi->node, errno);
return EX_FAIL;
}
@@ -631,21 +656,17 @@ static int nfsmount_fg(const char *spec, const char *node,
*
* EX_BG should cause the caller to fork and invoke nfsmount_child.
*/
-static int nfsmount_parent(const char *spec, const char *node,
- const char *type, char *hostname, int flags,
- struct mount_options *options,
- int fake, char **extra_opts)
+static int nfsmount_parent(struct nfsmount_info *mi)
{
- if (try_mount(spec, node, type, flags, options,
- fake, extra_opts))
+ if (nfs_try_mount(mi))
return EX_SUCCESS;
if (is_permanent_error(errno)) {
- mount_error(spec, node, errno);
+ mount_error(mi->spec, mi->node, errno);
return EX_FAIL;
}
- sys_mount_errors(hostname, errno, 1, 1);
+ sys_mount_errors(mi->hostname, errno, 1, 1);
return EX_BG;
}
@@ -657,15 +678,13 @@ static int nfsmount_parent(const char *spec, const char *node,
* error return, though, so we use sys_mount_errors to log the
* failure.
*/
-static int nfsmount_child(const char *spec, const char *node,
- const char *type, char *hostname, int flags,
- struct mount_options *options,
- int fake, char **extra_opts)
+static int nfsmount_child(struct nfsmount_info *mi)
{
unsigned int secs = 1;
time_t timeout;
- timeout = nfs_parse_retry_option(options, NFS_DEF_BG_TIMEOUT_MINUTES);
+ timeout = nfs_parse_retry_option(mi->options,
+ NFS_DEF_BG_TIMEOUT_MINUTES);
for (;;) {
if (sleep(secs))
@@ -674,8 +693,7 @@ static int nfsmount_child(const char *spec, const char *node,
if (secs > 120)
secs = 120;
- if (try_mount(spec, node, type, flags, options,
- fake, extra_opts))
+ if (nfs_try_mount(mi))
return EX_SUCCESS;
if (is_permanent_error(errno))
@@ -684,10 +702,10 @@ static int nfsmount_child(const char *spec, const char *node,
if (time(NULL) > timeout)
break;
- sys_mount_errors(hostname, errno, 1, 1);
+ sys_mount_errors(mi->hostname, errno, 1, 1);
};
- sys_mount_errors(hostname, errno, 1, 0);
+ sys_mount_errors(mi->hostname, errno, 1, 0);
return EX_FAIL;
}
@@ -696,17 +714,28 @@ static int nfsmount_child(const char *spec, const char *node,
*
* Returns a valid mount command exit code.
*/
-static int nfsmount_bg(const char *spec, const char *node,
- const char *type, char *hostname, int flags,
- struct mount_options *options,
- int fake, int child, char **extra_opts)
+static int nfsmount_bg(struct nfsmount_info *mi)
{
- if (!child)
- return nfsmount_parent(spec, node, type, hostname, flags,
- options, fake, extra_opts);
+ if (!mi->child)
+ return nfsmount_parent(mi);
+ else
+ return nfsmount_child(mi);
+}
+
+/*
+ * Process mount options and try a mount system call.
+ *
+ * Returns a valid mount command exit code.
+ */
+static int nfsmount_start(struct nfsmount_info *mi)
+{
+ if (!nfs_validate_options(mi))
+ return EX_FAIL;
+
+ if (po_rightmost(mi->options, "bg", "fg") == PO_KEY1_RIGHTMOST)
+ return nfsmount_bg(mi);
else
- return nfsmount_child(spec, node, type, hostname, flags,
- options, fake, extra_opts);
+ return nfsmount_fg(mi);
}
/**
@@ -723,35 +752,27 @@ static int nfsmount_bg(const char *spec, const char *node,
int nfsmount_string(const char *spec, const char *node, const char *type,
int flags, char **extra_opts, int fake, int child)
{
- struct mount_options *options = NULL;
- struct sockaddr_in saddr;
- char *hostname;
+ struct nfsmount_info mi = {
+ .spec = spec,
+ .node = node,
+ .type = type,
+ .extra_opts = extra_opts,
+ .flags = flags,
+ .fake = fake,
+ .child = child,
+ };
int retval = EX_FAIL;
- if (!parse_devname(spec, &hostname))
+ if (!nfs_parse_devname(&mi))
return retval;
- if (!fill_ipv4_sockaddr(hostname, &saddr))
- goto fail;
- options = po_split(*extra_opts);
- if (!options) {
+ mi.options = po_split(*extra_opts);
+ if (mi.options) {
+ retval = nfsmount_start(&mi);
+ po_destroy(mi.options);
+ } else
nfs_error(_("%s: internal option parsing error"), progname);
- goto fail;
- }
- if (!validate_options(type, &saddr, options, fake))
- goto out;
-
- if (po_rightmost(options, "bg", "fg") == PO_KEY1_RIGHTMOST)
- retval = nfsmount_bg(spec, node, type, hostname, flags,
- options, fake, child, extra_opts);
- else
- retval = nfsmount_fg(spec, node, type, flags, options,
- fake, extra_opts);
-
-out:
- po_destroy(options);
-fail:
- free(hostname);
+ free(mi.hostname);
return retval;
}

View File

@ -1,26 +0,0 @@
commit 697e28939b7d0a3e0ffe3b6bd516213a55f5a063
Author: Jeff Layton <jlaton@redhat.com>
Date: Mon Apr 14 09:03:13 2008 -0400
Change how mount.nfs handles EACCES errors. Currently,
EACCES is a non-fatal error which means the mount will be
retied. This caused mounts to hang for 2mins when the client
does not have permission to access the export. In a strict
interpretation, the error that should be returned is EPERM, but
this is not always the case. So due to the fuzzy interpretation,
of EPERM and EACCES, EACCESS is now a fatal error
Signed-off-by: Steve Dickson <steved@redhat.com>
diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c
index cadb1f4..cdd610e 100644
--- a/utils/mount/stropts.c
+++ b/utils/mount/stropts.c
@@ -252,7 +252,6 @@ static int set_mandatory_options(const char *type,
static int is_permanent_error(int error)
{
switch (error) {
- case EACCES:
case ESTALE:
case ETIMEDOUT:
case ECONNREFUSED:

View File

@ -1,66 +0,0 @@
commit 52dff26c60c07cf1b4fbf8fbd3a1eab7ba90405f
Author: Chuck Lever <chuck.lever@oracle.com>
Date: Fri Jun 6 15:07:24 2008 -0400
Fix error reporting when probe_bothports() fails while rewriting mount
options.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Steve Dickson <steved@redhat.com>
diff --git a/utils/mount/error.c b/utils/mount/error.c
index 23a91ff..147e919 100644
--- a/utils/mount/error.c
+++ b/utils/mount/error.c
@@ -227,6 +227,9 @@ void mount_error(const char *spec, const char *mount_point, int error)
nfs_error(_("%s: mount point %s does not exist"),
progname, mount_point);
break;
+ case ESPIPE:
+ rpc_mount_errors((char *)spec, 0, 0);
+ break;
case EIO:
case EFAULT:
nfs_error(_("%s: internal error"), progname);
diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c
index 3564f15..967fd69 100644
--- a/utils/mount/stropts.c
+++ b/utils/mount/stropts.c
@@ -356,6 +356,8 @@ static struct mount_options *rewrite_mount_options(char *str)
clnt_addr_t nfs_server = { };
int p;
+ errno = EIO;
+
options = po_split(str);
if (!options)
return NULL;
@@ -426,7 +428,7 @@ static struct mount_options *rewrite_mount_options(char *str)
po_remove_all(options, "udp");
if (!probe_bothports(&mnt_server, &nfs_server)) {
- rpc_mount_errors("rpcbind", 0, 0);
+ errno = ESPIPE;
goto err;
}
@@ -452,6 +454,7 @@ static struct mount_options *rewrite_mount_options(char *str)
}
+ errno = 0;
return options;
err:
@@ -498,10 +501,8 @@ static int nfs_retry_nfs23mount(struct nfsmount_info *mi)
char **extra_opts = mi->extra_opts;
retry_options = rewrite_mount_options(*extra_opts);
- if (!retry_options) {
- errno = EIO;
+ if (!retry_options)
return 0;
- }
if (po_join(retry_options, &retry_str) == PO_FAILED) {
po_destroy(retry_options);

View File

@ -1,51 +0,0 @@
commit 5fb4042ce4eb4fd5e50e3fb0f78bbd20b4d46e78
Author: Jeff Layton <jlaton@redhat.com>
Date: Wed May 7 10:37:40 2008 -0400
The prev_bg_host stuff made sense when NFS didn't have its own mount
handler. Now though, each mount.nfs invocation is really a one-shot
affair, and this check no longer works. It also leaked memory. Remove
it.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve Dickson <steved@redhat.com>
diff --git a/utils/mount/nfsmount.c b/utils/mount/nfsmount.c
index a9dd917..6a04518 100644
--- a/utils/mount/nfsmount.c
+++ b/utils/mount/nfsmount.c
@@ -494,7 +494,6 @@ int
nfsmount(const char *spec, const char *node, int flags,
char **extra_opts, int fake, int running_bg)
{
- static char *prev_bg_host;
char hostdir[1024];
char *hostname, *dirname, *old_opts, *mounthost = NULL;
char new_opts[1024], cbuf[1024];
@@ -628,18 +627,6 @@ nfsmount(const char *spec, const char *node, int flags,
if (flags & MS_REMOUNT)
goto out_ok;
- /*
- * If the previous mount operation on the same host was
- * backgrounded, and the "bg" for this mount is also set,
- * give up immediately, to avoid the initial timeout.
- */
- if (bg && !running_bg &&
- prev_bg_host && strcmp(hostname, prev_bg_host) == 0) {
- if (retry > 0)
- retval = EX_BG;
- return retval;
- }
-
/* create mount deamon client */
/*
@@ -708,7 +695,6 @@ nfsmount(const char *spec, const char *node, int flags,
continue;
}
if (!running_bg) {
- prev_bg_host = xstrdup(hostname);
if (retry > 0)
retval = EX_BG;
goto fail;

View File

@ -1,106 +0,0 @@
commit d7a1070383bcf40d32c7f10e535ba443209dedef
Author: Chuck Lever <chuck.lever@oracle.com>
Date: Fri Jun 6 15:02:18 2008 -0400
Steinar Gunderson reports:
"It seems retry= is now additive with the text-based mount interface. In
particular, "mount -o retry=0" still gives a two-minute timeout."
Correct the bug and make retry= option parsing more robust. If parsing
the retry option fails, the option is ignored and a default timeout is
used.
Note that currently the kernel parser ignores the "retry=" option if the
value is a number. If the value contains other characters, the kernel will
choke. A subsequent patch to the kernel will allow any characters as the
value of the retry option (excepting of course ",").
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Steve Dickson <steved@redhat.com>
diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c
index b2b56be..ad5bdee 100644
--- a/utils/mount/stropts.c
+++ b/utils/mount/stropts.c
@@ -65,6 +65,14 @@
#define NFS_MAXPATHNAME (1024)
#endif
+#ifndef NFS_DEF_FG_TIMEOUT_MINUTES
+#define NFS_DEF_FG_TIMEOUT_MINUTES (2u)
+#endif
+
+#ifndef NFS_DEF_BG_TIMEOUT_MINUTES
+#define NFS_DEF_BG_TIMEOUT_MINUTES (10000u)
+#endif
+
extern int nfs_mount_data_version;
extern char *progname;
extern int verbose;
@@ -141,6 +149,32 @@ static int fill_ipv4_sockaddr(const char *hostname, struct sockaddr_in *addr)
}
/*
+ * Obtain a retry timeout value based on the value of the "retry=" option.
+ *
+ * Returns a time_t timeout timestamp, in seconds.
+ */
+static time_t nfs_parse_retry_option(struct mount_options *options,
+ unsigned int timeout_minutes)
+{
+ char *retry_option, *endptr;
+
+ retry_option = po_get(options, "retry");
+ if (retry_option) {
+ long tmp;
+
+ errno = 0;
+ tmp = strtol(retry_option, &endptr, 10);
+ if (errno == 0 && endptr != retry_option && tmp >= 0)
+ timeout_minutes = tmp;
+ else if (verbose)
+ nfs_error(_("%s: invalid retry timeout was specified; "
+ "using default timeout"), progname);
+ }
+
+ return time(NULL) + (time_t)(timeout_minutes * 60);
+}
+
+/*
* Append the 'addr=' option to the options string to pass a resolved
* server address to the kernel. After a successful mount, this address
* is also added to /etc/mtab for use when unmounting.
@@ -557,14 +591,9 @@ static int nfsmount_fg(const char *spec, const char *node,
char **extra_opts)
{
unsigned int secs = 1;
- time_t timeout = time(NULL);
- char *retry;
-
- timeout += 60 * 2; /* default: 2 minutes */
- retry = po_get(options, "retry");
- if (retry)
- timeout += 60 * atoi(retry);
+ time_t timeout;
+ timeout = nfs_parse_retry_option(options, NFS_DEF_FG_TIMEOUT_MINUTES);
if (verbose)
printf(_("%s: timeout set for %s"),
progname, ctime(&timeout));
@@ -634,13 +663,9 @@ static int nfsmount_child(const char *spec, const char *node,
int fake, char **extra_opts)
{
unsigned int secs = 1;
- time_t timeout = time(NULL);
- char *retry;
+ time_t timeout;
- timeout += 60 * 10000; /* default: 10,000 minutes */
- retry = po_get(options, "retry");
- if (retry)
- timeout += 60 * atoi(retry);
+ timeout = nfs_parse_retry_option(options, NFS_DEF_BG_TIMEOUT_MINUTES);
for (;;) {
if (sleep(secs))

View File

@ -1,71 +0,0 @@
commit 331c2ca949d5b4b4d18d0aca90afb8ae9475bcd6
Author: Neil Brown <neilb@suse.de>
Date: Fri Jun 6 14:59:21 2008 -0400
Make the text-based mount path check whether statd is running if the "lock"
option is in effect. This echoes similar logic in the legacy mount path.
Signed-off-by: Neil Brown <neilb@suse.de>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Steve Dickson <steved@redhat.com>
diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c
index cdd610e..b2b56be 100644
--- a/utils/mount/stropts.c
+++ b/utils/mount/stropts.c
@@ -219,13 +219,34 @@ static int fix_mounthost_option(struct mount_options *options)
}
/*
+ * Returns zero if the "lock" option is in effect, but statd
+ * can't be started. Otherwise, returns 1.
+ */
+static int verify_lock_option(struct mount_options *options)
+{
+ if (po_rightmost(options, "nolock", "lock") == PO_KEY1_RIGHTMOST)
+ return 1;
+
+ if (!start_statd()) {
+ nfs_error(_("%s: rpc.statd is not running but is "
+ "required for remote locking."), progname);
+ nfs_error(_("%s: Either use '-o nolock' to keep "
+ "locks local, or start statd."), progname);
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
* Set up mandatory mount options.
*
* Returns 1 if successful; otherwise zero.
*/
-static int set_mandatory_options(const char *type,
- struct sockaddr_in *saddr,
- struct mount_options *options)
+static int validate_options(const char *type,
+ struct sockaddr_in *saddr,
+ struct mount_options *options,
+ int fake)
{
if (!append_addr_option(saddr, options))
return 0;
@@ -236,6 +257,8 @@ static int set_mandatory_options(const char *type,
} else {
if (!fix_mounthost_option(options))
return 0;
+ if (!fake && !verify_lock_option(options))
+ return 0;
}
return 1;
@@ -691,7 +714,7 @@ int nfsmount_string(const char *spec, const char *node, const char *type,
goto fail;
}
- if (!set_mandatory_options(type, &saddr, options))
+ if (!validate_options(type, &saddr, options, fake))
goto out;
if (po_rightmost(options, "bg", "fg") == PO_KEY1_RIGHTMOST)

View File

@ -1,42 +0,0 @@
commit 589a913e42476a965b686c9f2656b786eaae399e
Author: Tom Talpey <tmt@netapp.com>
Date: Mon Jun 23 12:54:08 2008 -0400
Add RDMA as a supported transport for reporting the
mountstats statistics
Signed-off-by: Tom Talpey <tmt@netapp.com>
Acked-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Steve Dickson <steved@redhat.com>
diff --git a/tools/mountstats/mountstats.py b/tools/mountstats/mountstats.py
index 5f20db6..f55595e 100644
--- a/tools/mountstats/mountstats.py
+++ b/tools/mountstats/mountstats.py
@@ -116,6 +116,26 @@ class DeviceData:
self.__rpc_data['badxids'] = int(words[9])
self.__rpc_data['inflightsends'] = long(words[10])
self.__rpc_data['backlogutil'] = int(words[11])
+ elif words[1] == 'rdma':
+ self.__rpc_data['port'] = words[2]
+ self.__rpc_data['bind_count'] = int(words[3])
+ self.__rpc_data['connect_count'] = int(words[4])
+ self.__rpc_data['connect_time'] = int(words[5])
+ self.__rpc_data['idle_time'] = int(words[6])
+ self.__rpc_data['rpcsends'] = int(words[7])
+ self.__rpc_data['rpcreceives'] = int(words[8])
+ self.__rpc_data['badxids'] = int(words[9])
+ self.__rpc_data['backlogutil'] = int(words[10])
+ self.__rpc_data['read_chunks'] = int(words[11])
+ self.__rpc_data['write_chunks'] = int(words[12])
+ self.__rpc_data['reply_chunks'] = int(words[13])
+ self.__rpc_data['total_rdma_req'] = int(words[14])
+ self.__rpc_data['total_rdma_rep'] = int(words[15])
+ self.__rpc_data['pullup'] = int(words[16])
+ self.__rpc_data['fixup'] = int(words[17])
+ self.__rpc_data['hardway'] = int(words[18])
+ self.__rpc_data['failed_marshal'] = int(words[19])
+ self.__rpc_data['bad_reply'] = int(words[20])
elif words[0] == 'per-op':
self.__rpc_data['per-op'] = words
else:

View File

@ -1,605 +0,0 @@
commit c761709ad3abb9c36a68c269f78118bf49d79639
Author: Chuck Lever <chuck.lever@oracle.com>
Date: Mon Jun 23 12:52:33 2008 -0400
The "mountstats" utility is a Python program that extracts and displays NFS
client performance information from /proc/self/mountstats.
Note that if mountstats is named 'ms-nfsstat' or 'ms-iostat' it offers
slightly different functionality. It needs two man pages and the install
script should provide both commands by installing the script and providing the
other command via a symlink.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Steve Dickson <steved@redhat.com>
diff --git a/tools/mountstats/mountstats.py b/tools/mountstats/mountstats.py
new file mode 100644
index 0000000..5f20db6
--- /dev/null
+++ b/tools/mountstats/mountstats.py
@@ -0,0 +1,584 @@
+#!/usr/bin/env python
+# -*- python-mode -*-
+"""Parse /proc/self/mountstats and display it in human readable form
+"""
+
+__copyright__ = """
+Copyright (C) 2005, Chuck Lever <cel@netapp.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License version 2 as
+published by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+"""
+
+import sys, os, time
+
+Mountstats_version = '0.2'
+
+def difference(x, y):
+ """Used for a map() function
+ """
+ return x - y
+
+class DeviceData:
+ """DeviceData objects provide methods for parsing and displaying
+ data for a single mount grabbed from /proc/self/mountstats
+ """
+ def __init__(self):
+ self.__nfs_data = dict()
+ self.__rpc_data = dict()
+ self.__rpc_data['ops'] = []
+
+ def __parse_nfs_line(self, words):
+ if words[0] == 'device':
+ self.__nfs_data['export'] = words[1]
+ self.__nfs_data['mountpoint'] = words[4]
+ self.__nfs_data['fstype'] = words[7]
+ if words[7].find('nfs') != -1:
+ self.__nfs_data['statvers'] = words[8]
+ elif words[0] == 'age:':
+ self.__nfs_data['age'] = long(words[1])
+ elif words[0] == 'opts:':
+ self.__nfs_data['mountoptions'] = ''.join(words[1:]).split(',')
+ elif words[0] == 'caps:':
+ self.__nfs_data['servercapabilities'] = ''.join(words[1:]).split(',')
+ elif words[0] == 'nfsv4:':
+ self.__nfs_data['nfsv4flags'] = ''.join(words[1:]).split(',')
+ elif words[0] == 'sec:':
+ keys = ''.join(words[1:]).split(',')
+ self.__nfs_data['flavor'] = int(keys[0].split('=')[1])
+ self.__nfs_data['pseudoflavor'] = 0
+ if self.__nfs_data['flavor'] == 6:
+ self.__nfs_data['pseudoflavor'] = int(keys[1].split('=')[1])
+ elif words[0] == 'events:':
+ self.__nfs_data['inoderevalidates'] = int(words[1])
+ self.__nfs_data['dentryrevalidates'] = int(words[2])
+ self.__nfs_data['datainvalidates'] = int(words[3])
+ self.__nfs_data['attrinvalidates'] = int(words[4])
+ self.__nfs_data['syncinodes'] = int(words[5])
+ self.__nfs_data['vfsopen'] = int(words[6])
+ self.__nfs_data['vfslookup'] = int(words[7])
+ self.__nfs_data['vfspermission'] = int(words[8])
+ self.__nfs_data['vfsreadpage'] = int(words[9])
+ self.__nfs_data['vfsreadpages'] = int(words[10])
+ self.__nfs_data['vfswritepage'] = int(words[11])
+ self.__nfs_data['vfswritepages'] = int(words[12])
+ self.__nfs_data['vfsreaddir'] = int(words[13])
+ self.__nfs_data['vfsflush'] = int(words[14])
+ self.__nfs_data['vfsfsync'] = int(words[15])
+ self.__nfs_data['vfslock'] = int(words[16])
+ self.__nfs_data['vfsrelease'] = int(words[17])
+ self.__nfs_data['setattrtrunc'] = int(words[18])
+ self.__nfs_data['extendwrite'] = int(words[19])
+ self.__nfs_data['sillyrenames'] = int(words[20])
+ self.__nfs_data['shortreads'] = int(words[21])
+ self.__nfs_data['shortwrites'] = int(words[22])
+ self.__nfs_data['delay'] = int(words[23])
+ elif words[0] == 'bytes:':
+ self.__nfs_data['normalreadbytes'] = long(words[1])
+ self.__nfs_data['normalwritebytes'] = long(words[2])
+ self.__nfs_data['directreadbytes'] = long(words[3])
+ self.__nfs_data['directwritebytes'] = long(words[4])
+ self.__nfs_data['serverreadbytes'] = long(words[5])
+ self.__nfs_data['serverwritebytes'] = long(words[6])
+
+ def __parse_rpc_line(self, words):
+ if words[0] == 'RPC':
+ self.__rpc_data['statsvers'] = float(words[3])
+ self.__rpc_data['programversion'] = words[5]
+ elif words[0] == 'xprt:':
+ self.__rpc_data['protocol'] = words[1]
+ if words[1] == 'udp':
+ self.__rpc_data['port'] = int(words[2])
+ self.__rpc_data['bind_count'] = int(words[3])
+ self.__rpc_data['rpcsends'] = int(words[4])
+ self.__rpc_data['rpcreceives'] = int(words[5])
+ self.__rpc_data['badxids'] = int(words[6])
+ self.__rpc_data['inflightsends'] = long(words[7])
+ self.__rpc_data['backlogutil'] = long(words[8])
+ elif words[1] == 'tcp':
+ self.__rpc_data['port'] = words[2]
+ self.__rpc_data['bind_count'] = int(words[3])
+ self.__rpc_data['connect_count'] = int(words[4])
+ self.__rpc_data['connect_time'] = int(words[5])
+ self.__rpc_data['idle_time'] = int(words[6])
+ self.__rpc_data['rpcsends'] = int(words[7])
+ self.__rpc_data['rpcreceives'] = int(words[8])
+ self.__rpc_data['badxids'] = int(words[9])
+ self.__rpc_data['inflightsends'] = long(words[10])
+ self.__rpc_data['backlogutil'] = int(words[11])
+ elif words[0] == 'per-op':
+ self.__rpc_data['per-op'] = words
+ else:
+ op = words[0][:-1]
+ self.__rpc_data['ops'] += [op]
+ self.__rpc_data[op] = [long(word) for word in words[1:]]
+
+ def parse_stats(self, lines):
+ """Turn a list of lines from a mount stat file into a
+ dictionary full of stats, keyed by name
+ """
+ found = False
+ for line in lines:
+ words = line.split()
+ if len(words) == 0:
+ continue
+ if (not found and words[0] != 'RPC'):
+ self.__parse_nfs_line(words)
+ continue
+
+ found = True
+ self.__parse_rpc_line(words)
+
+ def is_nfs_mountpoint(self):
+ """Return True if this is an NFS or NFSv4 mountpoint,
+ otherwise return False
+ """
+ if self.__nfs_data['fstype'] == 'nfs':
+ return True
+ elif self.__nfs_data['fstype'] == 'nfs4':
+ return True
+ return False
+
+ def display_nfs_options(self):
+ """Pretty-print the NFS options
+ """
+ print 'Stats for %s mounted on %s:' % \
+ (self.__nfs_data['export'], self.__nfs_data['mountpoint'])
+
+ print ' NFS mount options: %s' % ','.join(self.__nfs_data['mountoptions'])
+ print ' NFS server capabilities: %s' % ','.join(self.__nfs_data['servercapabilities'])
+ if self.__nfs_data.has_key('nfsv4flags'):
+ print ' NFSv4 capability flags: %s' % ','.join(self.__nfs_data['nfsv4flags'])
+ if self.__nfs_data.has_key('pseudoflavor'):
+ print ' NFS security flavor: %d pseudoflavor: %d' % \
+ (self.__nfs_data['flavor'], self.__nfs_data['pseudoflavor'])
+ else:
+ print ' NFS security flavor: %d' % self.__nfs_data['flavor']
+
+ def display_nfs_events(self):
+ """Pretty-print the NFS event counters
+ """
+ print
+ print 'Cache events:'
+ print ' data cache invalidated %d times' % self.__nfs_data['datainvalidates']
+ print ' attribute cache invalidated %d times' % self.__nfs_data['attrinvalidates']
+ print ' inodes synced %d times' % self.__nfs_data['syncinodes']
+ print
+ print 'VFS calls:'
+ print ' VFS requested %d inode revalidations' % self.__nfs_data['inoderevalidates']
+ print ' VFS requested %d dentry revalidations' % self.__nfs_data['dentryrevalidates']
+ print
+ print ' VFS called nfs_readdir() %d times' % self.__nfs_data['vfsreaddir']
+ print ' VFS called nfs_lookup() %d times' % self.__nfs_data['vfslookup']
+ print ' VFS called nfs_permission() %d times' % self.__nfs_data['vfspermission']
+ print ' VFS called nfs_file_open() %d times' % self.__nfs_data['vfsopen']
+ print ' VFS called nfs_file_flush() %d times' % self.__nfs_data['vfsflush']
+ print ' VFS called nfs_lock() %d times' % self.__nfs_data['vfslock']
+ print ' VFS called nfs_fsync() %d times' % self.__nfs_data['vfsfsync']
+ print ' VFS called nfs_file_release() %d times' % self.__nfs_data['vfsrelease']
+ print
+ print 'VM calls:'
+ print ' VFS called nfs_readpage() %d times' % self.__nfs_data['vfsreadpage']
+ print ' VFS called nfs_readpages() %d times' % self.__nfs_data['vfsreadpages']
+ print ' VFS called nfs_writepage() %d times' % self.__nfs_data['vfswritepage']
+ print ' VFS called nfs_writepages() %d times' % self.__nfs_data['vfswritepages']
+ print
+ print 'Generic NFS counters:'
+ print ' File size changing operations:'
+ print ' truncating SETATTRs: %d extending WRITEs: %d' % \
+ (self.__nfs_data['setattrtrunc'], self.__nfs_data['extendwrite'])
+ print ' %d silly renames' % self.__nfs_data['sillyrenames']
+ print ' short reads: %d short writes: %d' % \
+ (self.__nfs_data['shortreads'], self.__nfs_data['shortwrites'])
+ print ' NFSERR_DELAYs from server: %d' % self.__nfs_data['delay']
+
+ def display_nfs_bytes(self):
+ """Pretty-print the NFS event counters
+ """
+ print
+ print 'NFS byte counts:'
+ print ' applications read %d bytes via read(2)' % self.__nfs_data['normalreadbytes']
+ print ' applications wrote %d bytes via write(2)' % self.__nfs_data['normalwritebytes']
+ print ' applications read %d bytes via O_DIRECT read(2)' % self.__nfs_data['directreadbytes']
+ print ' applications wrote %d bytes via O_DIRECT write(2)' % self.__nfs_data['directwritebytes']
+ print ' client read %d bytes via NFS READ' % self.__nfs_data['serverreadbytes']
+ print ' client wrote %d bytes via NFS WRITE' % self.__nfs_data['serverwritebytes']
+
+ def display_rpc_generic_stats(self):
+ """Pretty-print the generic RPC stats
+ """
+ sends = self.__rpc_data['rpcsends']
+
+ print
+ print 'RPC statistics:'
+
+ print ' %d RPC requests sent, %d RPC replies received (%d XIDs not found)' % \
+ (sends, self.__rpc_data['rpcreceives'], self.__rpc_data['badxids'])
+ if sends != 0:
+ print ' average backlog queue length: %d' % \
+ (float(self.__rpc_data['backlogutil']) / sends)
+
+ def display_rpc_op_stats(self):
+ """Pretty-print the per-op stats
+ """
+ sends = self.__rpc_data['rpcsends']
+
+ # XXX: these should be sorted by 'count'
+ print
+ for op in self.__rpc_data['ops']:
+ stats = self.__rpc_data[op]
+ count = stats[0]
+ retrans = stats[1] - count
+ if count != 0:
+ print '%s:' % op
+ print '\t%d ops (%d%%)' % \
+ (count, ((count * 100) / sends)),
+ print '\t%d retrans (%d%%)' % (retrans, ((retrans * 100) / count)),
+ print '\t%d major timeouts' % stats[2]
+ print '\tavg bytes sent per op: %d\tavg bytes received per op: %d' % \
+ (stats[3] / count, stats[4] / count)
+ print '\tbacklog wait: %f' % (float(stats[5]) / count),
+ print '\tRTT: %f' % (float(stats[6]) / count),
+ print '\ttotal execute time: %f (milliseconds)' % \
+ (float(stats[7]) / count)
+
+ def compare_iostats(self, old_stats):
+ """Return the difference between two sets of stats
+ """
+ result = DeviceData()
+
+ # copy self into result
+ for key, value in self.__nfs_data.iteritems():
+ result.__nfs_data[key] = value
+ for key, value in self.__rpc_data.iteritems():
+ result.__rpc_data[key] = value
+
+ # compute the difference of each item in the list
+ # note the copy loop above does not copy the lists, just
+ # the reference to them. so we build new lists here
+ # for the result object.
+ for op in result.__rpc_data['ops']:
+ result.__rpc_data[op] = map(difference, self.__rpc_data[op], old_stats.__rpc_data[op])
+
+ # update the remaining keys we care about
+ result.__rpc_data['rpcsends'] -= old_stats.__rpc_data['rpcsends']
+ result.__rpc_data['backlogutil'] -= old_stats.__rpc_data['backlogutil']
+ result.__nfs_data['serverreadbytes'] -= old_stats.__nfs_data['serverreadbytes']
+ result.__nfs_data['serverwritebytes'] -= old_stats.__nfs_data['serverwritebytes']
+
+ return result
+
+ def display_iostats(self, sample_time):
+ """Display NFS and RPC stats in an iostat-like way
+ """
+ sends = float(self.__rpc_data['rpcsends'])
+ if sample_time == 0:
+ sample_time = float(self.__nfs_data['age'])
+
+ print
+ print '%s mounted on %s:' % \
+ (self.__nfs_data['export'], self.__nfs_data['mountpoint'])
+
+ print '\top/s\trpc bklog'
+ print '\t%.2f' % (sends / sample_time),
+ if sends != 0:
+ print '\t%.2f' % \
+ ((float(self.__rpc_data['backlogutil']) / sends) / sample_time)
+ else:
+ print '\t0.00'
+
+ # reads: ops/s, Kb/s, avg rtt, and avg exe
+ # XXX: include avg xfer size and retransmits?
+ read_rpc_stats = self.__rpc_data['READ']
+ ops = float(read_rpc_stats[0])
+ kilobytes = float(self.__nfs_data['serverreadbytes']) / 1024
+ rtt = float(read_rpc_stats[6])
+ exe = float(read_rpc_stats[7])
+
+ print '\treads:\tops/s\t\tKb/s\t\tavg RTT (ms)\tavg exe (ms)'
+ print '\t\t%.2f' % (ops / sample_time),
+ print '\t\t%.2f' % (kilobytes / sample_time),
+ if ops != 0:
+ print '\t\t%.2f' % (rtt / ops),
+ print '\t\t%.2f' % (exe / ops)
+ else:
+ print '\t\t0.00',
+ print '\t\t0.00'
+
+ # writes: ops/s, Kb/s, avg rtt, and avg exe
+ # XXX: include avg xfer size and retransmits?
+ write_rpc_stats = self.__rpc_data['WRITE']
+ ops = float(write_rpc_stats[0])
+ kilobytes = float(self.__nfs_data['serverwritebytes']) / 1024
+ rtt = float(write_rpc_stats[6])
+ exe = float(write_rpc_stats[7])
+
+ print '\twrites:\tops/s\t\tKb/s\t\tavg RTT (ms)\tavg exe (ms)'
+ print '\t\t%.2f' % (ops / sample_time),
+ print '\t\t%.2f' % (kilobytes / sample_time),
+ if ops != 0:
+ print '\t\t%.2f' % (rtt / ops),
+ print '\t\t%.2f' % (exe / ops)
+ else:
+ print '\t\t0.00',
+ print '\t\t0.00'
+
+def parse_stats_file(filename):
+ """pop the contents of a mountstats file into a dictionary,
+ keyed by mount point. each value object is a list of the
+ lines in the mountstats file corresponding to the mount
+ point named in the key.
+ """
+ ms_dict = dict()
+ key = ''
+
+ f = file(filename)
+ for line in f.readlines():
+ words = line.split()
+ if len(words) == 0:
+ continue
+ if words[0] == 'device':
+ key = words[4]
+ new = [ line.strip() ]
+ else:
+ new += [ line.strip() ]
+ ms_dict[key] = new
+ f.close
+
+ return ms_dict
+
+def print_mountstats_help(name):
+ print 'usage: %s [ options ] <mount point>' % name
+ print
+ print ' Version %s' % Mountstats_version
+ print
+ print ' Display NFS client per-mount statistics.'
+ print
+ print ' --version display the version of this command'
+ print ' --nfs display only the NFS statistics'
+ print ' --rpc display only the RPC statistics'
+ print ' --start sample and save statistics'
+ print ' --end resample statistics and compare them with saved'
+ print
+
+def mountstats_command():
+ """Mountstats command
+ """
+ mountpoints = []
+ nfs_only = False
+ rpc_only = False
+
+ for arg in sys.argv:
+ if arg in ['-h', '--help', 'help', 'usage']:
+ print_mountstats_help(prog)
+ return
+
+ if arg in ['-v', '--version', 'version']:
+ print '%s version %s' % (sys.argv[0], Mountstats_version)
+ sys.exit(0)
+
+ if arg in ['-n', '--nfs']:
+ nfs_only = True
+ continue
+
+ if arg in ['-r', '--rpc']:
+ rpc_only = True
+ continue
+
+ if arg in ['-s', '--start']:
+ raise Exception, 'Sampling is not yet implemented'
+
+ if arg in ['-e', '--end']:
+ raise Exception, 'Sampling is not yet implemented'
+
+ if arg == sys.argv[0]:
+ continue
+
+ mountpoints += [arg]
+
+ if mountpoints == []:
+ print_mountstats_help(prog)
+ return
+
+ if rpc_only == True and nfs_only == True:
+ print_mountstats_help(prog)
+ return
+
+ mountstats = parse_stats_file('/proc/self/mountstats')
+
+ for mp in mountpoints:
+ if mp not in mountstats:
+ print 'Statistics for mount point %s not found' % mp
+ continue
+
+ stats = DeviceData()
+ stats.parse_stats(mountstats[mp])
+
+ if not stats.is_nfs_mountpoint():
+ print 'Mount point %s exists but is not an NFS mount' % mp
+ continue
+
+ if nfs_only:
+ stats.display_nfs_options()
+ stats.display_nfs_events()
+ stats.display_nfs_bytes()
+ elif rpc_only:
+ stats.display_rpc_generic_stats()
+ stats.display_rpc_op_stats()
+ else:
+ stats.display_nfs_options()
+ stats.display_nfs_bytes()
+ stats.display_rpc_generic_stats()
+ stats.display_rpc_op_stats()
+
+def print_nfsstat_help(name):
+ print 'usage: %s [ options ]' % name
+ print
+ print ' Version %s' % Mountstats_version
+ print
+ print ' nfsstat-like program that uses NFS client per-mount statistics.'
+ print
+
+def nfsstat_command():
+ print_nfsstat_help(prog)
+
+def print_iostat_help(name):
+ print 'usage: %s [ <interval> [ <count> ] ] [ <mount point> ] ' % name
+ print
+ print ' Version %s' % Mountstats_version
+ print
+ print ' iostat-like program to display NFS client per-mount statistics.'
+ print
+ print ' The <interval> parameter specifies the amount of time in seconds between'
+ print ' each report. The first report contains statistics for the time since each'
+ print ' file system was mounted. Each subsequent report contains statistics'
+ print ' collected during the interval since the previous report.'
+ print
+ print ' If the <count> parameter is specified, the value of <count> determines the'
+ print ' number of reports generated at <interval> seconds apart. If the interval'
+ print ' parameter is specified without the <count> parameter, the command generates'
+ print ' reports continuously.'
+ print
+ print ' If one or more <mount point> names are specified, statistics for only these'
+ print ' mount points will be displayed. Otherwise, all NFS mount points on the'
+ print ' client are listed.'
+ print
+
+def print_iostat_summary(old, new, devices, time):
+ for device in devices:
+ stats = DeviceData()
+ stats.parse_stats(new[device])
+ if not old:
+ stats.display_iostats(time)
+ else:
+ old_stats = DeviceData()
+ old_stats.parse_stats(old[device])
+ diff_stats = stats.compare_iostats(old_stats)
+ diff_stats.display_iostats(time)
+
+def iostat_command():
+ """iostat-like command for NFS mount points
+ """
+ mountstats = parse_stats_file('/proc/self/mountstats')
+ devices = []
+ interval_seen = False
+ count_seen = False
+
+ for arg in sys.argv:
+ if arg in ['-h', '--help', 'help', 'usage']:
+ print_iostat_help(prog)
+ return
+
+ if arg in ['-v', '--version', 'version']:
+ print '%s version %s' % (sys.argv[0], Mountstats_version)
+ return
+
+ if arg == sys.argv[0]:
+ continue
+
+ if arg in mountstats:
+ devices += [arg]
+ elif not interval_seen:
+ interval = int(arg)
+ if interval > 0:
+ interval_seen = True
+ else:
+ print 'Illegal <interval> value'
+ return
+ elif not count_seen:
+ count = int(arg)
+ if count > 0:
+ count_seen = True
+ else:
+ print 'Illegal <count> value'
+ return
+
+ # make certain devices contains only NFS mount points
+ if len(devices) > 0:
+ check = []
+ for device in devices:
+ stats = DeviceData()
+ stats.parse_stats(mountstats[device])
+ if stats.is_nfs_mountpoint():
+ check += [device]
+ devices = check
+ else:
+ for device, descr in mountstats.iteritems():
+ stats = DeviceData()
+ stats.parse_stats(descr)
+ if stats.is_nfs_mountpoint():
+ devices += [device]
+ if len(devices) == 0:
+ print 'No NFS mount points were found'
+ return
+
+ old_mountstats = None
+ sample_time = 0
+
+ if not interval_seen:
+ print_iostat_summary(old_mountstats, mountstats, devices, sample_time)
+ return
+
+ if count_seen:
+ while count != 0:
+ print_iostat_summary(old_mountstats, mountstats, devices, sample_time)
+ old_mountstats = mountstats
+ time.sleep(interval)
+ sample_time = interval
+ mountstats = parse_stats_file('/proc/self/mountstats')
+ count -= 1
+ else:
+ while True:
+ print_iostat_summary(old_mountstats, mountstats, devices, sample_time)
+ old_mountstats = mountstats
+ time.sleep(interval)
+ sample_time = interval
+ mountstats = parse_stats_file('/proc/self/mountstats')
+
+#
+# Main
+#
+prog = os.path.basename(sys.argv[0])
+
+try:
+ if prog == 'mountstats':
+ mountstats_command()
+ elif prog == 'ms-nfsstat':
+ nfsstat_command()
+ elif prog == 'ms-iostat':
+ iostat_command()
+except KeyboardInterrupt:
+ print 'Caught ^C... exiting'
+ sys.exit(1)
+
+sys.exit(0)

View File

@ -1,75 +0,0 @@
commit 3c1bb23c0379864722e79d19f74c180edcf2c36e
Author: bc Wong <bcwong@cisco.com>
Date: Tue Mar 18 09:30:44 2008 -0400
There were 2 things wrong with auth flavour ordering:
- Mountd used to advertise AUTH_NULL as the first flavour on
the list, which means that it prefers AUTH_NULL to anything
else (as per RFC 2623 section 2.7).
- Mount.nfs used to scan the returned list in reverse order,
and stopping at the first AUTH_NULL or AUTH_SYS encountered.
If a server advertises (AUTH_SYS, AUTH_NULL), it will by
default choose AUTH_NULL and have degraded access.
I've fixed mount.nfs to scan from the beginning. For mountd,
it does not advertise AUTH_NULL anymore. This is necessary
to avoid backward compatibility issue. If AUTH_NULL appears
in the list, either the new or the old client will choose
that over AUTH_SYS.
Tested the server/client combination against the previous
versions, as well as Solaris and FreeBSD.
Signed-off-by: bc Wong <bcwong@cisco.com>
Signed-off-by: Steve Dickson <steved@redhat.com>
--- nfs-utils-1.1.2/utils/mount/nfsmount.c.orig 2008-03-14 11:46:29.000000000 -0400
+++ nfs-utils-1.1.2/utils/mount/nfsmount.c 2008-03-25 10:18:09.333839000 -0400
@@ -738,7 +738,7 @@ nfsmount(const char *spec, const char *n
#if NFS_MOUNT_VERSION >= 4
mountres3_ok *mountres;
fhandle3 *fhandle;
- int i, *flavor, yum = 0;
+ int i, n_flavors, *flavor, yum = 0;
if (mntres.nfsv3.fhs_status != 0) {
nfs_error(_("%s: %s:%s failed, reason given by server: %s"),
progname, hostname, dirname,
@@ -747,13 +747,16 @@ nfsmount(const char *spec, const char *n
}
#if NFS_MOUNT_VERSION >= 5
mountres = &mntres.nfsv3.mountres3_u.mountinfo;
- i = mountres->auth_flavors.auth_flavors_len;
- if (i <= 0)
+ n_flavors = mountres->auth_flavors.auth_flavors_len;
+ if (n_flavors <= 0)
goto noauth_flavors;
flavor = mountres->auth_flavors.auth_flavors_val;
- while (--i >= 0) {
- /* If no flavour requested, use first simple
+ for (i = 0; i < n_flavors; ++i) {
+ /*
+ * Per RFC2623, section 2.7, we should prefer the
+ * flavour listed first.
+ * If no flavour requested, use the first simple
* flavour that is offered.
*/
if (! (data.flags & NFS_MOUNT_SECFLAVOUR) &&
--- nfs-utils-1.1.2/utils/mountd/mountd.c.orig 2008-03-14 11:46:29.000000000 -0400
+++ nfs-utils-1.1.2/utils/mountd/mountd.c 2008-03-25 10:18:09.339833000 -0400
@@ -342,7 +342,14 @@ mount_mnt_3_svc(struct svc_req *rqstp, d
#define AUTH_GSS_KRB5 390003
#define AUTH_GSS_KRB5I 390004
#define AUTH_GSS_KRB5P 390005
- static int flavors[] = { AUTH_NULL, AUTH_UNIX, AUTH_GSS_KRB5, AUTH_GSS_KRB5I, AUTH_GSS_KRB5P};
+ static int flavors[] = { AUTH_UNIX, AUTH_GSS_KRB5, AUTH_GSS_KRB5I, AUTH_GSS_KRB5P};
+ /*
+ * We should advertise the preferred flavours first. (See RFC 2623
+ * section 2.7.) AUTH_UNIX is arbitrarily ranked over the GSS's.
+ * AUTH_NULL is dropped from the list to avoid backward compatibility
+ * issue with older Linux clients, who inspect the list in reversed
+ * order.
+ */
struct nfs_fh_len *fh;
xlog(D_CALL, "MNT3(%s) called", *path);

View File

@ -1,42 +0,0 @@
commit 2ef57222b10a91f4b96a06808d05a47e8f4c14f7
Author: Tom Talpey <tmt@netapp.com>
Date: Mon Jun 23 12:57:29 2008 -0400
Add RDMA as a supported transport for reporting
the mountstats statistics
Signed-off-by: Tom Talpey <tmt@netapp.com>
Acked-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Steve Dickson <steved@redhat.com>
diff --git a/tools/nfs-iostat/nfs-iostat.py b/tools/nfs-iostat/nfs-iostat.py
index 794d4a8..649c1bd 100644
--- a/tools/nfs-iostat/nfs-iostat.py
+++ b/tools/nfs-iostat/nfs-iostat.py
@@ -134,6 +134,26 @@ class DeviceData:
self.__rpc_data['badxids'] = int(words[9])
self.__rpc_data['inflightsends'] = long(words[10])
self.__rpc_data['backlogutil'] = long(words[11])
+ elif words[1] == 'rdma':
+ self.__rpc_data['port'] = words[2]
+ self.__rpc_data['bind_count'] = int(words[3])
+ self.__rpc_data['connect_count'] = int(words[4])
+ self.__rpc_data['connect_time'] = int(words[5])
+ self.__rpc_data['idle_time'] = int(words[6])
+ self.__rpc_data['rpcsends'] = int(words[7])
+ self.__rpc_data['rpcreceives'] = int(words[8])
+ self.__rpc_data['badxids'] = int(words[9])
+ self.__rpc_data['backlogutil'] = int(words[10])
+ self.__rpc_data['read_chunks'] = int(words[11])
+ self.__rpc_data['write_chunks'] = int(words[12])
+ self.__rpc_data['reply_chunks'] = int(words[13])
+ self.__rpc_data['total_rdma_req'] = int(words[14])
+ self.__rpc_data['total_rdma_rep'] = int(words[15])
+ self.__rpc_data['pullup'] = int(words[16])
+ self.__rpc_data['fixup'] = int(words[17])
+ self.__rpc_data['hardway'] = int(words[18])
+ self.__rpc_data['failed_marshal'] = int(words[19])
+ self.__rpc_data['bad_reply'] = int(words[20])
elif words[0] == 'per-op':
self.__rpc_data['per-op'] = words
else:

View File

@ -1,560 +0,0 @@
commit ba18e469a8507befdf8969c5ce7a25564744ae01
Author: Chuck Lever <chuck.lever@oracle.com>
Date: Mon Jun 23 12:56:14 2008 -0400
The "nfs-iostat" utility is a Python program that extracts and displays NFS
client performance information from /proc/self/mountstats.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Steve Dickson <steved@redhat.com>
diff --git a/tools/nfs-iostat/nfs-iostat.py b/tools/nfs-iostat/nfs-iostat.py
new file mode 100644
index 0000000..794d4a8
--- /dev/null
+++ b/tools/nfs-iostat/nfs-iostat.py
@@ -0,0 +1,544 @@
+#!/usr/bin/env python
+# -*- python-mode -*-
+"""Emulate iostat for NFS mount points using /proc/self/mountstats
+"""
+
+__copyright__ = """
+Copyright (C) 2005, Chuck Lever <cel@netapp.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License version 2 as
+published by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+"""
+
+import sys, os, time
+
+Iostats_version = '0.2'
+
+def difference(x, y):
+ """Used for a map() function
+ """
+ return x - y
+
+NfsEventCounters = [
+ 'inoderevalidates',
+ 'dentryrevalidates',
+ 'datainvalidates',
+ 'attrinvalidates',
+ 'vfsopen',
+ 'vfslookup',
+ 'vfspermission',
+ 'vfsupdatepage',
+ 'vfsreadpage',
+ 'vfsreadpages',
+ 'vfswritepage',
+ 'vfswritepages',
+ 'vfsreaddir',
+ 'vfssetattr',
+ 'vfsflush',
+ 'vfsfsync',
+ 'vfslock',
+ 'vfsrelease',
+ 'congestionwait',
+ 'setattrtrunc',
+ 'extendwrite',
+ 'sillyrenames',
+ 'shortreads',
+ 'shortwrites',
+ 'delay'
+]
+
+NfsByteCounters = [
+ 'normalreadbytes',
+ 'normalwritebytes',
+ 'directreadbytes',
+ 'directwritebytes',
+ 'serverreadbytes',
+ 'serverwritebytes',
+ 'readpages',
+ 'writepages'
+]
+
+class DeviceData:
+ """DeviceData objects provide methods for parsing and displaying
+ data for a single mount grabbed from /proc/self/mountstats
+ """
+ def __init__(self):
+ self.__nfs_data = dict()
+ self.__rpc_data = dict()
+ self.__rpc_data['ops'] = []
+
+ def __parse_nfs_line(self, words):
+ if words[0] == 'device':
+ self.__nfs_data['export'] = words[1]
+ self.__nfs_data['mountpoint'] = words[4]
+ self.__nfs_data['fstype'] = words[7]
+ if words[7] == 'nfs':
+ self.__nfs_data['statvers'] = words[8]
+ elif words[0] == 'age:':
+ self.__nfs_data['age'] = long(words[1])
+ elif words[0] == 'opts:':
+ self.__nfs_data['mountoptions'] = ''.join(words[1:]).split(',')
+ elif words[0] == 'caps:':
+ self.__nfs_data['servercapabilities'] = ''.join(words[1:]).split(',')
+ elif words[0] == 'nfsv4:':
+ self.__nfs_data['nfsv4flags'] = ''.join(words[1:]).split(',')
+ elif words[0] == 'sec:':
+ keys = ''.join(words[1:]).split(',')
+ self.__nfs_data['flavor'] = int(keys[0].split('=')[1])
+ self.__nfs_data['pseudoflavor'] = 0
+ if self.__nfs_data['flavor'] == 6:
+ self.__nfs_data['pseudoflavor'] = int(keys[1].split('=')[1])
+ elif words[0] == 'events:':
+ i = 1
+ for key in NfsEventCounters:
+ self.__nfs_data[key] = int(words[i])
+ i += 1
+ elif words[0] == 'bytes:':
+ i = 1
+ for key in NfsByteCounters:
+ self.__nfs_data[key] = long(words[i])
+ i += 1
+
+ def __parse_rpc_line(self, words):
+ if words[0] == 'RPC':
+ self.__rpc_data['statsvers'] = float(words[3])
+ self.__rpc_data['programversion'] = words[5]
+ elif words[0] == 'xprt:':
+ self.__rpc_data['protocol'] = words[1]
+ if words[1] == 'udp':
+ self.__rpc_data['port'] = int(words[2])
+ self.__rpc_data['bind_count'] = int(words[3])
+ self.__rpc_data['rpcsends'] = int(words[4])
+ self.__rpc_data['rpcreceives'] = int(words[5])
+ self.__rpc_data['badxids'] = int(words[6])
+ self.__rpc_data['inflightsends'] = long(words[7])
+ self.__rpc_data['backlogutil'] = long(words[8])
+ elif words[1] == 'tcp':
+ self.__rpc_data['port'] = words[2]
+ self.__rpc_data['bind_count'] = int(words[3])
+ self.__rpc_data['connect_count'] = int(words[4])
+ self.__rpc_data['connect_time'] = int(words[5])
+ self.__rpc_data['idle_time'] = int(words[6])
+ self.__rpc_data['rpcsends'] = int(words[7])
+ self.__rpc_data['rpcreceives'] = int(words[8])
+ self.__rpc_data['badxids'] = int(words[9])
+ self.__rpc_data['inflightsends'] = long(words[10])
+ self.__rpc_data['backlogutil'] = long(words[11])
+ elif words[0] == 'per-op':
+ self.__rpc_data['per-op'] = words
+ else:
+ op = words[0][:-1]
+ self.__rpc_data['ops'] += [op]
+ self.__rpc_data[op] = [long(word) for word in words[1:]]
+
+ def parse_stats(self, lines):
+ """Turn a list of lines from a mount stat file into a
+ dictionary full of stats, keyed by name
+ """
+ found = False
+ for line in lines:
+ words = line.split()
+ if len(words) == 0:
+ continue
+ if (not found and words[0] != 'RPC'):
+ self.__parse_nfs_line(words)
+ continue
+
+ found = True
+ self.__parse_rpc_line(words)
+
+ def is_nfs_mountpoint(self):
+ """Return True if this is an NFS or NFSv4 mountpoint,
+ otherwise return False
+ """
+ if self.__nfs_data['fstype'] == 'nfs':
+ return True
+ elif self.__nfs_data['fstype'] == 'nfs4':
+ return True
+ return False
+
+ def compare_iostats(self, old_stats):
+ """Return the difference between two sets of stats
+ """
+ result = DeviceData()
+
+ # copy self into result
+ for key, value in self.__nfs_data.iteritems():
+ result.__nfs_data[key] = value
+ for key, value in self.__rpc_data.iteritems():
+ result.__rpc_data[key] = value
+
+ # compute the difference of each item in the list
+ # note the copy loop above does not copy the lists, just
+ # the reference to them. so we build new lists here
+ # for the result object.
+ for op in result.__rpc_data['ops']:
+ result.__rpc_data[op] = map(difference, self.__rpc_data[op], old_stats.__rpc_data[op])
+
+ # update the remaining keys we care about
+ result.__rpc_data['rpcsends'] -= old_stats.__rpc_data['rpcsends']
+ result.__rpc_data['backlogutil'] -= old_stats.__rpc_data['backlogutil']
+
+ for key in NfsEventCounters:
+ result.__nfs_data[key] -= old_stats.__nfs_data[key]
+ for key in NfsByteCounters:
+ result.__nfs_data[key] -= old_stats.__nfs_data[key]
+
+ return result
+
+ def __print_data_cache_stats(self):
+ """Print the data cache hit rate
+ """
+ nfs_stats = self.__nfs_data
+ app_bytes_read = float(nfs_stats['normalreadbytes'])
+ if app_bytes_read != 0:
+ client_bytes_read = float(nfs_stats['serverreadbytes'] - nfs_stats['directreadbytes'])
+ ratio = ((app_bytes_read - client_bytes_read) * 100) / app_bytes_read
+
+ print
+ print 'app bytes: %f client bytes %f' % (app_bytes_read, client_bytes_read)
+ print 'Data cache hit ratio: %4.2f%%' % ratio
+
+ def __print_attr_cache_stats(self, sample_time):
+ """Print attribute cache efficiency stats
+ """
+ nfs_stats = self.__nfs_data
+ getattr_stats = self.__rpc_data['GETATTR']
+
+ if nfs_stats['inoderevalidates'] != 0:
+ getattr_ops = float(getattr_stats[1])
+ opens = float(nfs_stats['vfsopen'])
+ revalidates = float(nfs_stats['inoderevalidates']) - opens
+ if revalidates != 0:
+ ratio = ((revalidates - getattr_ops) * 100) / revalidates
+ else:
+ ratio = 0.0
+
+ data_invalidates = float(nfs_stats['datainvalidates'])
+ attr_invalidates = float(nfs_stats['attrinvalidates'])
+
+ print
+ print '%d inode revalidations, hitting in cache %4.2f%% of the time' % \
+ (revalidates, ratio)
+ print '%d open operations (mandatory GETATTR requests)' % opens
+ if getattr_ops != 0:
+ print '%4.2f%% of GETATTRs resulted in data cache invalidations' % \
+ ((data_invalidates * 100) / getattr_ops)
+
+ def __print_dir_cache_stats(self, sample_time):
+ """Print directory stats
+ """
+ nfs_stats = self.__nfs_data
+ lookup_ops = self.__rpc_data['LOOKUP'][0]
+ readdir_ops = self.__rpc_data['READDIR'][0]
+ if self.__rpc_data.has_key('READDIRPLUS'):
+ readdir_ops += self.__rpc_data['READDIRPLUS'][0]
+
+ dentry_revals = nfs_stats['dentryrevalidates']
+ opens = nfs_stats['vfsopen']
+ lookups = nfs_stats['vfslookup']
+ getdents = nfs_stats['vfsreaddir']
+
+ print
+ print '%d open operations (pathname lookups)' % opens
+ print '%d dentry revalidates and %d vfs lookup requests' % \
+ (dentry_revals, lookups),
+ print 'resulted in %d LOOKUPs on the wire' % lookup_ops
+ print '%d vfs getdents calls resulted in %d READDIRs on the wire' % \
+ (getdents, readdir_ops)
+
+ def __print_page_stats(self, sample_time):
+ """Print page cache stats
+ """
+ nfs_stats = self.__nfs_data
+
+ vfsreadpage = nfs_stats['vfsreadpage']
+ vfsreadpages = nfs_stats['vfsreadpages']
+ pages_read = nfs_stats['readpages']
+ vfswritepage = nfs_stats['vfswritepage']
+ vfswritepages = nfs_stats['vfswritepages']
+ pages_written = nfs_stats['writepages']
+
+ print
+ print '%d nfs_readpage() calls read %d pages' % \
+ (vfsreadpage, vfsreadpage)
+ print '%d nfs_readpages() calls read %d pages' % \
+ (vfsreadpages, pages_read - vfsreadpage),
+ if vfsreadpages != 0:
+ print '(%.1f pages per call)' % \
+ (float(pages_read - vfsreadpage) / vfsreadpages)
+ else:
+ print
+
+ print
+ print '%d nfs_updatepage() calls' % nfs_stats['vfsupdatepage']
+ print '%d nfs_writepage() calls wrote %d pages' % \
+ (vfswritepage, vfswritepage)
+ print '%d nfs_writepages() calls wrote %d pages' % \
+ (vfswritepages, pages_written - vfswritepage),
+ if (vfswritepages) != 0:
+ print '(%.1f pages per call)' % \
+ (float(pages_written - vfswritepage) / vfswritepages)
+ else:
+ print
+
+ congestionwaits = nfs_stats['congestionwait']
+ if congestionwaits != 0:
+ print
+ print '%d congestion waits' % congestionwaits
+
+ def __print_rpc_op_stats(self, op, sample_time):
+ """Print generic stats for one RPC op
+ """
+ if not self.__rpc_data.has_key(op):
+ return
+
+ rpc_stats = self.__rpc_data[op]
+ ops = float(rpc_stats[0])
+ retrans = float(rpc_stats[1] - rpc_stats[0])
+ kilobytes = float(rpc_stats[3] + rpc_stats[4]) / 1024
+ rtt = float(rpc_stats[6])
+ exe = float(rpc_stats[7])
+
+ # prevent floating point exceptions
+ if ops != 0:
+ kb_per_op = kilobytes / ops
+ retrans_percent = (retrans * 100) / ops
+ rtt_per_op = rtt / ops
+ exe_per_op = exe / ops
+ else:
+ kb_per_op = 0.0
+ retrans_percent = 0.0
+ rtt_per_op = 0.0
+ exe_per_op = 0.0
+
+ op += ':'
+ print '%s' % op.lower().ljust(15),
+ print ' ops/s\t\t Kb/s\t\t Kb/op\t\tretrans\t\tavg RTT (ms)\tavg exe (ms)'
+
+ print '\t\t%7.3f' % (ops / sample_time),
+ print '\t%7.3f' % (kilobytes / sample_time),
+ print '\t%7.3f' % kb_per_op,
+ print ' %7d (%3.1f%%)' % (retrans, retrans_percent),
+ print '\t%7.3f' % rtt_per_op,
+ print '\t%7.3f' % exe_per_op
+
+ def display_iostats(self, sample_time, which):
+ """Display NFS and RPC stats in an iostat-like way
+ """
+ sends = float(self.__rpc_data['rpcsends'])
+ if sample_time == 0:
+ sample_time = float(self.__nfs_data['age'])
+ if sends != 0:
+ backlog = (float(self.__rpc_data['backlogutil']) / sends) / sample_time
+ else:
+ backlog = 0.0
+
+ print
+ print '%s mounted on %s:' % \
+ (self.__nfs_data['export'], self.__nfs_data['mountpoint'])
+ print
+
+ print ' op/s\t\trpc bklog'
+ print '%7.2f' % (sends / sample_time),
+ print '\t%7.2f' % backlog
+
+ if which == 0:
+ self.__print_rpc_op_stats('READ', sample_time)
+ self.__print_rpc_op_stats('WRITE', sample_time)
+ elif which == 1:
+ self.__print_rpc_op_stats('GETATTR', sample_time)
+ self.__print_rpc_op_stats('ACCESS', sample_time)
+ self.__print_attr_cache_stats(sample_time)
+ elif which == 2:
+ self.__print_rpc_op_stats('LOOKUP', sample_time)
+ self.__print_rpc_op_stats('READDIR', sample_time)
+ if self.__rpc_data.has_key('READDIRPLUS'):
+ self.__print_rpc_op_stats('READDIRPLUS', sample_time)
+ self.__print_dir_cache_stats(sample_time)
+ elif which == 3:
+ self.__print_rpc_op_stats('READ', sample_time)
+ self.__print_rpc_op_stats('WRITE', sample_time)
+ self.__print_page_stats(sample_time)
+
+#
+# Functions
+#
+
+def print_iostat_help(name):
+ print 'usage: %s [ <interval> [ <count> ] ] [ <options> ] [ <mount point> ] ' % name
+ print
+ print ' Version %s' % Iostats_version
+ print
+ print ' Sample iostat-like program to display NFS client per-mount statistics.'
+ print
+ print ' The <interval> parameter specifies the amount of time in seconds between'
+ print ' each report. The first report contains statistics for the time since each'
+ print ' file system was mounted. Each subsequent report contains statistics'
+ print ' collected during the interval since the previous report.'
+ print
+ print ' If the <count> parameter is specified, the value of <count> determines the'
+ print ' number of reports generated at <interval> seconds apart. If the interval'
+ print ' parameter is specified without the <count> parameter, the command generates'
+ print ' reports continuously.'
+ print
+ print ' Options include "--attr", which displays statistics related to the attribute'
+ print ' cache, "--dir", which displays statistics related to directory operations,'
+ print ' and "--page", which displays statistics related to the page cache.'
+ print ' By default, if no option is specified, statistics related to file I/O are'
+ print ' displayed.'
+ print
+ print ' If one or more <mount point> names are specified, statistics for only these'
+ print ' mount points will be displayed. Otherwise, all NFS mount points on the'
+ print ' client are listed.'
+
+def parse_stats_file(filename):
+ """pop the contents of a mountstats file into a dictionary,
+ keyed by mount point. each value object is a list of the
+ lines in the mountstats file corresponding to the mount
+ point named in the key.
+ """
+ ms_dict = dict()
+ key = ''
+
+ f = file(filename)
+ for line in f.readlines():
+ words = line.split()
+ if len(words) == 0:
+ continue
+ if words[0] == 'device':
+ key = words[4]
+ new = [ line.strip() ]
+ else:
+ new += [ line.strip() ]
+ ms_dict[key] = new
+ f.close
+
+ return ms_dict
+
+def print_iostat_summary(old, new, devices, time, ac):
+ for device in devices:
+ stats = DeviceData()
+ stats.parse_stats(new[device])
+ if not old:
+ stats.display_iostats(time, ac)
+ else:
+ old_stats = DeviceData()
+ old_stats.parse_stats(old[device])
+ diff_stats = stats.compare_iostats(old_stats)
+ diff_stats.display_iostats(time, ac)
+
+def iostat_command(name):
+ """iostat-like command for NFS mount points
+ """
+ mountstats = parse_stats_file('/proc/self/mountstats')
+ devices = []
+ which = 0
+ interval_seen = False
+ count_seen = False
+
+ for arg in sys.argv:
+ if arg in ['-h', '--help', 'help', 'usage']:
+ print_iostat_help(name)
+ return
+
+ if arg in ['-v', '--version', 'version']:
+ print '%s version %s' % (name, Iostats_version)
+ return
+
+ if arg in ['-a', '--attr']:
+ which = 1
+ continue
+
+ if arg in ['-d', '--dir']:
+ which = 2
+ continue
+
+ if arg in ['-p', '--page']:
+ which = 3
+ continue
+
+ if arg == sys.argv[0]:
+ continue
+
+ if arg in mountstats:
+ devices += [arg]
+ elif not interval_seen:
+ interval = int(arg)
+ if interval > 0:
+ interval_seen = True
+ else:
+ print 'Illegal <interval> value'
+ return
+ elif not count_seen:
+ count = int(arg)
+ if count > 0:
+ count_seen = True
+ else:
+ print 'Illegal <count> value'
+ return
+
+ # make certain devices contains only NFS mount points
+ if len(devices) > 0:
+ check = []
+ for device in devices:
+ stats = DeviceData()
+ stats.parse_stats(mountstats[device])
+ if stats.is_nfs_mountpoint():
+ check += [device]
+ devices = check
+ else:
+ for device, descr in mountstats.iteritems():
+ stats = DeviceData()
+ stats.parse_stats(descr)
+ if stats.is_nfs_mountpoint():
+ devices += [device]
+ if len(devices) == 0:
+ print 'No NFS mount points were found'
+ return
+
+ old_mountstats = None
+ sample_time = 0.0
+
+ if not interval_seen:
+ print_iostat_summary(old_mountstats, mountstats, devices, sample_time, which)
+ return
+
+ if count_seen:
+ while count != 0:
+ print_iostat_summary(old_mountstats, mountstats, devices, sample_time, which)
+ old_mountstats = mountstats
+ time.sleep(interval)
+ sample_time = interval
+ mountstats = parse_stats_file('/proc/self/mountstats')
+ count -= 1
+ else:
+ while True:
+ print_iostat_summary(old_mountstats, mountstats, devices, sample_time, which)
+ old_mountstats = mountstats
+ time.sleep(interval)
+ sample_time = interval
+ mountstats = parse_stats_file('/proc/self/mountstats')
+
+#
+# Main
+#
+prog = os.path.basename(sys.argv[0])
+
+try:
+ iostat_command(prog)
+except KeyboardInterrupt:
+ print 'Caught ^C... exiting'
+ sys.exit(1)
+
+sys.exit(0)

View File

@ -1,60 +0,0 @@
commit 5be04020788598cb811e51c4b1342cf0796cbb65
Author: Jeff Layton <jlayton@redhat.com>
Date: Mon Jun 23 07:21:52 2008 -0400
The nfsstat program reads /proc/net/rpc/* files to gets info about
calls. This info is output as unsigned numbers (at least on any
relatively recent kernel). When nfsstat prints these numbers, they are
printed as signed integers. When the call counters reach 2^31, things
start being printed as negative numbers.
This patch changes nfsstat to read and print all counters as unsigned
integers. Tested by hacking up a kernel to initialize call counters to
2^31+1.
Thanks to Takafumi Miki for the initial version of this patch.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve Dickson <steved@redhat.com>
diff --git a/utils/nfsstat/nfsstat.c b/utils/nfsstat/nfsstat.c
index d2cca8d..1517414 100644
--- a/utils/nfsstat/nfsstat.c
+++ b/utils/nfsstat/nfsstat.c
@@ -539,7 +539,7 @@ print_numbers(const char *hdr, unsigned int *info, unsigned int nr)
fputs(hdr, stdout);
for (i = 0; i < nr; i++)
- printf("%s%-8d", i? " " : "", info[i]);
+ printf("%s%-8u", i? " " : "", info[i]);
printf("\n");
}
@@ -562,7 +562,7 @@ print_callstats(const char *hdr, const char **names,
printf("\n");
for (j = 0; j < 6 && i + j < nr; j++) {
pct = ((unsigned long long) info[i+j]*100)/total;
- printf("%-8d%3llu%% ", info[i+j], pct);
+ printf("%-8u%3llu%% ", info[i+j], pct);
}
printf("\n");
}
@@ -604,7 +604,7 @@ parse_raw_statfile(const char *name, struct statinfo *statp)
for (i = 0; i < cnt; i++) {
if (!(sp = strtok(NULL, " \t")))
break;
- ip->valptr[i] = atoi(sp);
+ ip->valptr[i] = (unsigned int) strtoul(sp, NULL, 0);
total += ip->valptr[i];
}
ip->valptr[cnt - 1] = total;
@@ -618,7 +618,8 @@ parse_raw_statfile(const char *name, struct statinfo *statp)
static int
parse_pretty_statfile(const char *filename, struct statinfo *info)
{
- int numvals, curindex, numconsumed, n, sum, err = 1;
+ int numvals, curindex, numconsumed, n, err = 1;
+ unsigned int sum;
char buf[4096], *bufp, *fmt, is_proc;
FILE *fp = NULL;
struct statinfo *ip;

View File

@ -1,26 +0,0 @@
commit d03090be4f440d70328988e9f792f3bd0ebd956b
Author: Neil Brown <neilb@suse.de>
Date: Fri Jun 6 15:17:55 2008 -0400
nfsstat -m lists all current nfs mounts, with the mount options.
It does this by reading /proc/mounts and looking for mounts of type
"nfs". It really should check for "nfs4" as well.
For simplicity, just check the first 3 characters of the type.
Signed-off-by: NeilBrown <neilb@suse.de>
Signed-off-by: Steve Dickson <steved@redhat.com>
diff --git a/utils/nfsstat/nfsstat.c b/utils/nfsstat/nfsstat.c
index aa6c961..d2cca8d 100644
--- a/utils/nfsstat/nfsstat.c
+++ b/utils/nfsstat/nfsstat.c
@@ -716,7 +716,7 @@ mounts(const char *name)
if (!(type = strtok(NULL, " \t")))
continue;
- if (strcmp(type, "nfs")) {
+ if (strcmp(type, "nfs") && strcmp(type,"nfs4")) {
continue;
}

View File

@ -1,28 +0,0 @@
commit 710765a87d599d95de51b79202ba3d82fd03ed95
Author: Steve Dickson <steved@redhat.com>
Date: Wed Jun 25 09:23:45 2008 -0400
When a FQDN exists in /var/lib/nfs/rmtab it causes
the exportfs command to seg fault due to the nfs_export pointer
not being allocated. Reworking the parentheses in rmtab_read()
so the htype variable is evaluated correctly fix the problem.
Signed-off-by: Steve Dickson <steved@redhat.com>
diff --git a/support/export/rmtab.c b/support/export/rmtab.c
index 0ce3682..e11a22a 100644
--- a/support/export/rmtab.c
+++ b/support/export/rmtab.c
@@ -31,10 +31,10 @@ rmtab_read(void)
int htype;
htype = client_gettype(rep->r_client);
- if (htype == MCL_FQDN || (htype == MCL_SUBNETWORK
+ if ((htype == MCL_FQDN || htype == MCL_SUBNETWORK)
&& (hp = gethostbyname (rep->r_client))
&& (hp = hostent_dup (hp),
- (exp = export_allowed (hp, rep->r_path))))) {
+ exp = export_allowed (hp, rep->r_path))) {
/* see if the entry already exists, otherwise this was an instantiated
* wild card, and we must add it
*/

View File

@ -1,28 +0,0 @@
commit ad1fc3feae447685a8ec8c7db0ad913fe3c4de5c
Author: Sten Spans <sten@blinkenlights.nl>
Date: Mon May 5 14:04:58 2008 -0400
Fixed arguments to the hosts_ctl() call in the good_client() routine
used in the tcpwrapper support.
Signe-off-by: Steve Dickson <steved@redhat.com>
diff --git a/support/misc/tcpwrapper.c b/support/misc/tcpwrapper.c
index 0cc9335..e4f453b 100644
--- a/support/misc/tcpwrapper.c
+++ b/support/misc/tcpwrapper.c
@@ -125,12 +125,12 @@ struct sockaddr_in *addr;
return 0;
/* Check the official name first. */
- if (hosts_ctl(daemon, "", hp->h_name, ""))
+ if (hosts_ctl(daemon, hp->h_name, "", ""))
return 1;
/* Check aliases. */
for (sp = hp->h_aliases; *sp ; sp++) {
- if (hosts_ctl(daemon, "", *sp, ""))
+ if (hosts_ctl(daemon, *sp, "", ""))
return 1;
}

View File

@ -1,34 +0,0 @@
commit fd54675db0806e81c17ee7e7eec0abfcd33f1f23
Author: Steve Dickson <steved@redhat.com>
Date: Fri Jun 6 14:44:48 2008 -0400
Cleaned up warnings in rmtab.c and xlog.c
Signed-off-by: Steve Dickson <steved@redhat.com>
diff --git a/support/export/rmtab.c b/support/export/rmtab.c
index 8f392a7..0ce3682 100644
--- a/support/export/rmtab.c
+++ b/support/export/rmtab.c
@@ -23,7 +23,7 @@ int
rmtab_read(void)
{
struct rmtabent *rep;
- nfs_export *exp;
+ nfs_export *exp = NULL;
setrmtabent("r");
while ((rep = getrmtabent(1, NULL)) != NULL) {
@@ -31,10 +31,10 @@ rmtab_read(void)
int htype;
htype = client_gettype(rep->r_client);
- if (htype == MCL_FQDN || htype == MCL_SUBNETWORK
+ if (htype == MCL_FQDN || (htype == MCL_SUBNETWORK
&& (hp = gethostbyname (rep->r_client))
&& (hp = hostent_dup (hp),
- exp = export_allowed (hp, rep->r_path))) {
+ (exp = export_allowed (hp, rep->r_path))))) {
/* see if the entry already exists, otherwise this was an instantiated
* wild card, and we must add it
*/

View File

@ -1,8 +1,8 @@
Summary: NFS utilities and supporting clients and daemons for the kernel NFS server
Name: nfs-utils
URL: http://sourceforge.net/projects/nfs
Version: 1.1.2
Release: 12%{?dist}
Version: 1.1.3
Release: 1%{?dist}
Epoch: 1
# group all 32bit related archs
@ -23,37 +23,8 @@ Source14: rpcsvcgssd.init
Source15: nfs.sysconfig
Patch00: nfs-utils-1.0.5-statdpath.patch
Patch01: nfs-utils-1.0.6-mountd.patch
Patch02: nfs-utils-1.0.6-gssd_mixed_case.patch
Patch03: nfs-utils-1.1.0-showmount-rpcerror.patch
Patch04: nfs-utils-1.1.0-exp-subtree-warn-off.patch
Patch05: nfs-utils-1.1.0-exportfs-open.patch
Patch06: nfs-utils-1.1.0-exportfs-man-update.patch
Patch07: nfs-utils-1.1.2-multi-auth-flavours.patch
Patch08: nfs-utils-1.1.2-mount-eacces.patch
Patch09: nfs-utils-1.1.0-smnotify-path.patch
Patch101: nfs-utils-1.1.2-tcpwrapper-fix.patch
Patch102: nfs-utils-1.1.2-mount-retry.patch
Patch103: nfs-utils-1.1.2-mount-bg-fix.patch
Patch104: nfs-utils-1.1.2-mount-remove-bg-host.patch
Patch105: nfs-utils-1.1.2-gssd-getport.patch
Patch106: nfs-utils-1.1.2-gssd-des-types.patch
Patch107: nfs-utils-1.1.2-gssd-getverbose.patch
Patch108: nfs-utils-1.1.2-gssd-creds.patch
Patch109: nfs-utils-1.1.2-mount-chk-setuid.patch
Patch110: nfs-utils-1.1.2-exportfs-man-typo.patch
Patch111: nfs-utils-1.1.2-warnings.patch
Patch112: nfs-utils-1.1.2-mount-statd-chk.patch
Patch113: nfs-utils-1.1.2-mount-cleanup.patch
Patch114: nfs-utils-1.1.2-mount-error-reporting.patch
Patch115: nfs-utils-1.1.2-nfsstat-m-arg.patch
Patch116: nfs-utils-1.1.2-nfsstat-counters.patch
Patch117: nfs-utils-1.1.2-mountstats.patch
Patch118: nfs-utils-1.1.2-mountstats-rdma.patch
Patch119: nfs-utils-1.1.2-nfs-iostat.patch
Patch120: nfs-utils-1.1.2-nfs-iostat-rdma.patch
Patch121: nfs-utils-1.1.2-rmtab-fqdn.patch
Patch01: nfs-utils-1.1.2-smnotifypath.patch
Patch02: nfs-utils-1.1.0-exp-subtree-warn-off.patch
%if %{enablefscache}
Patch90: nfs-utils-1.1.0-mount-fsc.patch
@ -107,35 +78,6 @@ This package also contains the mount.nfs and umount.nfs program.
%patch00 -p1
%patch01 -p1
%patch02 -p1
%patch03 -p1
%patch04 -p1
%patch05 -p1
%patch06 -p1
%patch07 -p1
%patch08 -p1
%patch09 -p1
%patch101 -p1
%patch102 -p1
%patch103 -p1
%patch104 -p1
%patch105 -p1
%patch106 -p1
%patch107 -p1
%patch108 -p1
%patch109 -p1
%patch110 -p1
%patch111 -p1
%patch112 -p1
%patch113 -p1
%patch114 -p1
%patch115 -p1
%patch116 -p1
%patch117 -p1
%patch118 -p1
%patch119 -p1
%patch120 -p1
%patch121 -p1
%if %{enablefscache}
%patch90 -p1
@ -299,6 +241,9 @@ fi
%attr(4755,root,root) /sbin/umount.nfs4
%changelog
* Mon Jul 28 2008 Steve Dickson <steved@redhat.com> 1.1.3-1
- Updated to latest upstream version: 1.1.3
* Wed Jul 2 2008 Steve Dickson <steved@redhat.com> 1.1.2-12
- Changed the default directories for sm-notify (bz 435480)
- Added 'condstop' to init scripts so service are not

View File

@ -1,2 +1,2 @@
ae7db9c61c5ad04f83bb99e5caed73da nfs.doc.tar.gz
f1d53d27cc246291841e0989530dc94b nfs-utils-1.1.2.tar.bz2
3ce0faed9e85e78c3017066530050a41 nfs-utils-1.1.3.tar.bz2