/*
- * Copyright (c) 2000-2017 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2019 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
#include <sys/mount_internal.h>
#include <sys/kpi_mbuf.h>
#include <sys/socket.h>
+#include <sys/un.h>
#include <sys/socketvar.h>
#include <sys/fcntl.h>
#include <sys/quota.h>
int mountnfs(char *, mount_t, vfs_context_t, vnode_t *);
+#if CONFIG_NETBOOT
static int nfs_mount_diskless(struct nfs_dlmount *, const char *, int, vnode_t *, mount_t *, vfs_context_t);
#if !defined(NO_MOUNT_PRIVATE)
static int nfs_mount_diskless_private(struct nfs_dlmount *, const char *, int, vnode_t *, mount_t *, vfs_context_t);
#endif /* NO_MOUNT_PRIVATE */
+#endif
int nfs_mount_connect(struct nfsmount *);
void nfs_mount_drain_and_cleanup(struct nfsmount *);
void nfs_mount_cleanup(struct nfsmount *);
#endif
const struct nfs_funcs nfs3_funcs = {
- nfs3_mount,
- nfs3_update_statfs,
- nfs3_getquota,
- nfs3_access_rpc,
- nfs3_getattr_rpc,
- nfs3_setattr_rpc,
- nfs3_read_rpc_async,
- nfs3_read_rpc_async_finish,
- nfs3_readlink_rpc,
- nfs3_write_rpc_async,
- nfs3_write_rpc_async_finish,
- nfs3_commit_rpc,
- nfs3_lookup_rpc_async,
- nfs3_lookup_rpc_async_finish,
- nfs3_remove_rpc,
- nfs3_rename_rpc,
- nfs3_setlock_rpc,
- nfs3_unlock_rpc,
- nfs3_getlock_rpc
+ .nf_mount = nfs3_mount,
+ .nf_update_statfs = nfs3_update_statfs,
+ .nf_getquota = nfs3_getquota,
+ .nf_access_rpc = nfs3_access_rpc,
+ .nf_getattr_rpc = nfs3_getattr_rpc,
+ .nf_setattr_rpc = nfs3_setattr_rpc,
+ .nf_read_rpc_async = nfs3_read_rpc_async,
+ .nf_read_rpc_async_finish = nfs3_read_rpc_async_finish,
+ .nf_readlink_rpc = nfs3_readlink_rpc,
+ .nf_write_rpc_async = nfs3_write_rpc_async,
+ .nf_write_rpc_async_finish = nfs3_write_rpc_async_finish,
+ .nf_commit_rpc = nfs3_commit_rpc,
+ .nf_lookup_rpc_async = nfs3_lookup_rpc_async,
+ .nf_lookup_rpc_async_finish = nfs3_lookup_rpc_async_finish,
+ .nf_remove_rpc = nfs3_remove_rpc,
+ .nf_rename_rpc = nfs3_rename_rpc,
+ .nf_setlock_rpc = nfs3_setlock_rpc,
+ .nf_unlock_rpc = nfs3_unlock_rpc,
+ .nf_getlock_rpc = nfs3_getlock_rpc
};
+#if CONFIG_NFS4
const struct nfs_funcs nfs4_funcs = {
- nfs4_mount,
- nfs4_update_statfs,
- nfs4_getquota,
- nfs4_access_rpc,
- nfs4_getattr_rpc,
- nfs4_setattr_rpc,
- nfs4_read_rpc_async,
- nfs4_read_rpc_async_finish,
- nfs4_readlink_rpc,
- nfs4_write_rpc_async,
- nfs4_write_rpc_async_finish,
- nfs4_commit_rpc,
- nfs4_lookup_rpc_async,
- nfs4_lookup_rpc_async_finish,
- nfs4_remove_rpc,
- nfs4_rename_rpc,
- nfs4_setlock_rpc,
- nfs4_unlock_rpc,
- nfs4_getlock_rpc
+ .nf_mount = nfs4_mount,
+ .nf_update_statfs = nfs4_update_statfs,
+ .nf_getquota = nfs4_getquota,
+ .nf_access_rpc = nfs4_access_rpc,
+ .nf_getattr_rpc = nfs4_getattr_rpc,
+ .nf_setattr_rpc = nfs4_setattr_rpc,
+ .nf_read_rpc_async = nfs4_read_rpc_async,
+ .nf_read_rpc_async_finish = nfs4_read_rpc_async_finish,
+ .nf_readlink_rpc = nfs4_readlink_rpc,
+ .nf_write_rpc_async = nfs4_write_rpc_async,
+ .nf_write_rpc_async_finish = nfs4_write_rpc_async_finish,
+ .nf_commit_rpc = nfs4_commit_rpc,
+ .nf_lookup_rpc_async = nfs4_lookup_rpc_async,
+ .nf_lookup_rpc_async_finish = nfs4_lookup_rpc_async_finish,
+ .nf_remove_rpc = nfs4_remove_rpc,
+ .nf_rename_rpc = nfs4_rename_rpc,
+ .nf_setlock_rpc = nfs4_setlock_rpc,
+ .nf_unlock_rpc = nfs4_unlock_rpc,
+ .nf_getlock_rpc = nfs4_getlock_rpc
};
+#endif
/*
* Called once to initialize data structures...
int
nfs_vfs_init(__unused struct vfsconf *vfsp)
{
+#if CONFIG_NFS4
int i;
-
+#endif
/*
* Check to see if major data structures haven't bloated.
*/
nfs_nbinit(); /* Init the nfsbuf table */
nfs_nhinit(); /* Init the nfsnode table */
nfs_lockinit(); /* Init the nfs lock state */
+#if CONFIG_NFS_GSS
nfs_gss_init(); /* Init RPCSEC_GSS security */
+#endif
+#if CONFIG_NFS4
/* NFSv4 stuff */
NFS4_PER_FS_ATTRIBUTES(nfs_fs_attr_bitmap);
NFS4_PER_OBJECT_ATTRIBUTES(nfs_object_attr_bitmap);
nfs_getattr_bitmap[i] &= nfs_object_attr_bitmap[i];
}
TAILQ_INIT(&nfsclientids);
+#endif
/* initialize NFS timer callouts */
nfs_request_timer_call = thread_call_allocate(nfs_request_timer, NULL);
nfs_buf_timer_call = thread_call_allocate(nfs_buf_timer, NULL);
+#if CONFIG_NFS4
nfs4_callback_timer_call = thread_call_allocate(nfs4_callback_timer, NULL);
-
+#endif
return 0;
}
+
/*
* nfs statfs call
*/
return error;
}
+#if CONFIG_NFS4
int
nfs4_update_statfs(struct nfsmount *nmp, vfs_context_t ctx)
{
vnode_put(NFSTOV(np));
return error;
}
+#endif /* CONFIG_NFS4 */
+
/*
* Return an NFS volume name from the mntfrom name.
*/
static void
-nfs_get_volname(struct mount *mp, char *volname, size_t len)
+nfs_get_volname(struct mount *mp, char *volname, size_t len, vfs_context_t ctx)
{
const char *ptr, *cptr;
const char *mntfrom = mp->mnt_vfsstat.f_mntfromname;
- size_t mflen = strnlen(mntfrom, MAXPATHLEN + 1);
+ struct nfsmount *nmp = VFSTONFS(mp);
+ size_t mflen;
+
+
+ mflen = strnlen(mntfrom, MAXPATHLEN + 1);
if (mflen > MAXPATHLEN || mflen == 0) {
strlcpy(volname, "Bad volname", len);
strlcpy(volname, ptr, len);
}
+
/*
* The NFS VFS_GETATTR function: "statfs"-type information is retrieved
* using the nf_update_statfs() function, and other attributes are cobbled
if (VFSATTR_IS_ACTIVE(fsap, f_vol_name)) {
/*%%% IF fail over support is implemented we may need to take nm_lock */
- nfs_get_volname(mp, fsap->f_vol_name, MAXPATHLEN);
+ nfs_get_volname(mp, fsap->f_vol_name, MAXPATHLEN, ctx);
VFSATTR_SET_SUPPORTED(fsap, f_vol_name);
}
- if (VFSATTR_IS_ACTIVE(fsap, f_capabilities)) {
+ if (VFSATTR_IS_ACTIVE(fsap, f_capabilities)
+ ) {
u_int32_t caps, valid;
nfsnode_t np = nmp->nm_dnp;
* The capabilities[] array defines what this volume supports.
*
* The valid[] array defines which bits this code understands
- * the meaning of (whether the volume has that capability or not).
- * Any zero bits here means "I don't know what you're asking about"
- * and the caller cannot tell whether that capability is
- * present or not.
+ * the meaning of (whether the volume has that capability or
+ * not). Any zero bits here means "I don't know what you're
+ * asking about" and the caller cannot tell whether that
+ * capability is present or not.
*/
caps = valid = 0;
if (NFS_BITMAP_ISSET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_SYMLINK_SUPPORT)) {
*/
caps |= VOL_CAP_FMT_2TB_FILESIZE;
}
+#if CONFIG_NFS4
if (nfsvers >= NFS_VER4) {
caps |= VOL_CAP_FMT_HIDDEN_FILES;
valid |= VOL_CAP_FMT_HIDDEN_FILES;
// caps |= VOL_CAP_FMT_OPENDENYMODES;
// valid |= VOL_CAP_FMT_OPENDENYMODES;
}
+#endif
// no version of nfs supports immutable files
caps |= VOL_CAP_FMT_NO_IMMUTABLE_FILES;
valid |= VOL_CAP_FMT_NO_IMMUTABLE_FILES;
/*
* We don't support most of the interfaces.
*
- * We MAY support locking, but we don't have any easy way of probing.
- * We can tell if there's no lockd running or if locks have been
- * disabled for a mount, so we can definitely answer NO in that case.
- * Any attempt to send a request to lockd to test for locking support
- * may cause the lazily-launched locking daemons to be started
- * unnecessarily. So we avoid that. However, we do record if we ever
- * successfully perform a lock operation on a mount point, so if it
- * looks like lock ops have worked, we do report that we support them.
+ * We MAY support locking, but we don't have any easy way of
+ * probing. We can tell if there's no lockd running or if
+ * locks have been disabled for a mount, so we can definitely
+ * answer NO in that case. Any attempt to send a request to
+ * lockd to test for locking support may cause the lazily-
+ * launched locking daemons to be started unnecessarily. So
+ * we avoid that. However, we do record if we ever successfully
+ * perform a lock operation on a mount point, so if it looks
+ * like lock ops have worked, we do report that we support them.
*/
caps = valid = 0;
+#if CONFIG_NFS4
if (nfsvers >= NFS_VER4) {
caps = VOL_CAP_INT_ADVLOCK | VOL_CAP_INT_FLOCK;
valid = VOL_CAP_INT_ADVLOCK | VOL_CAP_INT_FLOCK;
}
valid |= VOL_CAP_INT_NAMEDSTREAMS;
#endif
- } else if (nmp->nm_lockmode == NFS_LOCK_MODE_DISABLED) {
+ } else
+#endif
+ if (nmp->nm_lockmode == NFS_LOCK_MODE_DISABLED) {
/* locks disabled on this mount, so they definitely won't work */
valid = VOL_CAP_INT_ADVLOCK | VOL_CAP_INT_FLOCK;
} else if (nmp->nm_state & NFSSTA_LOCKSWORK) {
* if swdevt[0].sw_dev == NODEV
* - build the rootfs mount point and call mountnfs() to do the rest.
*/
+#if CONFIG_NETBOOT
int
nfs_mountroot(void)
{
uint32_t argslength_offset, attrslength_offset, end_offset;
procp = current_proc(); /* XXX */
- xb_init(&xb, 0);
+ xb_init(&xb, XDRBUF_NONE);
{
/*
}
#endif /* NO_MOUNT_PRIVATE */
+#endif
+
/*
* Convert old style NFS mount args to XDR.
*/
return error;
}
+#if CONFIG_NFS4
/*
* Update an NFSv4 mount path with the contents of the symlink.
*
nfsm_chain_cleanup(&nmrep);
return error;
}
+#endif /* CONFIG_NFS4 */
/*
* Thread to handle initial NFS mount connection.
{
int error = 0, slpflag;
thread_t thd;
- struct timespec ts = { 2, 0 };
+ struct timespec ts = { .tv_sec = 2, .tv_nsec = 0 };
/*
* Set up the socket. Perform initial search for a location/server/address to
uint32_t *mflags_mask;
uint32_t *mflags;
uint32_t argslength, attrslength;
- struct nfs_location_index firstloc = { NLI_VALID, 0, 0, 0 };
+ uid_t set_owner;
+ struct nfs_location_index firstloc = {
+ .nli_flags = NLI_VALID,
+ .nli_loc = 0,
+ .nli_serv = 0,
+ .nli_addr = 0
+ };
static const struct nfs_etype nfs_default_etypes = {
.count = NFS_MAX_ETYPES,
.selected = NFS_MAX_ETYPES,
NFS_AES128_CTS_HMAC_SHA1_96,
NFS_DES3_CBC_SHA1_KD}
};
+
/* make sure mbuf constants are set up */
if (!nfs_mbuf_mhlen) {
nfs_mbuf_init();
switch (val) {
case NFS_LOCK_MODE_DISABLED:
case NFS_LOCK_MODE_LOCAL:
+#if CONFIG_NFS4
if (nmp->nm_vers >= NFS_VER4) {
/* disabled/local lock mode only allowed on v2/v3 */
error = EINVAL;
break;
}
+#endif
/* FALLTHROUGH */
case NFS_LOCK_MODE_ENABLED:
nmp->nm_lockmode = val;
xb_get_32(error, &xb, nmp->nm_numgrps);
}
if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_SOCKET_TYPE)) {
- char sotype[6];
+ char sotype[16];
+ *sotype = '\0';
xb_get_32(error, &xb, val);
- if (!error && ((val < 3) || (val > 5))) {
+ if (!error && ((val < 3) || (val > sizeof(sotype)))) {
error = EINVAL;
}
nfsmerr_if(error);
nmp->nm_sofamily = AF_INET6;
} else if (!strcmp(sotype, "inet")) {
nmp->nm_sofamily = 0; /* ok */
+ } else if (!strcmp(sotype, "ticotsord")) {
+ nmp->nm_sofamily = AF_LOCAL;
+ nmp->nm_sotype = SOCK_STREAM;
+ } else if (!strcmp(sotype, "ticlts")) {
+ nmp->nm_sofamily = AF_LOCAL;
+ nmp->nm_sotype = SOCK_DGRAM;
} else {
error = EINVAL;
}
+#if CONFIG_NFS4
if (!error && (nmp->nm_vers >= NFS_VER4) && nmp->nm_sotype &&
(nmp->nm_sotype != SOCK_STREAM)) {
error = EINVAL; /* NFSv4 is only allowed over TCP. */
}
+#endif
+ if (error) {
+ NFS_VFS_DBG("EINVAL sotype = \"%s\"\n", sotype);
+ }
nfsmerr_if(error);
}
if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_NFS_PORT)) {
xb_get_32(error, &xb, nmp->nm_locations.nl_numlocs); /* fs location count */
/* sanity check location count */
if (!error && ((nmp->nm_locations.nl_numlocs < 1) || (nmp->nm_locations.nl_numlocs > 256))) {
+ NFS_VFS_DBG("Invalid number of fs_locations: %d", nmp->nm_locations.nl_numlocs);
error = EINVAL;
}
nfsmerr_if(error);
xb_get_32(error, &xb, fsl->nl_servcount); /* server count */
/* sanity check server count */
if (!error && ((fsl->nl_servcount < 1) || (fsl->nl_servcount > 256))) {
+ NFS_VFS_DBG("Invalid server count %d", fsl->nl_servcount);
error = EINVAL;
}
nfsmerr_if(error);
MALLOC(fsl->nl_servers, struct nfs_fs_server **, fsl->nl_servcount * sizeof(struct nfs_fs_server*), M_TEMP, M_WAITOK | M_ZERO);
if (!fsl->nl_servers) {
error = ENOMEM;
+ NFS_VFS_DBG("Server count = %d, error = %d\n", fsl->nl_servcount, error);
}
for (serv = 0; serv < fsl->nl_servcount; serv++) {
nfsmerr_if(error);
fsl->nl_servers[serv] = fss;
xb_get_32(error, &xb, val); /* server name length */
/* sanity check server name length */
- if (!error && ((val < 1) || (val > MAXPATHLEN))) {
+ if (!error && (val > MAXPATHLEN)) {
+ NFS_VFS_DBG("Invalid server name length %d", val);
error = EINVAL;
}
nfsmerr_if(error);
xb_get_32(error, &xb, fss->ns_addrcount); /* address count */
/* sanity check address count (OK to be zero) */
if (!error && (fss->ns_addrcount > 256)) {
+ NFS_VFS_DBG("Invalid address count %d", fss->ns_addrcount);
error = EINVAL;
}
nfsmerr_if(error);
for (addr = 0; addr < fss->ns_addrcount; addr++) {
xb_get_32(error, &xb, val); /* address length */
/* sanity check address length */
- if (!error && ((val < 1) || (val > 128))) {
+ if (!error && val > 128) {
+ NFS_VFS_DBG("Invalid address length %d", val);
error = EINVAL;
}
nfsmerr_if(error);
xb_get_32(error, &xb, fsp->np_compcount); /* component count */
/* sanity check component count */
if (!error && (fsp->np_compcount > MAXPATHLEN)) {
+ NFS_VFS_DBG("Invalid component count %d", fsp->np_compcount);
error = EINVAL;
}
nfsmerr_if(error);
continue;
}
if (!error && ((val < 1) || (val > MAXPATHLEN))) {
+ NFS_VFS_DBG("Invalid component path length %d", val);
error = EINVAL;
}
nfsmerr_if(error);
error = xb_get_bytes(&xb, fsp->np_components[comp], val, 0); /* component */
}
xb_get_32(error, &xb, val); /* fs location info length */
- xb_skip(error, &xb, val); /* skip fs location info */
+ NFS_VFS_DBG("Skipping fs location info bytes %d", val);
+ xb_skip(error, &xb, xdr_rndup(val)); /* skip fs location info */
}
}
if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_MNTFLAGS)) {
}
nfsmerr_if(error);
+ if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_LOCAL_NFS_PORT)) {
+ if (nmp->nm_nfsport) {
+ error = EINVAL;
+ NFS_VFS_DBG("Can't have ports specified over incompatible socket families");
+ }
+ nfsmerr_if(error);
+ xb_get_32(error, &xb, len);
+ if (!error && ((len < 1) || (len > sizeof(((struct sockaddr_un *)0)->sun_path)))) {
+ error = EINVAL;
+ }
+ nfsmerr_if(error);
+ MALLOC(nmp->nm_nfs_localport, char *, len + 1, M_TEMP, M_WAITOK | M_ZERO);
+ if (!nmp->nm_nfs_localport) {
+ error = ENOMEM;
+ }
+ nfsmerr_if(error);
+ error = xb_get_bytes(&xb, nmp->nm_nfs_localport, len, 0);
+ nmp->nm_sofamily = AF_LOCAL;
+ nmp->nm_nfsport = 1; /* We use the now deprecated tpcmux port to indcate that we have an AF_LOCAL port */
+ NFS_VFS_DBG("Setting nfs local port %s (%d)\n", nmp->nm_nfs_localport, nmp->nm_nfsport);
+ }
+ if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_LOCAL_MOUNT_PORT)) {
+ if (nmp->nm_mountport) {
+ error = EINVAL;
+ NFS_VFS_DBG("Can't have ports specified over mulitple socket families");
+ }
+ nfsmerr_if(error);
+ xb_get_32(error, &xb, len);
+ if (!error && ((len < 1) || (len > sizeof(((struct sockaddr_un *)0)->sun_path)))) {
+ error = EINVAL;
+ }
+ nfsmerr_if(error);
+ MALLOC(nmp->nm_mount_localport, char *, len + 1, M_TEMP, M_WAITOK | M_ZERO);
+ if (!nmp->nm_mount_localport) {
+ error = ENOMEM;
+ }
+ nfsmerr_if(error);
+ error = xb_get_bytes(&xb, nmp->nm_mount_localport, len, 0);
+ nmp->nm_sofamily = AF_LOCAL;
+ nmp->nm_mountport = 1; /* We use the now deprecated tpcmux port to indcate that we have an AF_LOCAL port */
+ NFS_VFS_DBG("Setting mount local port %s (%d)\n", nmp->nm_mount_localport, nmp->nm_mountport);
+ }
+ if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_SET_MOUNT_OWNER)) {
+ xb_get_32(error, &xb, set_owner);
+ nfsmerr_if(error);
+ error = vfs_context_suser(ctx);
+ /*
+ * root can set owner to whatever, user can set owner to self
+ */
+ if ((error) && (set_owner == kauth_cred_getuid(vfs_context_ucred(ctx)))) {
+ /* ok for non-root can set owner to self */
+ error = 0;
+ }
+ nfsmerr_if(error);
+ }
+
/*
* Sanity check/finalize settings.
*/
}
nfsmerr_if(error);
- /* init mount's mntfromname to first location */
if (!NM_OMATTR_GIVEN(nmp, MNTFROM)) {
+ /* init mount's mntfromname to first location */
nfs_location_mntfromname(&nmp->nm_locations, firstloc,
- vfs_statfs(mp)->f_mntfromname, sizeof(vfs_statfs(mp)->f_mntfromname), 0);
+ vfs_statfs(mp)->f_mntfromname,
+ sizeof(vfs_statfs(mp)->f_mntfromname), 0);
}
/* Need to save the mounting credential for v4. */
}
nfsmerr_if(error);
- /* do mount's initial socket connection */
- error = nfs_mount_connect(nmp);
- nfsmerr_if(error);
-
/* set up the version-specific function tables */
if (nmp->nm_vers < NFS_VER4) {
nmp->nm_funcs = &nfs3_funcs;
} else {
+#if CONFIG_NFS4
nmp->nm_funcs = &nfs4_funcs;
+#else
+ /* don't go any further if we don't support NFS4 */
+ nmp->nm_funcs = NULL;
+ error = ENOTSUP;
+ nfsmerr_if(error);
+#endif
}
+ /* do mount's initial socket connection */
+ error = nfs_mount_connect(nmp);
+ nfsmerr_if(error);
+
/* sanity check settings now that version/connection is set */
if (nmp->nm_vers == NFS_VER2) { /* ignore RDIRPLUS on NFSv2 */
NFS_BITMAP_CLR(nmp->nm_flags, NFS_MFLAG_RDIRPLUS);
}
+#if CONFIG_NFS4
if (nmp->nm_vers >= NFS_VER4) {
if (NFS_BITMAP_ISSET(nmp->nm_flags, NFS_MFLAG_ACLONLY)) { /* aclonly trumps noacl */
NFS_BITMAP_CLR(nmp->nm_flags, NFS_MFLAG_NOACL);
error = EINVAL; /* disabled/local lock mode only allowed on v2/v3 */
}
} else {
- /* ignore these if not v4 */
- NFS_BITMAP_CLR(nmp->nm_flags, NFS_MFLAG_NOCALLBACK);
- NFS_BITMAP_CLR(nmp->nm_flags, NFS_MFLAG_NAMEDATTR);
- NFS_BITMAP_CLR(nmp->nm_flags, NFS_MFLAG_NOACL);
- NFS_BITMAP_CLR(nmp->nm_flags, NFS_MFLAG_ACLONLY);
- }
+#endif
+ /* ignore these if not v4 */
+ NFS_BITMAP_CLR(nmp->nm_flags, NFS_MFLAG_NOCALLBACK);
+ NFS_BITMAP_CLR(nmp->nm_flags, NFS_MFLAG_NAMEDATTR);
+ NFS_BITMAP_CLR(nmp->nm_flags, NFS_MFLAG_NOACL);
+ NFS_BITMAP_CLR(nmp->nm_flags, NFS_MFLAG_ACLONLY);
+#if CONFIG_NFS4
+}
+#endif
nfsmerr_if(error);
if (nmp->nm_sotype == SOCK_DGRAM) {
TAILQ_INIT(&nmp->nm_cwndq);
}
+ if (nmp->nm_saddr->sa_family == AF_LOCAL) {
+ struct sockaddr_un *un = (struct sockaddr_un *)nmp->nm_saddr;
+ size_t size;
+ int n = snprintf(vfs_statfs(mp)->f_mntfromname, sizeof(vfs_statfs(mp)->f_mntfromname), "<%s>:", un->sun_path);
+
+ if (n > 0 && (size_t)n < sizeof(vfs_statfs(mp)->f_mntfromname)) {
+ size = sizeof(vfs_statfs(mp)->f_mntfromname) - n;
+ nfs_location_mntfromname(&nmp->nm_locations, firstloc,
+ &vfs_statfs(mp)->f_mntfromname[n], size, 1);
+ }
+ }
+
+
/*
* Get the root node/attributes from the NFS server and
* do any basic, version-specific setup.
*/
nmp->nm_dnp = np;
*vpp = NFSTOV(np);
+
+
/* get usecount and drop iocount */
error = vnode_ref(*vpp);
vnode_put(*vpp);
sbp->f_ffree = nmp->nm_fsattr.nfsa_files_free;
sbp->f_iosize = nfs_iosize;
+ if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_SET_MOUNT_OWNER)) {
+ sbp->f_owner = set_owner;
+ }
+
/*
* Calculate the size used for I/O buffers. Use the larger
* of the two sizes to minimise NFS requests but make sure
* buffers into multiple requests if the buffer size is
* larger than the I/O size.
*/
-#ifndef CONFIG_EMBEDDED
iosize = max(nmp->nm_rsize, nmp->nm_wsize);
if (iosize < PAGE_SIZE) {
iosize = PAGE_SIZE;
}
-#else
- iosize = PAGE_SIZE;
-#endif
nmp->nm_biosize = trunc_page_32(iosize);
/* For NFSv3 and greater, there is a (relatively) reliable ACCESS call. */
- if (nmp->nm_vers > NFS_VER2) {
+ if (nmp->nm_vers > NFS_VER2 && !NMFLAG(nmp, NOOPAQUE_AUTH)
+ ) {
vfs_setauthopaqueaccess(mp);
}
break;
}
+
/* success! */
lck_mtx_lock(&nmp->nm_lock);
nmp->nm_state |= NFSSTA_MOUNTED;
nfs_mirror_mount_domount(vnode_t dvp, vnode_t vp, vfs_context_t ctx)
{
nfsnode_t np = VTONFS(vp);
+#if CONFIG_NFS4
nfsnode_t dnp = VTONFS(dvp);
+#endif
struct nfsmount *nmp = NFSTONMP(np);
char fstype[MFSTYPENAMELEN], *mntfromname = NULL, *path = NULL, *relpath, *p, *cp;
int error = 0, pathbuflen = MAXPATHLEN, i, mntflags = 0, referral, skipcopy = 0;
bzero(&nfsls, sizeof(nfsls));
}
- xb_init(&xbnew, 0);
+ xb_init(&xbnew, XDRBUF_NONE);
if (!nmp || (nmp->nm_state & (NFSSTA_FORCE | NFSSTA_DEAD))) {
return ENXIO;
const char *vname = vnode_getname(NFSTOV(np));
if (!vname) {
error = ENOENT;
- } else {
+ }
+#if CONFIG_NFS4
+ else {
error = nfs4_get_fs_locations(nmp, dnp, NULL, 0, vname, ctx, &nfsls);
vnode_putname(vname);
if (!error && (nfsls.nl_numlocs < 1)) {
error = ENOENT;
}
}
+#endif
nfsmerr_if(error);
}
}
if (referral) {
NFS_BITMAP_SET(newmattrs, NFS_MATTR_FS_LOCATIONS);
+ NFS_BITMAP_CLR(newmattrs, NFS_MATTR_MNTFROM);
} else {
NFS_BITMAP_SET(newmattrs, NFS_MATTR_FH);
}
NFS_BITMAP_SET(newmattrs, NFS_MATTR_FLAGS);
NFS_BITMAP_SET(newmattrs, NFS_MATTR_MNTFLAGS);
- NFS_BITMAP_CLR(newmattrs, NFS_MATTR_MNTFROM);
+ NFS_BITMAP_SET(newmattrs, NFS_MATTR_SET_MOUNT_OWNER);
xb_add_bitmap(error, &xbnew, newmattrs, NFS_MATTR_BITMAP_LEN);
attrslength_offset = xb_offset(&xbnew);
xb_copy_32(error, &xb, &xbnew, val); /* attrs length */
xb_copy_opaque(error, &xb, &xbnew); /* component */
}
/* add additional components */
- for (comp = 0; !skipcopy && !error && (comp < relpathcomps); comp++) {
- p = relpath;
- while (*p && (*p == '/')) {
+ p = relpath;
+ while (*p && (*p == '/')) {
+ p++;
+ }
+ while (*p && !error) {
+ cp = p;
+ while (*p && (*p != '/')) {
p++;
}
- while (*p && !error) {
- cp = p;
- while (*p && (*p != '/')) {
- p++;
- }
- xb_add_string(error, &xbnew, cp, (p - cp)); /* component */
- while (*p && (*p == '/')) {
- p++;
- }
+ xb_add_string(error, &xbnew, cp, (p - cp)); /* component */
+ while (*p && (*p == '/')) {
+ p++;
}
}
xb_copy_opaque(error, &xb, &xbnew); /* fs location info */
error = xb_add_bytes(&xbnew, buf, count, 1);
}
}
+ /*
+ * The following string copies rely on the fact that we already validated
+ * these data when creating the initial mount point.
+ */
+ if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_REALM)) {
+ xb_add_string(error, &xbnew, nmp->nm_realm, strlen(nmp->nm_realm));
+ }
+ if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_PRINCIPAL)) {
+ xb_add_string(error, &xbnew, nmp->nm_principal, strlen(nmp->nm_principal));
+ }
+ if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_SVCPRINCIPAL)) {
+ xb_add_string(error, &xbnew, nmp->nm_sprinc, strlen(nmp->nm_sprinc));
+ }
+ if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_LOCAL_NFS_PORT)) {
+ xb_add_string(error, &xbnew, nmp->nm_nfs_localport, strlen(nmp->nm_nfs_localport));
+ }
+ if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_LOCAL_MOUNT_PORT)) {
+ xb_add_string(error, &xbnew, nmp->nm_mount_localport, strlen(nmp->nm_mount_localport));
+ }
+ if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_SET_MOUNT_OWNER)) {
+ /* drop embedded owner value */
+ xb_get_32(error, &xb, count);
+ }
+ /* New mount always gets same owner as this mount */
+ xb_add_32(error, &xbnew, vnode_mount(vp)->mnt_vfsstat.f_owner);
xb_build_done(error, &xbnew);
/* update opaque counts */
/*
* For kernel_mount() call, use the existing mount flags (instead of the
* original flags) because flags like MNT_NOSUID and MNT_NODEV may have
- * been silently enforced.
+ * been silently enforced. Also, in terms of MACF, the _kernel_ is
+ * performing the mount (and enforcing all of the mount options), so we
+ * use the kernel context for the mount call.
*/
mntflags = vnode_vfsvisflags(vp);
mntflags |= (MNT_AUTOMOUNTED | MNT_DONTBROWSE);
+ ctx = vfs_context_kernel();
/* do the mount */
error = kernel_mount(fstype, dvp, vp, path, xb_buffer_base(&xbnew), argslength,
/*
* trigger vnode functions
*/
+#define NFS_TRIGGER_DEBUG 1
resolver_result_t
nfs_mirror_mount_trigger_resolve(
__unused void *data,
vfs_context_t ctx)
{
- nfsnode_t np = VTONFS(vp);
- vnode_t pvp = NULLVP;
- int error = 0;
+ nfsnode_t np = VTONFS(vp);
+ vnode_t pvp = NULLVP;
+ int error = 0;
+ int didBusy = 0;
resolver_result_t result;
/*
#endif
return result;
}
+ didBusy = 1;
+
+ /* Check again, in case the mount happened while we were setting busy */
+ if (vnode_mountedhere(vp) != NULL) {
+ /* Been there. Done that. Let's just say it succeeded. */
+ error = 0;
+ goto skipmount;
+ }
+ nfs_node_lock_force(np);
+ if (np->n_flag & NDISARMTRIGGER) {
+ error = ECANCELED;
+ nfs_node_unlock(np);
+ goto skipmount;
+ }
+ nfs_node_unlock(np);
pvp = vnode_getparent(vp);
if (pvp == NULLVP) {
if (pvp != NULLVP) {
vnode_put(pvp);
}
- nfs_node_clear_busy(np);
+ if (didBusy) {
+ nfs_node_clear_busy(np);
+ }
return result;
}
return VFS_RETURNED;
}
nmp = VFSTONFS(mp);
- if (!nmp || !NMFLAG(nmp, EPHEMERAL)) {
+ if (!nmp || !NMFLAG(nmp, EPHEMERAL)
+ ) {
return VFS_RETURNED;
}
hinfo->mountcount++;
uint32_t mntvers, mntport, val;
struct sockaddr_storage ss;
struct sockaddr *saddr = (struct sockaddr*)&ss;
+ struct sockaddr_un *sun = (struct sockaddr_un*)saddr;
nfsm_chain_null(&nmreq);
nfsm_chain_null(&nmrep);
((struct sockaddr_in*)saddr)->sin_port = htons(nmp->nm_mountport);
}
mntport = ntohs(((struct sockaddr_in*)saddr)->sin_port);
- } else {
+ } else if (saddr->sa_family == AF_INET6) {
if (nmp->nm_mountport) {
((struct sockaddr_in6*)saddr)->sin6_port = htons(nmp->nm_mountport);
}
mntport = ntohs(((struct sockaddr_in6*)saddr)->sin6_port);
+ } else { /* Local domain socket */
+ mntport = ((struct sockaddr_un *)saddr)->sun_path[0]; /* Do we have and address? */
+ mntproto = IPPROTO_TCP; /* XXX rpcbind only listens on streams sockets for now */
}
while (!mntport) {
- error = nfs_portmap_lookup(nmp, ctx, saddr, NULL, RPCPROG_MNT, mntvers, mntproto, timeo);
+ error = nfs_portmap_lookup(nmp, ctx, saddr, NULL, RPCPROG_MNT, mntvers,
+ mntproto == IPPROTO_UDP ? SOCK_DGRAM : SOCK_STREAM, timeo);
nfsmout_if(error);
if (saddr->sa_family == AF_INET) {
mntport = ntohs(((struct sockaddr_in*)saddr)->sin_port);
- } else {
+ } else if (saddr->sa_family == AF_INET6) {
mntport = ntohs(((struct sockaddr_in6*)saddr)->sin6_port);
+ } else if (saddr->sa_family == AF_LOCAL) {
+ mntport = ((struct sockaddr_un*)saddr)->sun_path[0];
}
if (!mntport) {
/* if not found and TCP, then retry with UDP */
}
mntproto = IPPROTO_UDP;
bcopy(sa, saddr, min(sizeof(ss), sa->sa_len));
+ if (saddr->sa_family == AF_LOCAL) {
+ strlcpy(sun->sun_path, RPCB_TICLTS_PATH, sizeof(sun->sun_path));
+ }
}
}
nfsmout_if(error || !mntport);
bcopy(nmp->nm_saddr, saddr, min(sizeof(ss), nmp->nm_saddr->sa_len));
if (saddr->sa_family == AF_INET) {
((struct sockaddr_in*)saddr)->sin_port = htons(mntport);
- } else {
+ } else if (saddr->sa_family == AF_INET6) {
((struct sockaddr_in6*)saddr)->sin6_port = htons(mntport);
+ } else { /* Local domain socket */
+ mntport = ((struct sockaddr_un *)saddr)->sun_path[0]; /* Do we have and address? */
}
while (!mntport) {
nfsmout_if(error);
if (saddr->sa_family == AF_INET) {
mntport = ntohs(((struct sockaddr_in*)saddr)->sin_port);
- } else {
+ } else if (saddr->sa_family == AF_INET6) {
mntport = ntohs(((struct sockaddr_in6*)saddr)->sin6_port);
+ } else { /* Local domain socket */
+ mntport = ((struct sockaddr_un *)saddr)->sun_path[0]; /* Do we have and address? */
}
/* if not found and mntvers > VER1, then retry with VER1 */
if (!mntport) {
struct nfsmount *nmp;
vnode_t vp;
int error, flags = 0;
- struct timespec ts = { 1, 0 };
+ struct timespec ts = { .tv_sec = 1, .tv_nsec = 0 };
nmp = VFSTONFS(mp);
lck_mtx_lock(&nmp->nm_lock);
{
struct nfsreq *req, *treq;
struct nfs_reqqhead iodq, resendq;
- struct timespec ts = { 1, 0 };
+ struct timespec ts = { .tv_sec = 1, .tv_nsec = 0 };
struct nfs_open_owner *noop, *nextnoop;
nfsnode_t np;
int docallback;
nmp->nm_state |= nm_state_flags;
nmp->nm_ref++;
lck_mtx_unlock(&nmp->nm_lock);
-
+#if CONFIG_NFS4
/* stop callbacks */
if ((nmp->nm_vers >= NFS_VER4) && !NMFLAG(nmp, NOCALLBACK) && nmp->nm_cbid) {
nfs4_mount_callback_shutdown(nmp);
}
-
+#endif
+#if CONFIG_NFS_GSS
/* Destroy any RPCSEC_GSS contexts */
nfs_gss_clnt_ctx_unmount(nmp);
+#endif
/* mark the socket for termination */
lck_mtx_lock(&nmp->nm_lock);
lck_mtx_lock(&nmp->nm_lock);
+#if CONFIG_NFS4
if ((nmp->nm_vers >= NFS_VER4) && !NMFLAG(nmp, NOCALLBACK) && nmp->nm_cbid) {
/* clear out any pending delegation return requests */
while ((np = TAILQ_FIRST(&nmp->nm_dreturnq))) {
thread_call_free(nmp->nm_renew_timer);
nmp->nm_renew_timer = NULL;
}
-
+#endif
lck_mtx_unlock(&nmp->nm_lock);
if (nmp->nm_state & NFSSTA_MOUNTED) {
}
}
+#if CONFIG_NFS4
if ((nmp->nm_vers >= NFS_VER4) && nmp->nm_longid) {
/* remove/deallocate the client ID data */
lck_mtx_lock(nfs_global_mutex);
nmp->nm_longid = NULL;
lck_mtx_unlock(nfs_global_mutex);
}
-
+#endif
/*
* Be sure all requests for this mount are completed
* and removed from the resend queue.
}
lck_mtx_unlock(&nmp->nm_lock);
+#if CONFIG_NFS4
/* clean up NFSv4 state */
if (nmp->nm_vers >= NFS_VER4) {
lck_mtx_lock(&nmp->nm_lock);
}
lck_mtx_unlock(&nmp->nm_lock);
}
-
+#endif
nfs_mount_rele(nmp);
}
if (nmp->nm_fh) {
FREE(nmp->nm_fh, M_TEMP);
}
+
+
FREE_ZONE(nmp, sizeof(struct nfsmount), M_NFSMNT);
}
uint32_t val = 0, bsize = 0;
struct sockaddr *rqsaddr;
struct timeval now;
- struct timespec ts = { 1, 0 };
+ struct timespec ts = { .tv_sec = 1, .tv_nsec = 0 };
if (!nmp->nm_saddr) {
return ENXIO;
}
- if (NMFLAG(nmp, NOQUOTA)) {
+ if (NMFLAG(nmp, NOQUOTA) || nmp->nm_saddr->sa_family == AF_LOCAL /* XXX for now */) {
return ENOTSUP;
}
nfsm_chain_cleanup(&nmrep);
return error;
}
-
+#if CONFIG_NFS4
int
nfs4_getquota(struct nfsmount *nmp, vfs_context_t ctx, uid_t id, int type, struct dqblk *dqb)
{
kauth_cred_unref(&cred);
return error;
}
-
+#endif /* CONFIG_NFS4 */
int
nfs_vfs_quotactl(mount_t mp, int cmds, uid_t uid, caddr_t datap, vfs_context_t ctx)
{
nfs_mountinfo_assemble(struct nfsmount *nmp, struct xdrbuf *xb)
{
struct xdrbuf xbinfo, xborig;
- char sotype[6];
+ char sotype[16];
uint32_t origargsvers, origargslength;
uint32_t infolength_offset, curargsopaquelength_offset, curargslength_offset, attrslength_offset, curargs_end_offset, end_offset;
uint32_t miattrs[NFS_MIATTR_BITMAP_LEN];
NFS_BITMAP_ZERO(mattrs, NFS_MATTR_BITMAP_LEN);
NFS_BITMAP_SET(mattrs, NFS_MATTR_FLAGS);
NFS_BITMAP_SET(mattrs, NFS_MATTR_NFS_VERSION);
+#if CONFIG_NFS4
if (nmp->nm_vers >= NFS_VER4) {
NFS_BITMAP_SET(mattrs, NFS_MATTR_NFS_MINOR_VERSION);
}
+#endif
NFS_BITMAP_SET(mattrs, NFS_MATTR_READ_SIZE);
NFS_BITMAP_SET(mattrs, NFS_MATTR_WRITE_SIZE);
NFS_BITMAP_SET(mattrs, NFS_MATTR_READDIR_SIZE);
}
NFS_BITMAP_SET(mattrs, NFS_MATTR_MAX_GROUP_LIST);
NFS_BITMAP_SET(mattrs, NFS_MATTR_SOCKET_TYPE);
- NFS_BITMAP_SET(mattrs, NFS_MATTR_NFS_PORT);
- if ((nmp->nm_vers < NFS_VER4) && nmp->nm_mountport) {
+ if (nmp->nm_saddr->sa_family != AF_LOCAL) {
+ NFS_BITMAP_SET(mattrs, NFS_MATTR_NFS_PORT);
+ }
+ if ((nmp->nm_vers < NFS_VER4) && nmp->nm_mountport && !nmp->nm_mount_localport) {
NFS_BITMAP_SET(mattrs, NFS_MATTR_MOUNT_PORT);
}
NFS_BITMAP_SET(mattrs, NFS_MATTR_REQUEST_TIMEOUT);
if (nmp->nm_sprinc) {
NFS_BITMAP_SET(mattrs, NFS_MATTR_SVCPRINCIPAL);
}
+ if (nmp->nm_nfs_localport) {
+ NFS_BITMAP_SET(mattrs, NFS_MATTR_LOCAL_NFS_PORT);
+ }
+ if ((nmp->nm_vers < NFS_VER4) && nmp->nm_mount_localport) {
+ NFS_BITMAP_SET(mattrs, NFS_MATTR_LOCAL_MOUNT_PORT);
+ }
/* set up current mount flags bitmap */
/* first set the flags that we will be setting - either on OR off */
}
NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_NONEGNAMECACHE);
NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_MUTEJUKEBOX);
+#if CONFIG_NFS4
if (nmp->nm_vers >= NFS_VER4) {
NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_EPHEMERAL);
NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_NOCALLBACK);
NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_NOACL);
NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_ACLONLY);
}
+#endif
NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_NFC);
NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_NOQUOTA);
if (nmp->nm_vers < NFS_VER4) {
if (NMFLAG(nmp, MUTEJUKEBOX)) {
NFS_BITMAP_SET(mflags, NFS_MFLAG_MUTEJUKEBOX);
}
+#if CONFIG_NFS4
if (nmp->nm_vers >= NFS_VER4) {
if (NMFLAG(nmp, EPHEMERAL)) {
NFS_BITMAP_SET(mflags, NFS_MFLAG_EPHEMERAL);
NFS_BITMAP_SET(mflags, NFS_MFLAG_ACLONLY);
}
}
+#endif
if (NMFLAG(nmp, NFC)) {
NFS_BITMAP_SET(mflags, NFS_MFLAG_NFC);
}
xb_add_bitmap(error, &xbinfo, mflags_mask, NFS_MFLAG_BITMAP_LEN);
xb_add_bitmap(error, &xbinfo, mflags, NFS_MFLAG_BITMAP_LEN);
xb_add_32(error, &xbinfo, nmp->nm_vers); /* NFS_VERSION */
+#if CONFIG_NFS4
if (nmp->nm_vers >= NFS_VER4) {
xb_add_32(error, &xbinfo, nmp->nm_minor_vers); /* NFS_MINOR_VERSION */
}
+#endif
xb_add_32(error, &xbinfo, nmp->nm_rsize); /* READ_SIZE */
xb_add_32(error, &xbinfo, nmp->nm_wsize); /* WRITE_SIZE */
xb_add_32(error, &xbinfo, nmp->nm_readdirsize); /* READDIR_SIZE */
}
xb_add_32(error, &xbinfo, nmp->nm_numgrps); /* MAX_GROUP_LIST */
nfsmerr_if(error);
- snprintf(sotype, sizeof(sotype), "%s%s", (nmp->nm_sotype == SOCK_DGRAM) ? "udp" : "tcp",
- nmp->nm_sofamily ? (nmp->nm_sofamily == AF_INET) ? "4" : "6" : "");
- xb_add_string(error, &xbinfo, sotype, strlen(sotype)); /* SOCKET_TYPE */
- xb_add_32(error, &xbinfo, ntohs(((struct sockaddr_in*)nmp->nm_saddr)->sin_port)); /* NFS_PORT */
- if ((nmp->nm_vers < NFS_VER4) && nmp->nm_mountport) {
- xb_add_32(error, &xbinfo, nmp->nm_mountport); /* MOUNT_PORT */
+
+ switch (nmp->nm_saddr->sa_family) {
+ case AF_INET:
+ case AF_INET6:
+ snprintf(sotype, sizeof(sotype), "%s%s", (nmp->nm_sotype == SOCK_DGRAM) ? "udp" : "tcp",
+ nmp->nm_sofamily ? (nmp->nm_sofamily == AF_INET) ? "4" : "6" : "");
+ xb_add_string(error, &xbinfo, sotype, strlen(sotype)); /* SOCKET_TYPE */
+ xb_add_32(error, &xbinfo, ntohs(((struct sockaddr_in*)nmp->nm_saddr)->sin_port)); /* NFS_PORT */
+ if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_MOUNT_PORT)) {
+ xb_add_32(error, &xbinfo, nmp->nm_mountport); /* MOUNT_PORT */
+ }
+ break;
+ case AF_LOCAL:
+ strlcpy(sotype, (nmp->nm_sotype == SOCK_DGRAM) ? "ticlts" : "ticotsord", sizeof(sotype));
+ xb_add_string(error, &xbinfo, sotype, strlen(sotype));
+ break;
+ default:
+ NFS_VFS_DBG("Unsupported address family %d\n", nmp->nm_saddr->sa_family);
+ printf("Unsupported address family %d\n", nmp->nm_saddr->sa_family);
+ error = EINVAL;
+ break;
}
+
timeo = (nmp->nm_timeo * 10) / NFS_HZ;
xb_add_32(error, &xbinfo, timeo / 10); /* REQUEST_TIMEOUT */
xb_add_32(error, &xbinfo, (timeo % 10) * 100000000); /* REQUEST_TIMEOUT */
if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_SVCPRINCIPAL)) {
xb_add_string(error, &xbinfo, nmp->nm_sprinc, strlen(nmp->nm_sprinc));
}
-
+ if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_LOCAL_NFS_PORT)) {
+ struct sockaddr_un *un = (struct sockaddr_un *)nmp->nm_saddr;
+ xb_add_string(error, &xbinfo, un->sun_path, strlen(un->sun_path));
+ }
+ if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_LOCAL_MOUNT_PORT)) {
+ xb_add_string(error, &xbinfo, nmp->nm_mount_localport, strlen(nmp->nm_mount_localport));
+ }
curargs_end_offset = xb_offset(&xbinfo);
/* NFS_MIATTR_CUR_LOC_INDEX */
struct xdrbuf xb;
struct netfs_status *nsp = NULL;
int timeoutmask;
- uint pos, totlen, count, numThreads;
+ uint totlen, count, numThreads;
#if NFSSERVER
+ uint pos;
struct nfs_exportfs *nxfs;
struct nfs_export *nx;
struct nfs_active_user_list *ulist;
if (((nmp = VFSTONFS(mp))) == NULL) {
return ENOENT;
}
- xb_init(&xb, 0);
+ xb_init(&xb, XDRBUF_NONE);
if ((error = nfs_mountinfo_assemble(nmp, &xb))) {
return error;
}
if (nmp->nm_lockmode == NFS_LOCK_MODE_LOCAL) {
/* can't toggle locks when using local locks */
error = EINVAL;
+#if CONFIG_NFS4
} else if ((nmp->nm_vers >= NFS_VER4) && val) {
/* can't disable locks for NFSv4 */
error = EINVAL;
+#endif
} else if (val) {
if ((nmp->nm_vers <= NFS_VER3) && (nmp->nm_lockmode == NFS_LOCK_MODE_ENABLED)) {
nfs_lockd_mount_unregister(nmp);