Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 4 Jan 2012 03:14:10 +0000 (UTC)
From:      Rick Macklem <rmacklem@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r229460 - in projects/nfsv4.1-client/sys/fs: nfs nfsclient
Message-ID:  <201201040314.q043EAWe057348@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: rmacklem
Date: Wed Jan  4 03:14:10 2012
New Revision: 229460
URL: http://svn.freebsd.org/changeset/base/229460

Log:
  Add the function that does the GetDeviceInfo NFSv4.1 operation and
  stores the file layout in "struct nfsclfldevinfo". Also, add a function
  that can parse netaddr4 XDR structures for both IPv4 and IPv6, which
  is needed by nfsrpc_getdeviceinfo(). The nfsrpc_getdeviceinfo() function
  is not yet tested and it, plus "struct nfsclfldevinfo", could change.

Modified:
  projects/nfsv4.1-client/sys/fs/nfs/nfs_commonport.c
  projects/nfsv4.1-client/sys/fs/nfs/nfs_commonsubs.c
  projects/nfsv4.1-client/sys/fs/nfs/nfs_var.h
  projects/nfsv4.1-client/sys/fs/nfs/nfsclstate.h
  projects/nfsv4.1-client/sys/fs/nfs/nfsport.h
  projects/nfsv4.1-client/sys/fs/nfsclient/nfs_clrpcops.c

Modified: projects/nfsv4.1-client/sys/fs/nfs/nfs_commonport.c
==============================================================================
--- projects/nfsv4.1-client/sys/fs/nfs/nfs_commonport.c	Wed Jan  4 02:04:20 2012	(r229459)
+++ projects/nfsv4.1-client/sys/fs/nfs/nfs_commonport.c	Wed Jan  4 03:14:10 2012	(r229460)
@@ -105,6 +105,7 @@ MALLOC_DEFINE(M_NEWNFSDIROFF, "NFSCL dir
 MALLOC_DEFINE(M_NEWNFSDROLLBACK, "NFSD rollback",
     "New NFS local lock rollback");
 MALLOC_DEFINE(M_NEWNFSFLAYOUT, "NFSCL flayout", "NFSv4.1 File Layout");
+MALLOC_DEFINE(M_NEWNFSDEVINFO, "NFSCL devinfo", "NFSv4.1 Device Info");
 
 /*
  * Definition of mutex locks.

Modified: projects/nfsv4.1-client/sys/fs/nfs/nfs_commonsubs.c
==============================================================================
--- projects/nfsv4.1-client/sys/fs/nfs/nfs_commonsubs.c	Wed Jan  4 02:04:20 2012	(r229459)
+++ projects/nfsv4.1-client/sys/fs/nfs/nfs_commonsubs.c	Wed Jan  4 03:14:10 2012	(r229460)
@@ -3497,6 +3497,122 @@ newnfs_sndunlock(int *flagp)
 	NFSUNLOCKSOCK();
 }
 
+APPLESTATIC int
+nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_storage *sa,
+    int *isudp)
+{
+	struct sockaddr_in *sad;
+	struct sockaddr_in6 *sad6;
+	struct in_addr saddr;
+	uint32_t portnum, *tl;
+	int af = 0, i, j, k;
+	char addr[64], protocol[5], *cp;
+	int cantparse = 0, error = 0;
+	uint16_t portv;
+
+	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+	i = fxdr_unsigned(int, *tl);
+	if (i >= 3 && i <= 4) {
+		error = nfsrv_mtostr(nd, protocol, i);
+		if (error)
+			goto nfsmout;
+		if (strcmp(protocol, "tcp") == 0) {
+			af = AF_INET;
+			*isudp = 0;
+		} else if (strcmp(protocol, "udp") == 0) {
+			af = AF_INET;
+			*isudp = 1;
+		} else if (strcmp(protocol, "tcp6") == 0) {
+			af = AF_INET6;
+			*isudp = 0;
+		} else if (strcmp(protocol, "udp6") == 0) {
+			af = AF_INET6;
+			*isudp = 1;
+		} else
+			cantparse = 1;
+	} else {
+		cantparse = 1;
+		if (i > 0) {
+			error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
+			if (error)
+				goto nfsmout;
+		}
+	}
+	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+	i = fxdr_unsigned(int, *tl);
+	if (i < 0) {
+		error = NFSERR_BADXDR;
+		goto nfsmout;
+	} else if (cantparse == 0 && i >= 11 && i < 64) {
+		/*
+		 * The shortest address is 11chars and the longest is < 64.
+		 */
+		error = nfsrv_mtostr(nd, addr, i);
+		if (error)
+			goto nfsmout;
+
+		/* Find the port# at the end and extract that. */
+		i = strlen(addr);
+		k = 0;
+		cp = &addr[i - 1];
+		/* Count back two '.'s from end to get port# field. */
+		for (j = 0; j < i; j++) {
+			if (*cp == '.') {
+				k++;
+				if (k == 2)
+					break;
+			}
+			cp--;
+		}
+		if (k == 2) {
+			/*
+			 * The NFSv4 port# is appended as .N.N, where N is
+			 * a decimal # in the range 0-255, just like an inet4
+			 * address. Cheat and use inet_aton(), which will
+			 * return a Class A address and then shift the high
+			 * order 8bits over to convert it to the port#.
+			 */
+			*cp++ = '\0';
+			if (inet_aton(cp, &saddr) == 1) {
+				portnum = ntohl(saddr.s_addr);
+				portv = (uint16_t)((portnum >> 16) |
+				    (portnum & 0xff));
+			} else
+				cantparse = 1;
+		} else
+			cantparse = 1;
+		if (cantparse == 0) {
+			if (af == AF_INET) {
+				sad = (struct sockaddr_in *)sa;
+				if (inet_pton(af, addr, &sad->sin_addr) == 1) {
+					sad->sin_len = sizeof(*sad);
+					sad->sin_family = AF_INET;
+					sad->sin_port = htons(portv);
+					return (0);
+				}
+			} else {
+				sad6 = (struct sockaddr_in6 *)sa;
+				if (inet_pton(af, addr, &sad6->sin6_addr)
+				    == 1) {
+					sad6->sin6_len = sizeof(*sad6);
+					sad6->sin6_family = AF_INET6;
+					sad6->sin6_port = htons(portv);
+					return (0);
+				}
+			}
+		}
+	} else {
+		if (i > 0) {
+			error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
+			if (error)
+				goto nfsmout;
+		}
+	}
+	error = EPERM;
+nfsmout:
+	return (error);
+}
+
 /*
  * Handle an NFSv4.1 Sequence request for the session.
  */

