--- util-linux-2.12q/mount/Makefile
+++ util-linux-2.12q/mount/Makefile
@@ -29,7 +29,7 @@
 
 MAYBE = pivot_root swapoff
 
-NFS_OBJS = nfsmount.o nfsmount_xdr.o nfsmount_clnt.o
+NFS_OBJS = nfsmount.o nfsmount_xdr.o nfsmount_clnt.o nfs4mount.o
 GEN_FILES = nfsmount.h nfsmount_xdr.c nfsmount_clnt.c
 
 all: $(PROGS)
--- util-linux-2.12q/mount/mount.c
+++ util-linux-2.12q/mount/mount.c
@@ -847,8 +847,23 @@
 		      "without support for the type `nfs'"));
 #endif
   }
+#ifdef HAVE_NFS
+  /*
+   * NFSv4 support
+   */
+  if (!fake && types && streq (types, "nfs4")) {
+    mnt_err = nfs4mount(spec, node, &flags, &extra_opts, &mount_opts, bg);
+    if (mnt_err)
+      return mnt_err;
+	goto nosigblock;
+#else
+    die (EX_SOFTWARE, _("mount: this version was compiled "
+	              "without support for the type `nfs4'"));
+#endif
+  }
 
   block_signals (SIG_BLOCK);
+nosigblock:
 
   if (!fake) {
     mnt5_res = guess_fstype_and_mount (spec, node, &types, flags & ~MS_NOSYS,
--- util-linux-2.12q/mount/nfs4mount.c
+++ util-linux-2.12q/mount/nfs4mount.c
@@ -0,0 +1,460 @@
+/*
+ * nfs4mount.c -- Linux NFS mount
+ * Copyright (C) 2002 Trond Myklebust <trond.myklebust@fys.uio.no>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * 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.
+ *
+ * Note: this file based on the original nfsmount.c
+ */
+
+#include "../defines.h"	/* for HAVE_rpcsvc_nfs_prot_h and HAVE_inet_aton */
+
+#include <linux/posix_types.h>
+#include <asm/posix_types.h>
+#undef __FD_CLR
+#undef __FD_SET
+#undef __FD_ISSET
+#undef __FD_ZERO
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <netdb.h>
+#include <time.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/utsname.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <rpc/auth.h>
+#ifdef HAVE_rpcsvc_nfs_prot_h
+#include <rpcsvc/nfs_prot.h>
+#else
+#include <linux/nfs.h>
+#define nfsstat nfs_stat
+#endif
+
+#include "sundries.h"
+
+#include "mount_constants.h"
+#include "nfs4_mount.h"
+
+#include "nls.h"
+
+#ifndef NFS_PORT
+#define NFS_PORT 2049
+#endif
+
+extern int clnt_ping(struct sockaddr_in *, const u_long, const u_long, const u_int);
+extern void rpc_strerror(void);
+
+struct {
+	char    *flavour;
+	int     fnum;
+} flav_map[] = {
+	{ "krb5",	RPC_AUTH_GSS_KRB5	},
+	{ "krb5i",	RPC_AUTH_GSS_KRB5I	},
+	{ "krb5p",	RPC_AUTH_GSS_KRB5P	},
+	{ "lipkey",	RPC_AUTH_GSS_LKEY	},
+	{ "lipkey-i",	RPC_AUTH_GSS_LKEYI	},
+	{ "lipkey-p",	RPC_AUTH_GSS_LKEYP	},
+	{ "spkm3",	RPC_AUTH_GSS_SPKM	},
+	{ "spkm3i",	RPC_AUTH_GSS_SPKMI	},
+	{ "spkm3p",	RPC_AUTH_GSS_SPKMP	},
+	{ "unix",	AUTH_UNIX		},
+	{ "sys",	AUTH_SYS		},
+	{ "null",	AUTH_NULL		},
+	{ "none",	AUTH_NONE		},
+};
+
+#define FMAPSIZE		(sizeof(flav_map)/sizeof(flav_map[0]))
+#define MAX_USER_FLAVOUR	16
+
+static int parse_sec(char *sec, int *pseudoflavour)
+{
+	int i, num_flavour = 0;
+
+	for (sec = strtok(sec, ":"); sec; sec = strtok(NULL, ":")) {
+		if (num_flavour >= MAX_USER_FLAVOUR) {
+			fprintf(stderr,
+				_("mount: maximum number of security flavors "
+				  "exceeded\n"));
+			return 0;
+		}
+		for (i = 0; i < FMAPSIZE; i++) {
+			if (strcmp(sec, flav_map[i].flavour) == 0) {
+				pseudoflavour[num_flavour++] = flav_map[i].fnum;
+				break;
+			}
+		}
+		if (i == FMAPSIZE) {
+			fprintf(stderr,
+				_("mount: unknown security type %s\n"), sec);
+			return 0;
+		}
+	}
+	if (!num_flavour)
+		fprintf(stderr,
+			_("mount: no security flavors passed to sec= option\n"));
+	return num_flavour;
+}
+
+static int parse_devname(char *hostdir, char **hostname, char **dirname)
+{
+	char *s;
+
+	if (!(s = strchr(hostdir, ':'))) {
+		fprintf(stderr,
+			_("mount: "
+			  "directory to mount not in host:dir format\n"));
+		return -1;
+	}
+	*hostname = hostdir;
+	*dirname = s + 1;
+	*s = '\0';
+	/* Ignore all but first hostname in replicated mounts
+	   until they can be fully supported. (mack@sgi.com) */
+	if ((s = strchr(hostdir, ','))) {
+		*s = '\0';
+		fprintf(stderr,
+			_("mount: warning: "
+			  "multiple hostnames not supported\n"));
+	}
+	return 0;
+}
+
+static int fill_ipv4_sockaddr(const char *hostname, struct sockaddr_in *addr)
+{
+	struct hostent *hp;
+	addr->sin_family = AF_INET;
+
+	if (inet_aton(hostname, &addr->sin_addr))
+		return 0;
+	if ((hp = gethostbyname(hostname)) == NULL) {
+		fprintf(stderr, _("mount: can't get address for %s\n"),
+			hostname);
+		return -1;
+	}
+	if (hp->h_length > sizeof(struct in_addr)) {
+		fprintf(stderr,
+			_("mount: got bad hp->h_length\n"));
+		hp->h_length = sizeof(struct in_addr);
+	}
+	memcpy(&addr->sin_addr, hp->h_addr, hp->h_length);
+	return 0;
+}
+
+static int get_my_ipv4addr(char *ip_addr, int len)
+{
+	char myname[1024];
+	struct sockaddr_in myaddr;
+
+	if (gethostname(myname, sizeof(myname))) {
+		fprintf(stderr, _("mount: can't determine client address\n"));
+		return -1;
+	}
+	if (fill_ipv4_sockaddr(myname, &myaddr))
+		return -1;
+	snprintf(ip_addr, len, "%s", inet_ntoa(myaddr.sin_addr));
+	ip_addr[len-1] = '\0';
+	return 0;
+}
+
+/* Convert RPC errors into strings */
+void rpc_strerror(void)
+{
+	int cf_stat = rpc_createerr.cf_stat;
+	int cf_errno = rpc_createerr.cf_error.re_errno;
+	char *ptr, *estr = clnt_sperrno(cf_stat);
+
+	if (estr) {
+		if ((ptr = index(estr, ':')))
+			estr = ++ptr;
+
+		fprintf(stderr, "RPC Error: %d (%s )\n", cf_stat, estr);
+		if (cf_stat == RPC_SYSTEMERROR)
+			fprintf(stderr, "System Error: %d (%s)\n", cf_errno, strerror(cf_errno));
+	}
+}
+
+int
+clnt_ping(struct sockaddr_in *saddr, const u_long prog, const u_long vers,
+         const u_int prot)
+{
+	static const struct timeval TIMEOUT = { 20, 0 };
+	static const struct timeval RETRY_TIMEOUT = { 3, 0 };
+	CLIENT *clnt=NULL;
+	int sock, stat;
+	static char clnt_res;
+
+	rpc_createerr.cf_stat = stat = 0;
+	sock = RPC_ANYSOCK;
+	switch(prot) {
+	case IPPROTO_UDP:
+		clnt = clntudp_bufcreate(saddr, prog, vers,
+					RETRY_TIMEOUT, &sock,
+					RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
+		break;
+	case IPPROTO_TCP:
+		clnt = clnttcp_create(saddr, prog, vers, &sock,
+				     RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
+		break;
+	default:
+		goto out_bad;
+	}
+	if (!clnt)
+		goto out_bad;
+	memset(&clnt_res, 0, sizeof(clnt_res));
+	stat = clnt_call(clnt, NULLPROC,
+			(xdrproc_t)xdr_void, (caddr_t)NULL,
+			(xdrproc_t)xdr_void, (caddr_t)&clnt_res,
+			TIMEOUT);
+	clnt_destroy(clnt);
+	close(sock);
+	if (stat != RPC_PROGVERSMISMATCH)
+		return 1;
+
+	out_bad:
+	return 0;
+}
+
+
+int nfs4mount(const char *spec, const char *node, int *flags,
+	      char **extra_opts, char **mount_opts,
+	      int running_bg)
+{
+	static struct nfs4_mount_data data;
+	static char hostdir[1024];
+	static char ip_addr[16] = "127.0.0.1";
+	static struct sockaddr_in server_addr;
+	static int pseudoflavour[MAX_USER_FLAVOUR];
+	int num_flavour = 0;
+
+	char *hostname, *dirname, *old_opts;
+	char new_opts[1024];
+	char *opt, *opteq;
+	char *s;
+	int val;
+	int bg, soft, intr;
+	int nocto, noac;
+	int retry;
+	int retval;
+
+	retval = EX_FAIL;
+	if (strlen(spec) >= sizeof(hostdir)) {
+		fprintf(stderr, _("mount: "
+				  "excessively long host:dir argument\n"));
+		goto fail;
+	}
+	strcpy(hostdir, spec);
+	if (parse_devname(hostdir, &hostname, &dirname))
+		goto fail;
+
+	if (fill_ipv4_sockaddr(hostname, &server_addr))
+		goto fail;
+	if (get_my_ipv4addr(ip_addr, sizeof(ip_addr)))
+		goto fail;
+
+	/* add IP address to mtab options for use when unmounting */
+	s = inet_ntoa(server_addr.sin_addr);
+	old_opts = *extra_opts;
+	if (!old_opts)
+		old_opts = "";
+	if (strlen(old_opts) + strlen(s) + 10 >= sizeof(new_opts)) {
+		fprintf(stderr, _("mount: "
+				  "excessively long option argument\n"));
+		goto fail;
+	}
+	snprintf(new_opts, sizeof(new_opts), "%s%saddr=%s",
+		 old_opts, *old_opts ? "," : "", s);
+	*extra_opts = xstrdup(new_opts);
+
+	/* Set default options.
+	 * rsize/wsize and timeo are left 0 in order to
+	 * let the kernel decide.
+	 */
+	memset(&data, 0, sizeof(data));
+	data.retrans	= 3;
+	data.acregmin	= 3;
+	data.acregmax	= 60;
+	data.acdirmin	= 30;
+	data.acdirmax	= 60;
+	data.proto	= IPPROTO_TCP;
+
+	bg = 0;
+	soft = 0;
+	intr = NFS4_MOUNT_INTR;
+	nocto = 0;
+	noac = 0;
+	retry = 10000;		/* 10000 minutes ~ 1 week */
+
+	/*
+	 * NFSv4 specifies that the default port should be 2049
+	 */
+	server_addr.sin_port = htons(NFS_PORT);
+
+	/* parse options */
+
+	for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) {
+		if ((opteq = strchr(opt, '='))) {
+			val = atoi(opteq + 1);
+			*opteq = '\0';
+			if (!strcmp(opt, "rsize"))
+				data.rsize = val;
+			else if (!strcmp(opt, "wsize"))
+				data.wsize = val;
+			else if (!strcmp(opt, "timeo"))
+				data.timeo = val;
+			else if (!strcmp(opt, "retrans"))
+				data.retrans = val;
+			else if (!strcmp(opt, "acregmin"))
+				data.acregmin = val;
+			else if (!strcmp(opt, "acregmax"))
+				data.acregmax = val;
+			else if (!strcmp(opt, "acdirmin"))
+				data.acdirmin = val;
+			else if (!strcmp(opt, "acdirmax"))
+				data.acdirmax = val;
+			else if (!strcmp(opt, "actimeo")) {
+				data.acregmin = val;
+				data.acregmax = val;
+				data.acdirmin = val;
+				data.acdirmax = val;
+			}
+			else if (!strcmp(opt, "retry"))
+				retry = val;
+			else if (!strcmp(opt, "port"))
+				server_addr.sin_port = htons(val);
+			else if (!strcmp(opt, "proto")) {
+				if (!strncmp(opteq+1, "tcp", 3))
+					data.proto = IPPROTO_TCP;
+				else if (!strncmp(opteq+1, "udp", 3))
+					data.proto = IPPROTO_UDP;
+				else
+					printf(_("Warning: Unrecognized proto= option.\n"));
+			} else if (!strcmp(opt, "clientaddr")) {
+				if (strlen(opteq+1) >= sizeof(ip_addr))
+					printf(_("Invalid client address %s"),
+								opteq+1);
+				strncpy(ip_addr,opteq+1, sizeof(ip_addr));
+				ip_addr[sizeof(ip_addr)-1] = '\0';
+			} else if (!strcmp(opt, "sec")) {
+				num_flavour = parse_sec(opteq+1, pseudoflavour);
+				if (!num_flavour)
+					goto fail;
+			} else if (!strcmp(opt, "addr")) {
+				/* ignore */;
+			} else {
+				printf(_("unknown nfs mount parameter: "
+					 "%s=%d\n"), opt, val);
+				goto fail;
+			}
+		} else {
+			val = 1;
+			if (!strncmp(opt, "no", 2)) {
+				val = 0;
+				opt += 2;
+			}
+			if (!strcmp(opt, "bg"))
+				bg = val;
+			else if (!strcmp(opt, "fg"))
+				bg = !val;
+			else if (!strcmp(opt, "soft"))
+				soft = val;
+			else if (!strcmp(opt, "hard"))
+				soft = !val;
+			else if (!strcmp(opt, "intr"))
+				intr = val;
+			else if (!strcmp(opt, "cto"))
+				nocto = !val;
+			else if (!strcmp(opt, "ac"))
+				noac = !val;
+			else {
+				if (!sloppy) {
+					printf(_("unknown nfs mount option: "
+						 "%s%s\n"), val ? "" : "no", opt);
+					goto fail;
+				}
+			}
+		}
+	}
+
+	data.flags = (soft ? NFS4_MOUNT_SOFT : 0)
+		| (intr ? NFS4_MOUNT_INTR : 0)
+		| (nocto ? NFS4_MOUNT_NOCTO : 0)
+		| (noac ? NFS4_MOUNT_NOAC : 0);
+
+	if (num_flavour == 0)
+		pseudoflavour[num_flavour++] = AUTH_UNIX;
+	data.auth_flavourlen = num_flavour;
+	data.auth_flavours = pseudoflavour;
+
+	data.client_addr.data = ip_addr;
+	data.client_addr.len = strlen(ip_addr);
+
+	data.mnt_path.data = dirname;
+	data.mnt_path.len = strlen(dirname);
+
+	data.hostname.data = hostname;
+	data.hostname.len = strlen(hostname);
+	data.host_addr = (struct sockaddr *)&server_addr;
+	data.host_addrlen = sizeof(server_addr);
+
+#ifdef NFS_MOUNT_DEBUG
+	printf("rsize = %d, wsize = %d, timeo = %d, retrans = %d\n",
+	       data.rsize, data.wsize, data.timeo, data.retrans);
+	printf("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n",
+	       data.acregmin, data.acregmax, data.acdirmin, data.acdirmax);
+	printf("port = %d, bg = %d, retry = %d, flags = %.8x\n",
+	       ntohs(server_addr.sin_port), bg, retry, data.flags);
+	printf("soft = %d, intr = %d, nocto = %d, noac = %d\n",
+	       (data.flags & NFS4_MOUNT_SOFT) != 0,
+	       (data.flags & NFS4_MOUNT_INTR) != 0,
+	       (data.flags & NFS4_MOUNT_NOCTO) != 0,
+	       (data.flags & NFS4_MOUNT_NOAC) != 0);
+
+	if (num_flavour > 0) {
+		int pf_cnt, i;
+
+		printf("sec = ");
+		for (pf_cnt = 0; pf_cnt < num_flavour; pf_cnt++) {
+			for (i = 0; i < FMAPSIZE; i++) {
+				if (flav_map[i].fnum == pseudoflavour[pf_cnt]) {
+					printf("%s", flav_map[i].flavour);
+					break;
+				}
+			}
+			printf("%s", (pf_cnt < num_flavour-1) ? ":" : "\n");
+		}
+	}
+	printf("proto = %s\n", (data.proto == IPPROTO_TCP) ? "tcp" : "udp");
+#endif
+
+	data.version = NFS4_MOUNT_VERSION;
+
+	clnt_ping(&server_addr, NFS_PROGRAM, 4, data.proto);
+	if (rpc_createerr.cf_stat) {
+		fprintf(stderr, "mount to NFS server '%s' failed.\n", data.hostname.data);
+		goto fail;
+	}
+
+	*mount_opts = (char *) &data;
+	/* clean up */
+	return 0;
+
+fail:
+	if (verbose) {
+		rpc_strerror();
+	}
+	return retval;
+}
--- util-linux-2.12q/mount/nfs4_mount.h
+++ util-linux-2.12q/mount/nfs4_mount.h
@@ -0,0 +1,82 @@
+#ifndef _LINUX_NFS4_MOUNT_H
+#define _LINUX_NFS4_MOUNT_H
+
+/*
+ *  linux/include/linux/nfs4_mount.h
+ *
+ *  Copyright (C) 2002  Trond Myklebust
+ *
+ *  structure passed from user-space to kernel-space during an nfsv4 mount
+ */
+
+/*
+ * WARNING!  Do not delete or change the order of these fields.  If
+ * a new field is required then add it to the end.  The version field
+ * tracks which fields are present.  This will ensure some measure of
+ * mount-to-kernel version compatibility.  Some of these aren't used yet
+ * but here they are anyway.
+ */
+#define NFS4_MOUNT_VERSION	1
+
+struct nfs_string {
+	unsigned int len;
+	const char* data;
+};
+
+struct nfs4_mount_data {
+	int version;				/* 1 */
+	int flags;				/* 1 */
+	int rsize;				/* 1 */
+	int wsize;				/* 1 */
+	int timeo;				/* 1 */
+	int retrans;				/* 1 */
+	int acregmin;				/* 1 */
+	int acregmax;				/* 1 */
+	int acdirmin;				/* 1 */
+	int acdirmax;				/* 1 */
+
+	/* see the definition of 'struct clientaddr4' in RFC3010 */
+	struct nfs_string client_addr;		/* 1 */
+
+	/* Mount path */
+	struct nfs_string mnt_path;		/* 1 */
+
+	/* Server details */
+	struct nfs_string hostname;		/* 1 */
+	/* Server IP address */
+	unsigned int host_addrlen;		/* 1 */
+	struct sockaddr* host_addr;		/* 1 */
+
+	/* Transport protocol to use */
+	int proto;				/* 1 */
+
+	/* Pseudo-flavours to use for authentication. See RFC2623 */
+	int auth_flavourlen;			/* 1 */
+	int *auth_flavours;			/* 1 */
+};
+
+/* bits in the flags field */
+/* Note: the fields that correspond to existing NFSv2/v3 mount options
+ * 	 should mirror the values from include/linux/nfs_mount.h
+ */
+
+#define NFS4_MOUNT_SOFT		0x0001	/* 1 */
+#define NFS4_MOUNT_INTR		0x0002	/* 1 */
+#define NFS4_MOUNT_NOCTO	0x0010	/* 1 */
+#define NFS4_MOUNT_NOAC		0x0020	/* 1 */
+#define NFS4_MOUNT_STRICTLOCK	0x1000	/* 1 */
+#define NFS4_MOUNT_FLAGMASK	0xFFFF
+
+/* pseudoflavors: */
+
+#define RPC_AUTH_GSS_KRB5       390003
+#define RPC_AUTH_GSS_KRB5I      390004
+#define RPC_AUTH_GSS_KRB5P      390005
+#define RPC_AUTH_GSS_LKEY       390006
+#define RPC_AUTH_GSS_LKEYI      390007
+#define RPC_AUTH_GSS_LKEYP      390008
+#define RPC_AUTH_GSS_SPKM       390009
+#define RPC_AUTH_GSS_SPKMI      390010
+#define RPC_AUTH_GSS_SPKMP      390011
+
+#endif
--- util-linux-2.12q/mount/nfs_mount4.h
+++ util-linux-2.12q/mount/nfs_mount4.h
@@ -8,7 +8,9 @@
  * so it is easiest to ignore the kernel altogether (at compile time).
  */
 
-#define NFS_MOUNT_VERSION	4
+#define NFS_MOUNT_VERSION 6
+#define NFS_MAX_CONTEXT_LEN   256
+
 
 struct nfs2_fh {
         char                    data[32];
@@ -36,6 +38,9 @@
 	int		namlen;			/* 2 */
 	unsigned int	bsize;			/* 3 */
 	struct nfs3_fh	root;			/* 4 */
+	int		pseudoflavor;		/* 5 */
+	char    context[NFS_MAX_CONTEXT_LEN + 1]; /* 6 */
+
 };
 
 /* bits in the flags field */
@@ -52,3 +57,19 @@
 #define NFS_MOUNT_NONLM		0x0200	/* 3 */
 #define NFS_MOUNT_BROKEN_SUID	0x0400	/* 4 */
 #define NFS_MOUNT_NOACL		0x0800  /* 4 */
+#define NFS_MOUNT_SECFLAVOUR	0x2000	/* 5 */
+
+/* security pseudoflavors */
+
+#ifndef AUTH_GSS_KRB5
+#define AUTH_GSS_KRB5		390003
+#define AUTH_GSS_KRB5I		390004
+#define AUTH_GSS_KRB5P		390005
+#define AUTH_GSS_LKEY		390006
+#define AUTH_GSS_LKEYI		390007
+#define AUTH_GSS_LKEYP		390008
+#define AUTH_GSS_SPKM		390009
+#define AUTH_GSS_SPKMI		390010
+#define AUTH_GSS_SPKMP		390011
+#endif
+