/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2011 Bayard G. Bell. All rights reserved.
* Copyright 2013 Joyent, Inc. All rights reserved.
*/
/*
* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T
* All rights reserved.
*/
#include <sys/vfs_opreg.h>
#include <sys/pathname.h>
#include <sys/bootconf.h>
#include <nfs/nfs_clnt.h>
/*
* This is the loadable module wrapper.
*/
/*
* The pseudo NFS filesystem to allow diskless booting to dynamically
* mount either a NFS V2, NFS V3, or NFS V4 filesystem. This only implements
* the VFS_MOUNTROOT op and is only intended to be used by the
* diskless booting code until the real root filesystem is mounted.
* Nothing else should ever call this!
*
* The strategy is that if the initial rootfs type is set to "nfsdyn"
* by loadrootmodules() this filesystem is called to mount the
* root filesystem. It first attempts to mount a V4 filesystem, and if that
* fails due to an RPC version mismatch it tries V3 and finally V2.
* Once the real mount succeeds the vfsops and rootfs name are changed
* to reflect the real filesystem type.
*/
static int nfsdyninit(int, char *);
/*
* The following data structures are used to configure the NFS
* system call, the NFS Version 2 client VFS, and the NFS Version
* 3 client VFS into the system. The NFS Version 4 structures are defined in
*/
/*
* The NFS system call.
*/
2,
};
"NFS syscall, client, and common",
};
#ifdef _SYSCALL32_IMPL
"NFS syscall, client, and common (32-bit)",
};
#endif /* _SYSCALL32_IMPL */
/*
* The NFS Dynamic client VFS.
*/
"nfsdyn",
0,
};
"network filesystem",
&vfw
};
/*
* The NFS Version 2 client VFS.
*/
"nfs",
};
"network filesystem version 2",
&vfw2
};
/*
* The NFS Version 3 client VFS.
*/
"nfs3",
};
"network filesystem version 3",
&vfw3
};
/*
* We have too many linkage structures so we define our own XXX
*/
struct modlinkage_big {
/* linkage structures */
};
/*
* All of the module configuration linkages required to configure
* the system call and client VFS's into the system.
*/
&modlsys,
#ifdef _SYSCALL32_IMPL
#endif
&modlfs,
&modlfs2,
&modlfs3,
&modlfs4,
};
/*
* This routine is invoked automatically when the kernel module
* containing this routine is loaded. This allows module specific
* initialization to be done when the module is loaded.
*/
int
_init(void)
{
int status;
if ((status = nfs_clntinit()) != 0) {
return (status);
}
/*
* Create the version specific kstats.
*
* PSARC 2001/697 Contract Private Interface
* All nfs kstats are under SunMC contract
* Please refer to the PSARC listed above and contact
* SunMC before making any changes!
*
* Changes must be reviewed by Solaris File Sharing
* Changes must be communicated to contract-2001-697@sun.com
*
*/
if (status) {
(void) zone_key_delete(nfsstat_zone_key);
/*
* Failed to install module, cleanup previous
* initialization work.
*/
nfs_clntfini();
/*
* Clean up work performed indirectly by mod_installfs()
* as a result of our call to mod_install().
*/
nfs4fini();
nfs3fini();
nfsfini();
}
return (status);
}
int
_fini(void)
{
/* Don't allow module to be unloaded */
return (EBUSY);
}
int
{
}
/*
* General utilities
*/
/*
* Returns the preferred transfer size in bytes based on
* what network interfaces are available.
*/
int
nfstsize(void)
{
/*
* For the moment, just return NFS_MAXDATA until we can query the
* appropriate transport.
*/
return (NFS_MAXDATA);
}
/*
* Returns the preferred transfer size in bytes based on
* what network interfaces are available.
*/
/* this should reflect the largest transfer size possible */
int
nfs3tsize(void)
{
/*
* For the moment, just return nfs3_max_transfer_size until we
* can query the appropriate transport.
*/
return (nfs3_max_transfer_size);
}
{
return (nfs3_max_transfer_size_cots);
return (nfs3_max_transfer_size_rdma);
return (nfs3_max_transfer_size_clts);
}
{
return (nfs3_max_transfer_size_cots);
return (nfs3_max_transfer_size_rdma);
return (nfs3_max_transfer_size_clts);
}
/* ARGSUSED */
static int
{
};
int error;
if (error != 0)
return (error);
return (0);
}
/* ARGSUSED */
static int
{
int error;
int vfsflags;
char *root_path;
char *name;
/* do this BEFORE getfile which causes xid stamps to be initialized */
if (why == ROOT_REMOUNT) {
/*
* Shouldn't happen.
*/
panic("nfs3_mountroot: why == ROOT_REMOUNT\n");
}
if (why == ROOT_UNMOUNT) {
/*
* Nothing to do for NFS.
*/
return (0);
}
/*
* why == ROOT_INIT
*/
*name = 0;
/*
* First try version 4
*/
vfsflags = 0;
if (error != EPROTONOSUPPORT) {
"Unable to mount NFS root filesystem: %m");
return (error);
}
/*
* Then try version 3
*/
vfsflags = 0;
if (error != EPROTONOSUPPORT) {
"Unable to mount NFS root filesystem: %m");
return (error);
}
/*
* Finally, try version 2
*/
vfsflags = 0;
"Unable to mount NFS root filesystem: %m");
return (error);
}
}
}
}
int
{
int flags;
#ifdef lint
#endif
/*
* Set option fields in mount info record
*/
if (flags & NFSMNT_NOAC) {
}
if (flags & NFSMNT_NOCTO)
if (flags & NFSMNT_LLOCK)
if (flags & NFSMNT_GRPID)
if (flags & NFSMNT_RETRANS) {
return (EINVAL);
}
if (flags & NFSMNT_TIMEO) {
return (EINVAL);
/*
* The following scales the standard deviation and
* and current retransmission timer to match the
* initial value for the timeout specified.
*/
}
if (flags & NFSMNT_RSIZE) {
return (EINVAL);
}
if (flags & NFSMNT_WSIZE) {
return (EINVAL);
}
if (flags & NFSMNT_ACREGMIN) {
else
ACMINMAX);
}
if (flags & NFSMNT_ACREGMAX) {
else
ACMAXMAX);
}
if (flags & NFSMNT_ACDIRMIN) {
else
ACMINMAX);
}
if (flags & NFSMNT_ACDIRMAX) {
else
ACMAXMAX);
}
if (flags & NFSMNT_LOOPBACK)
return (0);
}
/*
* Set or Clear direct I/O flag
* VOP_RWLOCK() is held for write access to prevent a race condition
* which would occur if a process is in the middle of a write when
* directio flag gets set. It is possible that all pages may not get flushed.
*/
/* ARGSUSED */
int
{
int error = 0;
if (cmd == DIRECTIO_ON) {
return (0);
/*
* Flush the page cache.
*/
return (0);
}
if (vn_has_cached_data(vp) &&
if (error) {
}
return (error);
}
}
return (0);
}
if (cmd == DIRECTIO_OFF) {
return (0);
}
return (EINVAL);
}