* Copyright (c) 1989 The Regents of the University of California.
* 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 are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
* @(#)nfs_syscalls.c 7.16 (Berkeley) %G%
#include "../netinet/in.h"
#include "../netinet/tcp.h"
extern u_long nfs_prog
, nfs_vers
;
extern int (*nfsrv_procs
[NFS_NPROCS
])();
extern struct buf nfs_bqueue
;
extern int nfs_asyncdaemons
;
extern struct proc
*nfs_iodwant
[NFS_MAXASYNCDAEMON
];
extern int nfs_tcpnodelay
;
* NFS server system calls
* getfh() lives here too, but maybe should move to kern/vfs_syscalls.c
* Get file handle system call
register struct nameidata
*ndp
= &u
.u_nd
;
register struct vnode
*vp
;
if (error
= suser(ndp
->ni_cred
, &u
.u_acflag
))
ndp
->ni_nameiop
= LOOKUP
| LOCKLEAF
| FOLLOW
;
ndp
->ni_segflg
= UIO_USERSPACE
;
ndp
->ni_dirp
= uap
->fname
;
bzero((caddr_t
)&fh
, sizeof(fh
));
fh
.fh_fsid
= vp
->v_mount
->mnt_stat
.f_fsid
;
error
= VFS_VPTOFH(vp
, &fh
.fh_fid
);
error
= copyout((caddr_t
)&fh
, (caddr_t
)uap
->fhp
, sizeof (fh
));
* Nfs server psuedo system call for the nfsd's
* Never returns unless it fails or gets killed
register struct ucred
*cr
;
struct mbuf
*mreq
, *mrep
, *nam
, *md
;
int procid
, repstat
, error
, cacherep
;
if (error
= suser(u
.u_cred
, &u
.u_acflag
))
so
= (struct socket
*)fp
->f_data
;
siz
= NFS_MAXPACKET
+ sizeof(u_long
);
if (error
= soreserve(so
, siz
, siz
))
if (error
= sockargs(&nam
, uap
->mskval
, uap
->msklen
, MT_SONAME
))
bcopy((caddr_t
)nam
, (caddr_t
)&msk
, sizeof (struct mbuf
));
if (error
= sockargs(&nam
, uap
->mtchval
, uap
->mtchlen
, MT_SONAME
))
bcopy((caddr_t
)nam
, (caddr_t
)&mtch
, sizeof (struct mbuf
));
mtch
.m_data
= mtch
.m_dat
;
/* Copy the cred so others don't see changes */
cr
= u
.u_cred
= crcopy(u
.u_cred
);
* Set protocol specific options { for now TCP only } and
* reserve some space. For datagram sockets, this can get called
* repeatedly for the same socket, but that isn't harmful.
if (so
->so_proto
->pr_flags
& PR_CONNREQUIRED
) {
MGET(m
, M_WAIT
, MT_SOOPTS
);
sosetopt(so
, SOL_SOCKET
, SO_KEEPALIVE
, m
);
if (so
->so_proto
->pr_domain
->dom_family
== AF_INET
&&
so
->so_proto
->pr_protocol
== IPPROTO_TCP
&&
MGET(m
, M_WAIT
, MT_SOOPTS
);
sosetopt(so
, IPPROTO_TCP
, TCP_NODELAY
, m
);
so
->so_rcv
.sb_flags
&= ~SB_NOINTR
;
so
->so_snd
.sb_flags
&= ~SB_NOINTR
;
* Just loop around doin our stuff until SIGKILL
if (error
= nfs_getreq(so
, nfs_prog
, nfs_vers
, NFS_NPROCS
-1,
&nam
, &mrep
, &md
, &dpos
, &retxid
, &procid
, cr
,
if (error
== EPIPE
|| error
== EINTR
||
cacherep
= nfsrv_getcache(nam
, retxid
, procid
, &mreq
);
if (error
= (*(nfsrv_procs
[procid
]))(mrep
, md
, dpos
,
cr
, retxid
, &mreq
, &repstat
)) {
nfsrv_updatecache(nam
, retxid
, procid
,
nfsstats
.srvrpccnt
[procid
]++;
nfsrv_updatecache(nam
, retxid
, procid
, TRUE
,
if (siz
<= 0 || siz
> NFS_MAXPACKET
) {
printf("mbuf siz=%d\n",siz
);
panic("Bad nfs svc reply");
mreq
->m_pkthdr
.len
= siz
;
mreq
->m_pkthdr
.rcvif
= (struct ifnet
*)0;
* For non-atomic protocols, prepend a Sun RPC
if (!sosendallatonce(so
)) {
M_PREPEND(mreq
, sizeof(u_long
), M_WAIT
);
*mtod(mreq
, u_long
*) = htonl(0x80000000 | siz
);
error
= nfs_send(so
, nam
, mreq
, (struct nfsreq
*)0);
if (error
== EPIPE
|| error
== EINTR
||
* Nfs pseudo system call for asynchronous i/o daemons.
* These babies just pretend to be disk interrupt service routines
* for client nfs. They are mainly here for read ahead/write behind.
* Never returns unless it fails or gets killed
async_daemon(p
, uap
, retval
)
register struct buf
*bp
, *dp
;
if (error
= suser(u
.u_cred
, &u
.u_acflag
))
* Assign my position or return error if too many already running
if (nfs_asyncdaemons
> NFS_MAXASYNCDAEMON
)
myiod
= nfs_asyncdaemons
++;
* Just loop around doin our stuff until SIGKILL
while (dp
->b_actf
== NULL
) {
if (error
= tsleep((caddr_t
)&nfs_iodwant
[myiod
],
PWAIT
| PCATCH
, "nfsidl", 0))
/* Take one off the end of the list */
dp
->b_actf
= dp
->b_actl
= (struct buf
*)0;