* Copyright (c) 1989, 1993, 1995
* The Regents of the University of California. All rights reserved.
* This code is derived from software contributed to Berkeley by
* Rick Macklem at The University of Guelph.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* @(#)nfs_vfsops.c 8.12 (Berkeley) 5/20/95
#include <sys/socketvar.h>
#include <nfs/nfsproto.h>
#include <nfs/nfsmount.h>
#include <nfs/xdr_subs.h>
#include <nfs/nfsm_subs.h>
#include <nfs/nfsdiskless.h>
struct nfsstats nfsstats
;
static int nfs_sysctl(int *, u_int
, void *, size_t *, void *, size_t,
struct vfsops nfs_vfsops
= {
* This structure must be filled in by a primary bootstrap or bootstrap
* server for a diskless/dataless machine. It is initialized below just
* to ensure that it is allocated to initialized data (.data not .bss).
struct nfs_diskless nfs_diskless
= { 0 };
int nfs_diskless_valid
= 0;
void nfs_disconnect
__P((struct nfsmount
*));
void nfsargs_ntoh
__P((struct nfs_args
*));
int nfs_fsinfo
__P((struct nfsmount
*, struct vnode
*, struct ucred
*,
static int nfs_mountdiskless
__P((char *, char *, int, struct sockaddr_in
*,
struct nfs_args
*, struct proc
*, struct vnode
**, struct mount
**));
register struct statfs
*sbp
;
register struct vnode
*vp
;
register struct nfs_statfs
*sfp
;
struct nfsmount
*nmp
= VFSTONFS(mp
);
int error
= 0, v3
= (nmp
->nm_flag
& NFSMNT_NFSV3
), retattr
;
struct mbuf
*mreq
, *mrep
, *md
, *mb
, *mb2
;
sfp
= (struct nfs_statfs
*)0;
error
= nfs_nget(mp
, (nfsfh_t
*)nmp
->nm_fh
, nmp
->nm_fhsize
, &np
);
if (v3
&& (nmp
->nm_flag
& NFSMNT_GOTFSINFO
) == 0)
(void)nfs_fsinfo(nmp
, vp
, cred
, p
);
nfsstats
.rpccnt
[NFSPROC_FSSTAT
]++;
nfsm_reqhead(vp
, NFSPROC_FSSTAT
, NFSX_FH(v3
));
nfsm_request(vp
, NFSPROC_FSSTAT
, p
, cred
);
nfsm_postop_attr(vp
, retattr
);
nfsm_dissect(sfp
, struct nfs_statfs
*, NFSX_STATFS(v3
));
sbp
->f_iosize
= min(nmp
->nm_rsize
, nmp
->nm_wsize
);
sbp
->f_bsize
= NFS_FABLKSIZE
;
fxdr_hyper(&sfp
->sf_tbytes
, &tquad
);
sbp
->f_blocks
= (long)(tquad
/ ((u_quad_t
)NFS_FABLKSIZE
));
fxdr_hyper(&sfp
->sf_fbytes
, &tquad
);
sbp
->f_bfree
= (long)(tquad
/ ((u_quad_t
)NFS_FABLKSIZE
));
fxdr_hyper(&sfp
->sf_abytes
, &tquad
);
sbp
->f_bavail
= (long)(tquad
/ ((u_quad_t
)NFS_FABLKSIZE
));
sbp
->f_files
= (fxdr_unsigned(long, sfp
->sf_tfiles
.nfsuquad
[1])
sbp
->f_ffree
= (fxdr_unsigned(long, sfp
->sf_ffiles
.nfsuquad
[1])
sbp
->f_bsize
= fxdr_unsigned(long, sfp
->sf_bsize
);
sbp
->f_blocks
= fxdr_unsigned(long, sfp
->sf_blocks
);
sbp
->f_bfree
= fxdr_unsigned(long, sfp
->sf_bfree
);
sbp
->f_bavail
= fxdr_unsigned(long, sfp
->sf_bavail
);
if (sbp
!= &mp
->mnt_stat
) {
bcopy(mp
->mnt_stat
.f_mntonname
, sbp
->f_mntonname
, MNAMELEN
);
bcopy(mp
->mnt_stat
.f_mntfromname
, sbp
->f_mntfromname
, MNAMELEN
);
* nfs version 3 fsinfo rpc call
nfs_fsinfo(nmp
, vp
, cred
, p
)
register struct nfsmount
*nmp
;
register struct vnode
*vp
;
register struct nfsv3_fsinfo
*fsp
;
register u_long
*tl
, pref
, max
;
struct mbuf
*mreq
, *mrep
, *md
, *mb
, *mb2
;
nfsstats
.rpccnt
[NFSPROC_FSINFO
]++;
nfsm_reqhead(vp
, NFSPROC_FSINFO
, NFSX_FH(1));
nfsm_request(vp
, NFSPROC_FSINFO
, p
, cred
);
nfsm_postop_attr(vp
, retattr
);
nfsm_dissect(fsp
, struct nfsv3_fsinfo
*, NFSX_V3FSINFO
);
pref
= fxdr_unsigned(u_long
, fsp
->fs_wtpref
);
if (pref
< nmp
->nm_wsize
)
nmp
->nm_wsize
= (pref
+ NFS_FABLKSIZE
- 1) &
max
= fxdr_unsigned(u_long
, fsp
->fs_wtmax
);
if (max
< nmp
->nm_wsize
) {
nmp
->nm_wsize
= max
& ~(NFS_FABLKSIZE
- 1);
pref
= fxdr_unsigned(u_long
, fsp
->fs_rtpref
);
if (pref
< nmp
->nm_rsize
)
nmp
->nm_rsize
= (pref
+ NFS_FABLKSIZE
- 1) &
max
= fxdr_unsigned(u_long
, fsp
->fs_rtmax
);
if (max
< nmp
->nm_rsize
) {
nmp
->nm_rsize
= max
& ~(NFS_FABLKSIZE
- 1);
pref
= fxdr_unsigned(u_long
, fsp
->fs_dtpref
);
if (pref
< nmp
->nm_readdirsize
)
nmp
->nm_readdirsize
= (pref
+ NFS_DIRBLKSIZ
- 1) &
if (max
< nmp
->nm_readdirsize
) {
nmp
->nm_readdirsize
= max
& ~(NFS_DIRBLKSIZ
- 1);
if (nmp
->nm_readdirsize
== 0)
nmp
->nm_readdirsize
= max
;
nmp
->nm_flag
|= NFSMNT_GOTFSINFO
;
* Mount a remote root fs via. nfs. This depends on the info in the
* nfs_diskless structure that has been filled in properly by some primary
* It goes something like this:
* - do enough of "ifconfig" by calling ifioctl() so that the system
* - If nfs_diskless.mygateway is filled in, use that address as
* - hand craft the swap nfs vnode hanging off a fake mount point
* if swdevt[0].sw_dev == NODEV
* - build the rootfs mount point and call mountnfs() to do the rest.
struct mount
*mp
, *swap_mp
;
struct nfs_diskless
*nd
= &nfs_diskless
;
struct proc
*p
= curproc
; /* XXX */
* XXX time must be non-zero when we init the interface or else
* the arp code will wedge...
* XXX splnet, so networks will receive...
/* Set up swap credentials. */
proc0
.p_ucred
->cr_uid
= ntohl(nd
->swap_ucred
.cr_uid
);
proc0
.p_ucred
->cr_gid
= ntohl(nd
->swap_ucred
.cr_gid
);
if ((proc0
.p_ucred
->cr_ngroups
= ntohs(nd
->swap_ucred
.cr_ngroups
)) >
proc0
.p_ucred
->cr_ngroups
= NGROUPS
;
for (i
= 0; i
< proc0
.p_ucred
->cr_ngroups
; i
++)
proc0
.p_ucred
->cr_groups
[i
] = ntohl(nd
->swap_ucred
.cr_groups
[i
]);
* Do enough of ifconfig(8) so that the critical net interface can
error
= socreate(nd
->myif
.ifra_addr
.sa_family
, &so
, SOCK_DGRAM
, 0);
printf("nfs_mountroot: socreate(%04x): %d",
nd
->myif
.ifra_addr
.sa_family
, error
);
* We might not have been told the right interface, so we pass
* over the first ten interfaces of the same kind, until we get
* one of them configured.
for (i
= strlen(nd
->myif
.ifra_name
) - 1;
nd
->myif
.ifra_name
[i
] >= '0' &&
nd
->myif
.ifra_name
[i
] <= '9';
nd
->myif
.ifra_name
[i
] ++) {
error
= ifioctl(so
, SIOCAIFADDR
, (caddr_t
)&nd
->myif
, p
);
printf("nfs_mountroot: SIOCAIFADDR: %d", error
);
* If the gateway field is filled in, set it as the default route.
if (nd
->mygateway
.sin_len
!= 0) {
struct sockaddr_in mask
, sin
;
bzero((caddr_t
)&mask
, sizeof(mask
));
sin
.sin_family
= AF_INET
;
sin
.sin_len
= sizeof(sin
);
error
= rtrequest(RTM_ADD
, (struct sockaddr
*)&sin
,
(struct sockaddr
*)&nd
->mygateway
,
(struct sockaddr
*)&mask
,
RTF_UP
| RTF_GATEWAY
, (struct rtentry
**)0);
printf("nfs_mountroot: RTM_ADD: %d", error
);
* Create a fake mount point just for the swap vnode so that the
* swap file can be on a different server from the rootfs.
nd
->swap_args
.fh
= nd
->swap_fh
;
* If using nfsv3_diskless, replace NFSX_V2FH with
nd
->swap_args
.fhsize
= NFSX_V2FH
;
l
= ntohl(nd
->swap_saddr
.sin_addr
.s_addr
);
sprintf(buf
,"%ld.%ld.%ld.%ld:%s",
(l
>> 24) & 0xff, (l
>> 16) & 0xff,
(l
>> 8) & 0xff, (l
>> 0) & 0xff,nd
->swap_hostnam
);
printf("NFS SWAP: %s\n",buf
);
if (error
= nfs_mountdiskless(buf
, "/swap", 0,
&nd
->swap_saddr
, &nd
->swap_args
, p
, &vp
, &swap_mp
))
for (i
=0;swdevt
[i
].sw_dev
!= NODEV
;i
++) ;
* Since the swap file is not the root dir of a file system,
* hack it to a regular file.
swdevt
[i
].sw_nblks
= nd
->swap_nblks
*2;
if (!swdevt
[i
].sw_nblks
) {
swdevt
[i
].sw_nblks
= 2048;
printf("defaulting to %d kbyte.\n",
printf("using %d kbyte.\n",swdevt
[i
].sw_nblks
/2);
* Create the rootfs mount point.
nd
->root_args
.fh
= nd
->root_fh
;
* If using nfsv3_diskless, replace NFSX_V2FH with nd->root_fhsize.
nd
->root_args
.fhsize
= NFSX_V2FH
;
l
= ntohl(nd
->swap_saddr
.sin_addr
.s_addr
);
sprintf(buf
,"%ld.%ld.%ld.%ld:%s",
(l
>> 24) & 0xff, (l
>> 16) & 0xff,
(l
>> 8) & 0xff, (l
>> 0) & 0xff,nd
->root_hostnam
);
printf("NFS ROOT: %s\n",buf
);
if (error
= nfs_mountdiskless(buf
, "/", MNT_RDONLY
,
&nd
->root_saddr
, &nd
->root_args
, p
, &vp
, &mp
)) {
mp
->mnt_vfc
->vfc_refcount
--;
simple_lock(&mountlist_slock
);
CIRCLEQ_INSERT_TAIL(&mountlist
, mp
, mnt_list
);
simple_unlock(&mountlist_slock
);
* This is not really an nfs issue, but it is much easier to
* set hostname here and then let the "/etc/rc.xxx" files
* mount the right /var based upon its preset value.
bcopy(nd
->my_hostnam
, hostname
, MAXHOSTNAMELEN
);
hostname
[MAXHOSTNAMELEN
- 1] = '\0';
for (i
= 0; i
< MAXHOSTNAMELEN
; i
++)
inittodr(ntohl(nd
->root_time
));
* Internal version of mount system call for diskless setup.
nfs_mountdiskless(path
, which
, mountflag
, sin
, args
, p
, vpp
, mpp
)
if (error
= vfs_rootmountalloc("nfs", path
, &mp
)) {
printf("nfs_mountroot: NFS not configured");
mp
->mnt_flag
= mountflag
;
MGET(m
, MT_SONAME
, M_WAITOK
);
bcopy((caddr_t
)sin
, mtod(m
, caddr_t
), sin
->sin_len
);
if (error
= mountnfs(args
, mp
, m
, which
, path
, vpp
)) {
printf("nfs_mountroot: mount %s on %s: %d", path
, which
, error
);
mp
->mnt_vfc
->vfc_refcount
--;
(void) copystr(which
, mp
->mnt_stat
.f_mntonname
, MNAMELEN
- 1, 0);
* It seems a bit dumb to copyinstr() the host and path here and then
* bcopy() them in mountnfs(), but I wanted to detect errors before
* doing the sockargs() call because sockargs() allocates an mbuf and
* an error after that means that I have to release the mbuf.
nfs_mount(mp
, path
, data
, ndp
, p
)
char pth
[MNAMELEN
], hst
[MNAMELEN
];
u_char nfh
[NFSX_V3FHMAX
];
error
= copyin(data
, (caddr_t
)&args
, sizeof (struct nfs_args
));
if (args
.version
!= NFS_ARGSVERSION
)
error
= copyin((caddr_t
)args
.fh
, (caddr_t
)nfh
, args
.fhsize
);
error
= copyinstr(path
, pth
, MNAMELEN
-1, &len
);
bzero(&pth
[len
], MNAMELEN
- len
);
error
= copyinstr(args
.hostname
, hst
, MNAMELEN
-1, &len
);
bzero(&hst
[len
], MNAMELEN
- len
);
/* sockargs() call must be after above copyin() calls */
error
= sockargs(&nam
, (caddr_t
)args
.addr
, args
.addrlen
, MT_SONAME
);
error
= mountnfs(&args
, mp
, nam
, pth
, hst
, &vp
);
* Common code for mount and mountroot
mountnfs(argp
, mp
, nam
, pth
, hst
, vpp
)
register struct nfs_args
*argp
;
register struct mount
*mp
;
register struct nfsmount
*nmp
;
if (mp
->mnt_flag
& MNT_UPDATE
) {
/* update paths, file handles, etc, here XXX */
MALLOC(nmp
, struct nfsmount
*, sizeof (struct nfsmount
),
bzero((caddr_t
)nmp
, sizeof (struct nfsmount
));
TAILQ_INIT(&nmp
->nm_uidlruhead
);
mp
->mnt_data
= (qaddr_t
)nmp
;
nmp
->nm_flag
= argp
->flags
;
if (nmp
->nm_flag
& NFSMNT_NQNFS
)
* We have to set mnt_maxsymlink to a non-zero value so
* that COMPAT_43 routines will know that we are setting
* the d_type field in directories (and can zero it for
* unsuspecting binaries).
mp
->mnt_maxsymlinklen
= 1;
nmp
->nm_timeo
= NFS_TIMEO
;
nmp
->nm_retry
= NFS_RETRANS
;
nmp
->nm_wsize
= NFS_WSIZE
;
nmp
->nm_rsize
= NFS_RSIZE
;
nmp
->nm_readdirsize
= NFS_READDIRSIZE
;
nmp
->nm_numgrps
= NFS_MAXGRPS
;
nmp
->nm_readahead
= NFS_DEFRAHEAD
;
nmp
->nm_leaseterm
= NQ_DEFLEASE
;
nmp
->nm_deadthresh
= NQ_DEADTHRESH
;
CIRCLEQ_INIT(&nmp
->nm_timerhead
);
nmp
->nm_fhsize
= argp
->fhsize
;
bcopy((caddr_t
)argp
->fh
, (caddr_t
)nmp
->nm_fh
, argp
->fhsize
);
bcopy(hst
, mp
->mnt_stat
.f_mntfromname
, MNAMELEN
);
bcopy(pth
, mp
->mnt_stat
.f_mntonname
, MNAMELEN
);
if ((argp
->flags
& NFSMNT_TIMEO
) && argp
->timeo
> 0) {
nmp
->nm_timeo
= (argp
->timeo
* NFS_HZ
+ 5) / 10;
if (nmp
->nm_timeo
< NFS_MINTIMEO
)
nmp
->nm_timeo
= NFS_MINTIMEO
;
else if (nmp
->nm_timeo
> NFS_MAXTIMEO
)
nmp
->nm_timeo
= NFS_MAXTIMEO
;
if ((argp
->flags
& NFSMNT_RETRANS
) && argp
->retrans
> 1) {
nmp
->nm_retry
= argp
->retrans
;
if (nmp
->nm_retry
> NFS_MAXREXMIT
)
nmp
->nm_retry
= NFS_MAXREXMIT
;
if (argp
->flags
& NFSMNT_NFSV3
) {
if (argp
->sotype
== SOCK_DGRAM
)
maxio
= NFS_MAXDGRAMDATA
;
if ((argp
->flags
& NFSMNT_WSIZE
) && argp
->wsize
> 0) {
nmp
->nm_wsize
= argp
->wsize
;
/* Round down to multiple of blocksize */
nmp
->nm_wsize
&= ~(NFS_FABLKSIZE
- 1);
nmp
->nm_wsize
= NFS_FABLKSIZE
;
if (nmp
->nm_wsize
> maxio
)
if (nmp
->nm_wsize
> MAXBSIZE
)
nmp
->nm_wsize
= MAXBSIZE
;
if ((argp
->flags
& NFSMNT_RSIZE
) && argp
->rsize
> 0) {
nmp
->nm_rsize
= argp
->rsize
;
/* Round down to multiple of blocksize */
nmp
->nm_rsize
&= ~(NFS_FABLKSIZE
- 1);
nmp
->nm_rsize
= NFS_FABLKSIZE
;
if (nmp
->nm_rsize
> maxio
)
if (nmp
->nm_rsize
> MAXBSIZE
)
nmp
->nm_rsize
= MAXBSIZE
;
if ((argp
->flags
& NFSMNT_READDIRSIZE
) && argp
->readdirsize
> 0) {
nmp
->nm_readdirsize
= argp
->readdirsize
;
/* Round down to multiple of blocksize */
nmp
->nm_readdirsize
&= ~(NFS_DIRBLKSIZ
- 1);
if (nmp
->nm_readdirsize
< NFS_DIRBLKSIZ
)
nmp
->nm_readdirsize
= NFS_DIRBLKSIZ
;
if (nmp
->nm_readdirsize
> maxio
)
nmp
->nm_readdirsize
= maxio
;
if ((argp
->flags
& NFSMNT_MAXGRPS
) && argp
->maxgrouplist
>= 0 &&
argp
->maxgrouplist
<= NFS_MAXGRPS
)
nmp
->nm_numgrps
= argp
->maxgrouplist
;
if ((argp
->flags
& NFSMNT_READAHEAD
) && argp
->readahead
>= 0 &&
argp
->readahead
<= NFS_MAXRAHEAD
)
nmp
->nm_readahead
= argp
->readahead
;
if ((argp
->flags
& NFSMNT_LEASETERM
) && argp
->leaseterm
>= 2 &&
argp
->leaseterm
<= NQ_MAXLEASE
)
nmp
->nm_leaseterm
= argp
->leaseterm
;
if ((argp
->flags
& NFSMNT_DEADTHRESH
) && argp
->deadthresh
>= 1 &&
argp
->deadthresh
<= NQ_NEVERDEAD
)
nmp
->nm_deadthresh
= argp
->deadthresh
;
/* Set up the sockets and per-host congestion */
nmp
->nm_sotype
= argp
->sotype
;
nmp
->nm_soproto
= argp
->proto
;
* For Connection based sockets (TCP,...) defer the connect until
* the first request, in case the server is not responding.
if (nmp
->nm_sotype
== SOCK_DGRAM
&&
(error
= nfs_connect(nmp
, (struct nfsreq
*)0)))
* This is silly, but it has to be set so that vinifod() works.
* We do not want to do an nfs_statfs() here since we can get
* stuck on a dead server and we are holding a lock on the mount
mp
->mnt_stat
.f_iosize
= NFS_MAXDGRAMDATA
;
* A reference count is needed on the nfsnode representing the
* remote root. If this object is not persistent, then backward
* traversals of the mount point (i.e. "..") will not work if
* the nfsnode gets flushed out of the cache. Ufs does not have
* this problem, because one can identify root inodes by their
error
= nfs_nget(mp
, (nfsfh_t
*)nmp
->nm_fh
, nmp
->nm_fhsize
, &np
);
free((caddr_t
)nmp
, M_NFSMNT
);
nfs_unmount(mp
, mntflags
, p
)
register struct nfsmount
*nmp
;
if (mntflags
& MNT_FORCE
)
* Goes something like this..
* - Check for activity on the root vnode (other than ourselves).
* - Call vflush() to clear out vnodes for this file system,
* except for the root vnode.
* - Decrement reference on the vnode representing remote root.
* - Free up the data structures
* We need to decrement the ref. count on the nfsnode representing
* the remote root. See comment in mountnfs(). The VFS unmount()
* has done vput on this vnode, otherwise we would get deadlock!
error
= nfs_nget(mp
, (nfsfh_t
*)nmp
->nm_fh
, nmp
->nm_fhsize
, &np
);
if (vp
->v_usecount
> 2) {
* Must handshake with nqnfs_clientd() if it is active.
nmp
->nm_flag
|= NFSMNT_DISMINPROG
;
while (nmp
->nm_inprog
!= NULLVP
)
(void) tsleep((caddr_t
)&lbolt
, PSOCK
, "nfsdism", 0);
error
= vflush(mp
, vp
, flags
);
nmp
->nm_flag
&= ~NFSMNT_DISMINPROG
;
* We are now committed to the unmount.
* For NQNFS, let the server daemon free the nfsmount structure.
if (nmp
->nm_flag
& (NFSMNT_NQNFS
| NFSMNT_KERB
))
nmp
->nm_flag
|= NFSMNT_DISMNT
;
* There are two reference counts to get rid of here.
if ((nmp
->nm_flag
& (NFSMNT_NQNFS
| NFSMNT_KERB
)) == 0)
free((caddr_t
)nmp
, M_NFSMNT
);
* Return root of a filesystem
register struct vnode
*vp
;
error
= nfs_nget(mp
, (nfsfh_t
*)nmp
->nm_fh
, nmp
->nm_fhsize
, &np
);
* Flush out the buffer cache
nfs_sync(mp
, waitfor
, cred
, p
)
register struct vnode
*vp
;
* Force stale buffer cache information to be flushed.
for (vp
= mp
->mnt_vnodelist
.lh_first
;
vp
= vp
->v_mntvnodes
.le_next
) {
* If the vnode that we are about to sync is no longer
* associated with this mount point, start over.
if (VOP_ISLOCKED(vp
) || vp
->v_dirtyblkhd
.lh_first
== NULL
)
if (vget(vp
, LK_EXCLUSIVE
, p
))
error
= VOP_FSYNC(vp
, cred
, waitfor
, p
);
* NFS flat namespace lookup.
* At this point, this should never happen
nfs_fhtovp(mp
, fhp
, nam
, vpp
, exflagsp
, credanonp
)
register struct mount
*mp
;
struct ucred
**credanonp
;
* Vnode pointer to File handle, should never happen either
* Vfs start routine, a no-op.
* Do operations associated with quotas, not supported
nfs_quotactl(mp
, cmd
, uid
, arg
, p
)
* Do that sysctl thang...
nfs_sysctl(int *name
, u_int namelen
, void *oldp
, size_t *oldlenp
, void *newp
,
size_t newlen
, struct proc
*p
)
* All names at this level are terminal.
return ENOTDIR
; /* overloaded */
*oldlenp
= sizeof nfsstats
;
if(*oldlenp
< sizeof nfsstats
) {
*oldlenp
= sizeof nfsstats
;
rv
= copyout(&nfsstats
, oldp
, sizeof nfsstats
);
if(newp
&& newlen
!= sizeof nfsstats
)
return copyin(newp
, &nfsstats
, sizeof nfsstats
);