svn commit: r229460 - in projects/nfsv4.1-client/sys/fs: nfs
nfsclient
Rick Macklem
rmacklem at FreeBSD.org
Wed Jan 4 03:14:11 UTC 2012
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);
+}
+
More information about the svn-src-projects
mailing list