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>