Modified: projects/nfsv4.1-client/sys/fs/nfs/nfs_var.h
==============================================================================
--- projects/nfsv4.1-client/sys/fs/nfs/nfs_var.h	Wed Jan  4 02:04:20 2012	(r229459)
+++ projects/nfsv4.1-client/sys/fs/nfs/nfs_var.h	Wed Jan  4 03:14:10 2012	(r229460)
@@ -74,6 +74,7 @@ struct nfscllockowner;
 struct nfscllock;
 struct nfscldeleg;
 struct nfscllayout;
+struct nfsclfldevinfo;
 struct nfsv4lock;
 struct nfsvattr;
 struct nfs_vattr;
@@ -259,6 +260,8 @@ int nfsrv_mtostr(struct nfsrv_descript *
 int nfsrv_checkutf8(u_int8_t *, int);
 int newnfs_sndlock(int *);
 void newnfs_sndunlock(int *);
+int nfsv4_getipaddr(struct nfsrv_descript *, struct sockaddr_storage *,
+    int *);
 int nfsv4_seqsession(uint32_t, uint32_t, uint32_t, struct nfsslot *,
     struct mbuf **, uint16_t);
 void nfsv4_seqsess_cacherep(uint32_t, struct nfsslot *, struct mbuf *);
@@ -443,6 +446,8 @@ int nfsrpc_destroyclient(struct nfsmount
     struct ucred *, NFSPROC_T *);
 int nfsrpc_layoutget(vnode_t, int, uint64_t, uint64_t, uint64_t,
     struct nfscllayout *, struct ucred *, NFSPROC_T *, void *);
+int nfsrpc_getdeviceinfo(struct nfsmount *, uint8_t *, int, uint32_t *,
+    struct nfsclfldevinfo **, struct ucred *, NFSPROC_T *);
 
 /* nfs_clstate.c */
 int nfscl_open(vnode_t, u_int8_t *, int, u_int32_t, int,

Modified: projects/nfsv4.1-client/sys/fs/nfs/nfsclstate.h
==============================================================================
--- projects/nfsv4.1-client/sys/fs/nfs/nfsclstate.h	Wed Jan  4 02:04:20 2012	(r229459)
+++ projects/nfsv4.1-client/sys/fs/nfs/nfsclstate.h	Wed Jan  4 03:14:10 2012	(r229460)
@@ -232,6 +232,79 @@ struct nfsclflayout {
 };
 
 /*
+ * Stores the NFSv4.1 Device Info. Malloc'd to the correct length to
+ * store the list of indices and list of network addresses.
+ * nfsdi_data[] is allocated the following way:
+ * - nfsdi_addrcnt * struct sockaddr_storage
+ * - stripe indices, each stored as one byte, since there can be many
+ *   of them. (This implies a limit of 256 on nfsdi_addrcnt, since the
+ *   indices select which address. It is defined as uint64_t to ensure proper
+ *   alignment.)
+ */
+struct nfsclfldevinfo {
+	TAILQ_ENTRY(nfsclfldevinfo)	nfsdi_list;
+	LIST_ENTRY(nfsclfldevinfo)	nfsdi_hash;
+	uint8_t				nfsdi_deviceid[NFSX_V4DEVICEID];
+	struct nfsclclient		*nfsdi_clp;
+	uint16_t			nfsdi_stripecnt;
+	uint64_t			nfsdi_addrcnt;
+	uint8_t				nfsdi_data[1];
+};
+
+/* These inline functions return values from nfsdi_data[]. */
+/*
+ * Return a pointer to the address at "pos".
+ */
+static __inline void *
+nfsfldi_addr(struct nfsclfldevinfo *ndi, int pos)
+{
+
+	if (pos > ndi->nfsdi_addrcnt)
+		return (NULL);
+	return (&ndi->nfsdi_data[pos * sizeof(struct sockaddr_storage)]);
+}
+
+/*
+ * Return the Nth ("pos") stripe index.
+ */
+static __inline int
+nfsfldi_stripeindex(struct nfsclfldevinfo *ndi, int pos)
+{
+
+	if (pos > ndi->nfsdi_stripecnt)
+		return (-1);
+	return ((int)ndi->nfsdi_data[pos + ndi->nfsdi_addrcnt *
+	    sizeof(struct sockaddr_storage)]);
+}
+
+/*
+ * Set the Nth ("pos") stripe index to "val".
+ */
+static __inline void
+nfsfldi_setstripeindex(struct nfsclfldevinfo *ndi, int pos, uint8_t val)
+{
+
+	if (pos > ndi->nfsdi_stripecnt)
+		return;
+	ndi->nfsdi_data[pos + ndi->nfsdi_addrcnt *
+	    sizeof(struct sockaddr_storage)] = val;
+}
+
+/*
+ * Return a pointer to the address referred to by stripe index "pos".
+ */
+static __inline void *
+nfsfldi_stripeaddr(struct nfsclfldevinfo *ndi, int pos)
+{
+	int i;
+
+	i = nfsfldi_stripeindex(ndi, pos);
+	if (i < 0)
+		return (NULL);
+	return (nfsfldi_addr(ndi, i));
+}
+
+/*
  * Macro for incrementing the seqid#.
  */
 #define	NFSCL_INCRSEQID(s, n)	do { 					\

Modified: projects/nfsv4.1-client/sys/fs/nfs/nfsport.h
==============================================================================
--- projects/nfsv4.1-client/sys/fs/nfs/nfsport.h	Wed Jan  4 02:04:20 2012	(r229459)
+++ projects/nfsv4.1-client/sys/fs/nfs/nfsport.h	Wed Jan  4 03:14:10 2012	(r229460)
@@ -733,6 +733,7 @@ MALLOC_DECLARE(M_NEWNFSDIRECTIO);
 MALLOC_DECLARE(M_NEWNFSMNT);
 MALLOC_DECLARE(M_NEWNFSDROLLBACK);
 MALLOC_DECLARE(M_NEWNFSFLAYOUT);
+MALLOC_DECLARE(M_NEWNFSDEVINFO);
 #define	M_NFSRVCACHE	M_NEWNFSRVCACHE
 #define	M_NFSDCLIENT	M_NEWNFSDCLIENT
 #define	M_NFSDSTATE	M_NEWNFSDSTATE
@@ -753,6 +754,7 @@ MALLOC_DECLARE(M_NEWNFSFLAYOUT);
 #define	M_NFSDIRECTIO	M_NEWNFSDIRECTIO
 #define	M_NFSDROLLBACK	M_NEWNFSDROLLBACK
 #define	M_NFSFLAYOUT	M_NEWNFSFLAYOUT
+#define	M_NFSDEVINFO	M_NEWNFSDEVINFO
 
 #define	NFSINT_SIGMASK(set) 						\
 	(SIGISMEMBER(set, SIGINT) || SIGISMEMBER(set, SIGTERM) ||	\

Modified: projects/nfsv4.1-client/sys/fs/nfsclient/nfs_clrpcops.c
==============================================================================
--- projects/nfsv4.1-client/sys/fs/nfsclient/nfs_clrpcops.c	Wed Jan  4 02:04:20 2012	(r229459)
+++ projects/nfsv4.1-client/sys/fs/nfsclient/nfs_clrpcops.c	Wed Jan  4 03:14:10 2012	(r229460)
@@ -4593,3 +4593,144 @@ nfsmout:
 	return (error);
 }
 
+/*
+ * Do the NFSv4.1 Get Device Info.
+ */
+int
+nfsrpc_getdeviceinfo(struct nfsmount *nmp, uint8_t *deviceid, int layouttype,
+    uint32_t *notifybitsp, struct nfsclfldevinfo **ndip, struct ucred *cred,
+    NFSPROC_T *p)
+{
+	uint32_t cnt, *tl;
+	struct nfsrv_descript nfsd;
+	struct sockaddr_storage ss, *sa;
+	struct nfsrv_descript *nd = &nfsd;
+	struct nfsclfldevinfo *ndi;
+	int addrcnt, bitcnt, error, i, isudp, j, pos, safilled, stripecnt;
+	uint8_t stripeindex;
+
+	*ndip = NULL;
+	ndi = NULL;
+	nfscl_reqstart(nd, NFSPROC_GETDEVICEINFO, nmp, NULL, 0, NULL, NULL);
+	NFSM_BUILD(tl, uint32_t *, NFSX_V4DEVICEID + 3 * NFSX_UNSIGNED);
+	NFSBCOPY(deviceid, tl, NFSX_V4DEVICEID);
+	tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
+	*tl++ = txdr_unsigned(layouttype);
+	*tl++ = txdr_unsigned(100000);
+	if (*notifybitsp != 0) {
+		*tl = txdr_unsigned(1);		/* One word of bits. */
+		NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
+		*tl = txdr_unsigned(*notifybitsp);
+	} else
+		*tl = txdr_unsigned(0);
+	nd->nd_flag |= ND_USEGSSNAME;
+	error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
+	    NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
+	if (error != 0)
+		return (error);
+	if (nd->nd_repstat == 0) {
+		NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED);
+		if (layouttype != fxdr_unsigned(int, *tl++))
+			printf("EEK! devinfo layout type not same!\n");
+		stripecnt = fxdr_unsigned(int, *++tl);
+		if (stripecnt < 1 || stripecnt > 4096) {
+			printf("NFS devinfo stripecnt %d: out of range\n",
+			    stripecnt);
+			error = NFSERR_BADXDR;
+			goto nfsmout;
+		}
+		NFSM_DISSECT(tl, uint32_t *, (stripecnt + 1) * NFSX_UNSIGNED);
+		addrcnt = fxdr_unsigned(int, *(tl + stripecnt));
+		if (addrcnt < 0 || addrcnt > 128) {
+			printf("NFS devinfo addrcnt %d: out of range\n",
+			    addrcnt);
+			error = NFSERR_BADXDR;
+			goto nfsmout;
+		}
+
+		/*
+		 * Now we know how many stripe indices and addresses, so
+		 * we can allocate the structure the correct size.
+		 */
+		ndi = malloc(sizeof(*ndi) + addrcnt *
+		    sizeof(struct sockaddr_storage) + stripecnt - 1,
+		    M_NFSDEVINFO, M_WAITOK);
+		NFSBCOPY(deviceid, ndi->nfsdi_deviceid, NFSX_V4DEVICEID);
+		ndi->nfsdi_stripecnt = stripecnt;
+		ndi->nfsdi_addrcnt = addrcnt;
+		/* Fill in the stripe indices. */
+		for (i = 0; i < stripecnt; i++) {
+			stripeindex = fxdr_unsigned(uint8_t, *tl++);
+			if (stripeindex >= addrcnt) {
+				printf("NFS devinfo stripeindex %d: too big\n",
+				    (int)stripeindex);
+				error = NFSERR_BADXDR;
+				goto nfsmout;
+			}
+			nfsfldi_setstripeindex(ndi, i, stripeindex);
+		}
+
+		/* Now, dissect the server address(es). */
+		for (i = 0; i < addrcnt; i++) {
+			NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
+			cnt = fxdr_unsigned(uint32_t, *tl);
+			if (cnt == 0) {
+				printf("NFS devinfo 0 len addrlist\n");
+				error = NFSERR_BADXDR;
+				goto nfsmout;
+			}
+			sa = nfsfldi_addr(ndi, i);
+			pos = arc4random() % cnt;	/* Choose one. */
+			safilled = 0;
+			for (j = 0; j < cnt; j++) {
+				error = nfsv4_getipaddr(nd, &ss, &isudp);
+				if (error != 0 && error != EPERM) {
+					error = NFSERR_BADXDR;
+					goto nfsmout;
+				}
+				if (error == 0 && isudp == 0) {
+					/*
+					 * The algorithm is:
+					 * - use "pos" entry if it is of the
+					 *   same af_family or none of them
+					 *   is of the same af_family
+					 * else
+					 * - use the first one of the same
+					 *   af_family.
+					 */
+					if ((safilled == 0 && ss.ss_family ==
+					     nmp->nm_nam->sa_family) ||
+					    (j == pos &&
+					     (safilled == 0 || ss.ss_family ==
+					      nmp->nm_nam->sa_family)) ||
+					    (safilled == 1 && ss.ss_family ==
+					     nmp->nm_nam->sa_family)) {
+						NFSBCOPY(&ss, sa, sizeof(ss));
+						if (ss.ss_family ==
+						    nmp->nm_nam->sa_family)
+							safilled = 2;
+						else
+							safilled = 1;
+					}
+				}
+			}
+		}
+
+		/* And the notify bits. */
+		NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
+		bitcnt = fxdr_unsigned(int, *tl);
+		if (bitcnt > 0) {
+			NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
+			*notifybitsp = fxdr_unsigned(uint32_t, *tl);
+		}
+		*ndip = ndi;
+	}
+	if (nd->nd_repstat != 0)
+		error = nd->nd_repstat;
+nfsmout:
+	if (error != 0 && ndi != NULL)
+		free(ndi, M_NFSDEVINFO);
+	mbuf_freem(nd->nd_mrep);
+	return (error);
+}
+



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201201040314.q043EAWe057348>