/*
- * Copyright (c) 2000-2015 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2020 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
* FreeBSD-Id: nfs_socket.c,v 1.30 1997/10/28 15:59:07 bde Exp $
*/
+#include <nfs/nfs_conf.h>
+#if CONFIG_NFS
+
/*
* Socket operations for use by nfs
*/
#include <sys/domain.h>
#include <sys/protosw.h>
#include <sys/socket.h>
+#include <sys/un.h>
#include <sys/syslog.h>
#include <sys/tprintf.h>
#include <libkern/OSAtomic.h>
+#include <sys/reboot.h>
#include <sys/time.h>
#include <kern/clock.h>
#include <kern/task.h>
#include <nfs/nfsnode.h>
#define NFS_SOCK_DBG(...) NFS_DBG(NFS_FAC_SOCK, 7, ## __VA_ARGS__)
+#define NFS_SOCK_DUMP_MBUF(msg, mb) if (NFS_IS_DBG(NFS_FAC_SOCK, 15)) nfs_dump_mbuf(__func__, __LINE__, (msg), (mb))
+
+#ifndef SUN_LEN
+#define SUN_LEN(su) \
+ (sizeof(*(su)) - sizeof((su)->sun_path) + strnlen((su)->sun_path, sizeof((su)->sun_path)))
+#endif /* SUN_LEN */
/* XXX */
boolean_t current_thread_aborted(void);
kern_return_t thread_terminate(thread_t);
+ZONE_DECLARE(nfs_fhandle_zone, "fhandle", sizeof(struct fhandle), ZC_NONE);
+ZONE_DECLARE(nfs_req_zone, "NFS req", sizeof(struct nfsreq), ZC_NONE);
+ZONE_DECLARE(nfsrv_descript_zone, "NFSV3 srvdesc",
+ sizeof(struct nfsrv_descript), ZC_NONE);
+
-#if NFSSERVER
+#if CONFIG_NFS_SERVER
int nfsrv_sock_max_rec_queue_length = 128; /* max # RPC records queued on (UDP) socket */
int nfsrv_getstream(struct nfsrv_sock *, int);
int nfsrv_getreq(struct nfsrv_descript *);
extern int nfsv3_procid[NFS_NPROCS];
-#endif /* NFSSERVER */
+#endif /* CONFIG_NFS_SERVER */
/*
* compare two sockaddr structures
return -1;
}
-#if NFSCLIENT
+#if CONFIG_NFS_CLIENT
int nfs_connect_search_new_socket(struct nfsmount *, struct nfs_socket_search *, struct timeval *);
int nfs_connect_search_socket_connect(struct nfsmount *, struct nfs_socket *, int);
* 3 - read
* 4 - write
*/
-static int proct[NFS_NPROCS] = {
- 0, 1, 0, 2, 1, 3, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0
+static const int proct[] = {
+ [NFSPROC_NULL] = 0,
+ [NFSPROC_GETATTR] = 1,
+ [NFSPROC_SETATTR] = 0,
+ [NFSPROC_LOOKUP] = 2,
+ [NFSPROC_ACCESS] = 1,
+ [NFSPROC_READLINK] = 3,
+ [NFSPROC_READ] = 3,
+ [NFSPROC_WRITE] = 4,
+ [NFSPROC_CREATE] = 0,
+ [NFSPROC_MKDIR] = 0,
+ [NFSPROC_SYMLINK] = 0,
+ [NFSPROC_MKNOD] = 0,
+ [NFSPROC_REMOVE] = 0,
+ [NFSPROC_RMDIR] = 0,
+ [NFSPROC_RENAME] = 0,
+ [NFSPROC_LINK] = 0,
+ [NFSPROC_READDIR] = 3,
+ [NFSPROC_READDIRPLUS] = 3,
+ [NFSPROC_FSSTAT] = 0,
+ [NFSPROC_FSINFO] = 0,
+ [NFSPROC_PATHCONF] = 0,
+ [NFSPROC_COMMIT] = 0,
+ [NFSPROC_NOOP] = 0,
};
/*
* Get the mntfromname (or path portion only) for a given location.
*/
void
-nfs_location_mntfromname(struct nfs_fs_locations *locs, struct nfs_location_index idx, char *s, int size, int pathonly)
+nfs_location_mntfromname(struct nfs_fs_locations *locs, struct nfs_location_index idx, char *s, size_t size, int pathonly)
{
struct nfs_fs_location *fsl = locs->nl_locations[idx.nli_loc];
char *p;
p = s;
if (!pathonly) {
- cnt = snprintf(p, size, "%s:", fsl->nl_servers[idx.nli_serv]->ns_name);
+ char *name = fsl->nl_servers[idx.nli_serv]->ns_name;
+ if (name == NULL) {
+ name = "";
+ }
+ if (*name == '\0') {
+ if (*fsl->nl_servers[idx.nli_serv]->ns_addresses[idx.nli_addr]) {
+ name = fsl->nl_servers[idx.nli_serv]->ns_addresses[idx.nli_addr];
+ }
+ cnt = scnprintf(p, size, "<%s>:", name);
+ } else {
+ cnt = scnprintf(p, size, "%s:", name);
+ }
p += cnt;
size -= cnt;
}
}
/* append each server path component */
for (i = 0; (size > 0) && (i < (int)fsl->nl_path.np_compcount); i++) {
- cnt = snprintf(p, size, "/%s", fsl->nl_path.np_components[i]);
+ cnt = scnprintf(p, size, "/%s", fsl->nl_path.np_components[i]);
p += cnt;
size -= cnt;
}
int error = 0, recv = 1;
if (nso->nso_flags & NSO_CONNECTING) {
- NFS_SOCK_DBG("nfs connect - socket %p upcall - connecting\n", nso);
+ NFS_SOCK_DBG("nfs connect - socket %p upcall - connecting flags = %8.8x\n", nso, nso->nso_flags);
wakeup(nso->nso_wake);
return;
}
lck_mtx_unlock(&nso->nso_lock);
return;
}
- NFS_SOCK_DBG("nfs connect - socket %p upcall\n", nso);
+ NFS_SOCK_DBG("nfs connect - socket %p upcall %8.8x\n", nso, nso->nso_flags);
nso->nso_flags |= NSO_UPCALL;
/* loop while we make error-free progress */
m = NULL;
if (nso->nso_sotype == SOCK_STREAM) {
error = nfs_rpc_record_read(so, &nso->nso_rrs, MSG_DONTWAIT, &recv, &m);
+ NFS_SOCK_DBG("nfs_rpc_record_read returned %d recv = %d\n", error, recv);
} else {
rcvlen = 1000000;
error = sock_receivembuf(so, NULL, &m, MSG_DONTWAIT, &rcvlen);
uint32_t reply = 0, rxid = 0, verf_type, verf_len;
uint32_t reply_status, rejected_status, accepted_status;
+ NFS_SOCK_DUMP_MBUF("Got mbuf from ping", m);
nfsm_chain_dissect_init(error, &nmrep, m);
nfsm_chain_get_32(error, &nmrep, rxid);
nfsm_chain_get_32(error, &nmrep, reply);
}
nfsm_chain_get_32(error, &nmrep, accepted_status);
nfsmout_if(error);
+ NFS_SOCK_DBG("Recevied accepted_status of %d nso_version = %d\n", accepted_status, nso->nso_version);
if ((accepted_status == RPC_PROGMISMATCH) && !nso->nso_version) {
uint32_t minvers, maxvers;
nfsm_chain_get_32(error, &nmrep, minvers);
nfsmout:
nso->nso_flags &= ~NSO_PINGING;
if (error) {
+ NFS_SOCK_DBG("nfs upcalled failed for %d program %d vers error = %d\n",
+ nso->nso_protocol, nso->nso_version, error);
nso->nso_error = error;
nso->nso_flags |= NSO_DEAD;
} else {
nso->nso_flags &= ~NSO_UPCALL;
if ((error != EWOULDBLOCK) && (error || !recv)) {
/* problems with the socket... */
+ NFS_SOCK_DBG("connect upcall failed %d\n", error);
nso->nso_error = error ? error : EPIPE;
nso->nso_flags |= NSO_DEAD;
wakeup(nso->nso_wake);
nfs_socket_create(
struct nfsmount *nmp,
struct sockaddr *sa,
- int sotype,
+ uint8_t sotype,
in_port_t port,
uint32_t protocol,
uint32_t vers,
struct nfs_socket *nso;
struct timeval now;
int error;
+#define NFS_SOCKET_DEBUGGING
#ifdef NFS_SOCKET_DEBUGGING
- char naddr[MAX_IPv6_STR_LEN];
+ char naddr[sizeof((struct sockaddr_un *)0)->sun_path];
void *sinaddr;
- if (sa->sa_family == AF_INET) {
+ switch (sa->sa_family) {
+ case AF_INET:
+ if (sa->sa_len != sizeof(struct sockaddr_in)) {
+ return EINVAL;
+ }
sinaddr = &((struct sockaddr_in*)sa)->sin_addr;
- } else {
+ if (inet_ntop(sa->sa_family, sinaddr, naddr, sizeof(naddr)) != naddr) {
+ strlcpy(naddr, "<unknown>", sizeof(naddr));
+ }
+ break;
+ case AF_INET6:
+ if (sa->sa_len != sizeof(struct sockaddr_in6)) {
+ return EINVAL;
+ }
sinaddr = &((struct sockaddr_in6*)sa)->sin6_addr;
- }
- if (inet_ntop(sa->sa_family, sinaddr, naddr, sizeof(naddr)) != naddr) {
- strlcpy(naddr, "<unknown>", sizeof(naddr));
+ if (inet_ntop(sa->sa_family, sinaddr, naddr, sizeof(naddr)) != naddr) {
+ strlcpy(naddr, "<unknown>", sizeof(naddr));
+ }
+ break;
+ case AF_LOCAL:
+ if (sa->sa_len != sizeof(struct sockaddr_un) && sa->sa_len != SUN_LEN((struct sockaddr_un *)sa)) {
+ return EINVAL;
+ }
+ strlcpy(naddr, ((struct sockaddr_un *)sa)->sun_path, sizeof(naddr));
+ break;
+ default:
+ strlcpy(naddr, "<unsupported address family>", sizeof(naddr));
+ break;
}
#else
char naddr[1] = { 0 };
}
return ENOMEM;
}
- lck_mtx_init(&nso->nso_lock, nfs_request_grp, LCK_ATTR_NULL);
+ lck_mtx_init(&nso->nso_lock, &nfs_request_grp, LCK_ATTR_NULL);
nso->nso_sotype = sotype;
if (nso->nso_sotype == SOCK_STREAM) {
nfs_rpc_record_state_init(&nso->nso_rrs);
microuptime(&now);
nso->nso_timestamp = now.tv_sec;
bcopy(sa, nso->nso_saddr, sa->sa_len);
- if (sa->sa_family == AF_INET) {
- ((struct sockaddr_in*)nso->nso_saddr)->sin_port = htons(port);
- } else if (sa->sa_family == AF_INET6) {
- ((struct sockaddr_in6*)nso->nso_saddr)->sin6_port = htons(port);
+ switch (sa->sa_family) {
+ case AF_INET:
+ case AF_INET6:
+ if (sa->sa_family == AF_INET) {
+ ((struct sockaddr_in*)nso->nso_saddr)->sin_port = htons(port);
+ } else if (sa->sa_family == AF_INET6) {
+ ((struct sockaddr_in6*)nso->nso_saddr)->sin6_port = htons(port);
+ }
+ break;
+ case AF_LOCAL:
+ break;
}
nso->nso_protocol = protocol;
nso->nso_version = vers;
resvport ? "r" : "", port, protocol, vers);
nfs_socket_destroy(nso);
} else {
- NFS_SOCK_DBG("nfs connect %s created socket %p %s type %d%s port %d prot %d %d\n",
+ NFS_SOCK_DBG("nfs connect %s created socket %p <%s> type %d%s port %d prot %d %d\n",
vfs_statfs(nmp->nm_mountp)->f_mntfromname, nso, naddr,
sotype, resvport ? "r" : "", port, protocol, vers);
*nsop = nso;
void
nfs_socket_destroy(struct nfs_socket *nso)
{
- struct timespec ts = { 4, 0 };
+ struct timespec ts = { .tv_sec = 4, .tv_nsec = 0 };
+ NFS_SOCK_DBG("Destoring socket %p flags = %8.8x error = %d\n", nso, nso->nso_flags, nso->nso_error);
lck_mtx_lock(&nso->nso_lock);
nso->nso_flags |= NSO_DISCONNECTING;
if (nso->nso_flags & NSO_UPCALL) { /* give upcall a chance to complete */
if (nso->nso_sotype == SOCK_STREAM) {
nfs_rpc_record_state_cleanup(&nso->nso_rrs);
}
- lck_mtx_destroy(&nso->nso_lock, nfs_request_grp);
+ lck_mtx_destroy(&nso->nso_lock, &nfs_request_grp);
if (nso->nso_saddr) {
FREE(nso->nso_saddr, M_SONAME);
}
* Soft mounts will want to abort sooner.
*/
struct timeval timeo;
- int on = 1, proto;
+ int on = 1, proto, reserve, error;
timeo.tv_usec = 0;
timeo.tv_sec = (NMFLAG(nmp, SOFT) || nfs_can_squish(nmp)) ? 5 : 60;
sock_setsockopt(nso->nso_so, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
}
}
- if (nso->nso_sotype == SOCK_DGRAM) { /* set socket buffer sizes for UDP */
- int reserve = NFS_UDPSOCKBUF;
- sock_setsockopt(nso->nso_so, SOL_SOCKET, SO_SNDBUF, &reserve, sizeof(reserve));
- sock_setsockopt(nso->nso_so, SOL_SOCKET, SO_RCVBUF, &reserve, sizeof(reserve));
+
+ /* set socket buffer sizes for UDP/TCP */
+ reserve = (nso->nso_sotype == SOCK_DGRAM) ? NFS_UDPSOCKBUF : MAX(nfs_tcp_sockbuf, nmp->nm_wsize * 2);
+ {
+ error = sock_setsockopt(nso->nso_so, SOL_SOCKET, SO_SNDBUF, &reserve, sizeof(reserve));
+ }
+
+ if (error) {
+ log(LOG_INFO, "nfs_socket_options: error %d setting SO_SNDBUF to %u\n", error, reserve);
+ }
+
+ reserve = (nso->nso_sotype == SOCK_DGRAM) ? NFS_UDPSOCKBUF : MAX(nfs_tcp_sockbuf, nmp->nm_rsize * 2);
+ error = sock_setsockopt(nso->nso_so, SOL_SOCKET, SO_RCVBUF, &reserve, sizeof(reserve));
+ if (error) {
+ log(LOG_INFO, "nfs_socket_options: error %d setting SO_RCVBUF to %u\n", error, reserve);
}
+
/* set SO_NOADDRERR to detect network changes ASAP */
sock_setsockopt(nso->nso_so, SOL_SOCKET, SO_NOADDRERR, &on, sizeof(on));
/* just playin' it safe with upcalls */
fsl = nmp->nm_locations.nl_locations[nss->nss_nextloc.nli_loc];
fss = fsl->nl_servers[nss->nss_nextloc.nli_serv];
addrstr = fss->ns_addresses[nss->nss_nextloc.nli_addr];
+ NFS_SOCK_DBG("Trying address %s for program %d on port %d\n", addrstr, nss->nss_protocol, nss->nss_port);
+ if (*addrstr == '\0') {
+ /*
+ * We have an unspecified local domain address. We use the program to translate to
+ * a well known local transport address. We only support PMAPROG and NFS for this.
+ */
+ if (nss->nss_protocol == PMAPPROG) {
+ addrstr = (nss->nss_sotype == SOCK_DGRAM) ? RPCB_TICLTS_PATH : RPCB_TICOTSORD_PATH;
+ } else if (nss->nss_protocol == NFS_PROG) {
+ addrstr = nmp->nm_nfs_localport;
+ if (!addrstr || *addrstr == '\0') {
+ addrstr = (nss->nss_sotype == SOCK_DGRAM) ? NFS_TICLTS_PATH : NFS_TICOTSORD_PATH;
+ }
+ }
+ NFS_SOCK_DBG("Calling prog %d with <%s>\n", nss->nss_protocol, addrstr);
+ }
if (!nfs_uaddr2sockaddr(addrstr, (struct sockaddr*)&ss)) {
+ NFS_SOCK_DBG("Could not convert address %s to socket\n", addrstr);
nfs_location_next(&nmp->nm_locations, &nss->nss_nextloc);
nss->nss_addrcnt -= 1;
nss->nss_last = -2;
}
/* Check that socket family is acceptable. */
if (nmp->nm_sofamily && (ss.ss_family != nmp->nm_sofamily)) {
+ NFS_SOCK_DBG("Skipping socket family %d, want mount family %d\n", ss.ss_family, nmp->nm_sofamily);
nfs_location_next(&nmp->nm_locations, &nss->nss_nextloc);
nss->nss_addrcnt -= 1;
nss->nss_last = -2;
nso->nso_wake = nss;
error = sock_setupcall(nso->nso_so, nfs_connect_upcall, nso);
if (error) {
+ NFS_SOCK_DBG("sock_setupcall failed for socket %p setting nfs_connect_upcall error = %d\n", nso, error);
lck_mtx_lock(&nso->nso_lock);
nso->nso_error = error;
nso->nso_flags |= NSO_DEAD;
/* initiate the connection */
nso->nso_flags |= NSO_CONNECTING;
lck_mtx_unlock(&nso->nso_lock);
- NFS_SOCK_DBG("nfs connect %s connecting socket %p\n",
- vfs_statfs(nmp->nm_mountp)->f_mntfromname, nso);
+ NFS_SOCK_DBG("nfs connect %s connecting socket %p %s\n",
+ vfs_statfs(nmp->nm_mountp)->f_mntfromname, nso,
+ nso->nso_saddr->sa_family == AF_LOCAL ? ((struct sockaddr_un*)nso->nso_saddr)->sun_path : "");
error = sock_connect(nso->nso_so, nso->nso_saddr, MSG_DONTWAIT);
+ if (error) {
+ NFS_SOCK_DBG("nfs connect %s connecting socket %p returned %d\n",
+ vfs_statfs(nmp->nm_mountp)->f_mntfromname, nso, error);
+ }
lck_mtx_lock(&nso->nso_lock);
if (error && (error != EINPROGRESS)) {
nso->nso_error = error;
}
}
lck_mtx_unlock(&nso->nso_lock);
+ NFS_SOCK_DBG("Pinging socket %p %d %d %d\n", nso, nso->nso_sotype, nso->nso_protocol, vers);
error = nfsm_rpchead2(nmp, nso->nso_sotype, nso->nso_protocol, vers, 0, RPCAUTH_SYS,
vfs_context_ucred(vfs_context_kernel()), NULL, NULL, &xid, &mreq);
lck_mtx_lock(&nso->nso_lock);
reqlen += mbuf_len(m);
}
lck_mtx_unlock(&nso->nso_lock);
+ NFS_SOCK_DUMP_MBUF("Sending ping packet", mreq);
error = sock_sendmbuf(nso->nso_so, &msg, mreq, 0, &sentlen);
NFS_SOCK_DBG("nfs connect %s verifying socket %p send rv %d\n",
vfs_statfs(nmp->nm_mountp)->f_mntfromname, nso, error);
continue;
}
lck_mtx_unlock(&nso->nso_lock);
- NFS_SOCK_DBG("nfs connect %s reaping socket %p %d\n",
- vfs_statfs(nmp->nm_mountp)->f_mntfromname, nso, nso->nso_error);
+ NFS_SOCK_DBG("nfs connect %s reaping socket %p error = %d flags = %8.8x\n",
+ vfs_statfs(nmp->nm_mountp)->f_mntfromname, nso, nso->nso_error, nso->nso_flags);
nfs_socket_search_update_error(nss, nso->nso_error);
TAILQ_REMOVE(&nss->nss_socklist, nso, nso_link);
nss->nss_sockcnt--;
struct sockaddr_storage ss;
struct sockaddr *saddr, *oldsaddr;
sock_upcall upcall;
- struct timeval now, start;
+#if CONFIG_NFS4
+ struct timeval now;
+#endif
+ struct timeval start;
int error, savederror, nfsvers;
int tryv4 = 1;
uint8_t sotype = nmp->nm_sotype ? nmp->nm_sotype : SOCK_STREAM;
fhandle_t *fh = NULL;
char *path = NULL;
- in_port_t port;
+ in_port_t port = 0;
int addrtotal = 0;
/* paranoia... check that we have at least one address in the locations */
/* First time connecting, we may need to negotiate some things */
if (!(nmp->nm_sockflags & NMSOCK_HASCONNECTED)) {
+ NFS_SOCK_DBG("so_family = %d\n", nmp->nm_sofamily);
+ NFS_SOCK_DBG("nfs port = %d local: <%s>\n", nmp->nm_nfsport, nmp->nm_nfs_localport ? nmp->nm_nfs_localport : "");
+ NFS_SOCK_DBG("mount port = %d local: <%s>\n", nmp->nm_mountport, nmp->nm_mount_localport ? nmp->nm_mount_localport : "");
if (!nmp->nm_vers) {
/* No NFS version specified... */
if (!nmp->nm_nfsport || (!NM_OMATTR_GIVEN(nmp, FH) && !nmp->nm_mountport)) {
+#if CONFIG_NFS4
if (PVER2MAJOR(nmp->nm_max_vers) >= NFS_VER4 && tryv4) {
nss.nss_port = NFS_PORT;
nss.nss_protocol = NFS_PROG;
nss.nss_version = 4;
nss.nss_flags |= NSS_FALLBACK2PMAP;
} else {
- /* ...connect to portmapper first if we (may) need any ports. */
- nss.nss_port = PMAPPORT;
- nss.nss_protocol = PMAPPROG;
- nss.nss_version = 0;
- }
+#endif
+ /* ...connect to portmapper first if we (may) need any ports. */
+ nss.nss_port = PMAPPORT;
+ nss.nss_protocol = PMAPPROG;
+ nss.nss_version = 0;
+#if CONFIG_NFS4
+ }
+#endif
} else {
/* ...connect to NFS port first. */
nss.nss_port = nmp->nm_nfsport;
nss.nss_protocol = NFS_PROG;
nss.nss_version = 0;
}
+#if CONFIG_NFS4
} else if (nmp->nm_vers >= NFS_VER4) {
if (tryv4) {
/* For NFSv4, we use the given (or default) port. */
nss.nss_protocol = PMAPPROG;
nss.nss_version = 0;
}
+#endif
} else {
/* For NFSv3/v2... */
if (!nmp->nm_nfsport || (!NM_OMATTR_GIVEN(nmp, FH) && !nmp->nm_mountport)) {
vfs_statfs(nmp->nm_mountp)->f_mntfromname);
}
if (fh) {
- FREE(fh, M_TEMP);
+ NFS_ZFREE(nfs_fhandle_zone, fh);
}
if (path) {
- FREE_ZONE(path, MAXPATHLEN, M_NAMEI);
+ NFS_ZFREE(ZV_NAMEI, path);
}
NFS_SOCK_DBG("nfs connect %s search failed, returning %d\n",
vfs_statfs(nmp->nm_mountp)->f_mntfromname, error);
/* We may be speaking to portmap first... to determine port(s). */
if (nso->nso_saddr->sa_family == AF_INET) {
port = ntohs(((struct sockaddr_in*)nso->nso_saddr)->sin_port);
- } else {
+ } else if (nso->nso_saddr->sa_family == AF_INET6) {
port = ntohs(((struct sockaddr_in6*)nso->nso_saddr)->sin6_port);
+ } else if (nso->nso_saddr->sa_family == AF_LOCAL) {
+ if (nso->nso_protocol == PMAPPROG) {
+ port = PMAPPORT;
+ }
}
+
if (port == PMAPPORT) {
/* Use this portmapper port to get the port #s we need. */
NFS_SOCK_DBG("nfs connect %s got portmapper socket %p\n",
((struct sockaddr_in*)&ss)->sin_port = htons(0);
} else if (ss.ss_family == AF_INET6) {
((struct sockaddr_in6*)&ss)->sin6_port = htons(0);
+ } else if (ss.ss_family == AF_LOCAL) {
+ if (((struct sockaddr_un*)&ss)->sun_path[0] == '/') {
+ NFS_SOCK_DBG("Looking up NFS socket over %s\n", ((struct sockaddr_un*)&ss)->sun_path);
+ }
}
for (; nfsvers >= (int)PVER2MAJOR(nmp->nm_min_vers); nfsvers--) {
if (nmp->nm_vers && nmp->nm_vers != nfsvers) {
continue; /* Wrong version */
}
+#if CONFIG_NFS4
if (nfsvers == NFS_VER4 && nso->nso_sotype == SOCK_DGRAM) {
continue; /* NFSv4 does not do UDP */
}
- error = nfs_portmap_lookup(nmp, vfs_context_current(), (struct sockaddr*)&ss,
- nso->nso_so, NFS_PROG, nfsvers,
- (nso->nso_sotype == SOCK_DGRAM) ? IPPROTO_UDP : IPPROTO_TCP, timeo);
+#endif
+ if (ss.ss_family == AF_LOCAL && nmp->nm_nfs_localport) {
+ struct sockaddr_un *sun = (struct sockaddr_un *)&ss;
+ NFS_SOCK_DBG("Using supplied local address %s for NFS_PROG\n", nmp->nm_nfs_localport);
+ strlcpy(sun->sun_path, nmp->nm_nfs_localport, sizeof(sun->sun_path));
+ error = 0;
+ } else {
+ NFS_SOCK_DBG("Calling Portmap/Rpcbind for NFS_PROG");
+ error = nfs_portmap_lookup(nmp, vfs_context_current(), (struct sockaddr*)&ss,
+ nso->nso_so, NFS_PROG, nfsvers, nso->nso_sotype, timeo);
+ }
if (!error) {
if (ss.ss_family == AF_INET) {
port = ntohs(((struct sockaddr_in*)&ss)->sin_port);
} else if (ss.ss_family == AF_INET6) {
port = ntohs(((struct sockaddr_in6*)&ss)->sin6_port);
+ } else if (ss.ss_family == AF_LOCAL) {
+ port = ((struct sockaddr_un *)&ss)->sun_path[0] ? NFS_PORT : 0;
}
if (!port) {
error = EPROGUNAVAIL;
}
+#if CONFIG_NFS4
if (port == NFS_PORT && nfsvers == NFS_VER4 && tryv4 == 0) {
continue; /* We already tried this */
}
+#endif
}
if (!error) {
break;
if (error) {
nfs_socket_search_update_error(&nss, error);
nfs_socket_destroy(nso);
+ NFS_SOCK_DBG("Could not lookup NFS socket address for version %d error = %d\n", nfsvers, error);
goto keepsearching;
}
+ } else if (nmp->nm_nfs_localport) {
+ strlcpy(((struct sockaddr_un*)&ss)->sun_path, nmp->nm_nfs_localport, sizeof(((struct sockaddr_un*)&ss)->sun_path));
+ NFS_SOCK_DBG("Using supplied nfs_local_port %s for NFS_PROG\n", nmp->nm_nfs_localport);
}
+
/* Create NFS protocol socket and add it to the list of sockets. */
/* N.B. If nfsvers is NFS_VER4 at this point then we're on a non standard port */
+ if (ss.ss_family == AF_LOCAL) {
+ NFS_SOCK_DBG("Creating NFS socket for %s port = %d\n", ((struct sockaddr_un*)&ss)->sun_path, port);
+ }
error = nfs_socket_create(nmp, (struct sockaddr*)&ss, nso->nso_sotype, port,
NFS_PROG, nfsvers, NMFLAG(nmp, RESVPORT), &nsonfs);
if (error) {
nfs_socket_search_update_error(&nss, error);
nfs_socket_destroy(nso);
+ NFS_SOCK_DBG("Could not create NFS socket: %d\n", error);
goto keepsearching;
}
nsonfs->nso_location = nso->nso_location;
nfs_socket_search_update_error(&nss, error);
nfs_socket_destroy(nsonfs);
nfs_socket_destroy(nso);
+ NFS_SOCK_DBG("Could not nfs_connect_upcall: %d", error);
goto keepsearching;
}
TAILQ_INSERT_TAIL(&nss.nss_socklist, nsonfs, nso_link);
error = 0;
bcopy(nso->nso_saddr, &ss, nso->nso_saddr->sa_len);
port = nmp->nm_mountport;
+ NFS_SOCK_DBG("mount port = %d\n", port);
if (ss.ss_family == AF_INET) {
((struct sockaddr_in*)&ss)->sin_port = htons(port);
} else if (ss.ss_family == AF_INET6) {
((struct sockaddr_in6*)&ss)->sin6_port = htons(port);
+ } else if (ss.ss_family == AF_LOCAL && nmp->nm_mount_localport) {
+ NFS_SOCK_DBG("Setting mount address to %s port = %d\n", nmp->nm_mount_localport, nmp->nm_mountport);
+ strlcpy(((struct sockaddr_un*)&ss)->sun_path, nmp->nm_mount_localport, sizeof(((struct sockaddr_un*)&ss)->sun_path));
}
if (!port) {
/* Get port/sockaddr for MOUNT version corresponding to NFS version. */
/* If NFS version is unknown, optimistically choose for NFSv3. */
int mntvers = (nfsvers == NFS_VER2) ? RPCMNT_VER1 : RPCMNT_VER3;
int mntproto = (NM_OMFLAG(nmp, MNTUDP) || (nso->nso_sotype == SOCK_DGRAM)) ? IPPROTO_UDP : IPPROTO_TCP;
+ NFS_SOCK_DBG("Looking up mount port with socket %p\n", nso->nso_so);
error = nfs_portmap_lookup(nmp, vfs_context_current(), (struct sockaddr*)&ss,
- nso->nso_so, RPCPROG_MNT, mntvers, mntproto, timeo);
+ nso->nso_so, RPCPROG_MNT, mntvers, mntproto == IPPROTO_UDP ? SOCK_DGRAM : SOCK_STREAM, timeo);
}
if (!error) {
if (ss.ss_family == AF_INET) {
port = ntohs(((struct sockaddr_in*)&ss)->sin_port);
} else if (ss.ss_family == AF_INET6) {
port = ntohs(((struct sockaddr_in6*)&ss)->sin6_port);
+ } else if (ss.ss_family == AF_LOCAL) {
+ port = (((struct sockaddr_un*)&ss)->sun_path[0] != '\0');
}
if (!port) {
error = EPROGUNAVAIL;
bcopy(&ss, nsonfs->nso_saddr2, ss.ss_len);
}
if (error) {
+ NFS_SOCK_DBG("Could not create mount sockaet address %d", error);
lck_mtx_lock(&nsonfs->nso_lock);
nsonfs->nso_error = error;
nsonfs->nso_flags |= NSO_DEAD;
lck_mtx_unlock(&nsonfs->nso_lock);
}
}
+ NFS_SOCK_DBG("Destroying socket %p so %p\n", nso, nso->nso_so);
nfs_socket_destroy(nso);
goto keepsearching;
}
saddr = nso->nso_saddr2;
if (!saddr) {
/* Need sockaddr for MOUNT port */
+ NFS_SOCK_DBG("Getting mount address mountport = %d, mount_localport = %s\n", nmp->nm_mountport, nmp->nm_mount_localport);
bcopy(nso->nso_saddr, &ss, nso->nso_saddr->sa_len);
port = nmp->nm_mountport;
if (ss.ss_family == AF_INET) {
((struct sockaddr_in*)&ss)->sin_port = htons(port);
} else if (ss.ss_family == AF_INET6) {
((struct sockaddr_in6*)&ss)->sin6_port = htons(port);
+ } else if (ss.ss_family == AF_LOCAL && nmp->nm_mount_localport) {
+ NFS_SOCK_DBG("Setting mount address to %s port = %d\n", nmp->nm_mount_localport, nmp->nm_mountport);
+ strlcpy(((struct sockaddr_un*)&ss)->sun_path, nmp->nm_mount_localport, sizeof(((struct sockaddr_un*)&ss)->sun_path));
}
if (!port) {
/* Get port/sockaddr for MOUNT version corresponding to NFS version. */
int mntvers = (nfsvers == NFS_VER2) ? RPCMNT_VER1 : RPCMNT_VER3;
- int mntproto = (NM_OMFLAG(nmp, MNTUDP) || (nso->nso_sotype == SOCK_DGRAM)) ? IPPROTO_UDP : IPPROTO_TCP;
+ int so_type = NM_OMFLAG(nmp, MNTUDP) ? SOCK_DGRAM : nso->nso_sotype;
error = nfs_portmap_lookup(nmp, vfs_context_current(), (struct sockaddr*)&ss,
- NULL, RPCPROG_MNT, mntvers, mntproto, timeo);
+ NULL, RPCPROG_MNT, mntvers, so_type, timeo);
if (ss.ss_family == AF_INET) {
port = ntohs(((struct sockaddr_in*)&ss)->sin_port);
} else if (ss.ss_family == AF_INET6) {
}
}
}
+ if (!error) {
+ error = nfs3_check_lockmode(nmp, saddr, nso->nso_sotype, timeo);
+ if (error) {
+ nfs_socket_search_update_error(&nss, error);
+ nfs_socket_destroy(nso);
+ return error;
+ }
+ }
if (saddr) {
- MALLOC(fh, fhandle_t *, sizeof(fhandle_t), M_TEMP, M_WAITOK | M_ZERO);
+ fh = zalloc(nfs_fhandle_zone);
}
if (saddr && fh) {
- MALLOC_ZONE(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
+ path = zalloc(ZV_NAMEI);
}
if (!saddr || !fh || !path) {
if (!error) {
error = ENOMEM;
}
if (fh) {
- FREE(fh, M_TEMP);
+ NFS_ZFREE(nfs_fhandle_zone, fh);
}
if (path) {
- FREE_ZONE(path, MAXPATHLEN, M_NAMEI);
+ NFS_ZFREE(ZV_NAMEI, path);
}
- fh = NULL;
- path = NULL;
nfs_socket_search_update_error(&nss, error);
nfs_socket_destroy(nso);
goto keepsearching;
if (found && (nmp->nm_auth == RPCAUTH_NONE)) {
found = 0;
}
+ OS_FALLTHROUGH;
case RPCAUTH_NONE:
case RPCAUTH_KRB5:
case RPCAUTH_KRB5I:
}
error = !found ? EAUTH : 0;
}
- FREE_ZONE(path, MAXPATHLEN, M_NAMEI);
- path = NULL;
+ NFS_ZFREE(ZV_NAMEI, path);
if (error) {
nfs_socket_search_update_error(&nss, error);
- FREE(fh, M_TEMP);
- fh = NULL;
+ NFS_ZFREE(nfs_fhandle_zone, fh);
nfs_socket_destroy(nso);
goto keepsearching;
}
if (nmp->nm_fh) {
- FREE(nmp->nm_fh, M_TEMP);
+ NFS_ZFREE(nfs_fhandle_zone, nmp->nm_fh);
}
nmp->nm_fh = fh;
fh = NULL;
}
if (!nmp->nm_vers) {
nmp->nm_vers = nfsvers;
+#if CONFIG_NFS4
/* If we negotiated NFSv4, set nm_nfsport if we ended up on the standard NFS port */
if ((nfsvers >= NFS_VER4) && !NFS_BITMAP_ISSET(nmp->nm_mattrs, NFS_MATTR_NFS_PORT)) {
if (nso->nso_saddr->sa_family == AF_INET) {
nmp->nm_nfsport = NFS_PORT;
}
}
+#endif
}
+#if CONFIG_NFS4
/* do some version-specific pre-mount set up */
if (nmp->nm_vers >= NFS_VER4) {
microtime(&now);
nfs4_mount_callback_setup(nmp);
}
}
+#endif
}
/* Initialize NFS socket state variables */
if (!NFS_BITMAP_ISSET(nmp->nm_mattrs, NFS_MATTR_SOCKET_TYPE)) {
nmp->nm_sotype = 0;
}
- if (!NFS_BITMAP_ISSET(nmp->nm_mattrs, NFS_MATTR_NFS_VERSION)) {
- if (nmp->nm_vers >= NFS_VER4) {
- if (!NFS_BITMAP_ISSET(nmp->nm_mattrs, NFS_MATTR_NFS_PORT)) {
- nmp->nm_nfsport = 0;
- }
- if (nmp->nm_cbid) {
- nfs4_mount_callback_shutdown(nmp);
- }
- if (IS_VALID_CRED(nmp->nm_mcred)) {
- kauth_cred_unref(&nmp->nm_mcred);
- }
- bzero(&nmp->nm_un, sizeof(nmp->nm_un));
+#if CONFIG_NFS4
+ if (nmp->nm_vers >= NFS_VER4) {
+ if (!NFS_BITMAP_ISSET(nmp->nm_mattrs, NFS_MATTR_NFS_PORT)) {
+ nmp->nm_nfsport = 0;
+ }
+ if (nmp->nm_cbid) {
+ nfs4_mount_callback_shutdown(nmp);
}
- nmp->nm_vers = 0;
+ if (IS_VALID_CRED(nmp->nm_mcred)) {
+ kauth_cred_unref(&nmp->nm_mcred);
+ }
+ bzero(&nmp->nm_un, sizeof(nmp->nm_un));
}
+#endif
+ nmp->nm_vers = 0;
}
lck_mtx_unlock(&nmp->nm_lock);
nmp->nm_nso = NULL;
nmp->nm_nss = NULL;
nfs_socket_search_cleanup(&nss);
if (fh) {
- FREE(fh, M_TEMP);
+ NFS_ZFREE(nfs_fhandle_zone, fh);
}
if (path) {
- FREE_ZONE(path, MAXPATHLEN, M_NAMEI);
+ NFS_ZFREE(ZV_NAMEI, path);
}
NFS_SOCK_DBG("nfs connect %s success\n", vfs_statfs(nmp->nm_mountp)->f_mntfromname);
return 0;
/* setup & confirm socket connection is functional */
int
-nfs_connect_setup(struct nfsmount *nmp)
+nfs_connect_setup(
+#if !CONFIG_NFS4
+ __unused
+#endif
+ struct nfsmount *nmp)
{
int error = 0;
-
+#if CONFIG_NFS4
if (nmp->nm_vers >= NFS_VER4) {
if (nmp->nm_state & NFSSTA_CLIENTID) {
/* first, try to renew our current state */
}
error = nfs4_setclientid(nmp);
}
+#endif
return error;
}
* as needing a resend. (Though nfs_need_reconnect() probably
* marked them all already.)
*/
- lck_mtx_lock(nfs_request_mutex);
+ lck_mtx_lock(&nfs_request_mutex);
TAILQ_FOREACH(rq, &nfs_reqq, r_chain) {
if (rq->r_nmp == nmp) {
lck_mtx_lock(&rq->r_mtx);
lck_mtx_unlock(&rq->r_mtx);
}
}
- lck_mtx_unlock(nfs_request_mutex);
+ lck_mtx_unlock(&nfs_request_mutex);
return 0;
}
lck_mtx_lock(&nmp->nm_lock);
tryagain:
if (nmp->nm_nso) {
- struct timespec ts = { 1, 0 };
+ struct timespec ts = { .tv_sec = 1, .tv_nsec = 0 };
if (nmp->nm_state & NFSSTA_SENDING) { /* wait for sending to complete */
nmp->nm_state |= NFSSTA_WANTSND;
msleep(&nmp->nm_state, &nmp->nm_lock, PZERO - 1, "nfswaitsending", &ts);
* Loop through outstanding request list and
* mark all requests as needing a resend.
*/
- lck_mtx_lock(nfs_request_mutex);
+ lck_mtx_lock(&nfs_request_mutex);
TAILQ_FOREACH(rq, &nfs_reqq, r_chain) {
if (rq->r_nmp == nmp) {
lck_mtx_lock(&rq->r_mtx);
lck_mtx_unlock(&rq->r_mtx);
}
}
- lck_mtx_unlock(nfs_request_mutex);
+ lck_mtx_unlock(&nfs_request_mutex);
}
nfs_mount_sock_thread(void *arg, __unused wait_result_t wr)
{
struct nfsmount *nmp = arg;
- struct timespec ts = { 30, 0 };
+ struct timespec ts = { .tv_sec = 30, .tv_nsec = 0 };
thread_t thd = current_thread();
struct nfsreq *req;
struct timeval now;
if (error == EIO || error == EINTR) {
lvl = (do_reconnect_sleep++ % 600) ? 7 : 0;
}
- nfs_printf(NFS_FAC_SOCK, lvl, "nfs reconnect %s: returned %d\n",
+ NFS_DBG(NFS_FAC_SOCK, lvl, "nfs reconnect %s: returned %d\n",
vfs_statfs(nmp->nm_mountp)->f_mntfromname, error);
} else {
nmp->nm_reconnect_start = 0;
nfs_recover(nmp);
lck_mtx_lock(&nmp->nm_lock);
}
+#if CONFIG_NFS4
/* handle NFSv4 delegation returns */
while ((nmp->nm_vers >= NFS_VER4) && !(nmp->nm_state & (NFSSTA_FORCE | NFSSTA_DEAD)) &&
(nmp->nm_sockflags & NMSOCK_READY) && !(nmp->nm_state & NFSSTA_RECOVER) &&
nfs4_delegation_return(np, R_RECOVER, thd, nmp->nm_mcred);
lck_mtx_lock(&nmp->nm_lock);
}
+#endif
/* do resends, if necessary/possible */
while ((((nmp->nm_sockflags & NMSOCK_READY) && !(nmp->nm_state & NFSSTA_RECOVER)) ||
(nmp->nm_state & (NFSSTA_FORCE | NFSSTA_DEAD))) &&
if (!req) {
break;
}
+ /* acquire both locks in the right order: first req->r_mtx and then nmp->nm_lock */
+ lck_mtx_unlock(&nmp->nm_lock);
+ lck_mtx_lock(&req->r_mtx);
+ lck_mtx_lock(&nmp->nm_lock);
+ if ((req->r_flags & R_RESENDQ) == 0 || (req->r_rchain.tqe_next == NFSREQNOLIST)) {
+ lck_mtx_unlock(&req->r_mtx);
+ continue;
+ }
TAILQ_REMOVE(&nmp->nm_resendq, req, r_rchain);
+ req->r_flags &= ~R_RESENDQ;
req->r_rchain.tqe_next = NFSREQNOLIST;
lck_mtx_unlock(&nmp->nm_lock);
- lck_mtx_lock(&req->r_mtx);
/* Note that we have a reference on the request that was taken nfs_asyncio_resend */
if (req->r_error || req->r_nmrep.nmc_mhead) {
dofinish = req->r_callback.rcb_func && !(req->r_flags & R_WAITSENT);
- req->r_flags &= ~R_RESENDQ;
wakeup(req);
lck_mtx_unlock(&req->r_mtx);
if (dofinish) {
lck_mtx_unlock(&req->r_mtx);
/* async RPCs on GSS mounts need to be rebuilt and resent. */
nfs_reqdequeue(req);
+#if CONFIG_NFS_GSS
if (nfs_request_using_gss(req)) {
nfs_gss_clnt_rpcdone(req);
error = nfs_gss_clnt_args_restore(req);
req->r_xid = 0;
}
}
+#endif /* CONFIG_NFS_GSS */
NFS_SOCK_DBG("nfs async%s restart: p %d x 0x%llx f 0x%x rtt %d\n",
nfs_request_using_gss(req) ? " gss" : "", req->r_procnum, req->r_xid,
req->r_flags, req->r_rtt);
error = nfs_request_send(req, 0);
}
lck_mtx_lock(&req->r_mtx);
- if (req->r_flags & R_RESENDQ) {
- req->r_flags &= ~R_RESENDQ;
- }
if (error) {
req->r_error = error;
}
error = nfs_send(req, 0);
lck_mtx_lock(&req->r_mtx);
if (!error) {
- if (req->r_flags & R_RESENDQ) {
- req->r_flags &= ~R_RESENDQ;
- }
wakeup(req);
lck_mtx_unlock(&req->r_mtx);
nfs_request_rele(req);
}
}
req->r_error = error;
- if (req->r_flags & R_RESENDQ) {
- req->r_flags &= ~R_RESENDQ;
- }
wakeup(req);
dofinish = req->r_callback.rcb_func && !(req->r_flags & R_WAITSENT);
lck_mtx_unlock(&req->r_mtx);
#define NCBSOCK_UPCALLWANT 0x0002
#define NCBSOCK_DEAD 0x0004
+#if CONFIG_NFS4
/*
* NFS callback channel state
*
int error, on = 1;
in_port_t port;
- lck_mtx_lock(nfs_global_mutex);
+ lck_mtx_lock(&nfs_global_mutex);
if (nfs4_cb_id == 0) {
TAILQ_INIT(&nfs4_cb_mounts);
TAILQ_INIT(&nfs4_cb_socks);
TAILQ_INSERT_HEAD(&nfs4_cb_mounts, nmp, nm_cblink);
if (nfs4_cb_so) {
- lck_mtx_unlock(nfs_global_mutex);
+ lck_mtx_unlock(&nfs_global_mutex);
return;
}
}
so = nfs4_cb_so;
+ if (NFS_PORT_INVALID(nfs_callback_port)) {
+ error = EINVAL;
+ log(LOG_INFO, "nfs callback setup: error %d nfs_callback_port %d is not valid\n", error, nfs_callback_port);
+ goto fail;
+ }
+
sock_setsockopt(so, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
sin.sin_len = sizeof(struct sockaddr_in);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(INADDR_ANY);
- sin.sin_port = htons(nfs_callback_port); /* try to use specified port */
+ sin.sin_port = htons((in_port_t)nfs_callback_port); /* try to use specified port */
error = sock_bind(so, (struct sockaddr *)&sin);
if (error) {
log(LOG_INFO, "nfs callback setup: error %d binding listening IPv4 socket\n", error);
sock_setsockopt(so6, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
sock_setsockopt(so6, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
/* try to use specified port or same port as IPv4 */
- port = nfs_callback_port ? nfs_callback_port : nfs4_cb_port;
+ port = nfs_callback_port ? (in_port_t)nfs_callback_port : nfs4_cb_port;
ipv6_bind_again:
sin6.sin6_len = sizeof(struct sockaddr_in6);
sin6.sin6_family = AF_INET6;
fail:
if (error) {
nfs4_cb_so = nfs4_cb_so6 = NULL;
- lck_mtx_unlock(nfs_global_mutex);
+ lck_mtx_unlock(&nfs_global_mutex);
if (so) {
sock_shutdown(so, SHUT_RDWR);
sock_close(so);
sock_close(so6);
}
} else {
- lck_mtx_unlock(nfs_global_mutex);
+ lck_mtx_unlock(&nfs_global_mutex);
}
}
struct nfs_callback_socket *ncbsp;
socket_t so, so6;
struct nfs4_cb_sock_list cb_socks;
- struct timespec ts = {1, 0};
+ struct timespec ts = { .tv_sec = 1, .tv_nsec = 0 };
- lck_mtx_lock(nfs_global_mutex);
+ lck_mtx_lock(&nfs_global_mutex);
+ if (nmp->nm_cbid == 0) {
+ lck_mtx_unlock(&nfs_global_mutex);
+ return;
+ }
TAILQ_REMOVE(&nfs4_cb_mounts, nmp, nm_cblink);
/* wait for any callbacks in progress to complete */
while (nmp->nm_cbrefs) {
- msleep(&nmp->nm_cbrefs, nfs_global_mutex, PSOCK, "cbshutwait", &ts);
+ msleep(&nmp->nm_cbrefs, &nfs_global_mutex, PSOCK, "cbshutwait", &ts);
}
nmp->nm_cbid = 0;
if (--nfs4_cb_so_usecount) {
- lck_mtx_unlock(nfs_global_mutex);
+ lck_mtx_unlock(&nfs_global_mutex);
return;
}
so = nfs4_cb_so;
nfs4_cb_so = nfs4_cb_so6 = NULL;
TAILQ_INIT(&cb_socks);
TAILQ_CONCAT(&cb_socks, &nfs4_cb_socks, ncbs_link);
- lck_mtx_unlock(nfs_global_mutex);
+ lck_mtx_unlock(&nfs_global_mutex);
if (so) {
sock_shutdown(so, SHUT_RDWR);
sock_close(so);
struct timeval now;
loop:
- lck_mtx_lock(nfs_global_mutex);
+ lck_mtx_lock(&nfs_global_mutex);
if (TAILQ_EMPTY(&nfs4_cb_socks)) {
nfs4_callback_timer_on = 0;
- lck_mtx_unlock(nfs_global_mutex);
+ lck_mtx_unlock(&nfs_global_mutex);
return;
}
microuptime(&now);
continue;
}
TAILQ_REMOVE(&nfs4_cb_socks, ncbsp, ncbs_link);
- lck_mtx_unlock(nfs_global_mutex);
+ lck_mtx_unlock(&nfs_global_mutex);
sock_shutdown(ncbsp->ncbs_so, SHUT_RDWR);
sock_close(ncbsp->ncbs_so);
nfs_rpc_record_state_cleanup(&ncbsp->ncbs_rrs);
nfs4_callback_timer_on = 1;
nfs_interval_timer_start(nfs4_callback_timer_call,
NFS4_CB_TIMER_PERIOD * 1000);
- lck_mtx_unlock(nfs_global_mutex);
+ lck_mtx_unlock(&nfs_global_mutex);
}
/*
microuptime(&now);
ncbsp->ncbs_stamp = now.tv_sec;
- lck_mtx_lock(nfs_global_mutex);
+ lck_mtx_lock(&nfs_global_mutex);
/* add it to the list */
TAILQ_INSERT_HEAD(&nfs4_cb_socks, ncbsp, ncbs_link);
nfs_interval_timer_start(nfs4_callback_timer_call, 500);
}
- lck_mtx_unlock(nfs_global_mutex);
+ lck_mtx_unlock(&nfs_global_mutex);
}
/*
nfs4_cb_rcv(socket_t so, void *arg, __unused int waitflag)
{
struct nfs_callback_socket *ncbsp = arg;
- struct timespec ts = {1, 0};
+ struct timespec ts = { .tv_sec = 1, .tv_nsec = 0 };
struct timeval now;
mbuf_t m;
int error = 0, recv = 1;
- lck_mtx_lock(nfs_global_mutex);
+ lck_mtx_lock(&nfs_global_mutex);
while (ncbsp->ncbs_flags & NCBSOCK_UPCALL) {
/* wait if upcall is already in progress */
ncbsp->ncbs_flags |= NCBSOCK_UPCALLWANT;
- msleep(ncbsp, nfs_global_mutex, PSOCK, "cbupcall", &ts);
+ msleep(ncbsp, &nfs_global_mutex, PSOCK, "cbupcall", &ts);
}
ncbsp->ncbs_flags |= NCBSOCK_UPCALL;
- lck_mtx_unlock(nfs_global_mutex);
+ lck_mtx_unlock(&nfs_global_mutex);
/* loop while we make error-free progress */
while (!error && recv) {
ncbsp->ncbs_stamp = now.tv_sec;
}
- lck_mtx_lock(nfs_global_mutex);
+ lck_mtx_lock(&nfs_global_mutex);
ncbsp->ncbs_flags &= ~NCBSOCK_UPCALL;
- lck_mtx_unlock(nfs_global_mutex);
+ lck_mtx_unlock(&nfs_global_mutex);
wakeup(ncbsp);
}
mbuf_t mhead = NULL, mrest = NULL, m;
struct msghdr msg;
struct nfsmount *nmp;
- fhandle_t fh;
+ fhandle_t *fh;
nfsnode_t np;
nfs_stateid stateid;
uint32_t bitmap[NFS_ATTR_BITMAP_LEN], rbitmap[NFS_ATTR_BITMAP_LEN], bmlen, truncate, attrbytes;
size_t sentlen = 0;
xid = numops = op = status = procnum = taglen = cbid = 0;
+ fh = zalloc(nfs_fhandle_zone);
nfsm_chain_dissect_init(error, &nmreq, mreq);
nfsm_chain_get_32(error, &nmreq, xid); // RPC XID
goto nfsmout;
}
/* match the callback ID to a registered mount */
- lck_mtx_lock(nfs_global_mutex);
+ lck_mtx_lock(&nfs_global_mutex);
TAILQ_FOREACH(nmp, &nfs4_cb_mounts, nm_cblink) {
if (nmp->nm_cbid != cbid) {
continue;
if (nmp) {
nmp->nm_cbrefs++;
}
- lck_mtx_unlock(nfs_global_mutex);
+ lck_mtx_unlock(&nfs_global_mutex);
if (!nmp) {
/* if no mount match, just drop socket. */
error = EPERM;
case NFS_OP_CB_GETATTR:
// (FH, BITMAP) -> (STATUS, BITMAP, ATTRS)
np = NULL;
- nfsm_chain_get_fh(error, &nmreq, NFS_VER4, &fh);
+ nfsm_chain_get_fh(error, &nmreq, NFS_VER4, fh);
bmlen = NFS_ATTR_BITMAP_LEN;
nfsm_chain_get_bitmap(error, &nmreq, bitmap, bmlen);
if (error) {
numops = 0; /* don't process any more ops */
} else {
/* find the node for the file handle */
- error = nfs_nget(nmp->nm_mountp, NULL, NULL, fh.fh_data, fh.fh_len, NULL, NULL, RPCAUTH_UNKNOWN, NG_NOCREATE, &np);
+ error = nfs_nget(nmp->nm_mountp, NULL, NULL, fh->fh_data, fh->fh_len, NULL, NULL, RPCAUTH_UNKNOWN, NG_NOCREATE, &np);
if (error || !np) {
status = NFSERR_BADHANDLE;
error = 0;
np = NULL;
nfsm_chain_get_stateid(error, &nmreq, &stateid);
nfsm_chain_get_32(error, &nmreq, truncate);
- nfsm_chain_get_fh(error, &nmreq, NFS_VER4, &fh);
+ nfsm_chain_get_fh(error, &nmreq, NFS_VER4, fh);
if (error) {
status = error;
error = 0;
numops = 0; /* don't process any more ops */
} else {
/* find the node for the file handle */
- error = nfs_nget(nmp->nm_mountp, NULL, NULL, fh.fh_data, fh.fh_len, NULL, NULL, RPCAUTH_UNKNOWN, NG_NOCREATE, &np);
+ error = nfs_nget(nmp->nm_mountp, NULL, NULL, fh->fh_data, fh->fh_len, NULL, NULL, RPCAUTH_UNKNOWN, NG_NOCREATE, &np);
if (error || !np) {
status = NFSERR_BADHANDLE;
error = 0;
nfsm_chain_null(&nmrep);
/* drop the callback reference on the mount */
- lck_mtx_lock(nfs_global_mutex);
+ lck_mtx_lock(&nfs_global_mutex);
nmp->nm_cbrefs--;
if (!nmp->nm_cbid) {
wakeup(&nmp->nm_cbrefs);
}
- lck_mtx_unlock(nfs_global_mutex);
+ lck_mtx_unlock(&nfs_global_mutex);
break;
}
if (mreq) {
mbuf_freem(mreq);
}
+ NFS_ZFREE(nfs_fhandle_zone, fh);
return error;
}
-
+#endif /* CONFIG_NFS4 */
/*
* Initialize an nfs_rpc_record_state structure.
struct sockaddr *sendnam;
mbuf_t mreqcopy;
size_t sentlen = 0;
- struct timespec ts = { 2, 0 };
+ struct timespec ts = { .tv_sec = 2, .tv_nsec = 0 };
again:
error = nfs_sndlock(req);
msg.msg_name = (caddr_t)sendnam;
msg.msg_namelen = sendnam->sa_len;
}
+ NFS_SOCK_DUMP_MBUF("Sending mbuf\n", mreqcopy);
error = sock_sendmbuf(nso->nso_so, &msg, mreqcopy, 0, &sentlen);
if (error || (sentlen != req->r_mreqlen)) {
NFS_SOCK_DBG("nfs_send: 0x%llx sent %d/%d error %d\n",
if (sotype != SOCK_STREAM) {
break;
}
+ OS_FALLTHROUGH;
case EPIPE:
case EADDRNOTAVAIL:
case ENETDOWN:
u_int32_t reply = 0, rxid = 0;
int error = 0, asyncioq, t1;
+ bzero(&nmrep, sizeof(nmrep));
/* Get the xid and check that it is an rpc reply */
nfsm_chain_dissect_init(error, &nmrep, mrep);
nfsm_chain_get_32(error, &nmrep, rxid);
* Loop through the request list to match up the reply
* Iff no match, just drop it.
*/
- lck_mtx_lock(nfs_request_mutex);
+ lck_mtx_lock(&nfs_request_mutex);
TAILQ_FOREACH(req, &nfs_reqq, r_chain) {
if (req->r_nmrep.nmc_mhead || (rxid != R_XID32(req->r_xid))) {
continue;
/* signal anyone waiting on this request */
wakeup(req);
asyncioq = (req->r_callback.rcb_func != NULL);
+#if CONFIG_NFS_GSS
if (nfs_request_using_gss(req)) {
nfs_gss_clnt_rpcdone(req);
}
+#endif /* CONFIG_NFS_GSS */
lck_mtx_unlock(&req->r_mtx);
- lck_mtx_unlock(nfs_request_mutex);
+ lck_mtx_unlock(&nfs_request_mutex);
/* if it's an async RPC with a callback, queue it up */
if (asyncioq) {
nfs_asyncio_finish(req);
if (!req) {
/* not matched to a request, so drop it. */
- lck_mtx_unlock(nfs_request_mutex);
+ lck_mtx_unlock(&nfs_request_mutex);
OSAddAtomic64(1, &nfsstats.rpcunexpected);
mbuf_freem(mrep);
}
int
nfs_wait_reply(struct nfsreq *req)
{
- struct timespec ts = { 2, 0 };
+ struct timespec ts = { .tv_sec = 2, .tv_nsec = 0 };
int error = 0, slpflag, first = 1;
if (req->r_nmp && NMFLAG(req->r_nmp, INTR) && req->r_thread && !(req->r_flags & R_NOINTR)) {
req = *reqp;
if (!req) {
/* allocate a new NFS request structure */
- MALLOC_ZONE(newreq, struct nfsreq*, sizeof(*newreq), M_NFSREQ, M_WAITOK);
- if (!newreq) {
- mbuf_freem(nmrest->nmc_mhead);
- nmrest->nmc_mhead = NULL;
- return ENOMEM;
- }
- req = newreq;
+ req = newreq = zalloc_flags(nfs_req_zone, Z_WAITOK | Z_ZERO);
+ } else {
+ bzero(req, sizeof(*req));
}
-
- bzero(req, sizeof(*req));
if (req == newreq) {
req->r_flags = R_ALLOCATED;
}
nmp = VFSTONFS(np ? NFSTOMP(np) : mp);
if (nfs_mount_gone(nmp)) {
if (newreq) {
- FREE_ZONE(newreq, sizeof(*newreq), M_NFSREQ);
+ NFS_ZFREE(nfs_req_zone, newreq);
}
return ENXIO;
}
mbuf_freem(nmrest->nmc_mhead);
nmrest->nmc_mhead = NULL;
if (newreq) {
- FREE_ZONE(newreq, sizeof(*newreq), M_NFSREQ);
+ NFS_ZFREE(nfs_req_zone, newreq);
}
return ENXIO;
}
panic("nfs_request: invalid NFSv4 RPC request %d\n", procnum);
}
- lck_mtx_init(&req->r_mtx, nfs_request_grp, LCK_ATTR_NULL);
+ lck_mtx_init(&req->r_mtx, &nfs_request_grp, LCK_ATTR_NULL);
req->r_nmp = nmp;
nmp->nm_ref++;
req->r_np = np;
nfs_request_destroy(struct nfsreq *req)
{
struct nfsmount *nmp;
- struct gss_seq *gsp, *ngsp;
int clearjbtimeo = 0;
+#if CONFIG_NFS_GSS
+ struct gss_seq *gsp, *ngsp;
+#endif
+
if (!req || !(req->r_flags & R_INITTED)) {
return;
}
* Still on an async I/O queue?
* %%% But which one, we may be on a local iod.
*/
- lck_mtx_lock(nfsiod_mutex);
+ lck_mtx_lock(&nfsiod_mutex);
if (nmp && req->r_achain.tqe_next != NFSREQNOLIST) {
TAILQ_REMOVE(&nmp->nm_iodq, req, r_achain);
req->r_achain.tqe_next = NFSREQNOLIST;
}
- lck_mtx_unlock(nfsiod_mutex);
+ lck_mtx_unlock(&nfsiod_mutex);
}
lck_mtx_lock(&req->r_mtx);
wakeup(req2);
}
}
- assert((req->r_flags & R_RESENDQ) == 0);
/* XXX should we just remove this conditional, we should have a reference if we're resending */
- if (req->r_rchain.tqe_next != NFSREQNOLIST) {
+ if ((req->r_flags & R_RESENDQ) && req->r_rchain.tqe_next != NFSREQNOLIST) {
TAILQ_REMOVE(&nmp->nm_resendq, req, r_rchain);
+ req->r_flags &= ~R_RESENDQ;
req->r_rchain.tqe_next = NFSREQNOLIST;
- if (req->r_flags & R_RESENDQ) {
- req->r_flags &= ~R_RESENDQ;
- }
}
if (req->r_cchain.tqe_next != NFSREQNOLIST) {
TAILQ_REMOVE(&nmp->nm_cwndq, req, r_cchain);
if (IS_VALID_CRED(req->r_cred)) {
kauth_cred_unref(&req->r_cred);
}
+#if CONFIG_NFS_GSS
if (nfs_request_using_gss(req)) {
nfs_gss_clnt_rpcdone(req);
}
if (req->r_gss_ctx) {
nfs_gss_clnt_ctx_unref(req);
}
+#endif /* CONFIG_NFS_GSS */
if (req->r_wrongsec) {
FREE(req->r_wrongsec, M_TEMP);
}
if (nmp) {
nfs_mount_rele(nmp);
}
- lck_mtx_destroy(&req->r_mtx, nfs_request_grp);
+ lck_mtx_destroy(&req->r_mtx, &nfs_request_grp);
if (req->r_flags & R_ALLOCATED) {
- FREE_ZONE(req, sizeof(*req), M_NFSREQ);
+ NFS_ZFREE(nfs_req_zone, req);
}
}
req->r_flags |= R_SENDING;
lck_mtx_unlock(&req->r_mtx);
- lck_mtx_lock(nfs_request_mutex);
+ lck_mtx_lock(&nfs_request_mutex);
nmp = req->r_nmp;
if (nfs_mount_gone(nmp)) {
- lck_mtx_unlock(nfs_request_mutex);
+ lck_mtx_unlock(&nfs_request_mutex);
return ENXIO;
}
OSAddAtomic64(1, &nfsstats.rpcrequests);
+ /*
+ * Make sure the request is not in the queue.
+ */
+ if (req->r_lflags & RL_QUEUED) {
+#if DEVELOPMENT
+ panic("nfs_request_send: req %p is already in global requests queue", req);
+#else
+ TAILQ_REMOVE(&nfs_reqq, req, r_chain);
+ req->r_lflags &= ~RL_QUEUED;
+#endif /* DEVELOPMENT */
+ }
+
/*
* Chain request into list of outstanding requests. Be sure
* to put it LAST so timer finds oldest requests first.
nfs_interval_timer_start(nfs_request_timer_call,
NFS_REQUESTDELAY);
}
- lck_mtx_unlock(nfs_request_mutex);
+ lck_mtx_unlock(&nfs_request_mutex);
/* Send the request... */
return nfs_send(req, wait);
lck_mtx_unlock(&nmp->nm_lock);
}
+#if CONFIG_NFS_GSS
if (nfs_request_using_gss(req)) {
/*
* If the request used an RPCSEC_GSS credential
goto nfsmout;
}
}
+#endif /* CONFIG_NFS_GSS */
/*
* If there was a successful reply, make sure to mark the mount as up.
nfsm_chain_get_32(error, &nmrep, auth_status);
nfsmout_if(error);
switch (auth_status) {
+#if CONFIG_NFS_GSS
case RPCSEC_GSS_CREDPROBLEM:
case RPCSEC_GSS_CTXPROBLEM:
/*
req->r_xid = 0; // get a new XID
req->r_flags |= R_RESTART;
goto nfsmout;
+#endif /* CONFIG_NFS_GSS */
default:
error = EACCES;
break;
}
nfsm_chain_get_32(error, &nmrep, accepted_status);
break;
+#if CONFIG_NFS_GSS
case RPCAUTH_KRB5:
case RPCAUTH_KRB5I:
case RPCAUTH_KRB5P:
error = nfs_gss_clnt_verf_get(req, &nmrep,
verf_type, verf_len, &accepted_status);
break;
+#endif /* CONFIG_NFS_GSS */
}
nfsmout_if(error);
nfs_up(nmp, req->r_thread, clearjbtimeo, "resource available again");
}
+#if CONFIG_NFS4
if ((nmp->nm_vers >= NFS_VER4) && (*status == NFSERR_WRONGSEC)) {
/*
* Hmmm... we need to try a different security flavor.
req->r_np->n_auth = req->r_auth;
}
}
-
+#endif /* CONFIG_NFS4 */
if (*status == NFS_OK) {
/*
* Successful NFS request
u_int64_t *xidp,
int *status)
{
- struct nfsreq rq, *req = &rq;
+ struct nfsreq *req;
int error;
+ req = zalloc_flags(nfs_req_zone, Z_WAITOK);
if ((error = nfs_request_create(np, mp, nmrest, procnum, thd, cred, &req))) {
- return error;
+ goto out_free;
}
req->r_flags |= (flags & (R_OPTMASK | R_SOFT));
if (si) {
FSDBG_BOT(273, R_XID32(req->r_xid), np, procnum, error);
nfs_request_rele(req);
+out_free:
+ NFS_ZFREE(nfs_req_zone, req);
return error;
}
+#if CONFIG_NFS_GSS
/*
* Set up a new null proc request to exchange GSS context tokens with the
* server. Associate the context that we are setting up with the request that we
struct nfsm_chain *nmrepp,
int *status)
{
- struct nfsreq rq, *req = &rq;
+ struct nfsreq *req;
int error, wait = 1;
+ req = zalloc_flags(nfs_req_zone, Z_WAITOK);
if ((error = nfs_request_create(NULL, mp, nmrest, NFSPROC_NULL, thd, cred, &req))) {
- return error;
+ goto out_free;
}
req->r_flags |= (flags & R_OPTMASK);
if (cp == NULL) {
printf("nfs_request_gss request has no context\n");
nfs_request_rele(req);
- return NFSERR_EAUTH;
+ error = NFSERR_EAUTH;
+ goto out_free;
}
nfs_gss_clnt_ctx_ref(req, cp);
nfs_gss_clnt_ctx_unref(req);
nfs_request_rele(req);
-
+out_free:
+ NFS_ZFREE(nfs_req_zone, req);
return error;
}
+#endif /* CONFIG_NFS_GSS */
/*
* Create and start an asynchronous NFS request.
if (!error && !(req->r_flags & R_SENT) && req->r_callback.rcb_func) {
/* make sure to wait until this async I/O request gets sent */
int slpflag = (req->r_nmp && NMFLAG(req->r_nmp, INTR) && req->r_thread && !(req->r_flags & R_NOINTR)) ? PCATCH : 0;
- struct timespec ts = { 2, 0 };
+ struct timespec ts = { .tv_sec = 2, .tv_nsec = 0 };
while (!(req->r_flags & R_SENT)) {
nmp = req->r_nmp;
if ((req->r_flags & R_RESENDQ) && !nfs_mount_gone(nmp)) {
lck_mtx_lock(&nmp->nm_lock);
- if ((nmp->nm_state & NFSSTA_RECOVER) && (req->r_rchain.tqe_next != NFSREQNOLIST)) {
+ if ((req->r_flags & R_RESENDQ) && (nmp->nm_state & NFSSTA_RECOVER) && (req->r_rchain.tqe_next != NFSREQNOLIST)) {
/*
* It's not going to get off the resend queue if we're in recovery.
* So, just take it off ourselves. We could be holding mount state
* busy and thus holding up the start of recovery.
*/
TAILQ_REMOVE(&nmp->nm_resendq, req, r_rchain);
+ req->r_flags &= ~R_RESENDQ;
req->r_rchain.tqe_next = NFSREQNOLIST;
- if (req->r_flags & R_RESENDQ) {
- req->r_flags &= ~R_RESENDQ;
- }
lck_mtx_unlock(&nmp->nm_lock);
req->r_flags |= R_SENDING;
lck_mtx_unlock(&req->r_mtx);
req->r_flags |= R_ASYNCWAIT;
}
while (req->r_flags & R_RESENDQ) { /* wait until the request is off the resend queue */
- struct timespec ts = { 2, 0 };
+ struct timespec ts = { .tv_sec = 2, .tv_nsec = 0 };
if ((nmp = req->r_nmp)) {
lck_mtx_lock(&nmp->nm_lock);
- if ((nmp->nm_state & NFSSTA_RECOVER) && (req->r_rchain.tqe_next != NFSREQNOLIST)) {
+ if ((req->r_flags & R_RESENDQ) && (nmp->nm_state & NFSSTA_RECOVER) && (req->r_rchain.tqe_next != NFSREQNOLIST)) {
/*
* It's not going to get off the resend queue if we're in recovery.
* So, just take it off ourselves. We could be holding mount state
* busy and thus holding up the start of recovery.
*/
TAILQ_REMOVE(&nmp->nm_resendq, req, r_rchain);
+ req->r_flags &= ~R_RESENDQ;
req->r_rchain.tqe_next = NFSREQNOLIST;
- if (req->r_flags & R_RESENDQ) {
- req->r_flags &= ~R_RESENDQ;
- }
/* Remove the R_RESENDQ reference */
assert(req->r_refs > 0);
req->r_refs--;
void
nfs_reqdequeue(struct nfsreq *req)
{
- lck_mtx_lock(nfs_request_mutex);
+ lck_mtx_lock(&nfs_request_mutex);
while (req->r_lflags & RL_BUSY) {
req->r_lflags |= RL_WAITING;
- msleep(&req->r_lflags, nfs_request_mutex, PSOCK, "reqdeq", NULL);
+ msleep(&req->r_lflags, &nfs_request_mutex, PSOCK, "reqdeq", NULL);
}
if (req->r_lflags & RL_QUEUED) {
TAILQ_REMOVE(&nfs_reqq, req, r_chain);
req->r_lflags &= ~RL_QUEUED;
}
- lck_mtx_unlock(nfs_request_mutex);
+ lck_mtx_unlock(&nfs_request_mutex);
}
/*
TAILQ_INIT(&nfs_mount_poke_queue);
restart:
- lck_mtx_lock(nfs_request_mutex);
+ lck_mtx_lock(&nfs_request_mutex);
req = TAILQ_FIRST(&nfs_reqq);
if (req == NULL) { /* no requests - turn timer off */
nfs_request_timer_on = 0;
- lck_mtx_unlock(nfs_request_mutex);
+ lck_mtx_unlock(&nfs_request_mutex);
return;
}
TAILQ_REMOVE(&nfs_mount_poke_queue, nmp, nm_pokeq);
}
/* Release our lock state, so we can become a zombie */
- lck_mtx_unlock(nfs_request_mutex);
+ lck_mtx_unlock(&nfs_request_mutex);
/*
* Note nfs_mount_make zombie(nmp) must be
* work we release nm_lock in
* nfs_make_mount_zombie with out acquiring any
* other locks. (Later, in nfs_mount_zombie we
- * will acquire nfs_request_mutex, r_mtx,
+ * will acquire &nfs_request_mutex, r_mtx,
* nm_lock in that order). So we should not be
* introducing deadlock here. We take a reference
* on the mount so that its still there when we
lck_mtx_unlock(&req->r_mtx);
}
- lck_mtx_unlock(nfs_request_mutex);
+ lck_mtx_unlock(&nfs_request_mutex);
/* poke any sockets */
while ((nmp = TAILQ_FIRST(&nfs_mount_poke_queue))) {
* This is used to determine if we need to bail on a mount.
* ETIMEDOUT is returned if there has been a soft timeout.
* EINTR is returned if there is a signal pending that is not being ignored
+ * ESHUTDOWN is return if the system is in shutdown.
* and the mount is interruptable, or if we are a thread that is in the process
* of cancellation (also SIGKILL posted).
*/
return ENXIO;
}
+ if (get_system_inshutdown()) {
+ NFS_SOCK_DBG("Shutdown in progress\n");
+ return ESHUTDOWN;
+ }
+
if (req && (req->r_flags & R_SOFTTERM)) {
return ETIMEDOUT; /* request has been terminated. */
}
struct nfsmount *nmp = req->r_nmp;
int *statep;
int error = 0, slpflag = 0;
- struct timespec ts = { 0, 0 };
+ struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 };
if (nfs_mount_gone(nmp)) {
return ENXIO;
int error = 0, on = 1, try, sendat = 2, soproto, recv, optlen, restoreto = 0;
socket_t newso = NULL;
struct sockaddr_storage ss;
- struct timeval orig_rcvto, orig_sndto, tv = { 1, 0 };
+ struct timeval orig_rcvto, orig_sndto, tv = { .tv_sec = 1, .tv_usec = 0 };
mbuf_t m, mrep = NULL;
struct msghdr msg;
uint32_t rxid = 0, reply = 0, reply_status, rejected_status;
if (!so) {
/* create socket and set options */
- soproto = (sotype == SOCK_DGRAM) ? IPPROTO_UDP : IPPROTO_TCP;
+ if (saddr->sa_family == AF_LOCAL) {
+ soproto = 0;
+ } else {
+ soproto = (sotype == SOCK_DGRAM) ? IPPROTO_UDP : IPPROTO_TCP;
+ }
if ((error = sock_socket(saddr->sa_family, sotype, soproto, NULL, NULL, &newso))) {
goto nfsmout;
}
- if (bindresv) {
+ if (bindresv && saddr->sa_family != AF_LOCAL) {
int level = (saddr->sa_family == AF_INET) ? IPPROTO_IP : IPPROTO_IPV6;
int optname = (saddr->sa_family == AF_INET) ? IP_PORTRANGE : IPV6_PORTRANGE;
int portrange = IP_PORTRANGE_LOW;
socket_t so,
uint32_t protocol,
uint32_t vers,
- uint32_t ipproto,
+ uint32_t stype,
int timeo)
{
thread_t thd = vfs_context_thread(ctx);
kauth_cred_t cred = vfs_context_ucred(ctx);
struct sockaddr_storage ss;
struct sockaddr *saddr = (struct sockaddr*)&ss;
+ static struct sockaddr_un rpcbind_cots = {
+ sizeof(struct sockaddr_un),
+ AF_LOCAL,
+ RPCB_TICOTSORD_PATH
+ };
+ static struct sockaddr_un rpcbind_clts = {
+ sizeof(struct sockaddr_un),
+ AF_LOCAL,
+ RPCB_TICLTS_PATH
+ };
struct nfsm_chain nmreq, nmrep;
mbuf_t mreq;
int error = 0, ip, pmprog, pmvers, pmproc;
- uint32_t ualen = 0;
- uint32_t port;
+ uint32_t ualen = 0, scopeid = 0, port32;
uint64_t xid = 0;
char uaddr[MAX_IPv6_STR_LEN + 16];
pmprog = RPCBPROG;
pmvers = RPCBVERS4;
pmproc = RPCBPROC_GETVERSADDR;
+ } else if (saddr->sa_family == AF_LOCAL) {
+ ip = 0;
+ pmprog = RPCBPROG;
+ pmvers = RPCBVERS4;
+ pmproc = RPCBPROC_GETVERSADDR;
+ NFS_SOCK_DBG("%s\n", ((struct sockaddr_un*)sa)->sun_path);
+ saddr = (struct sockaddr*)((stype == SOCK_STREAM) ? &rpcbind_cots : &rpcbind_clts);
} else {
return EINVAL;
}
/* send portmapper request to get port/uaddr */
if (ip == 4) {
((struct sockaddr_in*)saddr)->sin_port = htons(PMAPPORT);
- } else {
+ } else if (ip == 6) {
((struct sockaddr_in6*)saddr)->sin6_port = htons(PMAPPORT);
}
nfsm_chain_build_alloc_init(error, &nmreq, 8 * NFSX_UNSIGNED);
nfsm_chain_add_32(error, &nmreq, protocol);
nfsm_chain_add_32(error, &nmreq, vers);
if (ip == 4) {
- nfsm_chain_add_32(error, &nmreq, ipproto);
+ nfsm_chain_add_32(error, &nmreq, stype == SOCK_STREAM ? IPPROTO_TCP : IPPROTO_UDP);
nfsm_chain_add_32(error, &nmreq, 0);
} else {
- if (ipproto == IPPROTO_TCP) {
- nfsm_chain_add_string(error, &nmreq, "tcp6", 4);
+ if (stype == SOCK_STREAM) {
+ if (ip == 6) {
+ nfsm_chain_add_string(error, &nmreq, "tcp6", 4);
+ } else {
+ nfsm_chain_add_string(error, &nmreq, "ticotsord", 9);
+ }
} else {
- nfsm_chain_add_string(error, &nmreq, "udp6", 4);
+ if (ip == 6) {
+ nfsm_chain_add_string(error, &nmreq, "udp6", 4);
+ } else {
+ nfsm_chain_add_string(error, &nmreq, "ticlts", 6);
+ }
}
nfsm_chain_add_string(error, &nmreq, "", 0); /* uaddr */
nfsm_chain_add_string(error, &nmreq, "", 0); /* owner */
}
nfsm_chain_build_done(error, &nmreq);
nfsmout_if(error);
- error = nfsm_rpchead2(nmp, (ipproto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM,
- pmprog, pmvers, pmproc, RPCAUTH_SYS, cred, NULL, nmreq.nmc_mhead,
- &xid, &mreq);
+ error = nfsm_rpchead2(nmp, stype, pmprog, pmvers, pmproc,
+ RPCAUTH_SYS, cred, NULL, nmreq.nmc_mhead, &xid, &mreq);
nfsmout_if(error);
nmreq.nmc_mhead = NULL;
- error = nfs_aux_request(nmp, thd, saddr, so, (ipproto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM,
- mreq, R_XID32(xid), 0, timeo, &nmrep);
+
+ NFS_SOCK_DUMP_MBUF("nfs_portmap_loockup request", mreq);
+ error = nfs_aux_request(nmp, thd, saddr, so,
+ stype, mreq, R_XID32(xid), 0, timeo, &nmrep);
+ NFS_SOCK_DUMP_MBUF("nfs_portmap_lookup reply", nmrep.nmc_mhead);
+ NFS_SOCK_DBG("rpcbind request returned %d for program %u vers %u: %s\n", error, protocol, vers,
+ (saddr->sa_family == AF_LOCAL) ? ((struct sockaddr_un *)saddr)->sun_path :
+ (saddr->sa_family == AF_INET6) ? "INET6 socket" : "INET socket");
/* grab port from portmap response */
if (ip == 4) {
- nfsm_chain_get_32(error, &nmrep, port);
+ nfsm_chain_get_32(error, &nmrep, port32);
if (!error) {
- ((struct sockaddr_in*)sa)->sin_port = htons(port);
+ if (NFS_PORT_INVALID(port32)) {
+ error = EBADRPC;
+ } else {
+ ((struct sockaddr_in*)sa)->sin_port = htons((in_port_t)port32);
+ }
}
} else {
/* get uaddr string and convert to sockaddr */
if (ualen < 1) {
/* program is not available, just return a zero port */
bcopy(sa, saddr, min(sizeof(ss), sa->sa_len));
- ((struct sockaddr_in6*)saddr)->sin6_port = htons(0);
+ if (ip == 6) {
+ ((struct sockaddr_in6*)saddr)->sin6_port = htons(0);
+ } else {
+ ((struct sockaddr_un*)saddr)->sun_path[0] = '\0';
+ }
+ NFS_SOCK_DBG("Program %u version %u unavailable", protocol, vers);
} else {
nfsm_chain_get_opaque(error, &nmrep, ualen, uaddr);
+ NFS_SOCK_DBG("Got uaddr %s\n", uaddr);
if (!error) {
uaddr[ualen] = '\0';
+ if (ip == 6) {
+ scopeid = ((struct sockaddr_in6*)saddr)->sin6_scope_id;
+ }
if (!nfs_uaddr2sockaddr(uaddr, saddr)) {
error = EIO;
}
+ if (ip == 6 && scopeid != ((struct sockaddr_in6*)saddr)->sin6_scope_id) {
+ NFS_SOCK_DBG("Setting scope_id from %u to %u\n", ((struct sockaddr_in6*)saddr)->sin6_scope_id, scopeid);
+ ((struct sockaddr_in6*)saddr)->sin6_scope_id = scopeid;
+ }
}
}
}
nfsmout:
nfsm_chain_cleanup(&nmreq);
nfsm_chain_cleanup(&nmrep);
+ NFS_SOCK_DBG("Returned %d\n", error);
+
return error;
}
#define NFS_SQUISH_SHUTDOWN 0x1000 /* Squish all mounts on shutdown. Currently not implemented */
uint32_t nfs_squishy_flags = NFS_SQUISH_MOBILE_ONLY | NFS_SQUISH_AUTOMOUNTED_ONLY | NFS_SQUISH_QUICK;
+uint32_t nfs_tcp_sockbuf = 128 * 1024; /* Default value of tcp_sendspace and tcp_recvspace */
int32_t nfs_is_mobile;
#define NFS_SQUISHY_DEADTIMEOUT 8 /* Dead time out for squishy mounts */
}
-#endif /* NFSCLIENT */
+#endif /* CONFIG_NFS_CLIENT */
-#if NFSSERVER
+#if CONFIG_NFS_SERVER
/*
* Generate the rpc reply header
msg.msg_namelen = sendnam->sa_len;
}
}
+ if (NFS_IS_DBG(NFS_FAC_SRV, 15)) {
+ nfs_dump_mbuf(__func__, __LINE__, "nfsrv_send\n", top);
+ }
error = sock_sendmbuf(so, &msg, top, 0, NULL);
if (!error) {
return 0;
int wake = (slp->ns_flag & SLP_WORKTODO);
lck_rw_done(&slp->ns_rwlock);
if (wake && nfsd_thread_count) {
- lck_mtx_lock(nfsd_mutex);
+ lck_mtx_lock(&nfsd_mutex);
nfsrv_wakenfsd(slp);
- lck_mtx_unlock(nfsd_mutex);
+ lck_mtx_unlock(&nfsd_mutex);
}
}
}
{
mbuf_t m;
char *cp1, *cp2, *mdata;
- int len, mlen, error;
+ int error;
+ size_t len, mlen;
mbuf_t om, m2, recm;
u_int32_t recmark;
if (!(slp->ns_flag & (SLP_VALID | SLP_DOREC)) || (slp->ns_rec == NULL)) {
return ENOBUFS;
}
- MALLOC_ZONE(nd, struct nfsrv_descript *,
- sizeof(struct nfsrv_descript), M_NFSRVDESC, M_WAITOK);
- if (!nd) {
- return ENOMEM;
- }
+ nd = zalloc(nfsrv_descript_zone);
m = slp->ns_rec;
slp->ns_rec = mbuf_nextpkt(m);
if (slp->ns_rec) {
if (nd->nd_gss_context) {
nfs_gss_svc_ctx_deref(nd->nd_gss_context);
}
- FREE_ZONE(nd, sizeof(*nd), M_NFSRVDESC);
+ NFS_ZFREE(nfsrv_descript_zone, nd);
return error;
}
nd->nd_mrep = NULL;
int error = 0;
uid_t user_id;
gid_t group_id;
- int ngroups;
+ short ngroups;
uint32_t val;
nd->nd_cr = NULL;
}
}
nfsmout_if(error);
- ngroups = (len >= NGROUPS) ? NGROUPS : (len + 1);
+ ngroups = (len >= NGROUPS) ? NGROUPS : (short)(len + 1);
if (ngroups > 1) {
nfsrv_group_sort(&temp_pcred.cr_groups[0], ngroups);
}
wakeup(nd);
}
-#endif /* NFSSERVER */
+#endif /* CONFIG_NFS_SERVER */
+
+#endif /* CONFIG_NFS */