From 1c178cd765f660288e215b9443f66f402a684eef Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 11 Mar 1996 19:34:14 +0000 Subject: Import 4.4BSD-Lite2 onto the vendor branch, note that in the kernel, all files are off the vendor branch, so this should not change anything. A "U" marker generally means that the file was not changed in between the 4.4Lite and Lite-2 releases, and does not need a merge. "C" generally means that there was a change. --- sys/nfs/nfs.h | 385 ++++++- sys/nfs/nfs_bio.c | 338 ++++-- sys/nfs/nfs_node.c | 171 ++- sys/nfs/nfs_nqlease.c | 484 +++++---- sys/nfs/nfs_serv.c | 2843 ++++++++++++++++++++++++++++++++++++------------ sys/nfs/nfs_socket.c | 610 +++++++---- sys/nfs/nfs_srvcache.c | 120 +- sys/nfs/nfs_subs.c | 1053 +++++++++++++++--- sys/nfs/nfs_syscalls.c | 745 ++++++++----- sys/nfs/nfs_vfsops.c | 487 ++++++--- sys/nfs/nfs_vnops.c | 2247 +++++++++++++++++++++++++------------- sys/nfs/nfsdiskless.h | 44 +- sys/nfs/nfsm_subs.h | 314 ++++-- sys/nfs/nfsmount.h | 22 +- sys/nfs/nfsnode.h | 120 +- sys/nfs/nfsproto.h | 4 +- sys/nfs/nfsrtt.h | 9 +- sys/nfs/nfsrvcache.h | 16 +- sys/nfs/nqnfs.h | 67 +- sys/nfs/rpcv2.h | 55 +- sys/nfs/xdr_subs.h | 38 +- 21 files changed, 7184 insertions(+), 2988 deletions(-) (limited to 'sys') diff --git a/sys/nfs/nfs.h b/sys/nfs/nfs.h index 261fd42..89c6094 100644 --- a/sys/nfs/nfs.h +++ b/sys/nfs/nfs.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1989, 1993 + * 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 @@ -33,34 +33,71 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfs.h 8.1 (Berkeley) 6/10/93 + * @(#)nfs.h 8.4 (Berkeley) 5/1/95 */ +#ifndef _NFS_NFS_H_ +#define _NFS_NFS_H_ + /* * Tunable constants for nfs */ #define NFS_MAXIOVEC 34 -#define NFS_HZ 25 /* Ticks per second for NFS timeouts */ -#define NFS_TIMEO (1*NFS_HZ) /* Default timeout = 1 second */ -#define NFS_MINTIMEO (1*NFS_HZ) /* Min timeout to use */ -#define NFS_MAXTIMEO (60*NFS_HZ) /* Max timeout to backoff to */ -#define NFS_MINIDEMTIMEO (5*NFS_HZ) /* Min timeout for non-idempotent ops*/ +#define NFS_TICKINTVL 5 /* Desired time for a tick (msec) */ +#define NFS_HZ (hz / nfs_ticks) /* Ticks/sec */ +#define NFS_TIMEO (1 * NFS_HZ) /* Default timeout = 1 second */ +#define NFS_MINTIMEO (1 * NFS_HZ) /* Min timeout to use */ +#define NFS_MAXTIMEO (60 * NFS_HZ) /* Max timeout to backoff to */ +#define NFS_MINIDEMTIMEO (5 * NFS_HZ) /* Min timeout for non-idempotent ops*/ #define NFS_MAXREXMIT 100 /* Stop counting after this many */ #define NFS_MAXWINDOW 1024 /* Max number of outstanding requests */ #define NFS_RETRANS 10 /* Num of retrans for soft mounts */ #define NFS_MAXGRPS 16 /* Max. size of groups list */ +#ifndef NFS_MINATTRTIMO #define NFS_MINATTRTIMO 5 /* Attribute cache timeout in sec */ +#endif +#ifndef NFS_MAXATTRTIMO #define NFS_MAXATTRTIMO 60 +#endif #define NFS_WSIZE 8192 /* Def. write data size <= 8192 */ #define NFS_RSIZE 8192 /* Def. read data size <= 8192 */ +#define NFS_READDIRSIZE 8192 /* Def. readdir size */ #define NFS_DEFRAHEAD 1 /* Def. read ahead # blocks */ #define NFS_MAXRAHEAD 4 /* Max. read ahead # blocks */ -#define NFS_MAXREADDIR NFS_MAXDATA /* Max. size of directory read */ #define NFS_MAXUIDHASH 64 /* Max. # of hashed uid entries/mp */ -#define NFS_MAXASYNCDAEMON 20 /* Max. number async_daemons runable */ -#define NFS_DIRBLKSIZ 1024 /* Size of an NFS directory block */ +#define NFS_MAXASYNCDAEMON 20 /* Max. number async_daemons runable */ +#define NFS_MAXGATHERDELAY 100 /* Max. write gather delay (msec) */ +#ifndef NFS_GATHERDELAY +#define NFS_GATHERDELAY 10 /* Default write gather delay (msec) */ +#endif +#define NFS_DIRBLKSIZ 4096 /* Must be a multiple of DIRBLKSIZ */ + +/* + * Oddballs + */ #define NMOD(a) ((a) % nfs_asyncdaemons) +#define NFS_CMPFH(n, f, s) \ + ((n)->n_fhsize == (s) && !bcmp((caddr_t)(n)->n_fhp, (caddr_t)(f), (s))) +#define NFS_ISV3(v) (VFSTONFS((v)->v_mount)->nm_flag & NFSMNT_NFSV3) +#define NFS_SRVMAXDATA(n) \ + (((n)->nd_flag & ND_NFSV3) ? (((n)->nd_nam2) ? \ + NFS_MAXDGRAMDATA : NFS_MAXDATA) : NFS_V2MAXDATA) + +/* + * XXX + * The B_INVAFTERWRITE flag should be set to whatever is required by the + * buffer cache code to say "Invalidate the block after it is written back". + */ +#define B_INVAFTERWRITE B_INVAL + +/* + * The IO_METASYNC flag should be implemented for local file systems. + * (Until then, it is nothin at all.) + */ +#ifndef IO_METASYNC +#define IO_METASYNC 0 +#endif /* * Set the attribute timeout based on how recently the file has been modified. @@ -72,12 +109,88 @@ (time.tv_sec - (np)->n_mtime) / 10)) /* + * Expected allocation sizes for major data structures. If the actual size + * of the structure exceeds these sizes, then malloc() will be allocating + * almost twice the memory required. This is used in nfs_init() to warn + * the sysadmin that the size of a structure should be reduced. + * (These sizes are always a power of 2. If the kernel malloc() changes + * to one that does not allocate space in powers of 2 size, then this all + * becomes bunk!) + */ +#define NFS_NODEALLOC 256 +#define NFS_MNTALLOC 512 +#define NFS_SVCALLOC 256 +#define NFS_UIDALLOC 128 + +/* + * Arguments to mount NFS + */ +#define NFS_ARGSVERSION 3 /* change when nfs_args changes */ +struct nfs_args { + int version; /* args structure version number */ + struct sockaddr *addr; /* file server address */ + int addrlen; /* length of address */ + int sotype; /* Socket type */ + int proto; /* and Protocol */ + u_char *fh; /* File handle to be mounted */ + int fhsize; /* Size, in bytes, of fh */ + int flags; /* flags */ + int wsize; /* write size in bytes */ + int rsize; /* read size in bytes */ + int readdirsize; /* readdir size in bytes */ + int timeo; /* initial timeout in .1 secs */ + int retrans; /* times to retry send */ + int maxgrouplist; /* Max. size of group list */ + int readahead; /* # of blocks to readahead */ + int leaseterm; /* Term (sec) of lease */ + int deadthresh; /* Retrans threshold */ + char *hostname; /* server's name */ +}; + +/* + * NFS mount option flags + */ +#define NFSMNT_SOFT 0x00000001 /* soft mount (hard is default) */ +#define NFSMNT_WSIZE 0x00000002 /* set write size */ +#define NFSMNT_RSIZE 0x00000004 /* set read size */ +#define NFSMNT_TIMEO 0x00000008 /* set initial timeout */ +#define NFSMNT_RETRANS 0x00000010 /* set number of request retries */ +#define NFSMNT_MAXGRPS 0x00000020 /* set maximum grouplist size */ +#define NFSMNT_INT 0x00000040 /* allow interrupts on hard mount */ +#define NFSMNT_NOCONN 0x00000080 /* Don't Connect the socket */ +#define NFSMNT_NQNFS 0x00000100 /* Use Nqnfs protocol */ +#define NFSMNT_NFSV3 0x00000200 /* Use NFS Version 3 protocol */ +#define NFSMNT_KERB 0x00000400 /* Use Kerberos authentication */ +#define NFSMNT_DUMBTIMR 0x00000800 /* Don't estimate rtt dynamically */ +#define NFSMNT_LEASETERM 0x00001000 /* set lease term (nqnfs) */ +#define NFSMNT_READAHEAD 0x00002000 /* set read ahead */ +#define NFSMNT_DEADTHRESH 0x00004000 /* set dead server retry thresh */ +#define NFSMNT_RESVPORT 0x00008000 /* Allocate a reserved port */ +#define NFSMNT_RDIRPLUS 0x00010000 /* Use Readdirplus for V3 */ +#define NFSMNT_READDIRSIZE 0x00020000 /* Set readdir size */ +#define NFSMNT_INTERNAL 0xfffc0000 /* Bits set internally */ +#define NFSMNT_HASWRITEVERF 0x00040000 /* Has write verifier for V3 */ +#define NFSMNT_GOTPATHCONF 0x00080000 /* Got the V3 pathconf info */ +#define NFSMNT_GOTFSINFO 0x00100000 /* Got the V3 fsinfo */ +#define NFSMNT_MNTD 0x00200000 /* Mnt server for mnt point */ +#define NFSMNT_DISMINPROG 0x00400000 /* Dismount in progress */ +#define NFSMNT_DISMNT 0x00800000 /* Dismounted */ +#define NFSMNT_SNDLOCK 0x01000000 /* Send socket lock */ +#define NFSMNT_WANTSND 0x02000000 /* Want above */ +#define NFSMNT_RCVLOCK 0x04000000 /* Rcv socket lock */ +#define NFSMNT_WANTRCV 0x08000000 /* Want above */ +#define NFSMNT_WAITAUTH 0x10000000 /* Wait for authentication */ +#define NFSMNT_HASAUTH 0x20000000 /* Has authenticator */ +#define NFSMNT_WANTAUTH 0x40000000 /* Wants an authenticator */ +#define NFSMNT_AUTHERR 0x80000000 /* Authentication error */ + +/* * Structures for the nfssvc(2) syscall. Not that anyone but nfsd and mount_nfs * should ever try and use it. */ struct nfsd_args { int sock; /* Socket to serve */ - caddr_t name; /* Client address for connection based sockets */ + caddr_t name; /* Client addr for connection based sockets */ int namelen; /* Length of name */ }; @@ -87,7 +200,12 @@ struct nfsd_srvargs { u_long nsd_haddr; /* Ip address of client */ struct ucred nsd_cr; /* Cred. uid maps to */ int nsd_authlen; /* Length of auth string (ret) */ - char *nsd_authstr; /* Auth string (ret) */ + u_char *nsd_authstr; /* Auth string (ret) */ + int nsd_verflen; /* and the verfier */ + u_char *nsd_verfstr; + struct timeval nsd_timestamp; /* timestamp from verifier */ + u_long nsd_ttl; /* credential ttl (sec) */ + NFSKERBKEY_T nsd_key; /* Session key */ }; struct nfsd_cargs { @@ -95,7 +213,10 @@ struct nfsd_cargs { uid_t ncd_authuid; /* Effective uid */ int ncd_authtype; /* Type of authenticator */ int ncd_authlen; /* Length of authenticator string */ - char *ncd_authstr; /* Authenticator string */ + u_char *ncd_authstr; /* Authenticator string */ + int ncd_verflen; /* and the verifier */ + u_char *ncd_verfstr; + NFSKERBKEY_T ncd_key; /* Session key */ }; /* @@ -134,6 +255,7 @@ struct nfsstats { int srvnqnfs_leases; int srvnqnfs_maxleases; int srvnqnfs_getleases; + int srvvop_writes; }; /* @@ -148,6 +270,16 @@ struct nfsstats { #define NFSSVC_MNTD 0x100 /* + * fs.nfs sysctl(3) identifiers + */ +#define NFS_NFSSTATS 1 /* struct: struct nfsstats */ + +#define FS_NFS_NAMES { \ + { 0, 0 }, \ + { "nfsstats", CTLTYPE_STRUCT }, \ +} + +/* * The set of signals the interrupt an I/O in progress for NFSMNT_INT mounts. * What should be in this set is open to debate, but I believe that since * I/O system calls on ufs are never interrupted by signals the set should @@ -156,6 +288,9 @@ struct nfsstats { * by them and break. */ #ifdef KERNEL + +struct uio; struct buf; struct vattr; struct nameidata; /* XXX */ + #define NFSINT_SIGMASK (sigmask(SIGINT)|sigmask(SIGTERM)|sigmask(SIGKILL)| \ sigmask(SIGHUP)|sigmask(SIGQUIT)) @@ -171,8 +306,7 @@ struct nfsstats { * Nfs outstanding request list element */ struct nfsreq { - struct nfsreq *r_next; - struct nfsreq *r_prev; + TAILQ_ENTRY(nfsreq) r_chain; struct mbuf *r_mreq; struct mbuf *r_mrep; struct mbuf *r_md; @@ -189,6 +323,11 @@ struct nfsreq { struct proc *r_procp; /* Proc that did I/O system call */ }; +/* + * Queue head for nfsreq's + */ +TAILQ_HEAD(, nfsreq) nfs_reqq; + /* Flag values for r_flags */ #define R_TIMING 0x01 /* timing request (in mntp) */ #define R_SENT 0x02 /* request has been sent */ @@ -199,16 +338,29 @@ struct nfsreq { #define R_MUSTRESEND 0x40 /* Must resend request */ #define R_GETONEREP 0x80 /* Probe for one reply only */ -struct nfsstats nfsstats; - /* * A list of nfssvc_sock structures is maintained with all the sockets * that require service by the nfsd. * The nfsuid structs hang off of the nfssvc_sock structs in both lru * and uid hash lists. */ -#define NUIDHASHSIZ 32 -#define NUIDHASH(uid) ((uid) & (NUIDHASHSIZ - 1)) +#ifndef NFS_UIDHASHSIZ +#define NFS_UIDHASHSIZ 29 /* Tune the size of nfssvc_sock with this */ +#endif +#define NUIDHASH(sock, uid) \ + (&(sock)->ns_uidhashtbl[(uid) % NFS_UIDHASHSIZ]) +#ifndef NFS_WDELAYHASHSIZ +#define NFS_WDELAYHASHSIZ 16 /* and with this */ +#endif +#define NWDELAYHASH(sock, f) \ + (&(sock)->ns_wdelayhashtbl[(*((u_long *)(f))) % NFS_WDELAYHASHSIZ]) +#ifndef NFS_MUIDHASHSIZ +#define NFS_MUIDHASHSIZ 67 /* Tune the size of nfsmount with this */ +#endif +#define NMUIDHASH(nmp, uid) \ + (&(nmp)->nm_uidhashtbl[(uid) % NFS_MUIDHASHSIZ]) +#define NFSNOHASH(fhsum) \ + (&nfsnodehashtbl[(fhsum) & nfsnodehash]) /* * Network address hash list element @@ -219,40 +371,44 @@ union nethostaddr { }; struct nfsuid { - struct nfsuid *nu_lrunext; /* MUST be first */ - struct nfsuid *nu_lruprev; - struct nfsuid *nu_hnext; - struct nfsuid *nu_hprev; + TAILQ_ENTRY(nfsuid) nu_lru; /* LRU chain */ + LIST_ENTRY(nfsuid) nu_hash; /* Hash list */ int nu_flag; /* Flags */ - uid_t nu_uid; /* Uid mapped by this entry */ union nethostaddr nu_haddr; /* Host addr. for dgram sockets */ struct ucred nu_cr; /* Cred uid mapped to */ + int nu_expire; /* Expiry time (sec) */ + struct timeval nu_timestamp; /* Kerb. timestamp */ + u_long nu_nickname; /* Nickname on server */ + NFSKERBKEY_T nu_key; /* and session key */ }; #define nu_inetaddr nu_haddr.had_inetaddr #define nu_nam nu_haddr.had_nam /* Bits for nu_flag */ #define NU_INETADDR 0x1 +#define NU_NAM 0x2 +#define NU_NETFAM(u) (((u)->nu_flag & NU_INETADDR) ? AF_INET : AF_ISO) struct nfssvc_sock { - struct nfsuid *ns_lrunext; /* MUST be first */ - struct nfsuid *ns_lruprev; - struct nfssvc_sock *ns_next; - struct nfssvc_sock *ns_prev; - int ns_flag; - u_long ns_sref; + TAILQ_ENTRY(nfssvc_sock) ns_chain; /* List of all nfssvc_sock's */ + TAILQ_HEAD(, nfsuid) ns_uidlruhead; struct file *ns_fp; struct socket *ns_so; - int ns_solock; struct mbuf *ns_nam; - int ns_cc; struct mbuf *ns_raw; struct mbuf *ns_rawend; - int ns_reclen; struct mbuf *ns_rec; struct mbuf *ns_recend; + struct mbuf *ns_frag; + int ns_flag; + int ns_solock; + int ns_cc; + int ns_reclen; int ns_numuids; - struct nfsuid *ns_uidh[NUIDHASHSIZ]; + u_long ns_sref; + LIST_HEAD(, nfsrv_descript) ns_tq; /* Write gather lists */ + LIST_HEAD(, nfsuid) ns_uidhashtbl[NFS_UIDHASHSIZ]; + LIST_HEAD(nfsrvw_delayhash, nfsrv_descript) ns_wdelayhashtbl[NFS_WDELAYHASHSIZ]; }; /* Bits for "ns_flag" */ @@ -261,37 +417,150 @@ struct nfssvc_sock { #define SLP_NEEDQ 0x04 #define SLP_DISCONN 0x08 #define SLP_GETSTREAM 0x10 -#define SLP_INIT 0x20 -#define SLP_WANTINIT 0x40 - +#define SLP_LASTFRAG 0x20 #define SLP_ALLFLAGS 0xff +TAILQ_HEAD(, nfssvc_sock) nfssvc_sockhead; +int nfssvc_sockhead_flag; +#define SLP_INIT 0x01 +#define SLP_WANTINIT 0x02 + /* * One of these structures is allocated for each nfsd. */ struct nfsd { - struct nfsd *nd_next; /* Must be first */ - struct nfsd *nd_prev; - int nd_flag; /* NFSD_ flags */ - struct nfssvc_sock *nd_slp; /* Current socket */ - struct mbuf *nd_nam; /* Client addr for datagram req. */ - struct mbuf *nd_mrep; /* Req. mbuf list */ - struct mbuf *nd_md; - caddr_t nd_dpos; /* Position in list */ - int nd_procnum; /* RPC procedure number */ - u_long nd_retxid; /* RPC xid */ - int nd_repstat; /* Reply status value */ - struct ucred nd_cr; /* Credentials for req. */ - int nd_nqlflag; /* Leasing flag */ - int nd_duration; /* Lease duration */ - int nd_authlen; /* Authenticator len */ - u_char nd_authstr[RPCAUTH_MAXSIZ]; /* Authenticator data */ - struct proc *nd_procp; /* Proc ptr */ + TAILQ_ENTRY(nfsd) nfsd_chain; /* List of all nfsd's */ + int nfsd_flag; /* NFSD_ flags */ + struct nfssvc_sock *nfsd_slp; /* Current socket */ + int nfsd_authlen; /* Authenticator len */ + u_char nfsd_authstr[RPCAUTH_MAXSIZ]; /* Authenticator data */ + int nfsd_verflen; /* and the Verifier */ + u_char nfsd_verfstr[RPCVERF_MAXSIZ]; + struct proc *nfsd_procp; /* Proc ptr */ + struct nfsrv_descript *nfsd_nd; /* Associated nfsrv_descript */ }; +/* Bits for "nfsd_flag" */ #define NFSD_WAITING 0x01 -#define NFSD_CHECKSLP 0x02 -#define NFSD_REQINPROG 0x04 -#define NFSD_NEEDAUTH 0x08 -#define NFSD_AUTHFAIL 0x10 +#define NFSD_REQINPROG 0x02 +#define NFSD_NEEDAUTH 0x04 +#define NFSD_AUTHFAIL 0x08 + +/* + * This structure is used by the server for describing each request. + * Some fields are used only when write request gathering is performed. + */ +struct nfsrv_descript { + u_quad_t nd_time; /* Write deadline (usec) */ + off_t nd_off; /* Start byte offset */ + off_t nd_eoff; /* and end byte offset */ + LIST_ENTRY(nfsrv_descript) nd_hash; /* Hash list */ + LIST_ENTRY(nfsrv_descript) nd_tq; /* and timer list */ + LIST_HEAD(,nfsrv_descript) nd_coalesce; /* coalesced writes */ + struct mbuf *nd_mrep; /* Request mbuf list */ + struct mbuf *nd_md; /* Current dissect mbuf */ + struct mbuf *nd_mreq; /* Reply mbuf list */ + struct mbuf *nd_nam; /* and socket addr */ + struct mbuf *nd_nam2; /* return socket addr */ + caddr_t nd_dpos; /* Current dissect pos */ + int nd_procnum; /* RPC # */ + int nd_stable; /* storage type */ + int nd_flag; /* nd_flag */ + int nd_len; /* Length of this write */ + int nd_repstat; /* Reply status */ + u_long nd_retxid; /* Reply xid */ + u_long nd_duration; /* Lease duration */ + struct timeval nd_starttime; /* Time RPC initiated */ + fhandle_t nd_fh; /* File handle */ + struct ucred nd_cr; /* Credentials */ +}; + +/* Bits for "nd_flag" */ +#define ND_READ LEASE_READ +#define ND_WRITE LEASE_WRITE +#define ND_CHECK 0x04 +#define ND_LEASE (ND_READ | ND_WRITE | ND_CHECK) +#define ND_NFSV3 0x08 +#define ND_NQNFS 0x10 +#define ND_KERBNICK 0x20 +#define ND_KERBFULL 0x40 +#define ND_KERBAUTH (ND_KERBNICK | ND_KERBFULL) + +TAILQ_HEAD(, nfsd) nfsd_head; +int nfsd_head_flag; +#define NFSD_CHECKSLP 0x01 + +/* + * These macros compare nfsrv_descript structures. + */ +#define NFSW_CONTIG(o, n) \ + ((o)->nd_eoff >= (n)->nd_off && \ + !bcmp((caddr_t)&(o)->nd_fh, (caddr_t)&(n)->nd_fh, NFSX_V3FH)) + +#define NFSW_SAMECRED(o, n) \ + (((o)->nd_flag & ND_KERBAUTH) == ((n)->nd_flag & ND_KERBAUTH) && \ + !bcmp((caddr_t)&(o)->nd_cr, (caddr_t)&(n)->nd_cr, \ + sizeof (struct ucred))) + +int nfs_reply __P((struct nfsreq *)); +int nfs_getreq __P((struct nfsrv_descript *,struct nfsd *,int)); +int nfs_send __P((struct socket *,struct mbuf *,struct mbuf *,struct nfsreq *)); +int nfs_rephead __P((int,struct nfsrv_descript *,struct nfssvc_sock *,int,int,u_quad_t *,struct mbuf **,struct mbuf **,caddr_t *)); +int nfs_sndlock __P((int *,struct nfsreq *)); +int nfs_disct __P((struct mbuf **,caddr_t *,int,int,caddr_t *)); +int nfs_vinvalbuf __P((struct vnode *,int,struct ucred *,struct proc *,int)); +int nfs_readrpc __P((struct vnode *,struct uio *,struct ucred *)); +int nfs_writerpc __P((struct vnode *,struct uio *,struct ucred *,int *,int *)); +int nfs_readdirrpc __P((register struct vnode *,struct uio *,struct ucred *)); +int nfs_setattrrpc __P((struct vnode *,struct vattr *,struct ucred *,struct proc *)); +int nfs_asyncio __P((struct buf *,struct ucred *)); +int nfs_doio __P((struct buf *,struct ucred *,struct proc *)); +int nfs_readlinkrpc __P((struct vnode *,struct uio *,struct ucred *)); +int nfs_sigintr __P((struct nfsmount *,struct nfsreq *r,struct proc *)); +int nfs_readdirplusrpc __P((struct vnode *,register struct uio *,struct ucred *)); +int nfsm_disct __P((struct mbuf **,caddr_t *,int,int,caddr_t *)); +void nfsm_srvfattr __P((struct nfsrv_descript *,struct vattr *,struct nfs_fattr *)); +void nfsm_srvwcc __P((struct nfsrv_descript *,int,struct vattr *,int,struct vattr *,struct mbuf **,char **)); +void nfsm_srvpostopattr __P((struct nfsrv_descript *,int,struct vattr *,struct mbuf **,char **)); +int nfsrv_fhtovp __P((fhandle_t *,int,struct vnode **,struct ucred *,struct nfssvc_sock *,struct mbuf *,int *,int)); +int nfsrv_access __P((struct vnode *,int,struct ucred *,int,struct proc *)); +int netaddr_match __P((int,union nethostaddr *,struct mbuf *)); +int nfs_request __P((struct vnode *,struct mbuf *,int,struct proc *,struct ucred *,struct mbuf **,struct mbuf **,caddr_t *)); +int nfs_loadattrcache __P((struct vnode **,struct mbuf **,caddr_t *,struct vattr *)); +int nfs_namei __P((struct nameidata *,fhandle_t *,int,struct nfssvc_sock *,struct mbuf *,struct mbuf **,caddr_t *,struct vnode **,struct proc *,int)); +void nfsm_adj __P((struct mbuf *,int,int)); +int nfsm_mbuftouio __P((struct mbuf **,struct uio *,int,caddr_t *)); +void nfsrv_initcache __P((void)); +int nfs_rcvlock __P((struct nfsreq *)); +int nfs_getauth __P((struct nfsmount *,struct nfsreq *,struct ucred *,char **,int *,char *,int *,NFSKERBKEY_T)); +int nfs_getnickauth __P((struct nfsmount *,struct ucred *,char **,int *,char *,int)); +int nfs_savenickauth __P((struct nfsmount *,struct ucred *,int,NFSKERBKEY_T,struct mbuf **,char **,struct mbuf *)); +int nfs_msg __P((struct proc *,char *,char *)); +int nfs_adv __P((struct mbuf **,caddr_t *,int,int)); +int nfsrv_getstream __P((struct nfssvc_sock *,int)); +void nfs_nhinit __P((void)); +void nfs_timer __P((void*)); +u_long nfs_hash __P((nfsfh_t *,int)); +int nfssvc_iod __P((struct proc *)); +int nfssvc_nfsd __P((struct nfsd_srvargs *,caddr_t,struct proc *)); +int nfssvc_addsock __P((struct file *,struct mbuf *)); +int nfsrv_dorec __P((struct nfssvc_sock *,struct nfsd *,struct nfsrv_descript **)); +int nfsrv_getcache __P((struct nfsrv_descript *,struct nfssvc_sock *,struct mbuf **)); +void nfsrv_updatecache __P((struct nfsrv_descript *,int,struct mbuf *)); +int mountnfs __P((struct nfs_args *,struct mount *,struct mbuf *,char *,char *,struct vnode **)); +int nfs_connect __P((struct nfsmount *,struct nfsreq *)); +int nfs_getattrcache __P((struct vnode *,struct vattr *)); +int nfsm_strtmbuf __P((struct mbuf **,char **,char *,long)); +int nfs_bioread __P((struct vnode *,struct uio *,int,struct ucred *)); +int nfsm_uiotombuf __P((struct uio *,struct mbuf **,int,caddr_t *)); +void nfsrv_init __P((int)); +void nfs_clearcommit __P((struct mount *)); +int nfsrv_errmap __P((struct nfsrv_descript *, int)); +void nfsrvw_coalesce __P((struct nfsrv_descript *,struct nfsrv_descript *)); +void nfsrvw_sort __P((gid_t [],int)); +void nfsrv_setcred __P((struct ucred *,struct ucred *)); +int nfs_flush __P((struct vnode *,struct ucred *,int,struct proc *,int)); +int nfs_writebp __P((struct buf *,int)); #endif /* KERNEL */ + +#endif diff --git a/sys/nfs/nfs_bio.c b/sys/nfs/nfs_bio.c index 177a278..2cce1fd 100644 --- a/sys/nfs/nfs_bio.c +++ b/sys/nfs/nfs_bio.c @@ -33,12 +33,14 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfs_bio.c 8.5 (Berkeley) 1/4/94 + * @(#)nfs_bio.c 8.9 (Berkeley) 3/30/95 */ + #include #include #include +#include #include #include #include @@ -48,21 +50,23 @@ #include -#include #include -#include +#include #include #include #include +#include -struct buf *incore(), *nfs_getcacheblk(); +struct buf *nfs_getcacheblk(); extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; extern int nfs_numasync; +extern struct nfsstats nfsstats; /* * Vnode op for read using bio * Any similarity to readip() is purely coincidental */ +int nfs_bioread(vp, uio, ioflag, cred) register struct vnode *vp; register struct uio *uio; @@ -70,29 +74,28 @@ nfs_bioread(vp, uio, ioflag, cred) struct ucred *cred; { register struct nfsnode *np = VTONFS(vp); - register int biosize, diff; - struct buf *bp, *rabp; + register int biosize, diff, i; + struct buf *bp = 0, *rabp; struct vattr vattr; struct proc *p; - struct nfsmount *nmp; - daddr_t lbn, bn, rabn; + struct nfsmount *nmp = VFSTONFS(vp->v_mount); + daddr_t lbn, bn, bn2, rabn; caddr_t baddr; - int got_buf, nra, error = 0, n, on, not_readin; + int got_buf = 0, nra, error = 0, n = 0, on = 0, not_readin; + nfsquad_t tquad; -#ifdef lint - ioflag = ioflag; -#endif /* lint */ #ifdef DIAGNOSTIC if (uio->uio_rw != UIO_READ) panic("nfs_read mode"); #endif if (uio->uio_resid == 0) return (0); - if (uio->uio_offset < 0 && vp->v_type != VDIR) + if (uio->uio_offset < 0) return (EINVAL); - nmp = VFSTONFS(vp->v_mount); - biosize = nmp->nm_rsize; p = uio->uio_procp; + if ((nmp->nm_flag & (NFSMNT_NFSV3 | NFSMNT_GOTFSINFO)) == NFSMNT_NFSV3) + (void)nfs_fsinfo(nmp, vp, cred, p); + biosize = nmp->nm_rsize; /* * For nfs, cache consistency can only be maintained approximately. * Although RFC1094 does not specify the criteria, the following is @@ -105,8 +108,6 @@ nfs_bioread(vp, uio, ioflag, cred) * server, so flush all of the file's data out of the cache. * Then force a getattr rpc to ensure that you have up to date * attributes. - * The mount flag NFSMNT_MYWRITE says "Assume that my writes are - * the ones changing the modify time. * NB: This implies that cache data can be read when up to * NFS_ATTRTIMEO seconds out of date. If you find that you need current * attributes this could be forced by setting n_attrstamp to 0 before @@ -114,22 +115,28 @@ nfs_bioread(vp, uio, ioflag, cred) */ if ((nmp->nm_flag & NFSMNT_NQNFS) == 0 && vp->v_type != VLNK) { if (np->n_flag & NMODIFIED) { - if ((nmp->nm_flag & NFSMNT_MYWRITE) == 0 || - vp->v_type != VREG) { - if (error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1)) + if (vp->v_type != VREG) { + if (vp->v_type != VDIR) + panic("nfs: bioread, not dir"); + nfs_invaldir(vp); + error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1); + if (error) return (error); } np->n_attrstamp = 0; - np->n_direofoffset = 0; - if (error = VOP_GETATTR(vp, &vattr, cred, p)) + error = VOP_GETATTR(vp, &vattr, cred, p); + if (error) return (error); np->n_mtime = vattr.va_mtime.ts_sec; } else { - if (error = VOP_GETATTR(vp, &vattr, cred, p)) + error = VOP_GETATTR(vp, &vattr, cred, p); + if (error) return (error); if (np->n_mtime != vattr.va_mtime.ts_sec) { - np->n_direofoffset = 0; - if (error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1)) + if (vp->v_type == VDIR) + nfs_invaldir(vp); + error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1); + if (error) return (error); np->n_mtime = vattr.va_mtime.ts_sec; } @@ -141,58 +148,55 @@ nfs_bioread(vp, uio, ioflag, cred) * Get a valid lease. If cached data is stale, flush it. */ if (nmp->nm_flag & NFSMNT_NQNFS) { - if (NQNFS_CKINVALID(vp, np, NQL_READ)) { + if (NQNFS_CKINVALID(vp, np, ND_READ)) { do { - error = nqnfs_getlease(vp, NQL_READ, cred, p); + error = nqnfs_getlease(vp, ND_READ, cred, p); } while (error == NQNFS_EXPIRED); if (error) return (error); if (np->n_lrev != np->n_brev || (np->n_flag & NQNFSNONCACHE) || ((np->n_flag & NMODIFIED) && vp->v_type == VDIR)) { - if (vp->v_type == VDIR) { - np->n_direofoffset = 0; - cache_purge(vp); - } - if (error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1)) + if (vp->v_type == VDIR) + nfs_invaldir(vp); + error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1); + if (error) return (error); np->n_brev = np->n_lrev; } } else if (vp->v_type == VDIR && (np->n_flag & NMODIFIED)) { - np->n_direofoffset = 0; - cache_purge(vp); - if (error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1)) + nfs_invaldir(vp); + error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1); + if (error) return (error); } } if (np->n_flag & NQNFSNONCACHE) { switch (vp->v_type) { case VREG: - error = nfs_readrpc(vp, uio, cred); - break; + return (nfs_readrpc(vp, uio, cred)); case VLNK: - error = nfs_readlinkrpc(vp, uio, cred); - break; + return (nfs_readlinkrpc(vp, uio, cred)); case VDIR: - error = nfs_readdirrpc(vp, uio, cred); break; + default: + printf(" NQNFSNONCACHE: type %x unexpected\n", + vp->v_type); }; - return (error); } baddr = (caddr_t)0; switch (vp->v_type) { case VREG: nfsstats.biocache_reads++; lbn = uio->uio_offset / biosize; - on = uio->uio_offset & (biosize-1); + on = uio->uio_offset & (biosize - 1); bn = lbn * (biosize / DEV_BSIZE); not_readin = 1; /* * Start the read ahead(s), as required. */ - if (nfs_numasync > 0 && nmp->nm_readahead > 0 && - lbn == vp->v_lastr + 1) { + if (nfs_numasync > 0 && nmp->nm_readahead > 0) { for (nra = 0; nra < nmp->nm_readahead && (lbn + 1 + nra) * biosize < np->n_size; nra++) { rabn = (lbn + 1 + nra) * (biosize / DEV_BSIZE); @@ -206,7 +210,8 @@ nfs_bioread(vp, uio, ioflag, cred) rabp->b_flags |= B_INVAL; brelse(rabp); } - } + } else + brelse(rabp); } } } @@ -230,7 +235,8 @@ again: if ((bp->b_flags & (B_DONE | B_DELWRI)) == 0) { bp->b_flags |= B_READ; not_readin = 0; - if (error = nfs_doio(bp, cred, p)) { + error = nfs_doio(bp, cred, p); + if (error) { brelse(bp); return (error); } @@ -248,7 +254,7 @@ again: return (EINTR); got_buf = 1; } - bp->b_flags |= B_INVAL; + bp->b_flags |= B_INVAFTERWRITE; if (bp->b_dirtyend > 0) { if ((bp->b_flags & B_DELWRI) == 0) panic("nfsbioread"); @@ -271,7 +277,8 @@ again: return (EINTR); if ((bp->b_flags & B_DONE) == 0) { bp->b_flags |= B_READ; - if (error = nfs_doio(bp, cred, p)) { + error = nfs_doio(bp, cred, p); + if (error) { brelse(bp); return (error); } @@ -282,28 +289,53 @@ again: break; case VDIR: nfsstats.biocache_readdirs++; - bn = (daddr_t)uio->uio_offset; - bp = nfs_getcacheblk(vp, bn, NFS_DIRBLKSIZ, p); + lbn = uio->uio_offset / NFS_DIRBLKSIZ; + on = uio->uio_offset & (NFS_DIRBLKSIZ - 1); + bp = nfs_getcacheblk(vp, lbn, NFS_DIRBLKSIZ, p); if (!bp) - return (EINTR); + return (EINTR); if ((bp->b_flags & B_DONE) == 0) { - bp->b_flags |= B_READ; - if (error = nfs_doio(bp, cred, p)) { - brelse(bp); - return (error); + bp->b_flags |= B_READ; + error = nfs_doio(bp, cred, p); + if (error) { + brelse(bp); + while (error == NFSERR_BAD_COOKIE) { + nfs_invaldir(vp); + error = nfs_vinvalbuf(vp, 0, cred, p, 1); + /* + * Yuck! The directory has been modified on the + * server. The only way to get the block is by + * reading from the beginning to get all the + * offset cookies. + */ + for (i = 0; i <= lbn && !error; i++) { + bp = nfs_getcacheblk(vp, i, NFS_DIRBLKSIZ, p); + if (!bp) + return (EINTR); + if ((bp->b_flags & B_DONE) == 0) { + bp->b_flags |= B_READ; + error = nfs_doio(bp, cred, p); + if (error) + brelse(bp); + } + } } + if (error) + return (error); + } } /* * If not eof and read aheads are enabled, start one. * (You need the current block first, so that you have the - * directory offset cookie of the next block. + * directory offset cookie of the next block.) */ - rabn = bp->b_blkno; if (nfs_numasync > 0 && nmp->nm_readahead > 0 && - rabn != 0 && rabn != np->n_direofoffset && - !incore(vp, rabn)) { - rabp = nfs_getcacheblk(vp, rabn, NFS_DIRBLKSIZ, p); + (np->n_direofoffset == 0 || + (lbn + 1) * NFS_DIRBLKSIZ < np->n_direofoffset) && + !(np->n_flag & NQNFSNONCACHE) && + !incore(vp, lbn + 1)) { + rabp = nfs_getcacheblk(vp, lbn + 1, NFS_DIRBLKSIZ, p); if (rabp) { if ((rabp->b_flags & (B_DONE | B_DELWRI)) == 0) { rabp->b_flags |= (B_READ | B_ASYNC); @@ -311,13 +343,16 @@ again: rabp->b_flags |= B_INVAL; brelse(rabp); } - } + } else + brelse(rabp); } } - on = 0; - n = min(uio->uio_resid, NFS_DIRBLKSIZ - bp->b_resid); + n = min(uio->uio_resid, NFS_DIRBLKSIZ - bp->b_resid - on); got_buf = 1; break; + default: + printf(" nfsbioread: type %x unexpected\n",vp->v_type); + break; }; if (n > 0) { @@ -327,16 +362,17 @@ again: } switch (vp->v_type) { case VREG: - if (n + on == biosize || uio->uio_offset == np->n_size) - bp->b_flags |= B_AGE; break; case VLNK: n = 0; break; case VDIR: - uio->uio_offset = bp->b_blkno; + if (np->n_flag & NQNFSNONCACHE) + bp->b_flags |= B_INVAL; break; - }; + default: + printf(" nfsbioread: type %x unexpected\n",vp->v_type); + } if (got_buf) brelse(bp); } while (error == 0 && uio->uio_resid > 0 && n > 0); @@ -346,6 +382,7 @@ again: /* * Vnode op for write using bio */ +int nfs_write(ap) struct vop_write_args /* { struct vnode *a_vp; @@ -363,9 +400,9 @@ nfs_write(ap) int ioflag = ap->a_ioflag; struct buf *bp; struct vattr vattr; - struct nfsmount *nmp; + struct nfsmount *nmp = VFSTONFS(vp->v_mount); daddr_t lbn, bn; - int n, on, error = 0; + int n, on, error = 0, iomode, must_commit; #ifdef DIAGNOSTIC if (uio->uio_rw != UIO_WRITE) @@ -379,20 +416,23 @@ nfs_write(ap) np->n_flag &= ~NWRITEERR; return (np->n_error); } + if ((nmp->nm_flag & (NFSMNT_NFSV3 | NFSMNT_GOTFSINFO)) == NFSMNT_NFSV3) + (void)nfs_fsinfo(nmp, vp, cred, p); if (ioflag & (IO_APPEND | IO_SYNC)) { if (np->n_flag & NMODIFIED) { np->n_attrstamp = 0; - if (error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1)) + error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1); + if (error) return (error); } if (ioflag & IO_APPEND) { np->n_attrstamp = 0; - if (error = VOP_GETATTR(vp, &vattr, cred, p)) + error = VOP_GETATTR(vp, &vattr, cred, p); + if (error) return (error); uio->uio_offset = np->n_size; } } - nmp = VFSTONFS(vp->v_mount); if (uio->uio_offset < 0) return (EINVAL); if (uio->uio_resid == 0) @@ -415,25 +455,35 @@ nfs_write(ap) do { /* + * XXX make sure we aren't cached in the VM page cache + */ + (void)vnode_pager_uncache(vp); + + /* * Check for a valid write lease. - * If non-cachable, just do the rpc */ if ((nmp->nm_flag & NFSMNT_NQNFS) && - NQNFS_CKINVALID(vp, np, NQL_WRITE)) { + NQNFS_CKINVALID(vp, np, ND_WRITE)) { do { - error = nqnfs_getlease(vp, NQL_WRITE, cred, p); + error = nqnfs_getlease(vp, ND_WRITE, cred, p); } while (error == NQNFS_EXPIRED); if (error) return (error); if (np->n_lrev != np->n_brev || (np->n_flag & NQNFSNONCACHE)) { - if (error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1)) + error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1); + if (error) return (error); np->n_brev = np->n_lrev; } } - if (np->n_flag & NQNFSNONCACHE) - return (nfs_writerpc(vp, uio, cred, ioflag)); + if ((np->n_flag & NQNFSNONCACHE) && uio->uio_iovcnt == 1) { + iomode = NFSV3WRITE_FILESYNC; + error = nfs_writerpc(vp, uio, cred, &iomode, &must_commit); + if (must_commit) + nfs_clearcommit(vp->v_mount); + return (error); + } nfsstats.biocache_writes++; lbn = uio->uio_offset / biosize; on = uio->uio_offset & (biosize-1); @@ -471,9 +521,9 @@ again: * In case getblk() and/or bwrite() delayed us. */ if ((nmp->nm_flag & NFSMNT_NQNFS) && - NQNFS_CKINVALID(vp, np, NQL_WRITE)) { + NQNFS_CKINVALID(vp, np, ND_WRITE)) { do { - error = nqnfs_getlease(vp, NQL_WRITE, cred, p); + error = nqnfs_getlease(vp, ND_WRITE, cred, p); } while (error == NQNFS_EXPIRED); if (error) { brelse(bp); @@ -482,13 +532,15 @@ again: if (np->n_lrev != np->n_brev || (np->n_flag & NQNFSNONCACHE)) { brelse(bp); - if (error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1)) + error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1); + if (error) return (error); np->n_brev = np->n_lrev; goto again; } } - if (error = uiomove((char *)bp->b_data + on, n, uio)) { + error = uiomove((char *)bp->b_data + on, n, uio); + if (error) { bp->b_flags |= B_ERROR; brelse(bp); return (error); @@ -500,7 +552,6 @@ again: bp->b_dirtyoff = on; bp->b_dirtyend = on + n; } -#ifndef notdef if (bp->b_validend == 0 || bp->b_validend < bp->b_dirtyoff || bp->b_validoff > bp->b_dirtyend) { bp->b_validoff = bp->b_dirtyoff; @@ -509,24 +560,24 @@ again: bp->b_validoff = min(bp->b_validoff, bp->b_dirtyoff); bp->b_validend = max(bp->b_validend, bp->b_dirtyend); } -#else - bp->b_validoff = bp->b_dirtyoff; - bp->b_validend = bp->b_dirtyend; -#endif - if (ioflag & IO_APPEND) - bp->b_flags |= B_APPENDWRITE; - /* * If the lease is non-cachable or IO_SYNC do bwrite(). */ if ((np->n_flag & NQNFSNONCACHE) || (ioflag & IO_SYNC)) { bp->b_proc = p; - if (error = VOP_BWRITE(bp)) + error = VOP_BWRITE(bp); + if (error) return (error); + if (np->n_flag & NQNFSNONCACHE) { + error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1); + if (error) + return (error); + } } else if ((n + on) == biosize && (nmp->nm_flag & NFSMNT_NQNFS) == 0) { bp->b_proc = (struct proc *)0; - bawrite(bp); + bp->b_flags |= B_ASYNC; + (void)nfs_writebp(bp, 0); } else bdwrite(bp); } while (uio->uio_resid > 0 && n > 0); @@ -566,6 +617,7 @@ nfs_getcacheblk(vp, bn, size, p) * Flush and invalidate all dirty buffers. If another process is already * doing the flush, just wait for completion. */ +int nfs_vinvalbuf(vp, flags, cred, p, intrflg) struct vnode *vp; int flags; @@ -626,6 +678,7 @@ nfs_vinvalbuf(vp, flags, cred, p, intrflg) * This is mainly to avoid queueing async I/O requests when the nfsiods * are all hung on a dead server. */ +int nfs_asyncio(bp, cred) register struct buf *bp; struct ucred *cred; @@ -642,6 +695,7 @@ nfs_asyncio(bp, cred) bp->b_rcred = cred; } } else { + bp->b_flags |= B_WRITEINPROG; if (bp->b_wcred == NOCRED && cred != NOCRED) { crhold(cred); bp->b_wcred = cred; @@ -653,7 +707,25 @@ nfs_asyncio(bp, cred) wakeup((caddr_t)&nfs_iodwant[i]); return (0); } - return (EIO); + + /* + * If it is a read or a write already marked B_WRITEINPROG or B_NOCACHE + * return EIO so the process will call nfs_doio() and do it + * synchronously. + */ + if (bp->b_flags & (B_READ | B_WRITEINPROG | B_NOCACHE)) + return (EIO); + + /* + * Just turn the async write into a delayed write, instead of + * doing in synchronously. Hopefully, at least one of the nfsiods + * is currently doing a write for this file and will pick up the + * delayed writes before going back to sleep. + */ + bp->b_flags |= B_DELWRI; + reassignbuf(bp, bp->b_vp); + biodone(bp); + return (0); } /* @@ -663,16 +735,17 @@ nfs_asyncio(bp, cred) int nfs_doio(bp, cr, p) register struct buf *bp; - struct cred *cr; + struct ucred *cr; struct proc *p; { register struct uio *uiop; register struct vnode *vp; struct nfsnode *np; struct nfsmount *nmp; - int error, diff, len; + int error = 0, diff, len, iomode, must_commit = 0; struct uio uio; struct iovec io; + nfsquad_t tquad; vp = bp->b_vp; np = VTONFS(vp); @@ -686,15 +759,31 @@ nfs_doio(bp, cr, p) /* * Historically, paging was done with physio, but no more. */ - if (bp->b_flags & B_PHYS) - panic("doio phys"); - if (bp->b_flags & B_READ) { + if (bp->b_flags & B_PHYS) { + /* + * ...though reading /dev/drum still gets us here. + */ + io.iov_len = uiop->uio_resid = bp->b_bcount; + /* mapping was done by vmapbuf() */ + io.iov_base = bp->b_data; + uiop->uio_offset = ((off_t)bp->b_blkno) * DEV_BSIZE; + if (bp->b_flags & B_READ) { + uiop->uio_rw = UIO_READ; + nfsstats.read_physios++; + error = nfs_readrpc(vp, uiop, cr); + } else + panic("physio write"); + if (error) { + bp->b_flags |= B_ERROR; + bp->b_error = error; + } + } else if (bp->b_flags & B_READ) { io.iov_len = uiop->uio_resid = bp->b_bcount; io.iov_base = bp->b_data; uiop->uio_rw = UIO_READ; switch (vp->v_type) { case VREG: - uiop->uio_offset = bp->b_blkno * DEV_BSIZE; + uiop->uio_offset = ((off_t)bp->b_blkno) * DEV_BSIZE; nfsstats.read_bios++; error = nfs_readrpc(vp, uiop, cr); if (!error) { @@ -707,7 +796,7 @@ nfs_doio(bp, cr, p) * Just zero fill the rest of the valid area. */ diff = bp->b_bcount - uiop->uio_resid; - len = np->n_size - (bp->b_blkno * DEV_BSIZE + len = np->n_size - (((u_quad_t)bp->b_blkno) * DEV_BSIZE + diff); if (len > 0) { len = min(len, uiop->uio_resid); @@ -720,6 +809,7 @@ nfs_doio(bp, cr, p) } if (p && (vp->v_flag & VTEXT) && (((nmp->nm_flag & NFSMNT_NQNFS) && + NQNFS_CKINVALID(vp, np, ND_READ) && np->n_lrev != np->n_brev) || (!(nmp->nm_flag & NFSMNT_NQNFS) && np->n_mtime != np->n_vattr.va_mtime.ts_sec))) { @@ -729,21 +819,23 @@ nfs_doio(bp, cr, p) } break; case VLNK: - uiop->uio_offset = 0; + uiop->uio_offset = (off_t)0; nfsstats.readlink_bios++; error = nfs_readlinkrpc(vp, uiop, cr); break; case VDIR: - uiop->uio_offset = bp->b_lblkno; nfsstats.readdir_bios++; - if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) - error = nfs_readdirlookrpc(vp, uiop, cr); - else - error = nfs_readdirrpc(vp, uiop, cr); - /* - * Save offset cookie in b_blkno. - */ - bp->b_blkno = uiop->uio_offset; + uiop->uio_offset = ((u_quad_t)bp->b_lblkno) * NFS_DIRBLKSIZ; + if (nmp->nm_flag & NFSMNT_RDIRPLUS) { + error = nfs_readdirplusrpc(vp, uiop, cr); + if (error == NFSERR_NOTSUPP) + nmp->nm_flag &= ~NFSMNT_RDIRPLUS; + } + if ((nmp->nm_flag & NFSMNT_RDIRPLUS) == 0) + error = nfs_readdirrpc(vp, uiop, cr); + break; + default: + printf("nfs_doio: type %x unexpected\n",vp->v_type); break; }; if (error) { @@ -753,16 +845,22 @@ nfs_doio(bp, cr, p) } else { io.iov_len = uiop->uio_resid = bp->b_dirtyend - bp->b_dirtyoff; - uiop->uio_offset = (bp->b_blkno * DEV_BSIZE) + uiop->uio_offset = ((off_t)bp->b_blkno) * DEV_BSIZE + bp->b_dirtyoff; io.iov_base = (char *)bp->b_data + bp->b_dirtyoff; uiop->uio_rw = UIO_WRITE; nfsstats.write_bios++; - if (bp->b_flags & B_APPENDWRITE) - error = nfs_writerpc(vp, uiop, cr, IO_APPEND); + if ((bp->b_flags & (B_ASYNC | B_NEEDCOMMIT | B_NOCACHE)) == B_ASYNC) + iomode = NFSV3WRITE_UNSTABLE; + else + iomode = NFSV3WRITE_FILESYNC; + bp->b_flags |= B_WRITEINPROG; + error = nfs_writerpc(vp, uiop, cr, &iomode, &must_commit); + if (!error && iomode == NFSV3WRITE_UNSTABLE) + bp->b_flags |= B_NEEDCOMMIT; else - error = nfs_writerpc(vp, uiop, cr, 0); - bp->b_flags &= ~(B_WRITEINPROG | B_APPENDWRITE); + bp->b_flags &= ~B_NEEDCOMMIT; + bp->b_flags &= ~B_WRITEINPROG; /* * For an interrupted write, the buffer is still valid and the @@ -770,9 +868,13 @@ nfs_doio(bp, cr, p) * B_ERROR and report the interruption by setting B_EINTR. For * the B_ASYNC case, B_EINTR is not relevant, so the rpc attempt * is essentially a noop. + * For the case of a V3 write rpc not being committed to stable + * storage, the block is still dirty and requires either a commit + * rpc or another write rpc with iomode == NFSV3WRITE_FILESYNC + * before the block is reused. This is indicated by setting the + * B_DELWRI and B_NEEDCOMMIT flags. */ - if (error == EINTR) { - bp->b_flags &= ~B_INVAL; + if (error == EINTR || (!error && (bp->b_flags & B_NEEDCOMMIT))) { bp->b_flags |= B_DELWRI; /* @@ -794,6 +896,8 @@ nfs_doio(bp, cr, p) } } bp->b_resid = uiop->uio_resid; + if (must_commit) + nfs_clearcommit(vp->v_mount); biodone(bp); return (error); } diff --git a/sys/nfs/nfs_node.c b/sys/nfs/nfs_node.c index 032bdef..ffd4b08 100644 --- a/sys/nfs/nfs_node.c +++ b/sys/nfs/nfs_node.c @@ -33,9 +33,10 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfs_node.c 8.2 (Berkeley) 12/30/93 + * @(#)nfs_node.c 8.6 (Berkeley) 5/22/95 */ + #include #include #include @@ -46,15 +47,14 @@ #include #include -#include +#include #include #include #include #include -struct nfsnode **nheadhashtbl; -u_long nheadhash; -#define NFSNOHASH(fhsum) ((fhsum)&nheadhash) +LIST_HEAD(nfsnodehashhead, nfsnode) *nfsnodehashtbl; +u_long nfsnodehash; #define TRUE 1 #define FALSE 0 @@ -63,6 +63,7 @@ u_long nheadhash; * Initialize hash links for nfsnodes * and build nfsnode free list. */ +void nfs_nhinit() { @@ -70,25 +71,26 @@ nfs_nhinit() if ((sizeof(struct nfsnode) - 1) & sizeof(struct nfsnode)) printf("nfs_nhinit: bad size %d\n", sizeof(struct nfsnode)); #endif /* not lint */ - nheadhashtbl = hashinit(desiredvnodes, M_NFSNODE, &nheadhash); + nfsnodehashtbl = hashinit(desiredvnodes, M_NFSNODE, &nfsnodehash); } /* * Compute an entry in the NFS hash table structure */ -struct nfsnode ** -nfs_hash(fhp) - register nfsv2fh_t *fhp; +u_long +nfs_hash(fhp, fhsize) + register nfsfh_t *fhp; + int fhsize; { register u_char *fhpp; register u_long fhsum; - int i; + register int i; fhpp = &fhp->fh_bytes[0]; fhsum = 0; - for (i = 0; i < NFSX_FH; i++) + for (i = 0; i < fhsize; i++) fhsum += *fhpp++; - return (&nheadhashtbl[NFSNOHASH(fhsum)]); + return (fhsum); } /* @@ -97,65 +99,62 @@ nfs_hash(fhp) * In all cases, a pointer to a * nfsnode structure is returned. */ -nfs_nget(mntp, fhp, npp) +int +nfs_nget(mntp, fhp, fhsize, npp) struct mount *mntp; - register nfsv2fh_t *fhp; + register nfsfh_t *fhp; + int fhsize; struct nfsnode **npp; { - register struct nfsnode *np, *nq, **nhpp; + struct proc *p = curproc; /* XXX */ + struct nfsnode *np; + struct nfsnodehashhead *nhpp; register struct vnode *vp; extern int (**nfsv2_vnodeop_p)(); struct vnode *nvp; int error; - nhpp = nfs_hash(fhp); + nhpp = NFSNOHASH(nfs_hash(fhp, fhsize)); loop: - for (np = *nhpp; np; np = np->n_forw) { - if (mntp != NFSTOV(np)->v_mount || - bcmp((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH)) + for (np = nhpp->lh_first; np != 0; np = np->n_hash.le_next) { + if (mntp != NFSTOV(np)->v_mount || np->n_fhsize != fhsize || + bcmp((caddr_t)fhp, (caddr_t)np->n_fhp, fhsize)) continue; vp = NFSTOV(np); - if (vget(vp, 1)) + if (vget(vp, LK_EXCLUSIVE, p)) goto loop; *npp = np; return(0); } - if (error = getnewvnode(VT_NFS, mntp, nfsv2_vnodeop_p, &nvp)) { + error = getnewvnode(VT_NFS, mntp, nfsv2_vnodeop_p, &nvp); + if (error) { *npp = 0; return (error); } vp = nvp; MALLOC(np, struct nfsnode *, sizeof *np, M_NFSNODE, M_WAITOK); + bzero((caddr_t)np, sizeof *np); vp->v_data = np; np->n_vnode = vp; /* * Insert the nfsnode in the hash queue for its new file handle */ - np->n_flag = 0; - if (nq = *nhpp) - nq->n_back = &np->n_forw; - np->n_forw = nq; - np->n_back = nhpp; - *nhpp = np; - bcopy((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH); - np->n_attrstamp = 0; - np->n_direofoffset = 0; - np->n_sillyrename = (struct sillyrename *)0; - np->n_size = 0; - np->n_mtime = 0; - if (VFSTONFS(mntp)->nm_flag & NFSMNT_NQNFS) { - np->n_brev = 0; - np->n_lrev = 0; - np->n_expiry = (time_t)0; - np->n_tnext = (struct nfsnode *)0; - } + LIST_INSERT_HEAD(nhpp, np, n_hash); + if (fhsize > NFS_SMALLFH) { + MALLOC(np->n_fhp, nfsfh_t *, fhsize, M_NFSBIGFH, M_WAITOK); + } else + np->n_fhp = &np->n_fh; + bcopy((caddr_t)fhp, (caddr_t)np->n_fhp, fhsize); + np->n_fhsize = fhsize; *npp = np; return (0); } +int nfs_inactive(ap) struct vop_inactive_args /* { struct vnode *a_vp; + struct proc *a_p; } */ *ap; { register struct nfsnode *np; @@ -166,7 +165,10 @@ nfs_inactive(ap) np = VTONFS(ap->a_vp); if (prtactive && ap->a_vp->v_usecount != 0) vprint("nfs_inactive: pushing active", ap->a_vp); - sp = np->n_sillyrename; + if (ap->a_vp->v_type != VDIR) + sp = np->n_sillyrename; + else + sp = (struct sillyrename *)0; np->n_sillyrename = (struct sillyrename *)0; if (sp) { /* @@ -176,18 +178,18 @@ nfs_inactive(ap) nfs_removeit(sp); crfree(sp->s_cred); vrele(sp->s_dvp); -#ifdef SILLYSEPARATE - free((caddr_t)sp, M_NFSREQ); -#endif + FREE((caddr_t)sp, M_NFSREQ); } np->n_flag &= (NMODIFIED | NFLUSHINPROG | NFLUSHWANT | NQNFSEVICTED | NQNFSNONCACHE | NQNFSWRITE); + VOP_UNLOCK(ap->a_vp, 0, ap->a_p); return (0); } /* * Reclaim an nfsnode so that it can be used for other purposes. */ +int nfs_reclaim(ap) struct vop_reclaim_args /* { struct vnode *a_vp; @@ -196,82 +198,41 @@ nfs_reclaim(ap) register struct vnode *vp = ap->a_vp; register struct nfsnode *np = VTONFS(vp); register struct nfsmount *nmp = VFSTONFS(vp->v_mount); - register struct nfsnode *nq; + register struct nfsdmap *dp, *dp2; extern int prtactive; if (prtactive && vp->v_usecount != 0) vprint("nfs_reclaim: pushing active", vp); - /* - * Remove the nfsnode from its hash chain. - */ - if (nq = np->n_forw) - nq->n_back = np->n_back; - *np->n_back = nq; + + LIST_REMOVE(np, n_hash); /* * For nqnfs, take it off the timer queue as required. */ - if ((nmp->nm_flag & NFSMNT_NQNFS) && np->n_tnext) { - if (np->n_tnext == (struct nfsnode *)nmp) - nmp->nm_tprev = np->n_tprev; - else - np->n_tnext->n_tprev = np->n_tprev; - if (np->n_tprev == (struct nfsnode *)nmp) - nmp->nm_tnext = np->n_tnext; - else - np->n_tprev->n_tnext = np->n_tnext; + if ((nmp->nm_flag & NFSMNT_NQNFS) && np->n_timer.cqe_next != 0) { + CIRCLEQ_REMOVE(&nmp->nm_timerhead, np, n_timer); } - cache_purge(vp); - FREE(vp->v_data, M_NFSNODE); - vp->v_data = (void *)0; - return (0); -} - -/* - * Lock an nfsnode - */ -nfs_lock(ap) - struct vop_lock_args /* { - struct vnode *a_vp; - } */ *ap; -{ - register struct vnode *vp = ap->a_vp; /* - * Ugh, another place where interruptible mounts will get hung. - * If you make this sleep interruptible, then you have to fix all - * the VOP_LOCK() calls to expect interruptibility. + * Free up any directory cookie structures and + * large file handle structures that might be associated with + * this nfs node. */ - while (vp->v_flag & VXLOCK) { - vp->v_flag |= VXWANT; - sleep((caddr_t)vp, PINOD); + if (vp->v_type == VDIR) { + dp = np->n_cookies.lh_first; + while (dp) { + dp2 = dp; + dp = dp->ndm_list.le_next; + FREE((caddr_t)dp2, M_NFSDIROFF); + } + } + if (np->n_fhsize > NFS_SMALLFH) { + FREE((caddr_t)np->n_fhp, M_NFSBIGFH); } - if (vp->v_tag == VT_NON) - return (ENOENT); - return (0); -} - -/* - * Unlock an nfsnode - */ -nfs_unlock(ap) - struct vop_unlock_args /* { - struct vnode *a_vp; - } */ *ap; -{ - - return (0); -} - -/* - * Check for a locked nfsnode - */ -nfs_islocked(ap) - struct vop_islocked_args /* { - struct vnode *a_vp; - } */ *ap; -{ + cache_purge(vp); + FREE(vp->v_data, M_NFSNODE); + vp->v_data = (void *)0; return (0); } diff --git a/sys/nfs/nfs_nqlease.c b/sys/nfs/nfs_nqlease.c index 965f461..5c348b3 100644 --- a/sys/nfs/nfs_nqlease.c +++ b/sys/nfs/nfs_nqlease.c @@ -33,9 +33,10 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfs_nqlease.c 8.3 (Berkeley) 1/4/94 + * @(#)nfs_nqlease.c 8.9 (Berkeley) 5/20/95 */ + /* * References: * Cary G. Gray and David R. Cheriton, "Leases: An Efficient Fault-Tolerant @@ -65,7 +66,7 @@ #include #include -#include +#include #include #include #include @@ -73,17 +74,7 @@ #include #include -/* - * List head for the lease queue and other global data. - * At any time a lease is linked into a list ordered by increasing expiry time. - */ -#define NQFHHASH(f) ((*((u_long *)(f)))&nqfheadhash) - -union nqsrvthead nqthead; -struct nqlease **nqfhead; -u_long nqfheadhash; time_t nqnfsstarttime = (time_t)0; -u_long nqnfs_prog, nqnfs_vers; int nqsrv_clockskew = NQ_CLOCKSKEW; int nqsrv_writeslack = NQ_WRITESLACK; int nqsrv_maxlease = NQ_MAXLEASE; @@ -99,43 +90,45 @@ struct mbuf *nfsm_rpchead(); */ int nqnfs_piggy[NFS_NPROCS] = { 0, - NQL_READ, - NQL_WRITE, 0, - NQL_READ, - NQL_READ, - NQL_READ, + ND_WRITE, + ND_READ, + 0, + ND_READ, + ND_READ, + ND_WRITE, + 0, + 0, + 0, 0, - NQL_WRITE, 0, 0, 0, 0, + ND_READ, + ND_READ, 0, 0, 0, - NQL_READ, 0, - NQL_READ, 0, 0, 0, 0, }; -int nnnnnn = sizeof (struct nqlease); -int oooooo = sizeof (struct nfsnode); -extern nfstype nfs_type[9]; +extern nfstype nfsv2_type[9]; +extern nfstype nfsv3_type[9]; extern struct nfssvc_sock *nfs_udpsock, *nfs_cltpsock; -extern struct nfsd nfsd_head; extern int nfsd_waiting; -extern struct nfsreq nfsreqh; +extern struct nfsstats nfsstats; +extern int nfs_mount_type; #define TRUE 1 #define FALSE 0 /* - * Get or check for a lease for "vp", based on NQL_CHECK flag. + * Get or check for a lease for "vp", based on ND_CHECK flag. * The rules are as follows: * - if a current non-caching lease, reply non-caching * - if a current lease for same host only, extend lease @@ -157,18 +150,21 @@ extern struct nfsreq nfsreqh; * is when a new lease is being allocated, since it is not in the timer * queue yet. (Ditto for the splsoftclock() and splx(s) calls) */ -nqsrv_getlease(vp, duration, flags, nd, nam, cachablep, frev, cred) +int +nqsrv_getlease(vp, duration, flags, slp, procp, nam, cachablep, frev, cred) struct vnode *vp; u_long *duration; int flags; - struct nfsd *nd; + struct nfssvc_sock *slp; + struct proc *procp; struct mbuf *nam; int *cachablep; u_quad_t *frev; struct ucred *cred; { - register struct nqlease *lp, *lq, **lpp; - register struct nqhost *lph; + register struct nqlease *lp; + register struct nqfhhashhead *lpp = 0; + register struct nqhost *lph = 0; struct nqlease *tlp; struct nqm **lphp; struct vattr vattr; @@ -179,12 +175,13 @@ nqsrv_getlease(vp, duration, flags, nd, nam, cachablep, frev, cred) return (0); if (*duration > nqsrv_maxlease) *duration = nqsrv_maxlease; - if (error = VOP_GETATTR(vp, &vattr, cred, nd->nd_procp)) + error = VOP_GETATTR(vp, &vattr, cred, procp); + if (error) return (error); *frev = vattr.va_filerev; s = splsoftclock(); tlp = vp->v_lease; - if ((flags & NQL_CHECK) == 0) + if ((flags & ND_CHECK) == 0) nfsstats.srvnqnfs_getleases++; if (tlp == (struct nqlease *)0) { @@ -192,12 +189,13 @@ nqsrv_getlease(vp, duration, flags, nd, nam, cachablep, frev, cred) * Find the lease by searching the hash list. */ fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid; - if (error = VFS_VPTOFH(vp, &fh.fh_fid)) { + error = VFS_VPTOFH(vp, &fh.fh_fid); + if (error) { splx(s); return (error); } - lpp = &nqfhead[NQFHHASH(fh.fh_fid.fid_data)]; - for (lp = *lpp; lp; lp = lp->lc_fhnext) + lpp = NQFHHASH(fh.fh_fid.fid_data); + for (lp = lpp->lh_first; lp != 0; lp = lp->lc_hash.le_next) if (fh.fh_fsid.val[0] == lp->lc_fsid.val[0] && fh.fh_fsid.val[1] == lp->lc_fsid.val[1] && !bcmp(fh.fh_fid.fid_data, lp->lc_fiddata, @@ -208,17 +206,17 @@ nqsrv_getlease(vp, duration, flags, nd, nam, cachablep, frev, cred) tlp = lp; break; } - } - lp = tlp; + } else + lp = tlp; if (lp) { if ((lp->lc_flag & LC_NONCACHABLE) || (lp->lc_morehosts == (struct nqm *)0 && - nqsrv_cmpnam(nd->nd_slp, nam, &lp->lc_host))) + nqsrv_cmpnam(slp, nam, &lp->lc_host))) goto doreply; - if ((flags & NQL_READ) && (lp->lc_flag & LC_WRITE)==0) { - if (flags & NQL_CHECK) + if ((flags & ND_READ) && (lp->lc_flag & LC_WRITE) == 0) { + if (flags & ND_CHECK) goto doreply; - if (nqsrv_cmpnam(nd->nd_slp, nam, &lp->lc_host)) + if (nqsrv_cmpnam(slp, nam, &lp->lc_host)) goto doreply; i = 0; if (lp->lc_morehosts) { @@ -230,7 +228,7 @@ nqsrv_getlease(vp, duration, flags, nd, nam, cachablep, frev, cred) ok = 0; } while (ok && (lph->lph_flag & LC_VALID)) { - if (nqsrv_cmpnam(nd->nd_slp, nam, lph)) + if (nqsrv_cmpnam(slp, nam, lph)) goto doreply; if (++i == LC_MOREHOSTSIZ) { i = 0; @@ -250,12 +248,12 @@ nqsrv_getlease(vp, duration, flags, nd, nam, cachablep, frev, cred) bzero((caddr_t)*lphp, sizeof (struct nqm)); lph = (*lphp)->lpm_hosts; } - nqsrv_addhost(lph, nd->nd_slp, nam); + nqsrv_addhost(lph, slp, nam); nqsrv_unlocklease(lp); } else { lp->lc_flag |= LC_NONCACHABLE; nqsrv_locklease(lp); - nqsrv_send_eviction(vp, lp, nd->nd_slp, nam, cred); + nqsrv_send_eviction(vp, lp, slp, nam, cred); nqsrv_waitfor_expiry(lp); nqsrv_unlocklease(lp); } @@ -263,20 +261,20 @@ doreply: /* * Update the lease and return */ - if ((flags & NQL_CHECK) == 0) + if ((flags & ND_CHECK) == 0) nqsrv_instimeq(lp, *duration); if (lp->lc_flag & LC_NONCACHABLE) *cachablep = 0; else { *cachablep = 1; - if (flags & NQL_WRITE) + if (flags & ND_WRITE) lp->lc_flag |= LC_WRITTEN; } splx(s); return (0); } splx(s); - if (flags & NQL_CHECK) + if (flags & ND_CHECK) return (0); /* @@ -293,17 +291,16 @@ doreply: } MALLOC(lp, struct nqlease *, sizeof (struct nqlease), M_NQLEASE, M_WAITOK); bzero((caddr_t)lp, sizeof (struct nqlease)); - if (flags & NQL_WRITE) + if (flags & ND_WRITE) lp->lc_flag |= (LC_WRITE | LC_WRITTEN); - nqsrv_addhost(&lp->lc_host, nd->nd_slp, nam); + nqsrv_addhost(&lp->lc_host, slp, nam); lp->lc_vp = vp; lp->lc_fsid = fh.fh_fsid; - bcopy(fh.fh_fid.fid_data, lp->lc_fiddata, fh.fh_fid.fid_len - sizeof (long)); - if (lq = *lpp) - lq->lc_fhprev = &lp->lc_fhnext; - lp->lc_fhnext = lq; - lp->lc_fhprev = lpp; - *lpp = lp; + bcopy(fh.fh_fid.fid_data, lp->lc_fiddata, + fh.fh_fid.fid_len - sizeof (long)); + if(!lpp) + panic("nfs_nqlease.c: Phoney lpp"); + LIST_INSERT_HEAD(lpp, lp, lc_hash); vp->v_lease = lp; s = splsoftclock(); nqsrv_instimeq(lp, *duration); @@ -318,21 +315,22 @@ doreply: * Local lease check for server syscalls. * Just set up args and let nqsrv_getlease() do the rest. */ -void -lease_check(vp, p, cred, flag) - struct vnode *vp; - struct proc *p; - struct ucred *cred; - int flag; +int +nqnfs_vop_lease_check(ap) + struct vop_lease_args /* { + struct vnode *a_vp; + struct proc *a_p; + struct ucred *a_cred; + int a_flag; + } */ *ap; { - int duration = 0, cache; - struct nfsd nfsd; + u_long duration = 0; + int cache; u_quad_t frev; - nfsd.nd_slp = NQLOCALSLP; - nfsd.nd_procp = p; - (void) nqsrv_getlease(vp, &duration, NQL_CHECK | flag, &nfsd, - (struct mbuf *)0, &cache, &frev, cred); + (void) nqsrv_getlease(ap->a_vp, &duration, ND_CHECK | ap->a_flag, + NQLOCALSLP, ap->a_p, (struct mbuf *)0, &cache, &frev, ap->a_cred); + return (0); } /* @@ -377,19 +375,26 @@ nqsrv_instimeq(lp, duration) newexpiry = time.tv_sec + duration + nqsrv_clockskew; if (lp->lc_expiry == newexpiry) return; - if (lp->lc_chain1[0]) - remque(lp); + if (lp->lc_timer.cqe_next != 0) { + CIRCLEQ_REMOVE(&nqtimerhead, lp, lc_timer); + } lp->lc_expiry = newexpiry; /* * Find where in the queue it should be. */ - tlp = nqthead.th_chain[1]; - while (tlp->lc_expiry > newexpiry && tlp != (struct nqlease *)&nqthead) - tlp = tlp->lc_chain1[1]; - if (tlp == nqthead.th_chain[1]) + tlp = nqtimerhead.cqh_last; + while (tlp != (void *)&nqtimerhead && tlp->lc_expiry > newexpiry) + tlp = tlp->lc_timer.cqe_prev; +#ifdef HASNVRAM + if (tlp == nqtimerhead.cqh_last) NQSTORENOVRAM(newexpiry); - insque(lp, tlp); +#endif /* HASNVRAM */ + if (tlp == (void *)&nqtimerhead) { + CIRCLEQ_INSERT_HEAD(&nqtimerhead, lp, lc_timer); + } else { + CIRCLEQ_INSERT_AFTER(&nqtimerhead, tlp, lp, lc_timer); + } } /* @@ -398,6 +403,7 @@ nqsrv_instimeq(lp, duration) * This is somewhat messy due to the union in the nqhost structure. * The local host is indicated by the special value of NQLOCALSLP for slp. */ +int nqsrv_cmpnam(slp, nam, lph) register struct nfssvc_sock *slp; struct mbuf *nam; @@ -486,9 +492,9 @@ nqsrv_send_eviction(vp, lp, slp, nam, cred) else solockp = (int *)0; nfsm_reqhead((struct vnode *)0, NQNFSPROC_EVICTED, - NFSX_FH); - nfsm_build(cp, caddr_t, NFSX_FH); - bzero(cp, NFSX_FH); + NFSX_V3FH); + nfsm_build(cp, caddr_t, NFSX_V3FH); + bzero(cp, NFSX_V3FH); fhp = (fhandle_t *)cp; fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; VFS_VPTOFH(vp, &fhp->fh_fid); @@ -502,8 +508,9 @@ nqsrv_send_eviction(vp, lp, slp, nam, cred) printf("mbuf siz=%d\n",siz); panic("Bad nfs svc reply"); } - m = nfsm_rpchead(cred, TRUE, NQNFSPROC_EVICTED, - RPCAUTH_UNIX, 5*NFSX_UNSIGNED, (char *)0, + m = nfsm_rpchead(cred, (NFSMNT_NFSV3 | NFSMNT_NQNFS), + NQNFSPROC_EVICTED, + RPCAUTH_UNIX, 5 * NFSX_UNSIGNED, (char *)0, mreq, siz, &mheadend, &xid); /* * For stream protocols, prepend a Sun RPC @@ -594,18 +601,18 @@ tryagain: void nqnfs_serverd() { - register struct nqlease *lp, *lq; + register struct nqlease *lp; register struct nqhost *lph; struct nqlease *nextlp; struct nqm *lphnext, *olphnext; struct mbuf *n; int i, len, ok; - lp = nqthead.th_chain[0]; - while (lp != (struct nqlease *)&nqthead) { + for (lp = nqtimerhead.cqh_first; lp != (void *)&nqtimerhead; + lp = nextlp) { if (lp->lc_expiry >= time.tv_sec) break; - nextlp = lp->lc_chain1[0]; + nextlp = lp->lc_timer.cqe_next; if (lp->lc_flag & LC_EXPIREDWANTED) { lp->lc_flag &= ~LC_EXPIREDWANTED; wakeup((caddr_t)&lp->lc_flag); @@ -626,10 +633,8 @@ nqnfs_serverd() lp->lc_flag &= ~LC_WRITTEN; nqsrv_instimeq(lp, nqsrv_writeslack); } else { - remque(lp); - if (lq = lp->lc_fhnext) - lq->lc_fhprev = lp->lc_fhprev; - *lp->lc_fhprev = lq; + CIRCLEQ_REMOVE(&nqtimerhead, lp, lc_timer); + LIST_REMOVE(lp, lc_hash); /* * This soft reference may no longer be valid, but * no harm done. The worst case is if the vnode was @@ -670,7 +675,6 @@ nqnfs_serverd() nfsstats.srvnqnfs_leases--; } } - lp = nextlp; } } @@ -679,18 +683,22 @@ nqnfs_serverd() * Do the from/to xdr translation and call nqsrv_getlease() to * do the real work. */ -nqnfsrv_getlease(nfsd, mrep, md, dpos, cred, nam, mrq) - struct nfsd *nfsd; - struct mbuf *mrep, *md; - caddr_t dpos; - struct ucred *cred; - struct mbuf *nam, **mrq; +int +nqnfsrv_getlease(nfsd, slp, procp, mrq) + struct nfsrv_descript *nfsd; + struct nfssvc_sock *slp; + struct proc *procp; + struct mbuf **mrq; { - register struct nfsv2_fattr *fp; + struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; + struct mbuf *nam = nfsd->nd_nam; + caddr_t dpos = nfsd->nd_dpos; + struct ucred *cred = &nfsd->nd_cr; + register struct nfs_fattr *fp; struct vattr va; register struct vattr *vap = &va; struct vnode *vp; - nfsv2fh_t nfh; + nfsfh_t nfh; fhandle_t *fhp; register u_long *tl; register long t1; @@ -703,27 +711,29 @@ nqnfsrv_getlease(nfsd, mrep, md, dpos, cred, nam, mrq) fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); - nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); + nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); flags = fxdr_unsigned(int, *tl++); nfsd->nd_duration = fxdr_unsigned(int, *tl); - if (error = nfsrv_fhtovp(fhp, - TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) + error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly, + (nfsd->nd_flag & ND_KERBAUTH)); + if (error) nfsm_reply(0); - if (rdonly && flags == NQL_WRITE) { + if (rdonly && flags == ND_WRITE) { + vput(vp); error = EROFS; nfsm_reply(0); } - (void) nqsrv_getlease(vp, &nfsd->nd_duration, flags, nfsd, + (void) nqsrv_getlease(vp, &nfsd->nd_duration, flags, slp, procp, nam, &cache, &frev, cred); - error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); + error = VOP_GETATTR(vp, vap, cred, procp); vput(vp); - nfsm_reply(NFSX_NQFATTR + 4*NFSX_UNSIGNED); - nfsm_build(tl, u_long *, 4*NFSX_UNSIGNED); + nfsm_reply(NFSX_V3FATTR + 4 * NFSX_UNSIGNED); + nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(cache); *tl++ = txdr_unsigned(nfsd->nd_duration); txdr_hyper(&frev, tl); - nfsm_build(fp, struct nfsv2_fattr *, NFSX_NQFATTR); - nfsm_srvfillattr; + nfsm_build(fp, struct nfs_fattr *, NFSX_V3FATTR); + nfsm_srvfillattr(vap, fp); nfsm_srvdone; } @@ -731,23 +741,29 @@ nqnfsrv_getlease(nfsd, mrep, md, dpos, cred, nam, mrq) * Called from nfssvc_nfsd() when a "vacated" message is received from a * client. Find the entry and expire it. */ -nqnfsrv_vacated(nfsd, mrep, md, dpos, cred, nam, mrq) - struct nfsd *nfsd; - struct mbuf *mrep, *md; - caddr_t dpos; - struct ucred *cred; - struct mbuf *nam, **mrq; +int +nqnfsrv_vacated(nfsd, slp, procp, mrq) + struct nfsrv_descript *nfsd; + struct nfssvc_sock *slp; + struct proc *procp; + struct mbuf **mrq; { + struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; + struct mbuf *nam = nfsd->nd_nam; + caddr_t dpos = nfsd->nd_dpos; + struct ucred *cred = &nfsd->nd_cr; register struct nqlease *lp; register struct nqhost *lph; struct nqlease *tlp = (struct nqlease *)0; - nfsv2fh_t nfh; + nfsfh_t nfh; fhandle_t *fhp; register u_long *tl; register long t1; struct nqm *lphnext; - int error = 0, i, len, ok, gotit = 0; - char *cp2; + struct mbuf *mreq, *mb; + int error = 0, i, len, ok, gotit = 0, cache = 0; + char *cp2, *bpos; + u_quad_t frev; fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); @@ -755,8 +771,8 @@ nqnfsrv_vacated(nfsd, mrep, md, dpos, cred, nam, mrq) /* * Find the lease by searching the hash list. */ - for (lp = nqfhead[NQFHHASH(fhp->fh_fid.fid_data)]; lp; - lp = lp->lc_fhnext) + for (lp = NQFHHASH(fhp->fh_fid.fid_data)->lh_first; lp != 0; + lp = lp->lc_hash.le_next) if (fhp->fh_fsid.val[0] == lp->lc_fsid.val[0] && fhp->fh_fsid.val[1] == lp->lc_fsid.val[1] && !bcmp(fhp->fh_fid.fid_data, lp->lc_fiddata, @@ -773,7 +789,7 @@ nqnfsrv_vacated(nfsd, mrep, md, dpos, cred, nam, mrq) lphnext = lp->lc_morehosts; ok = 1; while (ok && (lph->lph_flag & LC_VALID)) { - if (nqsrv_cmpnam(nfsd->nd_slp, nam, lph)) { + if (nqsrv_cmpnam(slp, nam, lph)) { lph->lph_flag |= LC_VACATED; gotit++; break; @@ -802,6 +818,7 @@ nfsmout: /* * Client get lease rpc function. */ +int nqnfs_getlease(vp, rwflag, cred, p) register struct vnode *vp; int rwflag; @@ -810,7 +827,7 @@ nqnfs_getlease(vp, rwflag, cred, p) { register u_long *tl; register caddr_t cp; - register long t1; + register long t1, t2; register struct nfsnode *np; struct nfsmount *nmp = VFSTONFS(vp->v_mount); caddr_t bpos, dpos, cp2; @@ -821,16 +838,16 @@ nqnfs_getlease(vp, rwflag, cred, p) u_quad_t frev; nfsstats.rpccnt[NQNFSPROC_GETLEASE]++; - mb = mreq = nfsm_reqh(vp, NQNFSPROC_GETLEASE, NFSX_FH+2*NFSX_UNSIGNED, + mb = mreq = nfsm_reqh(vp, NQNFSPROC_GETLEASE, NFSX_V3FH+2*NFSX_UNSIGNED, &bpos); - nfsm_fhtom(vp); - nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); + nfsm_fhtom(vp, 1); + nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(rwflag); *tl = txdr_unsigned(nmp->nm_leaseterm); reqtime = time.tv_sec; nfsm_request(vp, NQNFSPROC_GETLEASE, p, cred); np = VTONFS(vp); - nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED); + nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED); cachable = fxdr_unsigned(int, *tl++); reqtime += fxdr_unsigned(int, *tl++); if (reqtime > time.tv_sec) { @@ -846,6 +863,7 @@ nqnfs_getlease(vp, rwflag, cred, p) /* * Client vacated message function. */ +int nqnfs_vacated(vp, cred) register struct vnode *vp; struct ucred *cred; @@ -853,6 +871,8 @@ nqnfs_vacated(vp, cred) register caddr_t cp; register struct mbuf *m; register int i; + register u_long *tl; + register long t1, t2; caddr_t bpos; u_long xid; int error = 0; @@ -862,16 +882,16 @@ nqnfs_vacated(vp, cred) nmp = VFSTONFS(vp->v_mount); nfsstats.rpccnt[NQNFSPROC_VACATED]++; - nfsm_reqhead(vp, NQNFSPROC_VACATED, NFSX_FH); - nfsm_fhtom(vp); + nfsm_reqhead(vp, NQNFSPROC_VACATED, NFSX_V3FH); + nfsm_fhtom(vp, 1); m = mreq; i = 0; while (m) { i += m->m_len; m = m->m_next; } - m = nfsm_rpchead(cred, TRUE, NQNFSPROC_VACATED, - RPCAUTH_UNIX, 5*NFSX_UNSIGNED, (char *)0, + m = nfsm_rpchead(cred, nmp->nm_flag, NQNFSPROC_VACATED, + RPCAUTH_UNIX, 5 * NFSX_UNSIGNED, (char *)0, mreq, i, &mheadend, &xid); if (nmp->nm_sotype == SOCK_STREAM) { M_PREPEND(m, NFSX_UNSIGNED, M_WAIT); @@ -885,12 +905,14 @@ nqnfs_vacated(vp, cred) (void) nfs_send(nmp->nm_so, nmp->nm_nam, m, &myrep); if (nmp->nm_soflags & PR_CONNREQUIRED) nfs_sndunlock(&nmp->nm_flag); +nfsmout: return (error); } /* * Called for client side callbacks */ +int nqnfs_callback(nmp, mrep, md, dpos) struct nfsmount *nmp; struct mbuf *mrep, *md; @@ -899,46 +921,46 @@ nqnfs_callback(nmp, mrep, md, dpos) register struct vnode *vp; register u_long *tl; register long t1; - nfsv2fh_t nfh; + nfsfh_t nfh; fhandle_t *fhp; struct nfsnode *np; - struct nfsd nd; - int error; - char *cp2; + struct nfsd tnfsd; + struct nfssvc_sock *slp; + struct nfsrv_descript ndesc; + register struct nfsrv_descript *nfsd = &ndesc; + struct mbuf **mrq = (struct mbuf **)0, *mb, *mreq; + int error = 0, cache = 0; + char *cp2, *bpos; + u_quad_t frev; - nd.nd_mrep = mrep; - nd.nd_md = md; - nd.nd_dpos = dpos; - if (error = nfs_getreq(&nd, FALSE)) +#ifndef nolint + slp = NULL; +#endif + nfsd->nd_mrep = mrep; + nfsd->nd_md = md; + nfsd->nd_dpos = dpos; + error = nfs_getreq(nfsd, &tnfsd, FALSE); + if (error) return (error); - md = nd.nd_md; - dpos = nd.nd_dpos; - if (nd.nd_procnum != NQNFSPROC_EVICTED) { + md = nfsd->nd_md; + dpos = nfsd->nd_dpos; + if (nfsd->nd_procnum != NQNFSPROC_EVICTED) { m_freem(mrep); return (EPERM); } fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); m_freem(mrep); - if (error = nfs_nget(nmp->nm_mountp, fhp, &np)) + error = nfs_nget(nmp->nm_mountp, (nfsfh_t *)fhp, NFSX_V3FH, &np); + if (error) return (error); vp = NFSTOV(np); - if (np->n_tnext) { + if (np->n_timer.cqe_next != 0) { np->n_expiry = 0; np->n_flag |= NQNFSEVICTED; - if (np->n_tprev != (struct nfsnode *)nmp) { - if (np->n_tnext == (struct nfsnode *)nmp) - nmp->nm_tprev = np->n_tprev; - else - np->n_tnext->n_tprev = np->n_tprev; - np->n_tprev->n_tnext = np->n_tnext; - np->n_tnext = nmp->nm_tnext; - nmp->nm_tnext = np; - np->n_tprev = (struct nfsnode *)nmp; - if (np->n_tnext == (struct nfsnode *)nmp) - nmp->nm_tprev = np; - else - np->n_tnext->n_tprev = np; + if (nmp->nm_timerhead.cqh_first != np) { + CIRCLEQ_REMOVE(&nmp->nm_timerhead, np, n_timer); + CIRCLEQ_INSERT_HEAD(&nmp->nm_timerhead, np, n_timer); } } vrele(vp); @@ -952,6 +974,7 @@ nqnfs_callback(nmp, mrep, md, dpos) * "sleep" since nfs_reclaim() called from vclean() can pull a node off * the list asynchronously. */ +int nqnfs_clientd(nmp, cred, ncd, flag, argp, p) register struct nfsmount *nmp; struct ucred *cred; @@ -963,35 +986,39 @@ nqnfs_clientd(nmp, cred, ncd, flag, argp, p) register struct nfsnode *np; struct vnode *vp; struct nfsreq myrep; - int error, vpid; + struct nfsuid *nuidp, *nnuidp; + int error = 0, vpid; /* * First initialize some variables */ - nqnfs_prog = txdr_unsigned(NQNFS_PROG); - nqnfs_vers = txdr_unsigned(NQNFS_VER1); /* * If an authorization string is being passed in, get it. */ if ((flag & NFSSVC_GOTAUTH) && - (nmp->nm_flag & (NFSMNT_WAITAUTH | NFSMNT_DISMNT)) == 0) { - if (nmp->nm_flag & NFSMNT_HASAUTH) - panic("cld kerb"); - if ((flag & NFSSVC_AUTHINFAIL) == 0) { - if (ncd->ncd_authlen <= RPCAUTH_MAXSIZ && - copyin(ncd->ncd_authstr, nmp->nm_authstr, - ncd->ncd_authlen) == 0) { - nmp->nm_authtype = ncd->ncd_authtype; - nmp->nm_authlen = ncd->ncd_authlen; - } else - nmp->nm_flag |= NFSMNT_AUTHERR; + (nmp->nm_flag & (NFSMNT_WAITAUTH | NFSMNT_DISMNT)) == 0) { + if (nmp->nm_flag & NFSMNT_HASAUTH) + panic("cld kerb"); + if ((flag & NFSSVC_AUTHINFAIL) == 0) { + if (ncd->ncd_authlen <= nmp->nm_authlen && + ncd->ncd_verflen <= nmp->nm_verflen && + !copyin(ncd->ncd_authstr,nmp->nm_authstr,ncd->ncd_authlen)&& + !copyin(ncd->ncd_verfstr,nmp->nm_verfstr,ncd->ncd_verflen)){ + nmp->nm_authtype = ncd->ncd_authtype; + nmp->nm_authlen = ncd->ncd_authlen; + nmp->nm_verflen = ncd->ncd_verflen; +#ifdef NFSKERB + nmp->nm_key = ncd->ncd_key; +#endif } else - nmp->nm_flag |= NFSMNT_AUTHERR; - nmp->nm_flag |= NFSMNT_HASAUTH; - wakeup((caddr_t)&nmp->nm_authlen); + nmp->nm_flag |= NFSMNT_AUTHERR; + } else + nmp->nm_flag |= NFSMNT_AUTHERR; + nmp->nm_flag |= NFSMNT_HASAUTH; + wakeup((caddr_t)&nmp->nm_authlen); } else - nmp->nm_flag |= NFSMNT_WAITAUTH; + nmp->nm_flag |= NFSMNT_WAITAUTH; /* * Loop every second updating queue until there is a termination sig. @@ -1003,7 +1030,7 @@ nqnfs_clientd(nmp, cred, ncd, flag, argp, p) * processes in nfs_reply) and there is data in the receive * queue, poke for callbacks. */ - if (nfsreqh.r_next == &nfsreqh && nmp->nm_so && + if (nfs_reqq.tqh_first == 0 && nmp->nm_so && nmp->nm_so->so_rcv.sb_cc > 0) { myrep.r_flags = R_GETONEREP; myrep.r_nmp = nmp; @@ -1015,26 +1042,17 @@ nqnfs_clientd(nmp, cred, ncd, flag, argp, p) /* * Loop through the leases, updating as required. */ - np = nmp->nm_tnext; - while (np != (struct nfsnode *)nmp && + np = nmp->nm_timerhead.cqh_first; + while (np != (void *)&nmp->nm_timerhead && (nmp->nm_flag & NFSMNT_DISMINPROG) == 0) { vp = NFSTOV(np); -if (vp->v_mount->mnt_stat.f_fsid.val[1] != MOUNT_NFS) panic("trash2"); vpid = vp->v_id; if (np->n_expiry < time.tv_sec) { - if (vget(vp, 1) == 0) { + if (vget(vp, LK_EXCLUSIVE, p) == 0) { nmp->nm_inprog = vp; if (vpid == vp->v_id) { -if (vp->v_mount->mnt_stat.f_fsid.val[1] != MOUNT_NFS) panic("trash3"); - if (np->n_tnext == (struct nfsnode *)nmp) - nmp->nm_tprev = np->n_tprev; - else - np->n_tnext->n_tprev = np->n_tprev; - if (np->n_tprev == (struct nfsnode *)nmp) - nmp->nm_tnext = np->n_tnext; - else - np->n_tprev->n_tnext = np->n_tnext; - np->n_tnext = (struct nfsnode *)0; + CIRCLEQ_REMOVE(&nmp->nm_timerhead, np, n_timer); + np->n_timer.cqe_next = 0; if ((np->n_flag & (NMODIFIED | NQNFSEVICTED)) && vp->v_type == VREG) { if (np->n_flag & NQNFSEVICTED) { @@ -1052,28 +1070,22 @@ if (vp->v_mount->mnt_stat.f_fsid.val[1] != MOUNT_NFS) panic("trash3"); vrele(vp); nmp->nm_inprog = NULLVP; } - if (np != nmp->nm_tnext) - np = nmp->nm_tnext; - else - break; } else if ((np->n_expiry - NQ_RENEWAL) < time.tv_sec) { if ((np->n_flag & (NQNFSWRITE | NQNFSNONCACHE)) == NQNFSWRITE && vp->v_dirtyblkhd.lh_first && - vget(vp, 1) == 0) { + vget(vp, LK_EXCLUSIVE, p) == 0) { nmp->nm_inprog = vp; -if (vp->v_mount->mnt_stat.f_fsid.val[1] != MOUNT_NFS) panic("trash4"); if (vpid == vp->v_id && - nqnfs_getlease(vp, NQL_WRITE, cred, p)==0) + nqnfs_getlease(vp, ND_WRITE, cred, p)==0) np->n_brev = np->n_lrev; vrele(vp); nmp->nm_inprog = NULLVP; } - if (np != nmp->nm_tnext) - np = nmp->nm_tnext; - else - break; } else break; + if (np == nmp->nm_timerhead.cqh_first) + break; + np = nmp->nm_timerhead.cqh_first; } } @@ -1099,6 +1111,16 @@ if (vp->v_mount->mnt_stat.f_fsid.val[1] != MOUNT_NFS) panic("trash4"); (void) dounmount(nmp->nm_mountp, 0, p); } } + + /* + * Finally, we can free up the mount structure. + */ + for (nuidp = nmp->nm_uidlruhead.tqh_first; nuidp != 0; nuidp = nnuidp) { + nnuidp = nuidp->nu_lru.tqe_next; + LIST_REMOVE(nuidp, nu_hash); + TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp, nu_lru); + free((caddr_t)nuidp, M_NFSUID); + } free((caddr_t)nmp, M_NFSMNT); if (error == EWOULDBLOCK) error = 0; @@ -1110,41 +1132,49 @@ if (vp->v_mount->mnt_stat.f_fsid.val[1] != MOUNT_NFS) panic("trash4"); * Called from the settimeofday() syscall. */ void -lease_updatetime(deltat) +nqnfs_lease_updatetime(deltat) register int deltat; { - register struct nqlease *lp; - register struct nfsnode *np; - struct mount *mp; + struct proc *p = curproc; /* XXX */ + struct nqlease *lp; + struct nfsnode *np; + struct mount *mp, *nxtmp; struct nfsmount *nmp; int s; if (nqnfsstarttime != 0) nqnfsstarttime += deltat; s = splsoftclock(); - lp = nqthead.th_chain[0]; - while (lp != (struct nqlease *)&nqthead) { + for (lp = nqtimerhead.cqh_first; lp != (void *)&nqtimerhead; + lp = lp->lc_timer.cqe_next) lp->lc_expiry += deltat; - lp = lp->lc_chain1[0]; - } splx(s); /* * Search the mount list for all nqnfs mounts and do their timer * queues. */ - for (mp = mountlist.tqh_first; mp != NULL; mp = mp->mnt_list.tqe_next) { - if (mp->mnt_stat.f_fsid.val[1] == MOUNT_NFS) { + simple_lock(&mountlist_slock); + for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nxtmp) { + if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) { + nxtmp = mp->mnt_list.cqe_next; + continue; + } + if (mp->mnt_stat.f_type == nfs_mount_type) { nmp = VFSTONFS(mp); if (nmp->nm_flag & NFSMNT_NQNFS) { - np = nmp->nm_tnext; - while (np != (struct nfsnode *)nmp) { + for (np = nmp->nm_timerhead.cqh_first; + np != (void *)&nmp->nm_timerhead; + np = np->n_timer.cqe_next) { np->n_expiry += deltat; - np = np->n_tnext; } } } + simple_lock(&mountlist_slock); + nxtmp = mp->mnt_list.cqe_next; + vfs_unbusy(mp, p); } + simple_unlock(&mountlist_slock); } /* @@ -1189,18 +1219,11 @@ nqnfs_clientlease(nmp, np, rwflag, cachable, expiry, frev) { register struct nfsnode *tp; - if (np->n_tnext) { - if (np->n_tnext == (struct nfsnode *)nmp) - nmp->nm_tprev = np->n_tprev; - else - np->n_tnext->n_tprev = np->n_tprev; - if (np->n_tprev == (struct nfsnode *)nmp) - nmp->nm_tnext = np->n_tnext; - else - np->n_tprev->n_tnext = np->n_tnext; - if (rwflag == NQL_WRITE) + if (np->n_timer.cqe_next != 0) { + CIRCLEQ_REMOVE(&nmp->nm_timerhead, np, n_timer); + if (rwflag == ND_WRITE) np->n_flag |= NQNFSWRITE; - } else if (rwflag == NQL_READ) + } else if (rwflag == ND_READ) np->n_flag &= ~NQNFSWRITE; else np->n_flag |= NQNFSWRITE; @@ -1210,19 +1233,12 @@ nqnfs_clientlease(nmp, np, rwflag, cachable, expiry, frev) np->n_flag |= NQNFSNONCACHE; np->n_expiry = expiry; np->n_lrev = frev; - tp = nmp->nm_tprev; - while (tp != (struct nfsnode *)nmp && tp->n_expiry > np->n_expiry) - tp = tp->n_tprev; - if (tp == (struct nfsnode *)nmp) { - np->n_tnext = nmp->nm_tnext; - nmp->nm_tnext = np; + tp = nmp->nm_timerhead.cqh_last; + while (tp != (void *)&nmp->nm_timerhead && tp->n_expiry > np->n_expiry) + tp = tp->n_timer.cqe_prev; + if (tp == (void *)&nmp->nm_timerhead) { + CIRCLEQ_INSERT_HEAD(&nmp->nm_timerhead, np, n_timer); } else { - np->n_tnext = tp->n_tnext; - tp->n_tnext = np; + CIRCLEQ_INSERT_AFTER(&nmp->nm_timerhead, tp, np, n_timer); } - np->n_tprev = tp; - if (np->n_tnext == (struct nfsnode *)nmp) - nmp->nm_tprev = np; - else - np->n_tnext->n_tprev = np; } diff --git a/sys/nfs/nfs_serv.c b/sys/nfs/nfs_serv.c index f31b96e..3e6ef3d 100644 --- a/sys/nfs/nfs_serv.c +++ b/sys/nfs/nfs_serv.c @@ -33,11 +33,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfs_serv.c 8.3 (Berkeley) 1/12/94 + * @(#)nfs_serv.c 8.7 (Berkeley) 5/14/95 */ /* - * nfs version 2 server calls to vnode ops + * nfs version 2 and 3 server calls to vnode ops * - these routines generally have 3 phases * 1 - break down and validate rpc request in mbuf list * 2 - do the vnode ops for the request @@ -52,6 +52,8 @@ * returning an error from the server function implies a fatal error * such as a badly constructed rpc request that should be dropped without * a reply. + * For Version 3, nfsm_reply() does not return for the error case, since + * most version 3 rpcs return more than the status for error cases. */ #include @@ -61,83 +63,120 @@ #include #include #include +#include +#include #include #include #include +#include +#include #include -#include +#include #include #include #include #include #include -/* Defs */ -#define TRUE 1 -#define FALSE 0 - /* Global vars */ -extern u_long nfs_procids[NFS_NPROCS]; extern u_long nfs_xdrneg1; extern u_long nfs_false, nfs_true; -nfstype nfs_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON, +extern enum vtype nv3tov_type[8]; +extern struct nfsstats nfsstats; +nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON, NFCHR, NFNON }; +nfstype nfsv3_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK, + NFFIFO, NFNON }; +int nfsrvw_procrastinate = NFS_GATHERDELAY * 1000; /* - * nqnfs access service + * nfs v3 access service */ -nqnfsrv_access(nfsd, mrep, md, dpos, cred, nam, mrq) - struct nfsd *nfsd; - struct mbuf *mrep, *md; - caddr_t dpos; - struct ucred *cred; - struct mbuf *nam, **mrq; +int +nfsrv3_access(nfsd, slp, procp, mrq) + struct nfsrv_descript *nfsd; + struct nfssvc_sock *slp; + struct proc *procp; + struct mbuf **mrq; { + struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; + struct mbuf *nam = nfsd->nd_nam; + caddr_t dpos = nfsd->nd_dpos; + struct ucred *cred = &nfsd->nd_cr; struct vnode *vp; - nfsv2fh_t nfh; + nfsfh_t nfh; fhandle_t *fhp; register u_long *tl; register long t1; caddr_t bpos; - int error = 0, rdonly, cache, mode = 0; + int error = 0, rdonly, cache, getret; char *cp2; - struct mbuf *mb, *mreq; + struct mbuf *mb, *mreq, *mb2; + struct vattr vattr, *vap = &vattr; + u_long testmode, nfsmode; u_quad_t frev; +#ifndef nolint + cache = 0; +#endif fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); - nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED); - if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) - nfsm_reply(0); - if (*tl++ == nfs_true) - mode |= VREAD; - if (*tl++ == nfs_true) - mode |= VWRITE; - if (*tl == nfs_true) - mode |= VEXEC; - error = nfsrv_access(vp, mode, cred, rdonly, nfsd->nd_procp); + nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); + if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, + &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { + nfsm_reply(NFSX_UNSIGNED); + nfsm_srvpostop_attr(1, (struct vattr *)0); + return (0); + } + nfsmode = fxdr_unsigned(u_long, *tl); + if ((nfsmode & NFSV3ACCESS_READ) && + nfsrv_access(vp, VREAD, cred, rdonly, procp)) + nfsmode &= ~NFSV3ACCESS_READ; + if (vp->v_type == VDIR) + testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND | + NFSV3ACCESS_DELETE); + else + testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND); + if ((nfsmode & testmode) && + nfsrv_access(vp, VWRITE, cred, rdonly, procp)) + nfsmode &= ~testmode; + if (vp->v_type == VDIR) + testmode = NFSV3ACCESS_LOOKUP; + else + testmode = NFSV3ACCESS_EXECUTE; + if ((nfsmode & testmode) && + nfsrv_access(vp, VEXEC, cred, rdonly, procp)) + nfsmode &= ~testmode; + getret = VOP_GETATTR(vp, vap, cred, procp); vput(vp); - nfsm_reply(0); + nfsm_reply(NFSX_POSTOPATTR(1) + NFSX_UNSIGNED); + nfsm_srvpostop_attr(getret, vap); + nfsm_build(tl, u_long *, NFSX_UNSIGNED); + *tl = txdr_unsigned(nfsmode); nfsm_srvdone; } /* * nfs getattr service */ -nfsrv_getattr(nfsd, mrep, md, dpos, cred, nam, mrq) - struct nfsd *nfsd; - struct mbuf *mrep, *md; - caddr_t dpos; - struct ucred *cred; - struct mbuf *nam, **mrq; +int +nfsrv_getattr(nfsd, slp, procp, mrq) + struct nfsrv_descript *nfsd; + struct nfssvc_sock *slp; + struct proc *procp; + struct mbuf **mrq; { - register struct nfsv2_fattr *fp; + struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; + struct mbuf *nam = nfsd->nd_nam; + caddr_t dpos = nfsd->nd_dpos; + struct ucred *cred = &nfsd->nd_cr; + register struct nfs_fattr *fp; struct vattr va; register struct vattr *vap = &va; struct vnode *vp; - nfsv2fh_t nfh; + nfsfh_t nfh; fhandle_t *fhp; register u_long *tl; register long t1; @@ -149,81 +188,117 @@ nfsrv_getattr(nfsd, mrep, md, dpos, cred, nam, mrq) fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); - if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) + if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, + &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { nfsm_reply(0); - nqsrv_getl(vp, NQL_READ); - error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); + return (0); + } + nqsrv_getl(vp, ND_READ); + error = VOP_GETATTR(vp, vap, cred, procp); vput(vp); - nfsm_reply(NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); - nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); - nfsm_srvfillattr; + nfsm_reply(NFSX_FATTR(nfsd->nd_flag & ND_NFSV3)); + if (error) + return (0); + nfsm_build(fp, struct nfs_fattr *, NFSX_FATTR(nfsd->nd_flag & ND_NFSV3)); + nfsm_srvfillattr(vap, fp); nfsm_srvdone; } /* * nfs setattr service */ -nfsrv_setattr(nfsd, mrep, md, dpos, cred, nam, mrq) - struct nfsd *nfsd; - struct mbuf *mrep, *md; - caddr_t dpos; - struct ucred *cred; - struct mbuf *nam, **mrq; +int +nfsrv_setattr(nfsd, slp, procp, mrq) + struct nfsrv_descript *nfsd; + struct nfssvc_sock *slp; + struct proc *procp; + struct mbuf **mrq; { - struct vattr va; + struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; + struct mbuf *nam = nfsd->nd_nam; + caddr_t dpos = nfsd->nd_dpos; + struct ucred *cred = &nfsd->nd_cr; + struct vattr va, preat; register struct vattr *vap = &va; register struct nfsv2_sattr *sp; - register struct nfsv2_fattr *fp; + register struct nfs_fattr *fp; struct vnode *vp; - nfsv2fh_t nfh; + nfsfh_t nfh; fhandle_t *fhp; register u_long *tl; register long t1; caddr_t bpos; - int error = 0, rdonly, cache; + int error = 0, rdonly, cache, preat_ret = 1, postat_ret = 1; + int v3 = (nfsd->nd_flag & ND_NFSV3), gcheck = 0; char *cp2; struct mbuf *mb, *mb2, *mreq; - u_quad_t frev, frev2; + u_quad_t frev; + struct timespec guard; fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); - nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR(nfsd->nd_nqlflag != NQL_NOVAL)); - if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) - nfsm_reply(0); - nqsrv_getl(vp, NQL_WRITE); VATTR_NULL(vap); - /* - * Nah nah nah nah na nah - * There is a bug in the Sun client that puts 0xffff in the mode - * field of sattr when it should put in 0xffffffff. The u_short - * doesn't sign extend. - * --> check the low order 2 bytes for 0xffff - */ - if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff) - vap->va_mode = nfstov_mode(sp->sa_mode); - if (sp->sa_uid != nfs_xdrneg1) - vap->va_uid = fxdr_unsigned(uid_t, sp->sa_uid); - if (sp->sa_gid != nfs_xdrneg1) - vap->va_gid = fxdr_unsigned(gid_t, sp->sa_gid); - if (nfsd->nd_nqlflag == NQL_NOVAL) { - if (sp->sa_nfssize != nfs_xdrneg1) - vap->va_size = fxdr_unsigned(u_quad_t, sp->sa_nfssize); - if (sp->sa_nfsatime.nfs_sec != nfs_xdrneg1) { + if (v3) { + nfsm_srvsattr(vap); + nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); + gcheck = fxdr_unsigned(int, *tl); + if (gcheck) { + nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); + fxdr_nfsv3time(tl, &guard); + } + } else { + nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR); + /* + * Nah nah nah nah na nah + * There is a bug in the Sun client that puts 0xffff in the mode + * field of sattr when it should put in 0xffffffff. The u_short + * doesn't sign extend. + * --> check the low order 2 bytes for 0xffff + */ + if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff) + vap->va_mode = nfstov_mode(sp->sa_mode); + if (sp->sa_uid != nfs_xdrneg1) + vap->va_uid = fxdr_unsigned(uid_t, sp->sa_uid); + if (sp->sa_gid != nfs_xdrneg1) + vap->va_gid = fxdr_unsigned(gid_t, sp->sa_gid); + if (sp->sa_size != nfs_xdrneg1) + vap->va_size = fxdr_unsigned(u_quad_t, sp->sa_size); + if (sp->sa_atime.nfsv2_sec != nfs_xdrneg1) { #ifdef notyet - fxdr_nfstime(&sp->sa_nfsatime, &vap->va_atime); + fxdr_nfsv2time(&sp->sa_atime, &vap->va_atime); #else vap->va_atime.ts_sec = - fxdr_unsigned(long, sp->sa_nfsatime.nfs_sec); + fxdr_unsigned(long, sp->sa_atime.nfsv2_sec); vap->va_atime.ts_nsec = 0; #endif } - if (sp->sa_nfsmtime.nfs_sec != nfs_xdrneg1) - fxdr_nfstime(&sp->sa_nfsmtime, &vap->va_mtime); - } else { - fxdr_hyper(&sp->sa_nqsize, &vap->va_size); - fxdr_nqtime(&sp->sa_nqatime, &vap->va_atime); - fxdr_nqtime(&sp->sa_nqmtime, &vap->va_mtime); - vap->va_flags = fxdr_unsigned(u_long, sp->sa_nqflags); + if (sp->sa_mtime.nfsv2_sec != nfs_xdrneg1) + fxdr_nfsv2time(&sp->sa_mtime, &vap->va_mtime); + + } + + /* + * Now that we have all the fields, lets do it. + */ + if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, + &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { + nfsm_reply(2 * NFSX_UNSIGNED); + nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap); + return (0); + } + nqsrv_getl(vp, ND_WRITE); + if (v3) { + error = preat_ret = VOP_GETATTR(vp, &preat, cred, procp); + if (!error && gcheck && + (preat.va_ctime.ts_sec != guard.ts_sec || + preat.va_ctime.ts_nsec != guard.ts_nsec)) + error = NFSERR_NOT_SYNC; + if (error) { + vput(vp); + nfsm_reply(NFSX_WCCDATA(v3)); + nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap); + return (0); + } } /* @@ -240,22 +315,22 @@ nfsrv_setattr(nfsd, mrep, md, dpos, cred, nam, mrq) error = EISDIR; goto out; } else if (error = nfsrv_access(vp, VWRITE, cred, rdonly, - nfsd->nd_procp)) + procp)) goto out; } - if (error = VOP_SETATTR(vp, vap, cred, nfsd->nd_procp)) { - vput(vp); - nfsm_reply(0); - } - error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); + error = VOP_SETATTR(vp, vap, cred, procp); + postat_ret = VOP_GETATTR(vp, vap, cred, procp); + if (!error) + error = postat_ret; out: vput(vp); - nfsm_reply(NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL) + 2*NFSX_UNSIGNED); - nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); - nfsm_srvfillattr; - if (nfsd->nd_nqlflag != NQL_NOVAL) { - nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); - txdr_hyper(&frev2, tl); + nfsm_reply(NFSX_WCCORFATTR(v3)); + if (v3) { + nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap); + return (0); + } else { + nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR); + nfsm_srvfillattr(vap, fp); } nfsm_srvdone; } @@ -263,101 +338,112 @@ out: /* * nfs lookup rpc */ -nfsrv_lookup(nfsd, mrep, md, dpos, cred, nam, mrq) - struct nfsd *nfsd; - struct mbuf *mrep, *md; - caddr_t dpos; - struct ucred *cred; - struct mbuf *nam, **mrq; +int +nfsrv_lookup(nfsd, slp, procp, mrq) + struct nfsrv_descript *nfsd; + struct nfssvc_sock *slp; + struct proc *procp; + struct mbuf **mrq; { - register struct nfsv2_fattr *fp; + struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; + struct mbuf *nam = nfsd->nd_nam; + caddr_t dpos = nfsd->nd_dpos; + struct ucred *cred = &nfsd->nd_cr; + register struct nfs_fattr *fp; struct nameidata nd; - struct vnode *vp; - nfsv2fh_t nfh; + struct vnode *vp, *dirp; + nfsfh_t nfh; fhandle_t *fhp; register caddr_t cp; register u_long *tl; register long t1; caddr_t bpos; - int error = 0, cache, duration2, cache2, len; + int error = 0, cache, len, dirattr_ret = 1; + int v3 = (nfsd->nd_flag & ND_NFSV3); char *cp2; struct mbuf *mb, *mb2, *mreq; - struct vattr va, *vap = &va; - u_quad_t frev, frev2; + struct vattr va, dirattr, *vap = &va; + u_quad_t frev; fhp = &nfh.fh_generic; - duration2 = 0; - if (nfsd->nd_nqlflag != NQL_NOVAL) { - nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); - duration2 = fxdr_unsigned(int, *tl); - } nfsm_srvmtofh(fhp); - nfsm_srvstrsiz(len, NFS_MAXNAMLEN); + nfsm_srvnamesiz(len); nd.ni_cnd.cn_cred = cred; nd.ni_cnd.cn_nameiop = LOOKUP; nd.ni_cnd.cn_flags = LOCKLEAF | SAVESTART; - if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, - nfsd->nd_procp)) - nfsm_reply(0); - nqsrv_getl(nd.ni_startdir, NQL_READ); + error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, + &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH)); + if (dirp) { + if (v3) + dirattr_ret = VOP_GETATTR(dirp, &dirattr, cred, + procp); + vrele(dirp); + } + if (error) { + nfsm_reply(NFSX_POSTOPATTR(v3)); + nfsm_srvpostop_attr(dirattr_ret, &dirattr); + return (0); + } + nqsrv_getl(nd.ni_startdir, ND_READ); vrele(nd.ni_startdir); FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); vp = nd.ni_vp; bzero((caddr_t)fhp, sizeof(nfh)); fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; - if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { - vput(vp); - nfsm_reply(0); - } - if (duration2) - (void) nqsrv_getlease(vp, &duration2, NQL_READ, nfsd, - nam, &cache2, &frev2, cred); - error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); + error = VFS_VPTOFH(vp, &fhp->fh_fid); + if (!error) + error = VOP_GETATTR(vp, vap, cred, procp); vput(vp); - nfsm_reply(NFSX_FH + NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL) + 5*NFSX_UNSIGNED); - if (nfsd->nd_nqlflag != NQL_NOVAL) { - if (duration2) { - nfsm_build(tl, u_long *, 5*NFSX_UNSIGNED); - *tl++ = txdr_unsigned(NQL_READ); - *tl++ = txdr_unsigned(cache2); - *tl++ = txdr_unsigned(duration2); - txdr_hyper(&frev2, tl); - } else { - nfsm_build(tl, u_long *, NFSX_UNSIGNED); - *tl = 0; - } + nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPORFATTR(v3) + NFSX_POSTOPATTR(v3)); + if (error) { + nfsm_srvpostop_attr(dirattr_ret, &dirattr); + return (0); + } + nfsm_srvfhtom(fhp, v3); + if (v3) { + nfsm_srvpostop_attr(0, vap); + nfsm_srvpostop_attr(dirattr_ret, &dirattr); + } else { + nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR); + nfsm_srvfillattr(vap, fp); } - nfsm_srvfhtom(fhp); - nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); - nfsm_srvfillattr; nfsm_srvdone; } /* * nfs readlink service */ -nfsrv_readlink(nfsd, mrep, md, dpos, cred, nam, mrq) - struct nfsd *nfsd; - struct mbuf *mrep, *md; - caddr_t dpos; - struct ucred *cred; - struct mbuf *nam, **mrq; +int +nfsrv_readlink(nfsd, slp, procp, mrq) + struct nfsrv_descript *nfsd; + struct nfssvc_sock *slp; + struct proc *procp; + struct mbuf **mrq; { + struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; + struct mbuf *nam = nfsd->nd_nam; + caddr_t dpos = nfsd->nd_dpos; + struct ucred *cred = &nfsd->nd_cr; struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN]; register struct iovec *ivp = iv; register struct mbuf *mp; register u_long *tl; register long t1; caddr_t bpos; - int error = 0, rdonly, cache, i, tlen, len; + int error = 0, rdonly, cache, i, tlen, len, getret; + int v3 = (nfsd->nd_flag & ND_NFSV3); char *cp2; struct mbuf *mb, *mb2, *mp2, *mp3, *mreq; struct vnode *vp; - nfsv2fh_t nfh; + struct vattr attr; + nfsfh_t nfh; fhandle_t *fhp; struct uio io, *uiop = &io; u_quad_t frev; +#ifndef nolint + mp2 = mp3 = (struct mbuf *)0; +#endif fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); len = 0; @@ -389,21 +475,33 @@ nfsrv_readlink(nfsd, mrep, md, dpos, cred, nam, mrq) uiop->uio_rw = UIO_READ; uiop->uio_segflg = UIO_SYSSPACE; uiop->uio_procp = (struct proc *)0; - if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) { + if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, + &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { m_freem(mp3); - nfsm_reply(0); + nfsm_reply(2 * NFSX_UNSIGNED); + nfsm_srvpostop_attr(1, (struct vattr *)0); + return (0); } if (vp->v_type != VLNK) { - error = EINVAL; + if (v3) + error = EINVAL; + else + error = ENXIO; goto out; } - nqsrv_getl(vp, NQL_READ); + nqsrv_getl(vp, ND_READ); error = VOP_READLINK(vp, uiop, cred); out: + getret = VOP_GETATTR(vp, &attr, cred, procp); vput(vp); if (error) m_freem(mp3); - nfsm_reply(NFSX_UNSIGNED); + nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_UNSIGNED); + if (v3) { + nfsm_srvpostop_attr(getret, &attr); + if (error) + return (0); + } if (uiop->uio_resid > 0) { len -= uiop->uio_resid; tlen = nfsm_rndup(len); @@ -418,26 +516,32 @@ out: /* * nfs read service */ -nfsrv_read(nfsd, mrep, md, dpos, cred, nam, mrq) - struct nfsd *nfsd; - struct mbuf *mrep, *md; - caddr_t dpos; - struct ucred *cred; - struct mbuf *nam, **mrq; +int +nfsrv_read(nfsd, slp, procp, mrq) + struct nfsrv_descript *nfsd; + struct nfssvc_sock *slp; + struct proc *procp; + struct mbuf **mrq; { + struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; + struct mbuf *nam = nfsd->nd_nam; + caddr_t dpos = nfsd->nd_dpos; + struct ucred *cred = &nfsd->nd_cr; register struct iovec *iv; struct iovec *iv2; register struct mbuf *m; - register struct nfsv2_fattr *fp; + register struct nfs_fattr *fp; register u_long *tl; register long t1; + register int i; caddr_t bpos; - int error = 0, rdonly, cache, i, cnt, len, left, siz, tlen; + int error = 0, rdonly, cache, cnt, len, left, siz, tlen, getret; + int v3 = (nfsd->nd_flag & ND_NFSV3), reqlen; char *cp2; struct mbuf *mb, *mb2, *mreq; struct mbuf *m2; struct vnode *vp; - nfsv2fh_t nfh; + nfsfh_t nfh; fhandle_t *fhp; struct uio io, *uiop = &io; struct vattr va, *vap = &va; @@ -446,38 +550,57 @@ nfsrv_read(nfsd, mrep, md, dpos, cred, nam, mrq) fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); - if (nfsd->nd_nqlflag == NQL_NOVAL) { - nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); - off = (off_t)fxdr_unsigned(u_long, *tl); - } else { + if (v3) { nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); fxdr_hyper(tl, &off); + } else { + nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); + off = (off_t)fxdr_unsigned(u_long, *tl); + } + nfsm_srvstrsiz(reqlen, NFS_SRVMAXDATA(nfsd)); + if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, + &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { + nfsm_reply(2 * NFSX_UNSIGNED); + nfsm_srvpostop_attr(1, (struct vattr *)0); + return (0); } - nfsm_srvstrsiz(cnt, NFS_MAXDATA); - if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) - nfsm_reply(0); if (vp->v_type != VREG) { - error = (vp->v_type == VDIR) ? EISDIR : EACCES; - vput(vp); - nfsm_reply(0); + if (v3) + error = EINVAL; + else + error = (vp->v_type == VDIR) ? EISDIR : EACCES; } - nqsrv_getl(vp, NQL_READ); - if ((error = nfsrv_access(vp, VREAD, cred, rdonly, nfsd->nd_procp)) && - (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp))) { - vput(vp); - nfsm_reply(0); + if (!error) { + nqsrv_getl(vp, ND_READ); + if (error = nfsrv_access(vp, VREAD, cred, rdonly, procp)) + error = nfsrv_access(vp, VEXEC, cred, rdonly, procp); } - if (error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp)) { + getret = VOP_GETATTR(vp, vap, cred, procp); + if (!error) + error = getret; + if (error) { vput(vp); - nfsm_reply(0); + nfsm_reply(NFSX_POSTOPATTR(v3)); + nfsm_srvpostop_attr(getret, vap); + return (0); } if (off >= vap->va_size) cnt = 0; - else if ((off + cnt) > vap->va_size) + else if ((off + reqlen) > vap->va_size) cnt = nfsm_rndup(vap->va_size - off); - nfsm_reply(NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)+NFSX_UNSIGNED+nfsm_rndup(cnt)); - nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); - nfsm_build(tl, u_long *, NFSX_UNSIGNED); + else + cnt = reqlen; + nfsm_reply(NFSX_POSTOPORFATTR(v3) + 3 * NFSX_UNSIGNED+nfsm_rndup(cnt)); + if (v3) { + nfsm_build(tl, u_long *, NFSX_V3FATTR + 4 * NFSX_UNSIGNED); + *tl++ = nfs_true; + fp = (struct nfs_fattr *)tl; + tl += (NFSX_V3FATTR / sizeof (u_long)); + } else { + nfsm_build(tl, u_long *, NFSX_V2FATTR + NFSX_UNSIGNED); + fp = (struct nfs_fattr *)tl; + tl += (NFSX_V2FATTR / sizeof (u_long)); + } len = left = cnt; if (cnt > 0) { /* @@ -485,19 +608,11 @@ nfsrv_read(nfsd, mrep, md, dpos, cred, nam, mrq) */ i = 0; m = m2 = mb; - MALLOC(iv, struct iovec *, - ((NFS_MAXDATA+MLEN-1)/MLEN) * sizeof (struct iovec), - M_TEMP, M_WAITOK); - iv2 = iv; while (left > 0) { siz = min(M_TRAILINGSPACE(m), left); if (siz > 0) { - m->m_len += siz; - iv->iov_base = bpos; - iv->iov_len = siz; - iv++; - i++; left -= siz; + i++; } if (left > 0) { MGET(m, M_WAIT, MT_DATA); @@ -505,10 +620,28 @@ nfsrv_read(nfsd, mrep, md, dpos, cred, nam, mrq) m->m_len = 0; m2->m_next = m; m2 = m; - bpos = mtod(m, caddr_t); } } - uiop->uio_iov = iv2; + MALLOC(iv, struct iovec *, i * sizeof (struct iovec), + M_TEMP, M_WAITOK); + uiop->uio_iov = iv2 = iv; + m = mb; + left = cnt; + i = 0; + while (left > 0) { + if (m == NULL) + panic("nfsrv_read iov"); + siz = min(M_TRAILINGSPACE(m), left); + if (siz > 0) { + iv->iov_base = mtod(m, caddr_t) + m->m_len; + iv->iov_len = siz; + m->m_len += siz; + left -= siz; + iv++; + i++; + } + m = m->m_next; + } uiop->uio_iovcnt = i; uiop->uio_offset = off; uiop->uio_resid = cnt; @@ -517,19 +650,30 @@ nfsrv_read(nfsd, mrep, md, dpos, cred, nam, mrq) error = VOP_READ(vp, uiop, IO_NODELOCKED, cred); off = uiop->uio_offset; FREE((caddr_t)iv2, M_TEMP); - if (error || (error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp))) { + if (error || (getret = VOP_GETATTR(vp, vap, cred, procp))) { + if (!error) + error = getret; m_freem(mreq); vput(vp); - nfsm_reply(0); + nfsm_reply(NFSX_POSTOPATTR(v3)); + nfsm_srvpostop_attr(getret, vap); + return (0); } } else uiop->uio_resid = 0; vput(vp); - nfsm_srvfillattr; + nfsm_srvfillattr(vap, fp); len -= uiop->uio_resid; tlen = nfsm_rndup(len); if (cnt != tlen || tlen != len) - nfsm_adj(mb, cnt-tlen, tlen-len); + nfsm_adj(mb, cnt - tlen, tlen - len); + if (v3) { + *tl++ = txdr_unsigned(len); + if (len < reqlen) + *tl++ = nfs_true; + else + *tl++ = nfs_false; + } *tl = txdr_unsigned(len); nfsm_srvdone; } @@ -537,144 +681,600 @@ nfsrv_read(nfsd, mrep, md, dpos, cred, nam, mrq) /* * nfs write service */ -nfsrv_write(nfsd, mrep, md, dpos, cred, nam, mrq) - struct nfsd *nfsd; - struct mbuf *mrep, *md; - caddr_t dpos; - struct ucred *cred; - struct mbuf *nam, **mrq; +int +nfsrv_write(nfsd, slp, procp, mrq) + struct nfsrv_descript *nfsd; + struct nfssvc_sock *slp; + struct proc *procp; + struct mbuf **mrq; { + struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; + struct mbuf *nam = nfsd->nd_nam; + caddr_t dpos = nfsd->nd_dpos; + struct ucred *cred = &nfsd->nd_cr; register struct iovec *ivp; + register int i, cnt; register struct mbuf *mp; - register struct nfsv2_fattr *fp; - struct iovec iv[NFS_MAXIOVEC]; - struct vattr va; + register struct nfs_fattr *fp; + struct iovec *iv; + struct vattr va, forat; register struct vattr *vap = &va; register u_long *tl; register long t1; caddr_t bpos; - int error = 0, rdonly, cache, siz, len, xfer; - int ioflags = IO_SYNC | IO_NODELOCKED; + int error = 0, rdonly, cache, siz, len, xfer, forat_ret = 1; + int ioflags, aftat_ret = 1, retlen, zeroing, adjust; + int stable = NFSV3WRITE_FILESYNC; + int v3 = (nfsd->nd_flag & ND_NFSV3); char *cp2; struct mbuf *mb, *mb2, *mreq; struct vnode *vp; - nfsv2fh_t nfh; + nfsfh_t nfh; fhandle_t *fhp; struct uio io, *uiop = &io; off_t off; u_quad_t frev; + if (mrep == NULL) { + *mrq = NULL; + return (0); + } fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); - nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED); - if (nfsd->nd_nqlflag == NQL_NOVAL) { - off = (off_t)fxdr_unsigned(u_long, *++tl); - tl += 2; - } else { + if (v3) { + nfsm_dissect(tl, u_long *, 5 * NFSX_UNSIGNED); fxdr_hyper(tl, &off); + tl += 3; + stable = fxdr_unsigned(int, *tl++); + } else { + nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED); + off = (off_t)fxdr_unsigned(u_long, *++tl); tl += 2; - if (fxdr_unsigned(u_long, *tl++)) - ioflags |= IO_APPEND; - } - len = fxdr_unsigned(long, *tl); - if (len > NFS_MAXDATA || len <= 0) { - error = EBADRPC; - nfsm_reply(0); } - if (dpos == (mtod(md, caddr_t)+md->m_len)) { - mp = md->m_next; - if (mp == NULL) { - error = EBADRPC; - nfsm_reply(0); + retlen = len = fxdr_unsigned(long, *tl); + cnt = i = 0; + + /* + * For NFS Version 2, it is not obvious what a write of zero length + * should do, but I might as well be consistent with Version 3, + * which is to return ok so long as there are no permission problems. + */ + if (len > 0) { + zeroing = 1; + mp = mrep; + while (mp) { + if (mp == md) { + zeroing = 0; + adjust = dpos - mtod(mp, caddr_t); + mp->m_len -= adjust; + if (mp->m_len > 0 && adjust > 0) + NFSMADV(mp, adjust); } - } else { - mp = md; - siz = dpos-mtod(mp, caddr_t); - mp->m_len -= siz; - NFSMADV(mp, siz); + if (zeroing) + mp->m_len = 0; + else if (mp->m_len > 0) { + i += mp->m_len; + if (i > len) { + mp->m_len -= (i - len); + zeroing = 1; + } + if (mp->m_len > 0) + cnt++; + } + mp = mp->m_next; + } } - if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) - nfsm_reply(0); + if (len > NFS_MAXDATA || len < 0 || i < len) { + error = EIO; + nfsm_reply(2 * NFSX_UNSIGNED); + nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap); + return (0); + } + if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, + &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { + nfsm_reply(2 * NFSX_UNSIGNED); + nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap); + return (0); + } + if (v3) + forat_ret = VOP_GETATTR(vp, &forat, cred, procp); if (vp->v_type != VREG) { - error = (vp->v_type == VDIR) ? EISDIR : EACCES; - vput(vp); - nfsm_reply(0); + if (v3) + error = EINVAL; + else + error = (vp->v_type == VDIR) ? EISDIR : EACCES; + } + if (!error) { + nqsrv_getl(vp, ND_WRITE); + error = nfsrv_access(vp, VWRITE, cred, rdonly, procp); } - nqsrv_getl(vp, NQL_WRITE); - if (error = nfsrv_access(vp, VWRITE, cred, rdonly, nfsd->nd_procp)) { + if (error) { vput(vp); - nfsm_reply(0); + nfsm_reply(NFSX_WCCDATA(v3)); + nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap); + return (0); } - uiop->uio_resid = 0; - uiop->uio_rw = UIO_WRITE; - uiop->uio_segflg = UIO_SYSSPACE; - uiop->uio_procp = (struct proc *)0; + + if (len > 0) { + MALLOC(ivp, struct iovec *, cnt * sizeof (struct iovec), M_TEMP, + M_WAITOK); + uiop->uio_iov = iv = ivp; + uiop->uio_iovcnt = cnt; + mp = mrep; + while (mp) { + if (mp->m_len > 0) { + ivp->iov_base = mtod(mp, caddr_t); + ivp->iov_len = mp->m_len; + ivp++; + } + mp = mp->m_next; + } + + /* + * XXX + * The IO_METASYNC flag indicates that all metadata (and not just + * enough to ensure data integrity) mus be written to stable storage + * synchronously. + * (IO_METASYNC is not yet implemented in 4.4BSD-Lite.) + */ + if (stable == NFSV3WRITE_UNSTABLE) + ioflags = IO_NODELOCKED; + else if (stable == NFSV3WRITE_DATASYNC) + ioflags = (IO_SYNC | IO_NODELOCKED); + else + ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED); + uiop->uio_resid = len; + uiop->uio_rw = UIO_WRITE; + uiop->uio_segflg = UIO_SYSSPACE; + uiop->uio_procp = (struct proc *)0; + uiop->uio_offset = off; + error = VOP_WRITE(vp, uiop, ioflags, cred); + nfsstats.srvvop_writes++; + FREE((caddr_t)iv, M_TEMP); + } + aftat_ret = VOP_GETATTR(vp, vap, cred, procp); + vput(vp); + if (!error) + error = aftat_ret; + nfsm_reply(NFSX_PREOPATTR(v3) + NFSX_POSTOPORFATTR(v3) + + 2 * NFSX_UNSIGNED + NFSX_WRITEVERF(v3)); + if (v3) { + nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap); + if (error) + return (0); + nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED); + *tl++ = txdr_unsigned(retlen); + if (stable == NFSV3WRITE_UNSTABLE) + *tl++ = txdr_unsigned(stable); + else + *tl++ = txdr_unsigned(NFSV3WRITE_FILESYNC); + /* + * Actually, there is no need to txdr these fields, + * but it may make the values more human readable, + * for debugging purposes. + */ + *tl++ = txdr_unsigned(boottime.tv_sec); + *tl = txdr_unsigned(boottime.tv_usec); + } else { + nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR); + nfsm_srvfillattr(vap, fp); + } + nfsm_srvdone; +} + +/* + * NFS write service with write gathering support. Called when + * nfsrvw_procrastinate > 0. + * See: Chet Juszczak, "Improving the Write Performance of an NFS Server", + * in Proc. of the Winter 1994 Usenix Conference, pg. 247-259, San Franscisco, + * Jan. 1994. + */ +int +nfsrv_writegather(ndp, slp, procp, mrq) + struct nfsrv_descript **ndp; + struct nfssvc_sock *slp; + struct proc *procp; + struct mbuf **mrq; +{ + register struct iovec *ivp; + register struct mbuf *mp; + register struct nfsrv_descript *wp, *nfsd, *owp, *swp; + register struct nfs_fattr *fp; + register int i; + struct iovec *iov; + struct nfsrvw_delayhash *wpp; + struct ucred *cred; + struct vattr va, forat; + register u_long *tl; + register long t1; + caddr_t bpos, dpos; + int error = 0, rdonly, cache, len, forat_ret = 1; + int ioflags, aftat_ret = 1, s, adjust, v3, zeroing; + char *cp2; + struct mbuf *mb, *mb2, *mreq, *mrep, *md; + struct vnode *vp; + struct uio io, *uiop = &io; + off_t off; + u_quad_t frev, cur_usec; + +#ifndef nolint + i = 0; + len = 0; +#endif + *mrq = NULL; + if (*ndp) { + nfsd = *ndp; + *ndp = NULL; + mrep = nfsd->nd_mrep; + md = nfsd->nd_md; + dpos = nfsd->nd_dpos; + cred = &nfsd->nd_cr; + v3 = (nfsd->nd_flag & ND_NFSV3); + LIST_INIT(&nfsd->nd_coalesce); + nfsd->nd_mreq = NULL; + nfsd->nd_stable = NFSV3WRITE_FILESYNC; + cur_usec = (u_quad_t)time.tv_sec * 1000000 + (u_quad_t)time.tv_usec; + nfsd->nd_time = cur_usec + nfsrvw_procrastinate; + + /* + * Now, get the write header.. + */ + nfsm_srvmtofh(&nfsd->nd_fh); + if (v3) { + nfsm_dissect(tl, u_long *, 5 * NFSX_UNSIGNED); + fxdr_hyper(tl, &nfsd->nd_off); + tl += 3; + nfsd->nd_stable = fxdr_unsigned(int, *tl++); + } else { + nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED); + nfsd->nd_off = (off_t)fxdr_unsigned(u_long, *++tl); + tl += 2; + } + len = fxdr_unsigned(long, *tl); + nfsd->nd_len = len; + nfsd->nd_eoff = nfsd->nd_off + len; + + /* + * Trim the header out of the mbuf list and trim off any trailing + * junk so that the mbuf list has only the write data. + */ + zeroing = 1; + i = 0; + mp = mrep; + while (mp) { + if (mp == md) { + zeroing = 0; + adjust = dpos - mtod(mp, caddr_t); + mp->m_len -= adjust; + if (mp->m_len > 0 && adjust > 0) + NFSMADV(mp, adjust); + } + if (zeroing) + mp->m_len = 0; + else { + i += mp->m_len; + if (i > len) { + mp->m_len -= (i - len); + zeroing = 1; + } + } + mp = mp->m_next; + } + if (len > NFS_MAXDATA || len < 0 || i < len) { +nfsmout: + m_freem(mrep); + error = EIO; + nfsm_writereply(2 * NFSX_UNSIGNED, v3); + if (v3) + nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va); + nfsd->nd_mreq = mreq; + nfsd->nd_mrep = NULL; + nfsd->nd_time = 0; + } + + /* + * Add this entry to the hash and time queues. + */ + s = splsoftclock(); + owp = NULL; + wp = slp->ns_tq.lh_first; + while (wp && wp->nd_time < nfsd->nd_time) { + owp = wp; + wp = wp->nd_tq.le_next; + } + if (owp) { + LIST_INSERT_AFTER(owp, nfsd, nd_tq); + } else { + LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq); + } + if (nfsd->nd_mrep) { + wpp = NWDELAYHASH(slp, nfsd->nd_fh.fh_fid.fid_data); + owp = NULL; + wp = wpp->lh_first; + while (wp && + bcmp((caddr_t)&nfsd->nd_fh,(caddr_t)&wp->nd_fh,NFSX_V3FH)) { + owp = wp; + wp = wp->nd_hash.le_next; + } + while (wp && wp->nd_off < nfsd->nd_off && + !bcmp((caddr_t)&nfsd->nd_fh,(caddr_t)&wp->nd_fh,NFSX_V3FH)) { + owp = wp; + wp = wp->nd_hash.le_next; + } + if (owp) { + LIST_INSERT_AFTER(owp, nfsd, nd_hash); + + /* + * Search the hash list for overlapping entries and + * coalesce. + */ + for(; nfsd && NFSW_CONTIG(owp, nfsd); nfsd = wp) { + wp = nfsd->nd_hash.le_next; + if (NFSW_SAMECRED(owp, nfsd)) + nfsrvw_coalesce(owp, nfsd); + } + } else { + LIST_INSERT_HEAD(wpp, nfsd, nd_hash); + } + } + splx(s); + } + /* - * Do up to NFS_MAXIOVEC mbufs of write each iteration of the - * loop until done. + * Now, do VOP_WRITE()s for any one(s) that need to be done now + * and generate the associated reply mbuf list(s). */ - while (len > 0 && uiop->uio_resid == 0) { - ivp = iv; - siz = 0; - uiop->uio_iov = ivp; - uiop->uio_iovcnt = 0; - uiop->uio_offset = off; - while (len > 0 && uiop->uio_iovcnt < NFS_MAXIOVEC && mp != NULL) { - ivp->iov_base = mtod(mp, caddr_t); - if (len < mp->m_len) - ivp->iov_len = xfer = len; - else - ivp->iov_len = xfer = mp->m_len; -#ifdef notdef - /* Not Yet .. */ - if (M_HASCL(mp) && (((u_long)ivp->iov_base) & CLOFSET) == 0) - ivp->iov_op = NULL; /* what should it be ?? */ +loop1: + cur_usec = (u_quad_t)time.tv_sec * 1000000 + (u_quad_t)time.tv_usec; + s = splsoftclock(); + for (nfsd = slp->ns_tq.lh_first; nfsd; nfsd = owp) { + owp = nfsd->nd_tq.le_next; + if (nfsd->nd_time > cur_usec) + break; + if (nfsd->nd_mreq) + continue; + LIST_REMOVE(nfsd, nd_tq); + LIST_REMOVE(nfsd, nd_hash); + splx(s); + mrep = nfsd->nd_mrep; + nfsd->nd_mrep = NULL; + cred = &nfsd->nd_cr; + v3 = (nfsd->nd_flag & ND_NFSV3); + forat_ret = aftat_ret = 1; + error = nfsrv_fhtovp(&nfsd->nd_fh, 1, &vp, cred, slp, + nfsd->nd_nam, &rdonly, (nfsd->nd_flag & ND_KERBAUTH)); + if (!error) { + if (v3) + forat_ret = VOP_GETATTR(vp, &forat, cred, procp); + if (vp->v_type != VREG) { + if (v3) + error = EINVAL; else - ivp->iov_op = NULL; -#endif - uiop->uio_iovcnt++; - ivp++; - len -= xfer; - siz += xfer; - mp = mp->m_next; + error = (vp->v_type == VDIR) ? EISDIR : EACCES; + } + } else + vp = NULL; + if (!error) { + nqsrv_getl(vp, ND_WRITE); + error = nfsrv_access(vp, VWRITE, cred, rdonly, procp); } - if (len > 0 && mp == NULL) { - error = EBADRPC; - vput(vp); - nfsm_reply(0); + + if (nfsd->nd_stable == NFSV3WRITE_UNSTABLE) + ioflags = IO_NODELOCKED; + else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC) + ioflags = (IO_SYNC | IO_NODELOCKED); + else + ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED); + uiop->uio_rw = UIO_WRITE; + uiop->uio_segflg = UIO_SYSSPACE; + uiop->uio_procp = (struct proc *)0; + uiop->uio_offset = nfsd->nd_off; + uiop->uio_resid = nfsd->nd_eoff - nfsd->nd_off; + if (uiop->uio_resid > 0) { + mp = mrep; + i = 0; + while (mp) { + if (mp->m_len > 0) + i++; + mp = mp->m_next; + } + uiop->uio_iovcnt = i; + MALLOC(iov, struct iovec *, i * sizeof (struct iovec), + M_TEMP, M_WAITOK); + uiop->uio_iov = ivp = iov; + mp = mrep; + while (mp) { + if (mp->m_len > 0) { + ivp->iov_base = mtod(mp, caddr_t); + ivp->iov_len = mp->m_len; + ivp++; + } + mp = mp->m_next; + } + if (!error) { + error = VOP_WRITE(vp, uiop, ioflags, cred); + nfsstats.srvvop_writes++; + } + FREE((caddr_t)iov, M_TEMP); } - uiop->uio_resid = siz; - if (error = VOP_WRITE(vp, uiop, ioflags, cred)) { - vput(vp); - nfsm_reply(0); + m_freem(mrep); + if (vp) { + aftat_ret = VOP_GETATTR(vp, &va, cred, procp); + vput(vp); } - off = uiop->uio_offset; + + /* + * Loop around generating replies for all write rpcs that have + * now been completed. + */ + swp = nfsd; + do { + if (error) { + nfsm_writereply(NFSX_WCCDATA(v3), v3); + if (v3) { + nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va); + } + } else { + nfsm_writereply(NFSX_PREOPATTR(v3) + + NFSX_POSTOPORFATTR(v3) + 2 * NFSX_UNSIGNED + + NFSX_WRITEVERF(v3), v3); + if (v3) { + nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va); + nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED); + *tl++ = txdr_unsigned(nfsd->nd_len); + *tl++ = txdr_unsigned(swp->nd_stable); + /* + * Actually, there is no need to txdr these fields, + * but it may make the values more human readable, + * for debugging purposes. + */ + *tl++ = txdr_unsigned(boottime.tv_sec); + *tl = txdr_unsigned(boottime.tv_usec); + } else { + nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR); + nfsm_srvfillattr(&va, fp); + } + } + nfsd->nd_mreq = mreq; + if (nfsd->nd_mrep) + panic("nfsrv_write: nd_mrep not free"); + + /* + * Done. Put it at the head of the timer queue so that + * the final phase can return the reply. + */ + s = splsoftclock(); + if (nfsd != swp) { + nfsd->nd_time = 0; + LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq); + } + nfsd = swp->nd_coalesce.lh_first; + if (nfsd) { + LIST_REMOVE(nfsd, nd_tq); + } + splx(s); + } while (nfsd); + s = splsoftclock(); + swp->nd_time = 0; + LIST_INSERT_HEAD(&slp->ns_tq, swp, nd_tq); + splx(s); + goto loop1; } - error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); - vput(vp); - nfsm_reply(NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); - nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); - nfsm_srvfillattr; - if (nfsd->nd_nqlflag != NQL_NOVAL) { - nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); - txdr_hyper(&vap->va_filerev, tl); + splx(s); + + /* + * Search for a reply to return. + */ + s = splsoftclock(); + for (nfsd = slp->ns_tq.lh_first; nfsd; nfsd = nfsd->nd_tq.le_next) + if (nfsd->nd_mreq) { + LIST_REMOVE(nfsd, nd_tq); + *mrq = nfsd->nd_mreq; + *ndp = nfsd; + break; + } + splx(s); + return (0); +} + +/* + * Coalesce the write request nfsd into owp. To do this we must: + * - remove nfsd from the queues + * - merge nfsd->nd_mrep into owp->nd_mrep + * - update the nd_eoff and nd_stable for owp + * - put nfsd on owp's nd_coalesce list + * NB: Must be called at splsoftclock(). + */ +void +nfsrvw_coalesce(owp, nfsd) + register struct nfsrv_descript *owp; + register struct nfsrv_descript *nfsd; +{ + register int overlap; + register struct mbuf *mp; + + LIST_REMOVE(nfsd, nd_hash); + LIST_REMOVE(nfsd, nd_tq); + if (owp->nd_eoff < nfsd->nd_eoff) { + overlap = owp->nd_eoff - nfsd->nd_off; + if (overlap < 0) + panic("nfsrv_coalesce: bad off"); + if (overlap > 0) + m_adj(nfsd->nd_mrep, overlap); + mp = owp->nd_mrep; + while (mp->m_next) + mp = mp->m_next; + mp->m_next = nfsd->nd_mrep; + owp->nd_eoff = nfsd->nd_eoff; + } else + m_freem(nfsd->nd_mrep); + nfsd->nd_mrep = NULL; + if (nfsd->nd_stable == NFSV3WRITE_FILESYNC) + owp->nd_stable = NFSV3WRITE_FILESYNC; + else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC && + owp->nd_stable == NFSV3WRITE_UNSTABLE) + owp->nd_stable = NFSV3WRITE_DATASYNC; + LIST_INSERT_HEAD(&owp->nd_coalesce, nfsd, nd_tq); +} + +/* + * Sort the group list in increasing numerical order. + * (Insertion sort by Chris Torek, who was grossed out by the bubble sort + * that used to be here.) + */ +void +nfsrvw_sort(list, num) + register gid_t *list; + register int num; +{ + register int i, j; + gid_t v; + + /* Insertion sort. */ + for (i = 1; i < num; i++) { + v = list[i]; + /* find correct slot for value v, moving others up */ + for (j = i; --j >= 0 && v < list[j];) + list[j + 1] = list[j]; + list[j + 1] = v; } - nfsm_srvdone; +} + +/* + * copy credentials making sure that the result can be compared with bcmp(). + */ +void +nfsrv_setcred(incred, outcred) + register struct ucred *incred, *outcred; +{ + register int i; + + bzero((caddr_t)outcred, sizeof (struct ucred)); + outcred->cr_ref = 1; + outcred->cr_uid = incred->cr_uid; + outcred->cr_ngroups = incred->cr_ngroups; + for (i = 0; i < incred->cr_ngroups; i++) + outcred->cr_groups[i] = incred->cr_groups[i]; + nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups); } /* * nfs create service * now does a truncate to 0 length via. setattr if it already exists */ -nfsrv_create(nfsd, mrep, md, dpos, cred, nam, mrq) - struct nfsd *nfsd; - struct mbuf *mrep, *md; - caddr_t dpos; - struct ucred *cred; - struct mbuf *nam, **mrq; +int +nfsrv_create(nfsd, slp, procp, mrq) + struct nfsrv_descript *nfsd; + struct nfssvc_sock *slp; + struct proc *procp; + struct mbuf **mrq; { - register struct nfsv2_fattr *fp; - struct vattr va; + struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; + struct mbuf *nam = nfsd->nd_nam; + caddr_t dpos = nfsd->nd_dpos; + struct ucred *cred = &nfsd->nd_cr; + register struct nfs_fattr *fp; + struct vattr va, dirfor, diraft; register struct vattr *vap = &va; register struct nfsv2_sattr *sp; register u_long *tl; @@ -682,72 +1282,129 @@ nfsrv_create(nfsd, mrep, md, dpos, cred, nam, mrq) register caddr_t cp; register long t1; caddr_t bpos; - int error = 0, rdev, cache, len, tsize; + int error = 0, rdev, cache, len, tsize, dirfor_ret = 1, diraft_ret = 1; + int v3 = (nfsd->nd_flag & ND_NFSV3), how, exclusive_flag = 0; char *cp2; struct mbuf *mb, *mb2, *mreq; - struct vnode *vp; - nfsv2fh_t nfh; + struct vnode *vp, *dirp = (struct vnode *)0; + nfsfh_t nfh; fhandle_t *fhp; - u_quad_t frev; + u_quad_t frev, tempsize; + u_char cverf[NFSX_V3CREATEVERF]; +#ifndef nolint + rdev = 0; +#endif nd.ni_cnd.cn_nameiop = 0; fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); - nfsm_srvstrsiz(len, NFS_MAXNAMLEN); + nfsm_srvnamesiz(len); nd.ni_cnd.cn_cred = cred; nd.ni_cnd.cn_nameiop = CREATE; nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART; - if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, - nfsd->nd_procp)) - nfsm_reply(0); + error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, + &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH)); + if (dirp) { + if (v3) + dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, + procp); + else { + vrele(dirp); + dirp = (struct vnode *)0; + } + } + if (error) { + nfsm_reply(NFSX_WCCDATA(v3)); + nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); + if (dirp) + vrele(dirp); + return (0); + } VATTR_NULL(vap); - nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR(nfsd->nd_nqlflag != NQL_NOVAL)); + if (v3) { + nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); + how = fxdr_unsigned(int, *tl); + switch (how) { + case NFSV3CREATE_GUARDED: + if (nd.ni_vp) { + error = EEXIST; + break; + } + case NFSV3CREATE_UNCHECKED: + nfsm_srvsattr(vap); + break; + case NFSV3CREATE_EXCLUSIVE: + nfsm_dissect(cp, caddr_t, NFSX_V3CREATEVERF); + bcopy(cp, cverf, NFSX_V3CREATEVERF); + exclusive_flag = 1; + if (nd.ni_vp == NULL) + vap->va_mode = 0; + break; + }; + vap->va_type = VREG; + } else { + nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR); + vap->va_type = IFTOVT(fxdr_unsigned(u_long, sp->sa_mode)); + if (vap->va_type == VNON) + vap->va_type = VREG; + vap->va_mode = nfstov_mode(sp->sa_mode); + switch (vap->va_type) { + case VREG: + tsize = fxdr_unsigned(long, sp->sa_size); + if (tsize != -1) + vap->va_size = (u_quad_t)tsize; + break; + case VCHR: + case VBLK: + case VFIFO: + rdev = fxdr_unsigned(long, sp->sa_size); + break; + }; + } + /* * Iff doesn't exist, create it * otherwise just truncate to 0 length * should I set the mode too ?? */ if (nd.ni_vp == NULL) { - vap->va_type = IFTOVT(fxdr_unsigned(u_long, sp->sa_mode)); - if (vap->va_type == VNON) - vap->va_type = VREG; - vap->va_mode = nfstov_mode(sp->sa_mode); - if (nfsd->nd_nqlflag == NQL_NOVAL) - rdev = fxdr_unsigned(long, sp->sa_nfssize); - else - rdev = fxdr_unsigned(long, sp->sa_nqrdev); if (vap->va_type == VREG || vap->va_type == VSOCK) { vrele(nd.ni_startdir); - nqsrv_getl(nd.ni_dvp, NQL_WRITE); - if (error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) - nfsm_reply(0); - FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); + nqsrv_getl(nd.ni_dvp, ND_WRITE); + error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap); + if (!error) { + FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); + if (exclusive_flag) { + exclusive_flag = 0; + VATTR_NULL(vap); + bcopy(cverf, (caddr_t)&vap->va_atime, + NFSX_V3CREATEVERF); + error = VOP_SETATTR(nd.ni_vp, vap, cred, + procp); + } + } } else if (vap->va_type == VCHR || vap->va_type == VBLK || vap->va_type == VFIFO) { if (vap->va_type == VCHR && rdev == 0xffffffff) vap->va_type = VFIFO; - if (vap->va_type == VFIFO) { -#ifndef FIFO - VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); - vput(nd.ni_dvp); - error = ENXIO; - goto out; -#endif /* FIFO */ - } else if (error = suser(cred, (u_short *)0)) { + if (error = suser(cred, (u_short *)0)) { + vrele(nd.ni_startdir); + free(nd.ni_cnd.cn_pnbuf, M_NAMEI); VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); vput(nd.ni_dvp); - goto out; + nfsm_reply(0); + return (error); } else vap->va_rdev = (dev_t)rdev; - nqsrv_getl(nd.ni_dvp, NQL_WRITE); + nqsrv_getl(nd.ni_dvp, ND_WRITE); if (error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) { vrele(nd.ni_startdir); nfsm_reply(0); } nd.ni_cnd.cn_nameiop = LOOKUP; nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART); - nd.ni_cnd.cn_proc = nfsd->nd_procp; - nd.ni_cnd.cn_cred = nfsd->nd_procp->p_ucred; + nd.ni_cnd.cn_proc = procp; + nd.ni_cnd.cn_cred = cred; if (error = lookup(&nd)) { free(nd.ni_cnd.cn_pnbuf, M_NAMEI); nfsm_reply(0); @@ -761,10 +1418,11 @@ nfsrv_create(nfsd, mrep, md, dpos, cred, nam, mrq) nfsm_reply(0); } } else { + vrele(nd.ni_startdir); + free(nd.ni_cnd.cn_pnbuf, M_NAMEI); VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); vput(nd.ni_dvp); error = ENXIO; - goto out; } vp = nd.ni_vp; } else { @@ -776,43 +1434,56 @@ nfsrv_create(nfsd, mrep, md, dpos, cred, nam, mrq) else vput(nd.ni_dvp); VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); - if (nfsd->nd_nqlflag == NQL_NOVAL) { - tsize = fxdr_unsigned(long, sp->sa_nfssize); - if (tsize != -1) - vap->va_size = (u_quad_t)tsize; - else - vap->va_size = -1; - } else - fxdr_hyper(&sp->sa_nqsize, &vap->va_size); if (vap->va_size != -1) { - if (error = nfsrv_access(vp, VWRITE, cred, - (nd.ni_cnd.cn_flags & RDONLY), nfsd->nd_procp)) { - vput(vp); - nfsm_reply(0); + error = nfsrv_access(vp, VWRITE, cred, + (nd.ni_cnd.cn_flags & RDONLY), procp); + if (!error) { + nqsrv_getl(vp, ND_WRITE); + tempsize = vap->va_size; + VATTR_NULL(vap); + vap->va_size = tempsize; + error = VOP_SETATTR(vp, vap, cred, + procp); } - nqsrv_getl(vp, NQL_WRITE); - if (error = VOP_SETATTR(vp, vap, cred, nfsd->nd_procp)) { + if (error) vput(vp); - nfsm_reply(0); - } } } - bzero((caddr_t)fhp, sizeof(nfh)); - fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; - if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { + if (!error) { + bzero((caddr_t)fhp, sizeof(nfh)); + fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; + error = VFS_VPTOFH(vp, &fhp->fh_fid); + if (!error) + error = VOP_GETATTR(vp, vap, cred, procp); vput(vp); - nfsm_reply(0); } - error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); - vput(vp); - nfsm_reply(NFSX_FH+NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); - nfsm_srvfhtom(fhp); - nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); - nfsm_srvfillattr; - return (error); + if (v3) { + if (exclusive_flag && !error && + bcmp(cverf, (caddr_t)&vap->va_atime, NFSX_V3CREATEVERF)) + error = EEXIST; + diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); + vrele(dirp); + } + nfsm_reply(NFSX_SRVFH(v3) + NFSX_FATTR(v3) + NFSX_WCCDATA(v3)); + if (v3) { + if (!error) { + nfsm_srvpostop_fh(fhp); + nfsm_srvpostop_attr(0, vap); + } + nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); + } else { + nfsm_srvfhtom(fhp, v3); + nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR); + nfsm_srvfillattr(vap, fp); + } + return (0); nfsmout: - if (nd.ni_cnd.cn_nameiop || nd.ni_cnd.cn_flags) + if (dirp) + vrele(dirp); + if (nd.ni_cnd.cn_nameiop) { vrele(nd.ni_startdir); + free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI); + } VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); if (nd.ni_dvp == nd.ni_vp) vrele(nd.ni_dvp); @@ -821,103 +1492,285 @@ nfsmout: if (nd.ni_vp) vput(nd.ni_vp); return (error); - -out: - vrele(nd.ni_startdir); - free(nd.ni_cnd.cn_pnbuf, M_NAMEI); - nfsm_reply(0); } /* - * nfs remove service + * nfs v3 mknod service */ -nfsrv_remove(nfsd, mrep, md, dpos, cred, nam, mrq) - struct nfsd *nfsd; - struct mbuf *mrep, *md; - caddr_t dpos; - struct ucred *cred; - struct mbuf *nam, **mrq; +int +nfsrv_mknod(nfsd, slp, procp, mrq) + struct nfsrv_descript *nfsd; + struct nfssvc_sock *slp; + struct proc *procp; + struct mbuf **mrq; { - struct nameidata nd; + struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; + struct mbuf *nam = nfsd->nd_nam; + caddr_t dpos = nfsd->nd_dpos; + struct ucred *cred = &nfsd->nd_cr; + register struct nfs_fattr *fp; + struct vattr va, dirfor, diraft; + register struct vattr *vap = &va; register u_long *tl; + struct nameidata nd; + register caddr_t cp; register long t1; caddr_t bpos; - int error = 0, cache, len; + int error = 0, cache, len, tsize, dirfor_ret = 1, diraft_ret = 1; + u_long major, minor; + enum vtype vtyp; char *cp2; - struct mbuf *mb, *mreq; - struct vnode *vp; - nfsv2fh_t nfh; + struct mbuf *mb, *mb2, *mreq; + struct vnode *vp, *dirp = (struct vnode *)0; + nfsfh_t nfh; fhandle_t *fhp; u_quad_t frev; + nd.ni_cnd.cn_nameiop = 0; fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); - nfsm_srvstrsiz(len, NFS_MAXNAMLEN); + nfsm_srvnamesiz(len); nd.ni_cnd.cn_cred = cred; - nd.ni_cnd.cn_nameiop = DELETE; - nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; - if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, - nfsd->nd_procp)) - nfsm_reply(0); - vp = nd.ni_vp; - if (vp->v_type == VDIR && - (error = suser(cred, (u_short *)0))) + nd.ni_cnd.cn_nameiop = CREATE; + nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART; + error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, + &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH)); + if (dirp) + dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, procp); + if (error) { + nfsm_reply(NFSX_WCCDATA(1)); + nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); + if (dirp) + vrele(dirp); + return (0); + } + nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); + vtyp = nfsv3tov_type(*tl); + if (vtyp != VCHR && vtyp != VBLK && vtyp != VSOCK && vtyp != VFIFO) { + vrele(nd.ni_startdir); + free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI); + error = NFSERR_BADTYPE; + VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); + vput(nd.ni_dvp); goto out; + } + VATTR_NULL(vap); + nfsm_srvsattr(vap); + if (vtyp == VCHR || vtyp == VBLK) { + nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); + major = fxdr_unsigned(u_long, *tl++); + minor = fxdr_unsigned(u_long, *tl); + vap->va_rdev = makedev(major, minor); + } + /* - * The root of a mounted filesystem cannot be deleted. + * Iff doesn't exist, create it. */ - if (vp->v_flag & VROOT) { - error = EBUSY; + if (nd.ni_vp) { + vrele(nd.ni_startdir); + free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI); + error = EEXIST; + VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); + vput(nd.ni_dvp); goto out; } - if (vp->v_flag & VTEXT) - (void) vnode_pager_uncache(vp); -out: - if (!error) { - nqsrv_getl(nd.ni_dvp, NQL_WRITE); - nqsrv_getl(vp, NQL_WRITE); - error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); + vap->va_type = vtyp; + if (vtyp == VSOCK) { + vrele(nd.ni_startdir); + nqsrv_getl(nd.ni_dvp, ND_WRITE); + error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap); + if (!error) + FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); } else { - VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); - if (nd.ni_dvp == vp) - vrele(nd.ni_dvp); - else + if (error = suser(cred, (u_short *)0)) { + vrele(nd.ni_startdir); + free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI); + VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); vput(nd.ni_dvp); + goto out; + } + nqsrv_getl(nd.ni_dvp, ND_WRITE); + if (error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) { + vrele(nd.ni_startdir); + goto out; + } + nd.ni_cnd.cn_nameiop = LOOKUP; + nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART); + nd.ni_cnd.cn_proc = procp; + nd.ni_cnd.cn_cred = procp->p_ucred; + error = lookup(&nd); + FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); + if (error) + goto out; + if (nd.ni_cnd.cn_flags & ISSYMLINK) { + vrele(nd.ni_dvp); + vput(nd.ni_vp); + VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); + error = EINVAL; + } + } +out: + vp = nd.ni_vp; + if (!error) { + bzero((caddr_t)fhp, sizeof(nfh)); + fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; + error = VFS_VPTOFH(vp, &fhp->fh_fid); + if (!error) + error = VOP_GETATTR(vp, vap, cred, procp); vput(vp); } - nfsm_reply(0); + diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); + vrele(dirp); + nfsm_reply(NFSX_SRVFH(1) + NFSX_POSTOPATTR(1) + NFSX_WCCDATA(1)); + if (!error) { + nfsm_srvpostop_fh(fhp); + nfsm_srvpostop_attr(0, vap); + } + nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); + return (0); +nfsmout: + if (dirp) + vrele(dirp); + if (nd.ni_cnd.cn_nameiop) { + vrele(nd.ni_startdir); + free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI); + } + VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); + if (nd.ni_dvp == nd.ni_vp) + vrele(nd.ni_dvp); + else + vput(nd.ni_dvp); + if (nd.ni_vp) + vput(nd.ni_vp); + return (error); +} + +/* + * nfs remove service + */ +int +nfsrv_remove(nfsd, slp, procp, mrq) + struct nfsrv_descript *nfsd; + struct nfssvc_sock *slp; + struct proc *procp; + struct mbuf **mrq; +{ + struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; + struct mbuf *nam = nfsd->nd_nam; + caddr_t dpos = nfsd->nd_dpos; + struct ucred *cred = &nfsd->nd_cr; + struct nameidata nd; + register u_long *tl; + register long t1; + caddr_t bpos; + int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1; + int v3 = (nfsd->nd_flag & ND_NFSV3); + char *cp2; + struct mbuf *mb, *mreq, *mb2; + struct vnode *vp, *dirp; + struct vattr dirfor, diraft; + nfsfh_t nfh; + fhandle_t *fhp; + u_quad_t frev; + +#ifndef nolint + vp = (struct vnode *)0; +#endif + fhp = &nfh.fh_generic; + nfsm_srvmtofh(fhp); + nfsm_srvnamesiz(len); + nd.ni_cnd.cn_cred = cred; + nd.ni_cnd.cn_nameiop = DELETE; + nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; + error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, + &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH)); + if (dirp) { + if (v3) + dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, + procp); + else + vrele(dirp); + } + if (!error) { + vp = nd.ni_vp; + if (vp->v_type == VDIR && + (error = suser(cred, (u_short *)0))) + goto out; + /* + * The root of a mounted filesystem cannot be deleted. + */ + if (vp->v_flag & VROOT) { + error = EBUSY; + goto out; + } + if (vp->v_flag & VTEXT) + (void) vnode_pager_uncache(vp); +out: + if (!error) { + nqsrv_getl(nd.ni_dvp, ND_WRITE); + nqsrv_getl(vp, ND_WRITE); + error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); + } else { + VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); + if (nd.ni_dvp == vp) + vrele(nd.ni_dvp); + else + vput(nd.ni_dvp); + vput(vp); + } + } + if (dirp && v3) { + diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); + vrele(dirp); + } + nfsm_reply(NFSX_WCCDATA(v3)); + if (v3) { + nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); + return (0); + } nfsm_srvdone; } /* * nfs rename service */ -nfsrv_rename(nfsd, mrep, md, dpos, cred, nam, mrq) - struct nfsd *nfsd; - struct mbuf *mrep, *md; - caddr_t dpos; - struct ucred *cred; - struct mbuf *nam, **mrq; +int +nfsrv_rename(nfsd, slp, procp, mrq) + struct nfsrv_descript *nfsd; + struct nfssvc_sock *slp; + struct proc *procp; + struct mbuf **mrq; { + struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; + struct mbuf *nam = nfsd->nd_nam; + caddr_t dpos = nfsd->nd_dpos; + struct ucred *cred = &nfsd->nd_cr; register u_long *tl; register long t1; caddr_t bpos; - int error = 0, cache, len, len2; + int error = 0, cache, len, len2, fdirfor_ret = 1, fdiraft_ret = 1; + int tdirfor_ret = 1, tdiraft_ret = 1; + int v3 = (nfsd->nd_flag & ND_NFSV3); char *cp2; - struct mbuf *mb, *mreq; + struct mbuf *mb, *mreq, *mb2; struct nameidata fromnd, tond; - struct vnode *fvp, *tvp, *tdvp; - nfsv2fh_t fnfh, tnfh; + struct vnode *fvp, *tvp, *tdvp, *fdirp = (struct vnode *)0; + struct vnode *tdirp = (struct vnode *)0; + struct vattr fdirfor, fdiraft, tdirfor, tdiraft; + nfsfh_t fnfh, tnfh; fhandle_t *ffhp, *tfhp; u_quad_t frev; uid_t saved_uid; +#ifndef nolint + fvp = (struct vnode *)0; +#endif ffhp = &fnfh.fh_generic; tfhp = &tnfh.fh_generic; fromnd.ni_cnd.cn_nameiop = 0; tond.ni_cnd.cn_nameiop = 0; nfsm_srvmtofh(ffhp); - nfsm_srvstrsiz(len, NFS_MAXNAMLEN); + nfsm_srvnamesiz(len); /* * Remember our original uid so that we can reset cr_uid before * the second nfs_namei() call, in case it is remapped. @@ -926,9 +1779,25 @@ nfsrv_rename(nfsd, mrep, md, dpos, cred, nam, mrq) fromnd.ni_cnd.cn_cred = cred; fromnd.ni_cnd.cn_nameiop = DELETE; fromnd.ni_cnd.cn_flags = WANTPARENT | SAVESTART; - if (error = nfs_namei(&fromnd, ffhp, len, nfsd->nd_slp, nam, &md, - &dpos, nfsd->nd_procp)) - nfsm_reply(0); + error = nfs_namei(&fromnd, ffhp, len, slp, nam, &md, + &dpos, &fdirp, procp, (nfsd->nd_flag & ND_KERBAUTH)); + if (fdirp) { + if (v3) + fdirfor_ret = VOP_GETATTR(fdirp, &fdirfor, cred, + procp); + else { + vrele(fdirp); + fdirp = (struct vnode *)0; + } + } + if (error) { + nfsm_reply(2 * NFSX_WCCDATA(v3)); + nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft); + nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft); + if (fdirp) + vrele(fdirp); + return (0); + } fvp = fromnd.ni_vp; nfsm_srvmtofh(tfhp); nfsm_strsiz(len2, NFS_MAXNAMLEN); @@ -936,8 +1805,18 @@ nfsrv_rename(nfsd, mrep, md, dpos, cred, nam, mrq) tond.ni_cnd.cn_cred = cred; tond.ni_cnd.cn_nameiop = RENAME; tond.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART; - if (error = nfs_namei(&tond, tfhp, len2, nfsd->nd_slp, nam, &md, - &dpos, nfsd->nd_procp)) { + error = nfs_namei(&tond, tfhp, len2, slp, nam, &md, + &dpos, &tdirp, procp, (nfsd->nd_flag & ND_KERBAUTH)); + if (tdirp) { + if (v3) + tdirfor_ret = VOP_GETATTR(tdirp, &tdirfor, cred, + procp); + else { + vrele(tdirp); + tdirp = (struct vnode *)0; + } + } + if (error) { VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); vrele(fromnd.ni_dvp); vrele(fvp); @@ -947,27 +1826,45 @@ nfsrv_rename(nfsd, mrep, md, dpos, cred, nam, mrq) tvp = tond.ni_vp; if (tvp != NULL) { if (fvp->v_type == VDIR && tvp->v_type != VDIR) { - error = EISDIR; + if (v3) + error = EEXIST; + else + error = EISDIR; goto out; } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { - error = ENOTDIR; + if (v3) + error = EEXIST; + else + error = ENOTDIR; goto out; } if (tvp->v_type == VDIR && tvp->v_mountedhere) { - error = EXDEV; + if (v3) + error = EXDEV; + else + error = ENOTEMPTY; goto out; } } if (fvp->v_type == VDIR && fvp->v_mountedhere) { - error = EBUSY; + if (v3) + error = EXDEV; + else + error = ENOTEMPTY; goto out; } if (fvp->v_mount != tdvp->v_mount) { - error = EXDEV; + if (v3) + error = EXDEV; + else + error = ENOTEMPTY; goto out; } if (fvp == tdvp) - error = EINVAL; + if (v3) + error = EINVAL; + else + error = ENOTEMPTY; /* * If source is the same as the destination (that is the * same vnode with the same name in the same directory), @@ -980,10 +1877,10 @@ nfsrv_rename(nfsd, mrep, md, dpos, cred, nam, mrq) error = -1; out: if (!error) { - nqsrv_getl(fromnd.ni_dvp, NQL_WRITE); - nqsrv_getl(tdvp, NQL_WRITE); + nqsrv_getl(fromnd.ni_dvp, ND_WRITE); + nqsrv_getl(tdvp, ND_WRITE); if (tvp) - nqsrv_getl(tvp, NQL_WRITE); + nqsrv_getl(tvp, ND_WRITE); error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); } else { @@ -997,21 +1894,39 @@ out: VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); vrele(fromnd.ni_dvp); vrele(fvp); + if (error == -1) + error = 0; } vrele(tond.ni_startdir); FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); out1: + if (fdirp) { + fdiraft_ret = VOP_GETATTR(fdirp, &fdiraft, cred, procp); + vrele(fdirp); + } + if (tdirp) { + tdiraft_ret = VOP_GETATTR(tdirp, &tdiraft, cred, procp); + vrele(tdirp); + } vrele(fromnd.ni_startdir); FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); - nfsm_reply(0); - return (error); + nfsm_reply(2 * NFSX_WCCDATA(v3)); + if (v3) { + nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft); + nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft); + } + return (0); nfsmout: - if (tond.ni_cnd.cn_nameiop || tond.ni_cnd.cn_flags) { + if (fdirp) + vrele(fdirp); + if (tdirp) + vrele(tdirp); + if (tond.ni_cnd.cn_nameiop) { vrele(tond.ni_startdir); FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); } - if (fromnd.ni_cnd.cn_nameiop || fromnd.ni_cnd.cn_flags) { + if (fromnd.ni_cnd.cn_nameiop) { vrele(fromnd.ni_startdir); FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); @@ -1024,22 +1939,28 @@ nfsmout: /* * nfs link service */ -nfsrv_link(nfsd, mrep, md, dpos, cred, nam, mrq) - struct nfsd *nfsd; - struct mbuf *mrep, *md; - caddr_t dpos; - struct ucred *cred; - struct mbuf *nam, **mrq; +int +nfsrv_link(nfsd, slp, procp, mrq) + struct nfsrv_descript *nfsd; + struct nfssvc_sock *slp; + struct proc *procp; + struct mbuf **mrq; { + struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; + struct mbuf *nam = nfsd->nd_nam; + caddr_t dpos = nfsd->nd_dpos; + struct ucred *cred = &nfsd->nd_cr; struct nameidata nd; register u_long *tl; register long t1; caddr_t bpos; - int error = 0, rdonly, cache, len; + int error = 0, rdonly, cache, len, dirfor_ret = 1, diraft_ret = 1; + int getret = 1, v3 = (nfsd->nd_flag & ND_NFSV3); char *cp2; - struct mbuf *mb, *mreq; - struct vnode *vp, *xp; - nfsv2fh_t nfh, dnfh; + struct mbuf *mb, *mreq, *mb2; + struct vnode *vp, *xp, *dirp = (struct vnode *)0; + struct vattr dirfor, diraft, at; + nfsfh_t nfh, dnfh; fhandle_t *fhp, *dfhp; u_quad_t frev; @@ -1047,16 +1968,31 @@ nfsrv_link(nfsd, mrep, md, dpos, cred, nam, mrq) dfhp = &dnfh.fh_generic; nfsm_srvmtofh(fhp); nfsm_srvmtofh(dfhp); - nfsm_srvstrsiz(len, NFS_MAXNAMLEN); - if (error = nfsrv_fhtovp(fhp, FALSE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) - nfsm_reply(0); + nfsm_srvnamesiz(len); + if (error = nfsrv_fhtovp(fhp, FALSE, &vp, cred, slp, nam, + &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { + nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3)); + nfsm_srvpostop_attr(getret, &at); + nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); + return (0); + } if (vp->v_type == VDIR && (error = suser(cred, (u_short *)0))) goto out1; nd.ni_cnd.cn_cred = cred; nd.ni_cnd.cn_nameiop = CREATE; nd.ni_cnd.cn_flags = LOCKPARENT; - if (error = nfs_namei(&nd, dfhp, len, nfsd->nd_slp, nam, &md, &dpos, - nfsd->nd_procp)) + error = nfs_namei(&nd, dfhp, len, slp, nam, &md, &dpos, + &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH)); + if (dirp) { + if (v3) + dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, + procp); + else { + vrele(dirp); + dirp = (struct vnode *)0; + } + } + if (error) goto out1; xp = nd.ni_vp; if (xp != NULL) { @@ -1068,9 +2004,9 @@ nfsrv_link(nfsd, mrep, md, dpos, cred, nam, mrq) error = EXDEV; out: if (!error) { - nqsrv_getl(vp, NQL_WRITE); - nqsrv_getl(xp, NQL_WRITE); - error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); + nqsrv_getl(vp, ND_WRITE); + nqsrv_getl(xp, ND_WRITE); + error = VOP_LINK(vp, nd.ni_dvp, &nd.ni_cnd); } else { VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); if (nd.ni_dvp == nd.ni_vp) @@ -1081,47 +2017,76 @@ out: vrele(nd.ni_vp); } out1: + if (v3) + getret = VOP_GETATTR(vp, &at, cred, procp); + if (dirp) { + diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); + vrele(dirp); + } vrele(vp); - nfsm_reply(0); + nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3)); + if (v3) { + nfsm_srvpostop_attr(getret, &at); + nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); + return (0); + } nfsm_srvdone; } /* * nfs symbolic link service */ -nfsrv_symlink(nfsd, mrep, md, dpos, cred, nam, mrq) - struct nfsd *nfsd; - struct mbuf *mrep, *md; - caddr_t dpos; - struct ucred *cred; - struct mbuf *nam, **mrq; +int +nfsrv_symlink(nfsd, slp, procp, mrq) + struct nfsrv_descript *nfsd; + struct nfssvc_sock *slp; + struct proc *procp; + struct mbuf **mrq; { - struct vattr va; + struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; + struct mbuf *nam = nfsd->nd_nam; + caddr_t dpos = nfsd->nd_dpos; + struct ucred *cred = &nfsd->nd_cr; + struct vattr va, dirfor, diraft; struct nameidata nd; register struct vattr *vap = &va; register u_long *tl; register long t1; struct nfsv2_sattr *sp; - caddr_t bpos; + char *bpos, *cp, *pathcp = (char *)0, *cp2; struct uio io; struct iovec iv; - int error = 0, cache, len, len2; - char *pathcp, *cp2; - struct mbuf *mb, *mreq; - nfsv2fh_t nfh; + int error = 0, cache, len, len2, dirfor_ret = 1, diraft_ret = 1; + int v3 = (nfsd->nd_flag & ND_NFSV3); + struct mbuf *mb, *mreq, *mb2; + struct vnode *dirp = (struct vnode *)0; + nfsfh_t nfh; fhandle_t *fhp; u_quad_t frev; - pathcp = (char *)0; + nd.ni_cnd.cn_nameiop = 0; fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); - nfsm_srvstrsiz(len, NFS_MAXNAMLEN); + nfsm_srvnamesiz(len); nd.ni_cnd.cn_cred = cred; nd.ni_cnd.cn_nameiop = CREATE; - nd.ni_cnd.cn_flags = LOCKPARENT; - if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, - nfsd->nd_procp)) + nd.ni_cnd.cn_flags = LOCKPARENT | SAVESTART; + error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, + &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH)); + if (dirp) { + if (v3) + dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, + procp); + else { + vrele(dirp); + dirp = (struct vnode *)0; + } + } + if (error) goto out; + VATTR_NULL(vap); + if (v3) + nfsm_srvsattr(vap); nfsm_strsiz(len2, NFS_MAXPATHLEN); MALLOC(pathcp, caddr_t, len2 + 1, M_TEMP, M_WAITOK); iv.iov_base = pathcp; @@ -1134,9 +2099,14 @@ nfsrv_symlink(nfsd, mrep, md, dpos, cred, nam, mrq) io.uio_rw = UIO_READ; io.uio_procp = (struct proc *)0; nfsm_mtouio(&io, len2); - nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR(nfsd->nd_nqlflag != NQL_NOVAL)); + if (!v3) { + nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR); + vap->va_mode = fxdr_unsigned(u_short, sp->sa_mode); + } *(pathcp + len2) = '\0'; if (nd.ni_vp) { + vrele(nd.ni_startdir); + free(nd.ni_cnd.cn_pnbuf, M_NAMEI); VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); if (nd.ni_dvp == nd.ni_vp) vrele(nd.ni_dvp); @@ -1146,16 +2116,54 @@ nfsrv_symlink(nfsd, mrep, md, dpos, cred, nam, mrq) error = EEXIST; goto out; } - VATTR_NULL(vap); - vap->va_mode = fxdr_unsigned(u_short, sp->sa_mode); - nqsrv_getl(nd.ni_dvp, NQL_WRITE); + nqsrv_getl(nd.ni_dvp, ND_WRITE); error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap, pathcp); + if (error) + vrele(nd.ni_startdir); + else { + if (v3) { + nd.ni_cnd.cn_nameiop = LOOKUP; + nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART | FOLLOW); + nd.ni_cnd.cn_flags |= (NOFOLLOW | LOCKLEAF); + nd.ni_cnd.cn_proc = procp; + nd.ni_cnd.cn_cred = cred; + error = lookup(&nd); + if (!error) { + bzero((caddr_t)fhp, sizeof(nfh)); + fhp->fh_fsid = nd.ni_vp->v_mount->mnt_stat.f_fsid; + error = VFS_VPTOFH(nd.ni_vp, &fhp->fh_fid); + if (!error) + error = VOP_GETATTR(nd.ni_vp, vap, cred, + procp); + vput(nd.ni_vp); + } + } else + vrele(nd.ni_startdir); + FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); + } out: if (pathcp) FREE(pathcp, M_TEMP); - nfsm_reply(0); - return (error); + if (dirp) { + diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); + vrele(dirp); + } + nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3)); + if (v3) { + if (!error) { + nfsm_srvpostop_fh(fhp); + nfsm_srvpostop_attr(0, vap); + } + nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); + } + return (0); nfsmout: + if (nd.ni_cnd.cn_nameiop) { + vrele(nd.ni_startdir); + free(nd.ni_cnd.cn_pnbuf, M_NAMEI); + } + if (dirp) + vrele(dirp); VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); if (nd.ni_dvp == nd.ni_vp) vrele(nd.ni_dvp); @@ -1171,42 +2179,66 @@ nfsmout: /* * nfs mkdir service */ -nfsrv_mkdir(nfsd, mrep, md, dpos, cred, nam, mrq) - struct nfsd *nfsd; - struct mbuf *mrep, *md; - caddr_t dpos; - struct ucred *cred; - struct mbuf *nam, **mrq; +int +nfsrv_mkdir(nfsd, slp, procp, mrq) + struct nfsrv_descript *nfsd; + struct nfssvc_sock *slp; + struct proc *procp; + struct mbuf **mrq; { - struct vattr va; + struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; + struct mbuf *nam = nfsd->nd_nam; + caddr_t dpos = nfsd->nd_dpos; + struct ucred *cred = &nfsd->nd_cr; + struct vattr va, dirfor, diraft; register struct vattr *vap = &va; - register struct nfsv2_fattr *fp; + register struct nfs_fattr *fp; struct nameidata nd; register caddr_t cp; register u_long *tl; register long t1; caddr_t bpos; - int error = 0, cache, len; + int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1; + int v3 = (nfsd->nd_flag & ND_NFSV3); char *cp2; struct mbuf *mb, *mb2, *mreq; - struct vnode *vp; - nfsv2fh_t nfh; + struct vnode *vp, *dirp = (struct vnode *)0; + nfsfh_t nfh; fhandle_t *fhp; u_quad_t frev; fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); - nfsm_srvstrsiz(len, NFS_MAXNAMLEN); + nfsm_srvnamesiz(len); nd.ni_cnd.cn_cred = cred; nd.ni_cnd.cn_nameiop = CREATE; nd.ni_cnd.cn_flags = LOCKPARENT; - if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, - nfsd->nd_procp)) - nfsm_reply(0); - nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); + error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, + &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH)); + if (dirp) { + if (v3) + dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, + procp); + else { + vrele(dirp); + dirp = (struct vnode *)0; + } + } + if (error) { + nfsm_reply(NFSX_WCCDATA(v3)); + nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); + if (dirp) + vrele(dirp); + return (0); + } VATTR_NULL(vap); + if (v3) { + nfsm_srvsattr(vap); + } else { + nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); + vap->va_mode = nfstov_mode(*tl++); + } vap->va_type = VDIR; - vap->va_mode = nfstov_mode(*tl++); vp = nd.ni_vp; if (vp != NULL) { VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); @@ -1216,26 +2248,40 @@ nfsrv_mkdir(nfsd, mrep, md, dpos, cred, nam, mrq) vput(nd.ni_dvp); vrele(vp); error = EEXIST; - nfsm_reply(0); + goto out; } - nqsrv_getl(nd.ni_dvp, NQL_WRITE); - if (error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) - nfsm_reply(0); - vp = nd.ni_vp; - bzero((caddr_t)fhp, sizeof(nfh)); - fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; - if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { + nqsrv_getl(nd.ni_dvp, ND_WRITE); + error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap); + if (!error) { + vp = nd.ni_vp; + bzero((caddr_t)fhp, sizeof(nfh)); + fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; + error = VFS_VPTOFH(vp, &fhp->fh_fid); + if (!error) + error = VOP_GETATTR(vp, vap, cred, procp); vput(vp); - nfsm_reply(0); } - error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); - vput(vp); - nfsm_reply(NFSX_FH+NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); - nfsm_srvfhtom(fhp); - nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)); - nfsm_srvfillattr; - return (error); +out: + if (dirp) { + diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); + vrele(dirp); + } + nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3)); + if (v3) { + if (!error) { + nfsm_srvpostop_fh(fhp); + nfsm_srvpostop_attr(0, vap); + } + nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); + } else { + nfsm_srvfhtom(fhp, v3); + nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR); + nfsm_srvfillattr(vap, fp); + } + return (0); nfsmout: + if (dirp) + vrele(dirp); VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); if (nd.ni_dvp == nd.ni_vp) vrele(nd.ni_dvp); @@ -1249,34 +2295,55 @@ nfsmout: /* * nfs rmdir service */ -nfsrv_rmdir(nfsd, mrep, md, dpos, cred, nam, mrq) - struct nfsd *nfsd; - struct mbuf *mrep, *md; - caddr_t dpos; - struct ucred *cred; - struct mbuf *nam, **mrq; +int +nfsrv_rmdir(nfsd, slp, procp, mrq) + struct nfsrv_descript *nfsd; + struct nfssvc_sock *slp; + struct proc *procp; + struct mbuf **mrq; { + struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; + struct mbuf *nam = nfsd->nd_nam; + caddr_t dpos = nfsd->nd_dpos; + struct ucred *cred = &nfsd->nd_cr; register u_long *tl; register long t1; caddr_t bpos; - int error = 0, cache, len; + int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1; + int v3 = (nfsd->nd_flag & ND_NFSV3); char *cp2; - struct mbuf *mb, *mreq; - struct vnode *vp; - nfsv2fh_t nfh; + struct mbuf *mb, *mreq, *mb2; + struct vnode *vp, *dirp = (struct vnode *)0; + struct vattr dirfor, diraft; + nfsfh_t nfh; fhandle_t *fhp; struct nameidata nd; u_quad_t frev; fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); - nfsm_srvstrsiz(len, NFS_MAXNAMLEN); + nfsm_srvnamesiz(len); nd.ni_cnd.cn_cred = cred; nd.ni_cnd.cn_nameiop = DELETE; nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; - if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, - nfsd->nd_procp)) - nfsm_reply(0); + error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, + &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH)); + if (dirp) { + if (v3) + dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, + procp); + else { + vrele(dirp); + dirp = (struct vnode *)0; + } + } + if (error) { + nfsm_reply(NFSX_WCCDATA(v3)); + nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); + if (dirp) + vrele(dirp); + return (0); + } vp = nd.ni_vp; if (vp->v_type != VDIR) { error = ENOTDIR; @@ -1296,8 +2363,8 @@ nfsrv_rmdir(nfsd, mrep, md, dpos, cred, nam, mrq) error = EBUSY; out: if (!error) { - nqsrv_getl(nd.ni_dvp, NQL_WRITE); - nqsrv_getl(vp, NQL_WRITE); + nqsrv_getl(nd.ni_dvp, ND_WRITE); + nqsrv_getl(vp, ND_WRITE); error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); } else { VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); @@ -1307,7 +2374,15 @@ out: vput(nd.ni_dvp); vput(vp); } - nfsm_reply(0); + if (dirp) { + diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); + vrele(dirp); + } + nfsm_reply(NFSX_WCCDATA(v3)); + if (v3) { + nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); + return (0); + } nfsm_srvdone; } @@ -1331,7 +2406,7 @@ out: * than requested, but this may not apply to all filesystems. For * example, client NFS does not { although it is never remote mounted * anyhow } - * The alternate call nqnfsrv_readdirlook() does lookups as well. + * The alternate call nfsrv_readdirplus() does lookups as well. * PS: The NFS protocol spec. does not clarify what the "count" byte * argument is a count of.. just name strings and file id's or the * entire reply rpc or ... @@ -1341,20 +2416,25 @@ out: * "entry" structures, but are in the rpc. */ struct flrep { - u_long fl_cachable; - u_long fl_duration; - u_long fl_frev[2]; - nfsv2fh_t fl_nfh; - u_long fl_fattr[NFSX_NQFATTR / sizeof (u_long)]; + nfsuint64 fl_off; + u_long fl_postopok; + u_long fl_fattr[NFSX_V3FATTR / sizeof (u_long)]; + u_long fl_fhok; + u_long fl_fhsize; + u_long fl_nfh[NFSX_V3FH / sizeof (u_long)]; }; -nfsrv_readdir(nfsd, mrep, md, dpos, cred, nam, mrq) - struct nfsd *nfsd; - struct mbuf *mrep, *md; - caddr_t dpos; - struct ucred *cred; - struct mbuf *nam, **mrq; +int +nfsrv_readdir(nfsd, slp, procp, mrq) + struct nfsrv_descript *nfsd; + struct nfssvc_sock *slp; + struct proc *procp; + struct mbuf **mrq; { + struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; + struct mbuf *nam = nfsd->nd_nam; + caddr_t dpos = nfsd->nd_dpos; + struct ucred *cred = &nfsd->nd_cr; register char *bp, *be; register struct mbuf *mp; register struct dirent *dp; @@ -1365,34 +2445,57 @@ nfsrv_readdir(nfsd, mrep, md, dpos, cred, nam, mrq) struct mbuf *mb, *mb2, *mreq, *mp2; char *cpos, *cend, *cp2, *rbuf; struct vnode *vp; - nfsv2fh_t nfh; + struct vattr at; + nfsfh_t nfh; fhandle_t *fhp; struct uio io; struct iovec iv; - int len, nlen, rem, xfer, tsiz, i, error = 0; - int siz, cnt, fullsiz, eofflag, rdonly, cache; - u_quad_t frev; - u_long on, off, toff; + int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1; + int siz, cnt, fullsiz, eofflag, rdonly, cache, ncookies; + int v3 = (nfsd->nd_flag & ND_NFSV3); + u_quad_t frev, off, toff, verf; + u_long *cookies = NULL, *cookiep; fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); - nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); - toff = fxdr_unsigned(u_long, *tl++); - off = (toff & ~(NFS_DIRBLKSIZ-1)); - on = (toff & (NFS_DIRBLKSIZ-1)); + if (v3) { + nfsm_dissect(tl, u_long *, 5 * NFSX_UNSIGNED); + fxdr_hyper(tl, &toff); + tl += 2; + fxdr_hyper(tl, &verf); + tl += 2; + } else { + nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); + toff = fxdr_unsigned(u_quad_t, *tl++); + } + off = toff; cnt = fxdr_unsigned(int, *tl); - siz = ((cnt+NFS_DIRBLKSIZ-1) & ~(NFS_DIRBLKSIZ-1)); - if (cnt > NFS_MAXREADDIR) - siz = NFS_MAXREADDIR; + siz = ((cnt + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1)); + xfer = NFS_SRVMAXDATA(nfsd); + if (siz > xfer) + siz = xfer; fullsiz = siz; - if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) - nfsm_reply(0); - nqsrv_getl(vp, NQL_READ); - if (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp)) { + if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, + &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { + nfsm_reply(NFSX_UNSIGNED); + nfsm_srvpostop_attr(getret, &at); + return (0); + } + nqsrv_getl(vp, ND_READ); + if (v3) { + error = getret = VOP_GETATTR(vp, &at, cred, procp); + if (!error && toff && verf != at.va_filerev) + error = NFSERR_BAD_COOKIE; + } + if (!error) + error = nfsrv_access(vp, VEXEC, cred, rdonly, procp); + if (error) { vput(vp); - nfsm_reply(0); + nfsm_reply(NFSX_POSTOPATTR(v3)); + nfsm_srvpostop_attr(getret, &at); + return (0); } - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, procp); MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK); again: iv.iov_base = rbuf; @@ -1404,17 +2507,29 @@ again: io.uio_segflg = UIO_SYSSPACE; io.uio_rw = UIO_READ; io.uio_procp = (struct proc *)0; - error = VOP_READDIR(vp, &io, cred); + eofflag = 0; + if (cookies) { + free((caddr_t)cookies, M_TEMP); + cookies = NULL; + } + error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies); off = (off_t)io.uio_offset; + if (!cookies && !error) + error = NFSERR_PERM; + if (v3) { + getret = VOP_GETATTR(vp, &at, cred, procp); + if (!error) + error = getret; + } if (error) { vrele(vp); free((caddr_t)rbuf, M_TEMP); - nfsm_reply(0); + if (cookies) + free((caddr_t)cookies, M_TEMP); + nfsm_reply(NFSX_POSTOPATTR(v3)); + nfsm_srvpostop_attr(getret, &at); + return (0); } - if (io.uio_resid < fullsiz) - eofflag = 0; - else - eofflag = 1; if (io.uio_resid) { siz -= io.uio_resid; @@ -1424,11 +2539,19 @@ again: */ if (siz == 0) { vrele(vp); - nfsm_reply(2*NFSX_UNSIGNED); - nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); + nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) + + 2 * NFSX_UNSIGNED); + if (v3) { + nfsm_srvpostop_attr(getret, &at); + nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED); + txdr_hyper(&at.va_filerev, tl); + tl += 2; + } else + nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED); *tl++ = nfs_false; *tl = nfs_true; FREE((caddr_t)rbuf, M_TEMP); + FREE((caddr_t)cookies, M_TEMP); return (0); } } @@ -1437,35 +2560,41 @@ again: * Check for degenerate cases of nothing useful read. * If so go try again */ - cpos = rbuf + on; + cpos = rbuf; cend = rbuf + siz; dp = (struct dirent *)cpos; - while (cpos < cend && dp->d_fileno == 0) { + cookiep = cookies; + while (dp->d_fileno == 0 && cpos < cend && ncookies > 0) { cpos += dp->d_reclen; dp = (struct dirent *)cpos; + cookiep++; + ncookies--; } - if (cpos >= cend) { + if (cpos >= cend || ncookies == 0) { toff = off; siz = fullsiz; - on = 0; goto again; } - cpos = rbuf + on; - cend = rbuf + siz; - dp = (struct dirent *)cpos; - len = 3*NFSX_UNSIGNED; /* paranoia, probably can be 0 */ - nfsm_reply(siz); + len = 3 * NFSX_UNSIGNED; /* paranoia, probably can be 0 */ + nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) + siz); + if (v3) { + nfsm_srvpostop_attr(getret, &at); + nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED); + txdr_hyper(&at.va_filerev, tl); + } mp = mp2 = mb; bp = bpos; be = bp + M_TRAILINGSPACE(mp); /* Loop through the records and build reply */ - while (cpos < cend) { + while (cpos < cend && ncookies > 0) { if (dp->d_fileno != 0) { nlen = dp->d_namlen; rem = nfsm_rndup(nlen)-nlen; - len += (4*NFSX_UNSIGNED + nlen + rem); + len += (4 * NFSX_UNSIGNED + nlen + rem); + if (v3) + len += 2 * NFSX_UNSIGNED; if (len > cnt) { eofflag = 0; break; @@ -1477,6 +2606,11 @@ again: nfsm_clget; *tl = nfs_true; bp += NFSX_UNSIGNED; + if (v3) { + nfsm_clget; + *tl = 0; + bp += NFSX_UNSIGNED; + } nfsm_clget; *tl = txdr_unsigned(dp->d_fileno); bp += NFSX_UNSIGNED; @@ -1505,13 +2639,18 @@ again: nfsm_clget; /* Finish off the record */ - toff += dp->d_reclen; - *tl = txdr_unsigned(toff); + if (v3) { + *tl = 0; + bp += NFSX_UNSIGNED; + nfsm_clget; + } + *tl = txdr_unsigned(*cookiep); bp += NFSX_UNSIGNED; - } else - toff += dp->d_reclen; + } cpos += dp->d_reclen; dp = (struct dirent *)cpos; + cookiep++; + ncookies--; } vrele(vp); nfsm_clget; @@ -1528,17 +2667,22 @@ again: mp->m_len = bp - mtod(mp, caddr_t); } else mp->m_len += bp - bpos; - FREE(rbuf, M_TEMP); + FREE((caddr_t)rbuf, M_TEMP); + FREE((caddr_t)cookies, M_TEMP); nfsm_srvdone; } -nqnfsrv_readdirlook(nfsd, mrep, md, dpos, cred, nam, mrq) - struct nfsd *nfsd; - struct mbuf *mrep, *md; - caddr_t dpos; - struct ucred *cred; - struct mbuf *nam, **mrq; +int +nfsrv_readdirplus(nfsd, slp, procp, mrq) + struct nfsrv_descript *nfsd; + struct nfssvc_sock *slp; + struct proc *procp; + struct mbuf **mrq; { + struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; + struct mbuf *nam = nfsd->nd_nam; + caddr_t dpos = nfsd->nd_dpos; + struct ucred *cred = &nfsd->nd_cr; register char *bp, *be; register struct mbuf *mp; register struct dirent *dp; @@ -1550,37 +2694,52 @@ nqnfsrv_readdirlook(nfsd, mrep, md, dpos, cred, nam, mrq) char *cpos, *cend, *cp2, *rbuf; struct vnode *vp, *nvp; struct flrep fl; - nfsv2fh_t nfh; - fhandle_t *fhp; + nfsfh_t nfh; + fhandle_t *fhp, *nfhp = (fhandle_t *)fl.fl_nfh; struct uio io; struct iovec iv; - struct vattr va, *vap = &va; - struct nfsv2_fattr *fp; - int len, nlen, rem, xfer, tsiz, i, error = 0, duration2, cache2; - int siz, cnt, fullsiz, eofflag, rdonly, cache; - u_quad_t frev, frev2; - u_long on, off, toff; + struct vattr va, at, *vap = &va; + struct nfs_fattr *fp; + int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1; + int siz, cnt, fullsiz, eofflag, rdonly, cache, dirlen, ncookies; + u_quad_t frev, off, toff, verf; + u_long *cookies = NULL, *cookiep; fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); - nfsm_dissect(tl, u_long *, 3*NFSX_UNSIGNED); - toff = fxdr_unsigned(u_long, *tl++); - off = (toff & ~(NFS_DIRBLKSIZ-1)); - on = (toff & (NFS_DIRBLKSIZ-1)); - cnt = fxdr_unsigned(int, *tl++); - duration2 = fxdr_unsigned(int, *tl); - siz = ((cnt+NFS_DIRBLKSIZ-1) & ~(NFS_DIRBLKSIZ-1)); - if (cnt > NFS_MAXREADDIR) - siz = NFS_MAXREADDIR; + nfsm_dissect(tl, u_long *, 6 * NFSX_UNSIGNED); + fxdr_hyper(tl, &toff); + tl += 2; + fxdr_hyper(tl, &verf); + tl += 2; + siz = fxdr_unsigned(int, *tl++); + cnt = fxdr_unsigned(int, *tl); + off = toff; + siz = ((siz + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1)); + xfer = NFS_SRVMAXDATA(nfsd); + if (siz > xfer) + siz = xfer; fullsiz = siz; - if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) - nfsm_reply(0); - nqsrv_getl(vp, NQL_READ); - if (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp)) { + if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, + &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { + nfsm_reply(NFSX_UNSIGNED); + nfsm_srvpostop_attr(getret, &at); + return (0); + } + error = getret = VOP_GETATTR(vp, &at, cred, procp); + if (!error && toff && verf != at.va_filerev) + error = NFSERR_BAD_COOKIE; + if (!error) { + nqsrv_getl(vp, ND_READ); + error = nfsrv_access(vp, VEXEC, cred, rdonly, procp); + } + if (error) { vput(vp); - nfsm_reply(0); + nfsm_reply(NFSX_V3POSTOPATTR); + nfsm_srvpostop_attr(getret, &at); + return (0); } - VOP_UNLOCK(vp); + VOP_UNLOCK(vp, 0, procp); MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK); again: iv.iov_base = rbuf; @@ -1592,17 +2751,27 @@ again: io.uio_segflg = UIO_SYSSPACE; io.uio_rw = UIO_READ; io.uio_procp = (struct proc *)0; - error = VOP_READDIR(vp, &io, cred); - off = (u_long)io.uio_offset; + eofflag = 0; + if (cookies) { + free((caddr_t)cookies, M_TEMP); + cookies = NULL; + } + error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies); + off = (u_quad_t)io.uio_offset; + getret = VOP_GETATTR(vp, &at, cred, procp); + if (!cookies && !error) + error = NFSERR_PERM; + if (!error) + error = getret; if (error) { vrele(vp); + if (cookies) + free((caddr_t)cookies, M_TEMP); free((caddr_t)rbuf, M_TEMP); - nfsm_reply(0); + nfsm_reply(NFSX_V3POSTOPATTR); + nfsm_srvpostop_attr(getret, &at); + return (0); } - if (io.uio_resid < fullsiz) - eofflag = 0; - else - eofflag = 1; if (io.uio_resid) { siz -= io.uio_resid; @@ -1612,10 +2781,15 @@ again: */ if (siz == 0) { vrele(vp); - nfsm_reply(2 * NFSX_UNSIGNED); - nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED); + nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + + 2 * NFSX_UNSIGNED); + nfsm_srvpostop_attr(getret, &at); + nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED); + txdr_hyper(&at.va_filerev, tl); + tl += 2; *tl++ = nfs_false; *tl = nfs_true; + FREE((caddr_t)cookies, M_TEMP); FREE((caddr_t)rbuf, M_TEMP); return (0); } @@ -1625,31 +2799,33 @@ again: * Check for degenerate cases of nothing useful read. * If so go try again */ - cpos = rbuf + on; + cpos = rbuf; cend = rbuf + siz; dp = (struct dirent *)cpos; - while (cpos < cend && dp->d_fileno == 0) { + cookiep = cookies; + while (dp->d_fileno == 0 && cpos < cend && ncookies > 0) { cpos += dp->d_reclen; dp = (struct dirent *)cpos; + cookiep++; + ncookies--; } - if (cpos >= cend) { + if (cpos >= cend || ncookies == 0) { toff = off; siz = fullsiz; - on = 0; goto again; } - cpos = rbuf + on; - cend = rbuf + siz; - dp = (struct dirent *)cpos; - len = 3 * NFSX_UNSIGNED; /* paranoia, probably can be 0 */ - nfsm_reply(siz); + dirlen = len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 2 * NFSX_UNSIGNED; + nfsm_reply(cnt); + nfsm_srvpostop_attr(getret, &at); + nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED); + txdr_hyper(&at.va_filerev, tl); mp = mp2 = mb; bp = bpos; be = bp + M_TRAILINGSPACE(mp); /* Loop through the records and build reply */ - while (cpos < cend) { + while (cpos < cend && ncookies > 0) { if (dp->d_fileno != 0) { nlen = dp->d_namlen; rem = nfsm_rndup(nlen)-nlen; @@ -1660,59 +2836,51 @@ again: */ if (VFS_VGET(vp->v_mount, dp->d_fileno, &nvp)) goto invalid; - bzero((caddr_t)&fl.fl_nfh, sizeof (nfsv2fh_t)); - fl.fl_nfh.fh_generic.fh_fsid = + bzero((caddr_t)nfhp, NFSX_V3FH); + nfhp->fh_fsid = nvp->v_mount->mnt_stat.f_fsid; - if (VFS_VPTOFH(nvp, &fl.fl_nfh.fh_generic.fh_fid)) { + if (VFS_VPTOFH(nvp, &nfhp->fh_fid)) { vput(nvp); goto invalid; } - if (duration2) { - (void) nqsrv_getlease(nvp, &duration2, NQL_READ, - nfsd, nam, &cache2, &frev2, cred); - fl.fl_duration = txdr_unsigned(duration2); - fl.fl_cachable = txdr_unsigned(cache2); - txdr_hyper(&frev2, fl.fl_frev); - } else - fl.fl_duration = 0; - if (VOP_GETATTR(nvp, vap, cred, nfsd->nd_procp)) { + if (VOP_GETATTR(nvp, vap, cred, procp)) { vput(nvp); goto invalid; } vput(nvp); - fp = (struct nfsv2_fattr *)&fl.fl_fattr; - nfsm_srvfillattr; - len += (4*NFSX_UNSIGNED + nlen + rem + NFSX_FH - + NFSX_NQFATTR); - if (len > cnt) { + + /* + * If either the dircount or maxcount will be + * exceeded, get out now. Both of these lengths + * are calculated conservatively, including all + * XDR overheads. + */ + len += (7 * NFSX_UNSIGNED + nlen + rem + NFSX_V3FH + + NFSX_V3POSTOPATTR); + dirlen += (6 * NFSX_UNSIGNED + nlen + rem); + if (len > cnt || dirlen > fullsiz) { eofflag = 0; break; } + /* * Build the directory record xdr from * the dirent entry. */ + fp = (struct nfs_fattr *)&fl.fl_fattr; + nfsm_srvfillattr(vap, fp); + fl.fl_fhsize = txdr_unsigned(NFSX_V3FH); + fl.fl_fhok = nfs_true; + fl.fl_postopok = nfs_true; + fl.fl_off.nfsuquad[0] = 0; + fl.fl_off.nfsuquad[1] = txdr_unsigned(*cookiep); + nfsm_clget; *tl = nfs_true; bp += NFSX_UNSIGNED; - - /* - * For readdir_and_lookup copy the stuff out. - */ - xfer = sizeof (struct flrep); - cp = (caddr_t)&fl; - while (xfer > 0) { - nfsm_clget; - if ((bp+xfer) > be) - tsiz = be-bp; - else - tsiz = xfer; - bcopy(cp, bp, tsiz); - bp += tsiz; - xfer -= tsiz; - if (xfer > 0) - cp += tsiz; - } + nfsm_clget; + *tl = 0; + bp += NFSX_UNSIGNED; nfsm_clget; *tl = txdr_unsigned(dp->d_fileno); bp += NFSX_UNSIGNED; @@ -1725,8 +2893,8 @@ again: cp = dp->d_name; while (xfer > 0) { nfsm_clget; - if ((bp+xfer) > be) - tsiz = be-bp; + if ((bp + xfer) > be) + tsiz = be - bp; else tsiz = xfer; bcopy(cp, bp, tsiz); @@ -1738,17 +2906,30 @@ again: /* And null pad to a long boundary */ for (i = 0; i < rem; i++) *bp++ = '\0'; - nfsm_clget; - /* Finish off the record */ - toff += dp->d_reclen; - *tl = txdr_unsigned(toff); - bp += NFSX_UNSIGNED; - } else + /* + * Now copy the flrep structure out. + */ + xfer = sizeof (struct flrep); + cp = (caddr_t)&fl; + while (xfer > 0) { + nfsm_clget; + if ((bp + xfer) > be) + tsiz = be - bp; + else + tsiz = xfer; + bcopy(cp, bp, tsiz); + bp += tsiz; + xfer -= tsiz; + if (xfer > 0) + cp += tsiz; + } + } invalid: - toff += dp->d_reclen; cpos += dp->d_reclen; dp = (struct dirent *)cpos; + cookiep++; + ncookies--; } vrele(vp); nfsm_clget; @@ -1765,53 +2946,286 @@ invalid: mp->m_len = bp - mtod(mp, caddr_t); } else mp->m_len += bp - bpos; - FREE(rbuf, M_TEMP); + FREE((caddr_t)cookies, M_TEMP); + FREE((caddr_t)rbuf, M_TEMP); + nfsm_srvdone; +} + +/* + * nfs commit service + */ +int +nfsrv_commit(nfsd, slp, procp, mrq) + struct nfsrv_descript *nfsd; + struct nfssvc_sock *slp; + struct proc *procp; + struct mbuf **mrq; +{ + struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; + struct mbuf *nam = nfsd->nd_nam; + caddr_t dpos = nfsd->nd_dpos; + struct ucred *cred = &nfsd->nd_cr; + struct vattr bfor, aft; + struct vnode *vp; + nfsfh_t nfh; + fhandle_t *fhp; + register u_long *tl; + register long t1; + caddr_t bpos; + int error = 0, rdonly, for_ret = 1, aft_ret = 1, cnt, cache; + char *cp2; + struct mbuf *mb, *mb2, *mreq; + u_quad_t frev, off; + +#ifndef nolint + cache = 0; +#endif + fhp = &nfh.fh_generic; + nfsm_srvmtofh(fhp); + nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED); + + /* + * XXX At this time VOP_FSYNC() does not accept offset and byte + * count parameters, so these arguments are useless (someday maybe). + */ + fxdr_hyper(tl, &off); + tl += 2; + cnt = fxdr_unsigned(int, *tl); + if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, + &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { + nfsm_reply(2 * NFSX_UNSIGNED); + nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft); + return (0); + } + for_ret = VOP_GETATTR(vp, &bfor, cred, procp); + error = VOP_FSYNC(vp, cred, MNT_WAIT, procp); + aft_ret = VOP_GETATTR(vp, &aft, cred, procp); + vput(vp); + nfsm_reply(NFSX_V3WCCDATA + NFSX_V3WRITEVERF); + nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft); + if (!error) { + nfsm_build(tl, u_long *, NFSX_V3WRITEVERF); + *tl++ = txdr_unsigned(boottime.tv_sec); + *tl = txdr_unsigned(boottime.tv_usec); + } else + return (0); nfsm_srvdone; } /* * nfs statfs service */ -nfsrv_statfs(nfsd, mrep, md, dpos, cred, nam, mrq) - struct nfsd *nfsd; - struct mbuf *mrep, *md; - caddr_t dpos; - struct ucred *cred; - struct mbuf *nam, **mrq; +int +nfsrv_statfs(nfsd, slp, procp, mrq) + struct nfsrv_descript *nfsd; + struct nfssvc_sock *slp; + struct proc *procp; + struct mbuf **mrq; { + struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; + struct mbuf *nam = nfsd->nd_nam; + caddr_t dpos = nfsd->nd_dpos; + struct ucred *cred = &nfsd->nd_cr; register struct statfs *sf; - register struct nfsv2_statfs *sfp; + register struct nfs_statfs *sfp; register u_long *tl; register long t1; caddr_t bpos; - int error = 0, rdonly, cache, isnq; + int error = 0, rdonly, cache, getret = 1; + int v3 = (nfsd->nd_flag & ND_NFSV3); char *cp2; struct mbuf *mb, *mb2, *mreq; struct vnode *vp; - nfsv2fh_t nfh; + struct vattr at; + nfsfh_t nfh; fhandle_t *fhp; struct statfs statfs; - u_quad_t frev; + u_quad_t frev, tval; +#ifndef nolint + cache = 0; +#endif fhp = &nfh.fh_generic; - isnq = (nfsd->nd_nqlflag != NQL_NOVAL); nfsm_srvmtofh(fhp); - if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) - nfsm_reply(0); + if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, + &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { + nfsm_reply(NFSX_UNSIGNED); + nfsm_srvpostop_attr(getret, &at); + return (0); + } sf = &statfs; - error = VFS_STATFS(vp->v_mount, sf, nfsd->nd_procp); + error = VFS_STATFS(vp->v_mount, sf, procp); + getret = VOP_GETATTR(vp, &at, cred, procp); + vput(vp); + nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_STATFS(v3)); + if (v3) + nfsm_srvpostop_attr(getret, &at); + if (error) + return (0); + nfsm_build(sfp, struct nfs_statfs *, NFSX_STATFS(v3)); + if (v3) { + tval = (u_quad_t)sf->f_blocks; + tval *= (u_quad_t)sf->f_bsize; + txdr_hyper(&tval, &sfp->sf_tbytes); + tval = (u_quad_t)sf->f_bfree; + tval *= (u_quad_t)sf->f_bsize; + txdr_hyper(&tval, &sfp->sf_fbytes); + tval = (u_quad_t)sf->f_bavail; + tval *= (u_quad_t)sf->f_bsize; + txdr_hyper(&tval, &sfp->sf_abytes); + sfp->sf_tfiles.nfsuquad[0] = 0; + sfp->sf_tfiles.nfsuquad[1] = txdr_unsigned(sf->f_files); + sfp->sf_ffiles.nfsuquad[0] = 0; + sfp->sf_ffiles.nfsuquad[1] = txdr_unsigned(sf->f_ffree); + sfp->sf_afiles.nfsuquad[0] = 0; + sfp->sf_afiles.nfsuquad[1] = txdr_unsigned(sf->f_ffree); + sfp->sf_invarsec = 0; + } else { + sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA); + sfp->sf_bsize = txdr_unsigned(sf->f_bsize); + sfp->sf_blocks = txdr_unsigned(sf->f_blocks); + sfp->sf_bfree = txdr_unsigned(sf->f_bfree); + sfp->sf_bavail = txdr_unsigned(sf->f_bavail); + } + nfsm_srvdone; +} + +/* + * nfs fsinfo service + */ +int +nfsrv_fsinfo(nfsd, slp, procp, mrq) + struct nfsrv_descript *nfsd; + struct nfssvc_sock *slp; + struct proc *procp; + struct mbuf **mrq; +{ + struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; + struct mbuf *nam = nfsd->nd_nam; + caddr_t dpos = nfsd->nd_dpos; + struct ucred *cred = &nfsd->nd_cr; + register u_long *tl; + register struct nfsv3_fsinfo *sip; + register long t1; + caddr_t bpos; + int error = 0, rdonly, cache, getret = 1, pref; + char *cp2; + struct mbuf *mb, *mb2, *mreq; + struct vnode *vp; + struct vattr at; + nfsfh_t nfh; + fhandle_t *fhp; + u_quad_t frev; + +#ifndef nolint + cache = 0; +#endif + fhp = &nfh.fh_generic; + nfsm_srvmtofh(fhp); + if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, + &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { + nfsm_reply(NFSX_UNSIGNED); + nfsm_srvpostop_attr(getret, &at); + return (0); + } + getret = VOP_GETATTR(vp, &at, cred, procp); vput(vp); - nfsm_reply(NFSX_STATFS(isnq)); - nfsm_build(sfp, struct nfsv2_statfs *, NFSX_STATFS(isnq)); - sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA); - sfp->sf_bsize = txdr_unsigned(sf->f_bsize); - sfp->sf_blocks = txdr_unsigned(sf->f_blocks); - sfp->sf_bfree = txdr_unsigned(sf->f_bfree); - sfp->sf_bavail = txdr_unsigned(sf->f_bavail); - if (isnq) { - sfp->sf_files = txdr_unsigned(sf->f_files); - sfp->sf_ffree = txdr_unsigned(sf->f_ffree); + nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3FSINFO); + nfsm_srvpostop_attr(getret, &at); + nfsm_build(sip, struct nfsv3_fsinfo *, NFSX_V3FSINFO); + + /* + * XXX + * There should be file system VFS OP(s) to get this information. + * For now, assume ufs. + */ + if (slp->ns_so->so_type == SOCK_DGRAM) + pref = NFS_MAXDGRAMDATA; + else + pref = NFS_MAXDATA; + sip->fs_rtmax = txdr_unsigned(NFS_MAXDATA); + sip->fs_rtpref = txdr_unsigned(pref); + sip->fs_rtmult = txdr_unsigned(NFS_FABLKSIZE); + sip->fs_wtmax = txdr_unsigned(NFS_MAXDATA); + sip->fs_wtpref = txdr_unsigned(pref); + sip->fs_wtmult = txdr_unsigned(NFS_FABLKSIZE); + sip->fs_dtpref = txdr_unsigned(pref); + sip->fs_maxfilesize.nfsuquad[0] = 0xffffffff; + sip->fs_maxfilesize.nfsuquad[1] = 0xffffffff; + sip->fs_timedelta.nfsv3_sec = 0; + sip->fs_timedelta.nfsv3_nsec = txdr_unsigned(1); + sip->fs_properties = txdr_unsigned(NFSV3FSINFO_LINK | + NFSV3FSINFO_SYMLINK | NFSV3FSINFO_HOMOGENEOUS | + NFSV3FSINFO_CANSETTIME); + nfsm_srvdone; +} + +/* + * nfs pathconf service + */ +int +nfsrv_pathconf(nfsd, slp, procp, mrq) + struct nfsrv_descript *nfsd; + struct nfssvc_sock *slp; + struct proc *procp; + struct mbuf **mrq; +{ + struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; + struct mbuf *nam = nfsd->nd_nam; + caddr_t dpos = nfsd->nd_dpos; + struct ucred *cred = &nfsd->nd_cr; + register u_long *tl; + register struct nfsv3_pathconf *pc; + register long t1; + caddr_t bpos; + int error = 0, rdonly, cache, getret = 1, linkmax, namemax; + int chownres, notrunc; + char *cp2; + struct mbuf *mb, *mb2, *mreq; + struct vnode *vp; + struct vattr at; + nfsfh_t nfh; + fhandle_t *fhp; + u_quad_t frev; + +#ifndef nolint + cache = 0; +#endif + fhp = &nfh.fh_generic; + nfsm_srvmtofh(fhp); + if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, + &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { + nfsm_reply(NFSX_UNSIGNED); + nfsm_srvpostop_attr(getret, &at); + return (0); } + error = VOP_PATHCONF(vp, _PC_LINK_MAX, &linkmax); + if (!error) + error = VOP_PATHCONF(vp, _PC_NAME_MAX, &namemax); + if (!error) + error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &chownres); + if (!error) + error = VOP_PATHCONF(vp, _PC_NO_TRUNC, ¬runc); + getret = VOP_GETATTR(vp, &at, cred, procp); + vput(vp); + nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3PATHCONF); + nfsm_srvpostop_attr(getret, &at); + if (error) + return (0); + nfsm_build(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF); + + pc->pc_linkmax = txdr_unsigned(linkmax); + pc->pc_namemax = txdr_unsigned(namemax); + pc->pc_notrunc = txdr_unsigned(notrunc); + pc->pc_chownrestricted = txdr_unsigned(chownres); + + /* + * These should probably be supported by VOP_PATHCONF(), but + * until msdosfs is exportable (why would you want to?), the + * Unix defaults should be ok. + */ + pc->pc_caseinsensitive = nfs_false; + pc->pc_casepreserving = nfs_true; nfsm_srvdone; } @@ -1819,44 +3233,58 @@ nfsrv_statfs(nfsd, mrep, md, dpos, cred, nam, mrq) * Null operation, used by clients to ping server */ /* ARGSUSED */ -nfsrv_null(nfsd, mrep, md, dpos, cred, nam, mrq) - struct nfsd *nfsd; - struct mbuf *mrep, *md; - caddr_t dpos; - struct ucred *cred; - struct mbuf *nam, **mrq; +int +nfsrv_null(nfsd, slp, procp, mrq) + struct nfsrv_descript *nfsd; + struct nfssvc_sock *slp; + struct proc *procp; + struct mbuf **mrq; { + struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; + struct mbuf *nam = nfsd->nd_nam; + caddr_t dpos = nfsd->nd_dpos; + struct ucred *cred = &nfsd->nd_cr; caddr_t bpos; - int error = VNOVAL, cache; + int error = NFSERR_RETVOID, cache; struct mbuf *mb, *mreq; u_quad_t frev; +#ifndef nolint + cache = 0; +#endif nfsm_reply(0); - return (error); + return (0); } /* * No operation, used for obsolete procedures */ /* ARGSUSED */ -nfsrv_noop(nfsd, mrep, md, dpos, cred, nam, mrq) - struct nfsd *nfsd; - struct mbuf *mrep, *md; - caddr_t dpos; - struct ucred *cred; - struct mbuf *nam, **mrq; +int +nfsrv_noop(nfsd, slp, procp, mrq) + struct nfsrv_descript *nfsd; + struct nfssvc_sock *slp; + struct proc *procp; + struct mbuf **mrq; { + struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; + struct mbuf *nam = nfsd->nd_nam; + caddr_t dpos = nfsd->nd_dpos; + struct ucred *cred = &nfsd->nd_cr; caddr_t bpos; int error, cache; struct mbuf *mb, *mreq; u_quad_t frev; +#ifndef nolint + cache = 0; +#endif if (nfsd->nd_repstat) error = nfsd->nd_repstat; else error = EPROCUNAVAIL; nfsm_reply(0); - return (error); + return (0); } /* @@ -1869,6 +3297,7 @@ nfsrv_noop(nfsd, mrep, md, dpos, cred, nam, mrq) * this because it opens a security hole, but since the nfs server opens * a security hole the size of a barn door anyhow, what the heck. */ +int nfsrv_access(vp, flags, cred, rdonly, p) register struct vnode *vp; int flags; diff --git a/sys/nfs/nfs_socket.c b/sys/nfs/nfs_socket.c index cf88ed3..4326da0 100644 --- a/sys/nfs/nfs_socket.c +++ b/sys/nfs/nfs_socket.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1989, 1991, 1993 + * Copyright (c) 1989, 1991, 1993, 1995 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -33,7 +33,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfs_socket.c 8.3 (Berkeley) 1/12/94 + * @(#)nfs_socket.c 8.5 (Berkeley) 3/30/95 */ /* @@ -56,8 +56,9 @@ #include #include + #include -#include +#include #include #include #include @@ -92,36 +93,13 @@ * External data, mostly RPC constants in XDR form */ extern u_long rpc_reply, rpc_msgdenied, rpc_mismatch, rpc_vers, rpc_auth_unix, - rpc_msgaccepted, rpc_call, rpc_autherr, rpc_rejectedcred, + rpc_msgaccepted, rpc_call, rpc_autherr, rpc_auth_kerb; -extern u_long nfs_prog, nfs_vers, nqnfs_prog, nqnfs_vers; +extern u_long nfs_prog, nqnfs_prog; extern time_t nqnfsstarttime; -extern int nonidempotent[NFS_NPROCS]; - -/* - * Maps errno values to nfs error numbers. - * Use NFSERR_IO as the catch all for ones not specifically defined in - * RFC 1094. - */ -static int nfsrv_errmap[ELAST] = { - NFSERR_PERM, NFSERR_NOENT, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_NXIO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_IO, NFSERR_IO, NFSERR_ACCES, NFSERR_IO, NFSERR_IO, - NFSERR_IO, NFSERR_EXIST, NFSERR_IO, NFSERR_NODEV, NFSERR_NOTDIR, - NFSERR_ISDIR, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_IO, NFSERR_FBIG, NFSERR_NOSPC, NFSERR_IO, NFSERR_ROFS, - NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_IO, NFSERR_IO, NFSERR_NAMETOL, NFSERR_IO, NFSERR_IO, - NFSERR_NOTEMPTY, NFSERR_IO, NFSERR_IO, NFSERR_DQUOT, NFSERR_STALE, - NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_IO, -}; +extern struct nfsstats nfsstats; +extern int nfsv3_procid[NFS_NPROCS]; +extern int nfs_ticks; /* * Defines which timer to use for the procnum. @@ -132,7 +110,8 @@ static int nfsrv_errmap[ELAST] = { * 4 - write */ static int proct[NFS_NPROCS] = { - 0, 1, 0, 0, 2, 3, 3, 0, 4, 0, 0, 0, 0, 0, 0, 0, 3, 0, 3, 0, 0, 0, 0, + 0, 1, 0, 2, 1, 3, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, + 0, 0, 0, }; /* @@ -157,16 +136,17 @@ void nfs_rcvunlock(), nqnfs_serverd(), nqnfs_clientlease(); struct mbuf *nfsm_rpchead(); int nfsrtton = 0; struct nfsrtt nfsrtt; -struct nfsd nfsd_head; int nfsrv_null(), nfsrv_getattr(), nfsrv_setattr(), nfsrv_lookup(), + nfsrv3_access(), nfsrv_readlink(), nfsrv_read(), nfsrv_write(), nfsrv_create(), + nfsrv_mknod(), nfsrv_remove(), nfsrv_rename(), nfsrv_link(), @@ -174,45 +154,49 @@ int nfsrv_null(), nfsrv_mkdir(), nfsrv_rmdir(), nfsrv_readdir(), + nfsrv_readdirplus(), nfsrv_statfs(), + nfsrv_fsinfo(), + nfsrv_pathconf(), + nfsrv_commit(), nfsrv_noop(), - nqnfsrv_readdirlook(), nqnfsrv_getlease(), - nqnfsrv_vacated(), - nqnfsrv_access(); + nqnfsrv_vacated(); -int (*nfsrv_procs[NFS_NPROCS])() = { +int (*nfsrv3_procs[NFS_NPROCS])() = { nfsrv_null, nfsrv_getattr, nfsrv_setattr, - nfsrv_noop, nfsrv_lookup, + nfsrv3_access, nfsrv_readlink, nfsrv_read, - nfsrv_noop, nfsrv_write, nfsrv_create, + nfsrv_mkdir, + nfsrv_symlink, + nfsrv_mknod, nfsrv_remove, + nfsrv_rmdir, nfsrv_rename, nfsrv_link, - nfsrv_symlink, - nfsrv_mkdir, - nfsrv_rmdir, nfsrv_readdir, + nfsrv_readdirplus, nfsrv_statfs, - nqnfsrv_readdirlook, + nfsrv_fsinfo, + nfsrv_pathconf, + nfsrv_commit, nqnfsrv_getlease, nqnfsrv_vacated, nfsrv_noop, - nqnfsrv_access, + nfsrv_noop }; -struct nfsreq nfsreqh; - /* * Initialize sockets and congestion for a new NFS connection. * We do not free the sockaddr if error. */ +int nfs_connect(nmp, rep) register struct nfsmount *nmp; struct nfsreq *rep; @@ -226,8 +210,9 @@ nfs_connect(nmp, rep) nmp->nm_so = (struct socket *)0; saddr = mtod(nmp->nm_nam, struct sockaddr *); - if (error = socreate(saddr->sa_family, - &nmp->nm_so, nmp->nm_sotype, nmp->nm_soproto)) + error = socreate(saddr->sa_family, &nmp->nm_so, nmp->nm_sotype, + nmp->nm_soproto); + if (error) goto bad; so = nmp->nm_so; nmp->nm_soflags = so->so_proto->pr_flags; @@ -261,7 +246,8 @@ nfs_connect(nmp, rep) goto bad; } } else { - if (error = soconnect(so, nmp->nm_nam)) + error = soconnect(so, nmp->nm_nam); + if (error) goto bad; /* @@ -322,7 +308,8 @@ nfs_connect(nmp, rep) rcvreserve = (nmp->nm_rsize + NFS_MAXPKTHDR + sizeof (u_long)) * 2; } - if (error = soreserve(so, sndreserve, rcvreserve)) + error = soreserve(so, sndreserve, rcvreserve); + if (error) goto bad; so->so_rcv.sb_flags |= SB_NOINTR; so->so_snd.sb_flags |= SB_NOINTR; @@ -351,6 +338,7 @@ bad: * If this fails the mount point is DEAD! * nb: Must be called with the nfs_sndlock() set on the mount point. */ +int nfs_reconnect(rep) register struct nfsreq *rep; { @@ -359,7 +347,7 @@ nfs_reconnect(rep) int error; nfs_disconnect(nmp); - while (error = nfs_connect(nmp, rep)) { + while ((error = nfs_connect(nmp, rep))) { if (error == EINTR || error == ERESTART) return (EINTR); (void) tsleep((caddr_t)&lbolt, PSOCK, "nfscon", 0); @@ -369,11 +357,9 @@ nfs_reconnect(rep) * Loop through outstanding request list and fix up all requests * on old socket. */ - rp = nfsreqh.r_next; - while (rp != &nfsreqh) { + for (rp = nfs_reqq.tqh_first; rp != 0; rp = rp->r_chain.tqe_next) { if (rp->r_nmp == nmp) rp->r_flags |= R_MUSTRESEND; - rp = rp->r_next; } return (0); } @@ -408,6 +394,7 @@ nfs_disconnect(nmp) * - return EPIPE if a connection is lost for connection based sockets (TCP...) * - do any cleanup required by recoverable socket errors (???) */ +int nfs_send(so, nam, top, rep) register struct socket *so; struct mbuf *nam; @@ -475,6 +462,7 @@ nfs_send(so, nam, top, rep) * For SOCK_STREAM we must be very careful to read an entire record once * we have read any of it, even if the system call has been interrupted. */ +int nfs_receive(rep, aname, mp) register struct nfsreq *rep; struct mbuf **aname; @@ -506,7 +494,8 @@ nfs_receive(rep, aname, mp) * until we have an entire rpc request/reply. */ if (sotype != SOCK_DGRAM) { - if (error = nfs_sndlock(&rep->r_nmp->nm_flag, rep)) + error = nfs_sndlock(&rep->r_nmp->nm_flag, rep); + if (error) return (error); tryagain: /* @@ -522,8 +511,10 @@ tryagain: nfs_sndunlock(&rep->r_nmp->nm_flag); return (EINTR); } - if ((so = rep->r_nmp->nm_so) == NULL) { - if (error = nfs_reconnect(rep)) { + so = rep->r_nmp->nm_so; + if (!so) { + error = nfs_reconnect(rep); + if (error) { nfs_sndunlock(&rep->r_nmp->nm_flag); return (error); } @@ -532,7 +523,8 @@ tryagain: while (rep->r_flags & R_MUSTRESEND) { m = m_copym(rep->r_mreq, 0, M_COPYALL, M_WAIT); nfsstats.rpcretries++; - if (error = nfs_send(so, rep->r_nmp->nm_nam, m, rep)) { + error = nfs_send(so, rep->r_nmp->nm_nam, m, rep); + if (error) { if (error == EINTR || error == ERESTART || (error = nfs_reconnect(rep))) { nfs_sndunlock(&rep->r_nmp->nm_flag); @@ -681,6 +673,7 @@ errout: * with outstanding requests using the xid, until ours is found. */ /* ARGSUSED */ +int nfs_reply(myrep) struct nfsreq *myrep; { @@ -702,7 +695,8 @@ nfs_reply(myrep) * Also necessary for connection based protocols to avoid * race conditions during a reconnect. */ - if (error = nfs_rcvlock(myrep)) + error = nfs_rcvlock(myrep); + if (error) return (error); /* Already received, bye bye */ if (myrep->r_mrep != NULL) { @@ -755,8 +749,8 @@ nfsmout: * Loop through the request list to match up the reply * Iff no match, just drop the datagram */ - rep = nfsreqh.r_next; - while (rep != &nfsreqh) { + for (rep = nfs_reqq.tqh_first; rep != 0; + rep = rep->r_chain.tqe_next) { if (rep->r_mrep == NULL && rxid == rep->r_xid) { /* Found it.. */ rep->r_mrep = mrep; @@ -818,13 +812,12 @@ nfsmout: nmp->nm_timeouts = 0; break; } - rep = rep->r_next; } /* * If not matched to a request, drop it. * If it's mine, get out. */ - if (rep == &nfsreqh) { + if (rep == 0) { nfsstats.rpcunexpected++; m_freem(mrep); } else if (rep == myrep) { @@ -847,6 +840,7 @@ nfsmout: * by mrep or error * nb: always frees up mreq mbuf list */ +int nfs_request(vp, mrest, procnum, procp, cred, mrp, mdp, dposp) struct vnode *vp; struct mbuf *mrest; @@ -863,15 +857,17 @@ nfs_request(vp, mrest, procnum, procp, cred, mrp, mdp, dposp) register int i; struct nfsmount *nmp; struct mbuf *md, *mheadend; - struct nfsreq *reph; struct nfsnode *np; + char nickv[RPCX_NICKVERF]; time_t reqtime, waituntil; caddr_t dpos, cp2; int t1, nqlflag, cachable, s, error = 0, mrest_len, auth_len, auth_type; int trylater_delay = NQ_TRYLATERDEL, trylater_cnt = 0, failed_auth = 0; + int verf_len, verf_type; u_long xid; u_quad_t frev; - char *auth_str; + char *auth_str, *verf_str; + NFSKERBKEY_T key; /* save session key */ nmp = VFSTONFS(vp->v_mount); MALLOC(rep, struct nfsreq *, sizeof(struct nfsreq), M_NFSREQ, M_WAITOK); @@ -891,19 +887,21 @@ nfs_request(vp, mrest, procnum, procp, cred, mrp, mdp, dposp) * Get the RPC header with authorization. */ kerbauth: - auth_str = (char *)0; + verf_str = auth_str = (char *)0; if (nmp->nm_flag & NFSMNT_KERB) { - if (failed_auth) { - error = nfs_getauth(nmp, rep, cred, &auth_type, - &auth_str, &auth_len); + verf_str = nickv; + verf_len = sizeof (nickv); + auth_type = RPCAUTH_KERB4; + bzero((caddr_t)key, sizeof (key)); + if (failed_auth || nfs_getnickauth(nmp, cred, &auth_str, + &auth_len, verf_str, verf_len)) { + error = nfs_getauth(nmp, rep, cred, &auth_str, + &auth_len, verf_str, &verf_len, key); if (error) { free((caddr_t)rep, M_NFSREQ); m_freem(mrest); return (error); } - } else { - auth_type = RPCAUTH_UNIX; - auth_len = 5 * NFSX_UNSIGNED; } } else { auth_type = RPCAUTH_UNIX; @@ -913,8 +911,8 @@ kerbauth: nmp->nm_numgrps : (cred->cr_ngroups - 1)) << 2) + 5 * NFSX_UNSIGNED; } - m = nfsm_rpchead(cred, (nmp->nm_flag & NFSMNT_NQNFS), procnum, - auth_type, auth_len, auth_str, mrest, mrest_len, &mheadend, &xid); + m = nfsm_rpchead(cred, nmp->nm_flag, procnum, auth_type, auth_len, + auth_str, verf_len, verf_str, mrest, mrest_len, &mheadend, &xid); if (auth_str) free(auth_str, M_TEMP); @@ -949,11 +947,7 @@ tryagain: * to put it LAST so timer finds oldest requests first. */ s = splsoftclock(); - reph = &nfsreqh; - reph->r_prev->r_next = rep; - rep->r_prev = reph->r_prev; - reph->r_prev = rep; - rep->r_next = reph; + TAILQ_INSERT_TAIL(&nfs_reqq, rep, r_chain); /* Get send time for nqnfs */ reqtime = time.tv_sec; @@ -994,8 +988,7 @@ tryagain: * RPC done, unlink the request. */ s = splsoftclock(); - rep->r_prev->r_next = rep->r_next; - rep->r_next->r_prev = rep->r_prev; + TAILQ_REMOVE(&nfs_reqq, rep, r_chain); splx(s); /* @@ -1025,12 +1018,12 @@ tryagain: /* * break down the rpc header and check if ok */ - nfsm_dissect(tl, u_long *, 3*NFSX_UNSIGNED); + nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED); if (*tl++ == rpc_msgdenied) { if (*tl == rpc_mismatch) error = EOPNOTSUPP; else if ((nmp->nm_flag & NFSMNT_KERB) && *tl++ == rpc_autherr) { - if (*tl == rpc_rejectedcred && failed_auth == 0) { + if (!failed_auth) { failed_auth++; mheadend->m_next = (struct mbuf *)0; m_freem(mrep); @@ -1047,22 +1040,25 @@ tryagain: } /* - * skip over the auth_verf, someday we may want to cache auth_short's - * for nfs_reqhead(), but for now just dump it + * Grab any Kerberos verifier, otherwise just throw it away. */ - if (*++tl != 0) { - i = nfsm_rndup(fxdr_unsigned(long, *tl)); - nfsm_adv(i); - } + verf_type = fxdr_unsigned(int, *tl++); + i = fxdr_unsigned(int, *tl); + if ((nmp->nm_flag & NFSMNT_KERB) && verf_type == RPCAUTH_KERB4) { + error = nfs_savenickauth(nmp, cred, i, key, &md, &dpos, mrep); + if (error) + goto nfsmout; + } else if (i > 0) + nfsm_adv(nfsm_rndup(i)); nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); /* 0 == ok */ if (*tl == 0) { nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); if (*tl != 0) { error = fxdr_unsigned(int, *tl); - m_freem(mrep); - if ((nmp->nm_flag & NFSMNT_NQNFS) && - error == NQNFS_TRYLATER) { + if ((nmp->nm_flag & NFSMNT_NFSV3) && + error == NFSERR_TRYLATER) { + m_freem(mrep); error = 0; waituntil = time.tv_sec + trylater_delay; while (time.tv_sec < waituntil) @@ -1080,6 +1076,13 @@ tryagain: */ if (error == ESTALE) cache_purge(vp); + if (nmp->nm_flag & NFSMNT_NFSV3) { + *mrp = mrep; + *mdp = md; + *dposp = dpos; + error |= NFSERR_RETERR; + } else + m_freem(mrep); m_freem(rep->r_mreq); free((caddr_t)rep, M_NFSREQ); return (error); @@ -1111,10 +1114,10 @@ tryagain: return (0); } m_freem(mrep); - m_freem(rep->r_mreq); - free((caddr_t)rep, M_NFSREQ); error = EPROTONOSUPPORT; nfsmout: + m_freem(rep->r_mreq); + free((caddr_t)rep, M_NFSREQ); return (error); } @@ -1122,9 +1125,11 @@ nfsmout: * Generate the rpc reply header * siz arg. is used to decide if adding a cluster is worthwhile */ -nfs_rephead(siz, nd, err, cache, frev, mrq, mbp, bposp) +int +nfs_rephead(siz, nd, slp, err, cache, frev, mrq, mbp, bposp) int siz; - struct nfsd *nd; + struct nfsrv_descript *nd; + struct nfssvc_sock *slp; int err; int cache; u_quad_t *frev; @@ -1149,47 +1154,98 @@ nfs_rephead(siz, nd, err, cache, frev, mrq, mbp, bposp) } else mreq->m_data += max_hdr; tl = mtod(mreq, u_long *); - mreq->m_len = 6*NFSX_UNSIGNED; - bpos = ((caddr_t)tl)+mreq->m_len; - *tl++ = nd->nd_retxid; + mreq->m_len = 6 * NFSX_UNSIGNED; + bpos = ((caddr_t)tl) + mreq->m_len; + *tl++ = txdr_unsigned(nd->nd_retxid); *tl++ = rpc_reply; - if (err == ERPCMISMATCH || err == NQNFS_AUTHERR) { + if (err == ERPCMISMATCH || (err & NFSERR_AUTHERR)) { *tl++ = rpc_msgdenied; - if (err == NQNFS_AUTHERR) { + if (err & NFSERR_AUTHERR) { *tl++ = rpc_autherr; - *tl = rpc_rejectedcred; + *tl = txdr_unsigned(err & ~NFSERR_AUTHERR); mreq->m_len -= NFSX_UNSIGNED; bpos -= NFSX_UNSIGNED; } else { *tl++ = rpc_mismatch; - *tl++ = txdr_unsigned(2); - *tl = txdr_unsigned(2); + *tl++ = txdr_unsigned(RPC_VER2); + *tl = txdr_unsigned(RPC_VER2); } } else { *tl++ = rpc_msgaccepted; - *tl++ = 0; - *tl++ = 0; + + /* + * For Kerberos authentication, we must send the nickname + * verifier back, otherwise just RPCAUTH_NULL. + */ + if (nd->nd_flag & ND_KERBFULL) { + register struct nfsuid *nuidp; + struct timeval ktvin, ktvout; + NFSKERBKEYSCHED_T keys; /* stores key schedule */ + + for (nuidp = NUIDHASH(slp, nd->nd_cr.cr_uid)->lh_first; + nuidp != 0; nuidp = nuidp->nu_hash.le_next) { + if (nuidp->nu_cr.cr_uid == nd->nd_cr.cr_uid && + (!nd->nd_nam2 || netaddr_match(NU_NETFAM(nuidp), + &nuidp->nu_haddr, nd->nd_nam2))) + break; + } + if (nuidp) { + ktvin.tv_sec = + txdr_unsigned(nuidp->nu_timestamp.tv_sec - 1); + ktvin.tv_usec = + txdr_unsigned(nuidp->nu_timestamp.tv_usec); + + /* + * Encrypt the timestamp in ecb mode using the + * session key. + */ +#ifdef NFSKERB + XXX +#endif + + *tl++ = rpc_auth_kerb; + *tl++ = txdr_unsigned(3 * NFSX_UNSIGNED); + *tl = ktvout.tv_sec; + nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED); + *tl++ = ktvout.tv_usec; + *tl++ = txdr_unsigned(nuidp->nu_cr.cr_uid); + } else { + *tl++ = 0; + *tl++ = 0; + } + } else { + *tl++ = 0; + *tl++ = 0; + } switch (err) { case EPROGUNAVAIL: *tl = txdr_unsigned(RPC_PROGUNAVAIL); break; case EPROGMISMATCH: *tl = txdr_unsigned(RPC_PROGMISMATCH); - nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); - *tl++ = txdr_unsigned(2); - *tl = txdr_unsigned(2); /* someday 3 */ + nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED); + if (nd->nd_flag & ND_NQNFS) { + *tl++ = txdr_unsigned(3); + *tl = txdr_unsigned(3); + } else { + *tl++ = txdr_unsigned(2); + *tl = txdr_unsigned(3); + } break; case EPROCUNAVAIL: *tl = txdr_unsigned(RPC_PROCUNAVAIL); break; + case EBADRPC: + *tl = txdr_unsigned(RPC_GARBAGE); + break; default: *tl = 0; - if (err != VNOVAL) { + if (err != NFSERR_RETVOID) { nfsm_build(tl, u_long *, NFSX_UNSIGNED); if (err) - *tl = txdr_unsigned(nfsrv_errmap[err - 1]); + *tl = txdr_unsigned(nfsrv_errmap(nd, err)); else - *tl = 0; + *tl = 0; } break; }; @@ -1198,16 +1254,14 @@ nfs_rephead(siz, nd, err, cache, frev, mrq, mbp, bposp) /* * For nqnfs, piggyback lease as requested. */ - if (nd->nd_nqlflag != NQL_NOVAL && err == 0) { - if (nd->nd_nqlflag) { - nfsm_build(tl, u_long *, 5*NFSX_UNSIGNED); - *tl++ = txdr_unsigned(nd->nd_nqlflag); + if ((nd->nd_flag & ND_NQNFS) && err == 0) { + if (nd->nd_flag & ND_LEASE) { + nfsm_build(tl, u_long *, 5 * NFSX_UNSIGNED); + *tl++ = txdr_unsigned(nd->nd_flag & ND_LEASE); *tl++ = txdr_unsigned(cache); *tl++ = txdr_unsigned(nd->nd_duration); txdr_hyper(frev, tl); } else { - if (nd->nd_nqlflag != 0) - panic("nqreph"); nfsm_build(tl, u_long *, NFSX_UNSIGNED); *tl = 0; } @@ -1215,7 +1269,7 @@ nfs_rephead(siz, nd, err, cache, frev, mrq, mbp, bposp) *mrq = mreq; *mbp = mb; *bposp = bpos; - if (err != 0 && err != VNOVAL) + if (err != 0 && err != NFSERR_RETVOID) nfsstats.srvrpc_errs++; return (0); } @@ -1228,18 +1282,20 @@ nfs_rephead(siz, nd, err, cache, frev, mrq, mbp, bposp) */ void nfs_timer(arg) - void *arg; + void *arg; /* never used */ { register struct nfsreq *rep; register struct mbuf *m; register struct socket *so; register struct nfsmount *nmp; register int timeo; + register struct nfssvc_sock *slp; static long lasttime = 0; int s, error; + u_quad_t cur_usec; s = splnet(); - for (rep = nfsreqh.r_next; rep != &nfsreqh; rep = rep->r_next) { + for (rep = nfs_reqq.tqh_first; rep != 0; rep = rep->r_chain.tqe_next) { nmp = rep->r_nmp; if (rep->r_mrep || (rep->r_flags & R_SOFTTERM)) continue; @@ -1333,14 +1389,26 @@ nfs_timer(arg) lasttime = time.tv_sec; nqnfs_serverd(); } + + /* + * Scan the write gathering queues for writes that need to be + * completed now. + */ + cur_usec = (u_quad_t)time.tv_sec * 1000000 + (u_quad_t)time.tv_usec; + for (slp = nfssvc_sockhead.tqh_first; slp != 0; + slp = slp->ns_chain.tqe_next) { + if (slp->ns_tq.lh_first && slp->ns_tq.lh_first->nd_time<=cur_usec) + nfsrv_wakenfsd(slp); + } splx(s); - timeout(nfs_timer, (void *)0, hz / NFS_HZ); + timeout(nfs_timer, (void *)0, nfs_ticks); } /* * Test for a termination condition pending on the process. * This is used for NFSMNT_INT mounts. */ +int nfs_sigintr(nmp, rep, p) struct nfsmount *nmp; struct nfsreq *rep; @@ -1364,6 +1432,7 @@ nfs_sigintr(nmp, rep, p) * and also to avoid race conditions between the processes with nfs requests * in progress when a reconnect is necessary. */ +int nfs_sndlock(flagp, rep) register int *flagp; struct nfsreq *rep; @@ -1409,6 +1478,7 @@ nfs_sndunlock(flagp) } } +int nfs_rcvlock(rep) register struct nfsreq *rep; { @@ -1609,7 +1679,8 @@ nfsrv_rcv(so, arg, waitflag) /* * Now try and parse record(s) out of the raw stream data. */ - if (error = nfsrv_getstream(slp, waitflag)) { + error = nfsrv_getstream(slp, waitflag); + if (error) { if (error == EPERM) slp->ns_flag |= SLP_DISCONN; else @@ -1659,14 +1730,15 @@ dorecs: * stream socket. The "waitflag" argument indicates whether or not it * can sleep. */ +int nfsrv_getstream(slp, waitflag) register struct nfssvc_sock *slp; int waitflag; { - register struct mbuf *m; + register struct mbuf *m, **mpp; register char *cp1, *cp2; register int len; - struct mbuf *om, *m2, *recm; + struct mbuf *om, *m2, *recm = 0; u_long recmark; if (slp->ns_flag & SLP_GETSTREAM) @@ -1697,7 +1769,12 @@ nfsrv_getstream(slp, waitflag) } } slp->ns_cc -= NFSX_UNSIGNED; - slp->ns_reclen = ntohl(recmark) & ~0x80000000; + recmark = ntohl(recmark); + slp->ns_reclen = recmark & ~0x80000000; + if (recmark & 0x80000000) + slp->ns_flag |= SLP_LASTFRAG; + else + slp->ns_flag &= ~SLP_LASTFRAG; if (slp->ns_reclen < NFS_MINPACKET || slp->ns_reclen > NFS_MAXPACKET) { slp->ns_flag &= ~SLP_GETSTREAM; return (EPERM); @@ -1751,45 +1828,67 @@ nfsrv_getstream(slp, waitflag) slp->ns_flag &= ~SLP_GETSTREAM; return (0); } - nfs_realign(recm, 10 * NFSX_UNSIGNED); - if (slp->ns_recend) - slp->ns_recend->m_nextpkt = recm; - else - slp->ns_rec = recm; - slp->ns_recend = recm; + + /* + * Accumulate the fragments into a record. + */ + mpp = &slp->ns_frag; + while (*mpp) + mpp = &((*mpp)->m_next); + *mpp = recm; + if (slp->ns_flag & SLP_LASTFRAG) { + nfs_realign(slp->ns_frag, 10 * NFSX_UNSIGNED); + if (slp->ns_recend) + slp->ns_recend->m_nextpkt = slp->ns_frag; + else + slp->ns_rec = slp->ns_frag; + slp->ns_recend = slp->ns_frag; + slp->ns_frag = (struct mbuf *)0; + } } } /* * Parse an RPC header. */ -nfsrv_dorec(slp, nd) +int +nfsrv_dorec(slp, nfsd, ndp) register struct nfssvc_sock *slp; - register struct nfsd *nd; + struct nfsd *nfsd; + struct nfsrv_descript **ndp; { - register struct mbuf *m; + register struct mbuf *m, *nam; + register struct nfsrv_descript *nd; int error; + *ndp = NULL; if ((slp->ns_flag & SLP_VALID) == 0 || (m = slp->ns_rec) == (struct mbuf *)0) return (ENOBUFS); - if (slp->ns_rec = m->m_nextpkt) + slp->ns_rec = m->m_nextpkt; + if (slp->ns_rec) m->m_nextpkt = (struct mbuf *)0; else slp->ns_recend = (struct mbuf *)0; if (m->m_type == MT_SONAME) { - nd->nd_nam = m; - nd->nd_md = nd->nd_mrep = m->m_next; - m->m_next = (struct mbuf *)0; - } else { - nd->nd_nam = (struct mbuf *)0; - nd->nd_md = nd->nd_mrep = m; - } - nd->nd_dpos = mtod(nd->nd_md, caddr_t); - if (error = nfs_getreq(nd, TRUE)) { - m_freem(nd->nd_nam); + nam = m; + m = m->m_next; + nam->m_next = NULL; + } else + nam = NULL; + MALLOC(nd, struct nfsrv_descript *, sizeof (struct nfsrv_descript), + M_NFSRVDESC, M_WAITOK); + nd->nd_md = nd->nd_mrep = m; + nd->nd_nam2 = nam; + nd->nd_dpos = mtod(m, caddr_t); + error = nfs_getreq(nd, nfsd, TRUE); + if (error) { + m_freem(nam); + free((caddr_t)nd, M_NFSRVDESC); return (error); } + *ndp = nd; + nfsd->nfsd_nd = nd; return (0); } @@ -1798,8 +1897,10 @@ nfsrv_dorec(slp, nd) * - verify it * - fill in the cred struct. */ -nfs_getreq(nd, has_header) - register struct nfsd *nd; +int +nfs_getreq(nd, nfsd, has_header) + register struct nfsrv_descript *nd; + struct nfsd *nfsd; int has_header; { register int len, i; @@ -1807,57 +1908,67 @@ nfs_getreq(nd, has_header) register long t1; struct uio uio; struct iovec iov; - caddr_t dpos, cp2; + caddr_t dpos, cp2, cp; u_long nfsvers, auth_type; - int error = 0, nqnfs = 0; + uid_t nickuid; + int error = 0, nqnfs = 0, ticklen; struct mbuf *mrep, *md; + register struct nfsuid *nuidp; + struct timeval tvin, tvout; + NFSKERBKEYSCHED_T keys; /* stores key schedule */ mrep = nd->nd_mrep; md = nd->nd_md; dpos = nd->nd_dpos; if (has_header) { - nfsm_dissect(tl, u_long *, 10*NFSX_UNSIGNED); - nd->nd_retxid = *tl++; + nfsm_dissect(tl, u_long *, 10 * NFSX_UNSIGNED); + nd->nd_retxid = fxdr_unsigned(u_long, *tl++); if (*tl++ != rpc_call) { m_freem(mrep); return (EBADRPC); } - } else { - nfsm_dissect(tl, u_long *, 8*NFSX_UNSIGNED); - } + } else + nfsm_dissect(tl, u_long *, 8 * NFSX_UNSIGNED); nd->nd_repstat = 0; + nd->nd_flag = 0; if (*tl++ != rpc_vers) { nd->nd_repstat = ERPCMISMATCH; nd->nd_procnum = NFSPROC_NOOP; return (0); } - nfsvers = nfs_vers; if (*tl != nfs_prog) { - if (*tl == nqnfs_prog) { + if (*tl == nqnfs_prog) nqnfs++; - nfsvers = nqnfs_vers; - } else { + else { nd->nd_repstat = EPROGUNAVAIL; nd->nd_procnum = NFSPROC_NOOP; return (0); } } tl++; - if (*tl++ != nfsvers) { + nfsvers = fxdr_unsigned(u_long, *tl++); + if (((nfsvers < NFS_VER2 || nfsvers > NFS_VER3) && !nqnfs) || + (nfsvers != NQNFS_VER3 && nqnfs)) { nd->nd_repstat = EPROGMISMATCH; nd->nd_procnum = NFSPROC_NOOP; return (0); } + if (nqnfs) + nd->nd_flag = (ND_NFSV3 | ND_NQNFS); + else if (nfsvers == NFS_VER3) + nd->nd_flag = ND_NFSV3; nd->nd_procnum = fxdr_unsigned(u_long, *tl++); if (nd->nd_procnum == NFSPROC_NULL) return (0); if (nd->nd_procnum >= NFS_NPROCS || - (!nqnfs && nd->nd_procnum > NFSPROC_STATFS) || - (*tl != rpc_auth_unix && *tl != rpc_auth_kerb)) { + (!nqnfs && nd->nd_procnum >= NQNFSPROC_GETLEASE) || + (!nd->nd_flag && nd->nd_procnum > NFSV2PROC_STATFS)) { nd->nd_repstat = EPROCUNAVAIL; nd->nd_procnum = NFSPROC_NOOP; return (0); } + if ((nd->nd_flag & ND_NFSV3) == 0) + nd->nd_procnum = nfsv3_procid[nd->nd_procnum]; auth_type = *tl++; len = fxdr_unsigned(int, *tl++); if (len < 0 || len > RPCAUTH_MAXSIZ) { @@ -1865,6 +1976,7 @@ nfs_getreq(nd, has_header) return (EBADRPC); } + nd->nd_flag &= ~ND_KERBAUTH; /* * Handle auth_unix or auth_kerb. */ @@ -1875,7 +1987,9 @@ nfs_getreq(nd, has_header) return (EBADRPC); } nfsm_adv(nfsm_rndup(len)); - nfsm_dissect(tl, u_long *, 3*NFSX_UNSIGNED); + nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED); + bzero((caddr_t)&nd->nd_cr, sizeof (struct ucred)); + nd->nd_cr.cr_ref = 1; nd->nd_cr.cr_uid = fxdr_unsigned(uid_t, *tl++); nd->nd_cr.cr_gid = fxdr_unsigned(gid_t, *tl++); len = fxdr_unsigned(int, *tl); @@ -1883,45 +1997,124 @@ nfs_getreq(nd, has_header) m_freem(mrep); return (EBADRPC); } - nfsm_dissect(tl, u_long *, (len + 2)*NFSX_UNSIGNED); + nfsm_dissect(tl, u_long *, (len + 2) * NFSX_UNSIGNED); for (i = 1; i <= len; i++) - if (i < NGROUPS) - nd->nd_cr.cr_groups[i] = fxdr_unsigned(gid_t, *tl++); - else - tl++; + if (i < NGROUPS) + nd->nd_cr.cr_groups[i] = fxdr_unsigned(gid_t, *tl++); + else + tl++; nd->nd_cr.cr_ngroups = (len >= NGROUPS) ? NGROUPS : (len + 1); - } else if (auth_type == rpc_auth_kerb) { - nd->nd_cr.cr_uid = fxdr_unsigned(uid_t, *tl++); - nd->nd_authlen = fxdr_unsigned(int, *tl); - uio.uio_resid = nfsm_rndup(nd->nd_authlen); - if (uio.uio_resid > (len - 2 * NFSX_UNSIGNED)) { + if (nd->nd_cr.cr_ngroups > 1) + nfsrvw_sort(nd->nd_cr.cr_groups, nd->nd_cr.cr_ngroups); + len = fxdr_unsigned(int, *++tl); + if (len < 0 || len > RPCAUTH_MAXSIZ) { m_freem(mrep); return (EBADRPC); } - uio.uio_offset = 0; - uio.uio_iov = &iov; - uio.uio_iovcnt = 1; - uio.uio_segflg = UIO_SYSSPACE; - iov.iov_base = (caddr_t)nd->nd_authstr; - iov.iov_len = RPCAUTH_MAXSIZ; - nfsm_mtouio(&uio, uio.uio_resid); - nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); - nd->nd_flag |= NFSD_NEEDAUTH; - } + if (len > 0) + nfsm_adv(nfsm_rndup(len)); + } else if (auth_type == rpc_auth_kerb) { + switch (fxdr_unsigned(int, *tl++)) { + case RPCAKN_FULLNAME: + ticklen = fxdr_unsigned(int, *tl); + *((u_long *)nfsd->nfsd_authstr) = *tl; + uio.uio_resid = nfsm_rndup(ticklen) + NFSX_UNSIGNED; + nfsd->nfsd_authlen = uio.uio_resid + NFSX_UNSIGNED; + if (uio.uio_resid > (len - 2 * NFSX_UNSIGNED)) { + m_freem(mrep); + return (EBADRPC); + } + uio.uio_offset = 0; + uio.uio_iov = &iov; + uio.uio_iovcnt = 1; + uio.uio_segflg = UIO_SYSSPACE; + iov.iov_base = (caddr_t)&nfsd->nfsd_authstr[4]; + iov.iov_len = RPCAUTH_MAXSIZ - 4; + nfsm_mtouio(&uio, uio.uio_resid); + nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); + if (*tl++ != rpc_auth_kerb || + fxdr_unsigned(int, *tl) != 4 * NFSX_UNSIGNED) { + printf("Bad kerb verifier\n"); + nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADVERF); + nd->nd_procnum = NFSPROC_NOOP; + return (0); + } + nfsm_dissect(cp, caddr_t, 4 * NFSX_UNSIGNED); + tl = (u_long *)cp; + if (fxdr_unsigned(int, *tl) != RPCAKN_FULLNAME) { + printf("Not fullname kerb verifier\n"); + nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADVERF); + nd->nd_procnum = NFSPROC_NOOP; + return (0); + } + cp += NFSX_UNSIGNED; + bcopy(cp, nfsd->nfsd_verfstr, 3 * NFSX_UNSIGNED); + nfsd->nfsd_verflen = 3 * NFSX_UNSIGNED; + nd->nd_flag |= ND_KERBFULL; + nfsd->nfsd_flag |= NFSD_NEEDAUTH; + break; + case RPCAKN_NICKNAME: + if (len != 2 * NFSX_UNSIGNED) { + printf("Kerb nickname short\n"); + nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADCRED); + nd->nd_procnum = NFSPROC_NOOP; + return (0); + } + nickuid = fxdr_unsigned(uid_t, *tl); + nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); + if (*tl++ != rpc_auth_kerb || + fxdr_unsigned(int, *tl) != 3 * NFSX_UNSIGNED) { + printf("Kerb nick verifier bad\n"); + nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADVERF); + nd->nd_procnum = NFSPROC_NOOP; + return (0); + } + nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED); + tvin.tv_sec = *tl++; + tvin.tv_usec = *tl; + + for (nuidp = NUIDHASH(nfsd->nfsd_slp,nickuid)->lh_first; + nuidp != 0; nuidp = nuidp->nu_hash.le_next) { + if (nuidp->nu_cr.cr_uid == nickuid && + (!nd->nd_nam2 || + netaddr_match(NU_NETFAM(nuidp), + &nuidp->nu_haddr, nd->nd_nam2))) + break; + } + if (!nuidp) { + nd->nd_repstat = + (NFSERR_AUTHERR|AUTH_REJECTCRED); + nd->nd_procnum = NFSPROC_NOOP; + return (0); + } - /* - * Do we have any use for the verifier. - * According to the "Remote Procedure Call Protocol Spec." it - * should be AUTH_NULL, but some clients make it AUTH_UNIX? - * For now, just skip over it - */ - len = fxdr_unsigned(int, *++tl); - if (len < 0 || len > RPCAUTH_MAXSIZ) { - m_freem(mrep); - return (EBADRPC); - } - if (len > 0) { - nfsm_adv(nfsm_rndup(len)); + /* + * Now, decrypt the timestamp using the session key + * and validate it. + */ +#ifdef NFSKERB + XXX +#endif + + tvout.tv_sec = fxdr_unsigned(long, tvout.tv_sec); + tvout.tv_usec = fxdr_unsigned(long, tvout.tv_usec); + if (nuidp->nu_expire < time.tv_sec || + nuidp->nu_timestamp.tv_sec > tvout.tv_sec || + (nuidp->nu_timestamp.tv_sec == tvout.tv_sec && + nuidp->nu_timestamp.tv_usec > tvout.tv_usec)) { + nuidp->nu_expire = 0; + nd->nd_repstat = + (NFSERR_AUTHERR|AUTH_REJECTVERF); + nd->nd_procnum = NFSPROC_NOOP; + return (0); + } + nfsrv_setcred(&nuidp->nu_cr, &nd->nd_cr); + nd->nd_flag |= ND_KERBNICK; + }; + } else { + nd->nd_repstat = (NFSERR_AUTHERR | AUTH_REJECTCRED); + nd->nd_procnum = NFSPROC_NOOP; + return (0); } /* @@ -1929,16 +2122,14 @@ nfs_getreq(nd, has_header) */ if (nqnfs && nd->nd_procnum != NQNFSPROC_EVICTED) { nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); - nd->nd_nqlflag = fxdr_unsigned(int, *tl); - if (nd->nd_nqlflag) { + nd->nd_flag |= fxdr_unsigned(int, *tl); + if (nd->nd_flag & ND_LEASE) { nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); nd->nd_duration = fxdr_unsigned(int, *tl); } else nd->nd_duration = NQ_MINLEASE; - } else { - nd->nd_nqlflag = NQL_NOVAL; + } else nd->nd_duration = NQ_MINLEASE; - } nd->nd_md = md; nd->nd_dpos = dpos; return (0); @@ -1955,26 +2146,26 @@ void nfsrv_wakenfsd(slp) struct nfssvc_sock *slp; { - register struct nfsd *nd = nfsd_head.nd_next; + register struct nfsd *nd; if ((slp->ns_flag & SLP_VALID) == 0) return; - while (nd != (struct nfsd *)&nfsd_head) { - if (nd->nd_flag & NFSD_WAITING) { - nd->nd_flag &= ~NFSD_WAITING; - if (nd->nd_slp) + for (nd = nfsd_head.tqh_first; nd != 0; nd = nd->nfsd_chain.tqe_next) { + if (nd->nfsd_flag & NFSD_WAITING) { + nd->nfsd_flag &= ~NFSD_WAITING; + if (nd->nfsd_slp) panic("nfsd wakeup"); slp->ns_sref++; - nd->nd_slp = slp; + nd->nfsd_slp = slp; wakeup((caddr_t)nd); return; } - nd = nd->nd_next; } slp->ns_flag |= SLP_DOREC; - nfsd_head.nd_flag |= NFSD_CHECKSLP; + nfsd_head_flag |= NFSD_CHECKSLP; } +int nfs_msg(p, server, msg) struct proc *p; char *server, *msg; @@ -1987,4 +2178,5 @@ nfs_msg(p, server, msg) tpr = NULL; tprintf(tpr, "nfs server %s: %s\n", server, msg); tprintf_close(tpr); + return (0); } diff --git a/sys/nfs/nfs_srvcache.c b/sys/nfs/nfs_srvcache.c index 63d8bb7..954987b 100644 --- a/sys/nfs/nfs_srvcache.c +++ b/sys/nfs/nfs_srvcache.c @@ -33,7 +33,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfs_srvcache.c 8.1 (Berkeley) 6/10/93 + * @(#)nfs_srvcache.c 8.3 (Berkeley) 3/30/95 */ /* @@ -58,17 +58,20 @@ #endif #include #include -#include +#include #include #include #include +extern struct nfsstats nfsstats; +extern int nfsv2_procid[NFS_NPROCS]; long numnfsrvcache, desirednfsrvcache = NFSRVCACHESIZ; -#define NFSRCHASH(xid) (((xid) + ((xid) >> 24)) & rheadhash) -static struct nfsrvcache *nfsrvlruhead, **nfsrvlrutail = &nfsrvlruhead; -static struct nfsrvcache **rheadhtbl; -static u_long rheadhash; +#define NFSRCHASH(xid) \ + (&nfsrvhashtbl[((xid) + ((xid) >> 24)) & nfsrvhash]) +LIST_HEAD(nfsrvhash, nfsrvcache) *nfsrvhashtbl; +TAILQ_HEAD(nfsrvlru, nfsrvcache) nfsrvlruhead; +u_long nfsrvhash; #define TRUE 1 #define FALSE 0 @@ -87,7 +90,6 @@ int nonidempotent[NFS_NPROCS] = { FALSE, FALSE, FALSE, - FALSE, TRUE, TRUE, TRUE, @@ -96,6 +98,10 @@ int nonidempotent[NFS_NPROCS] = { TRUE, TRUE, TRUE, + TRUE, + FALSE, + FALSE, + FALSE, FALSE, FALSE, FALSE, @@ -106,7 +112,7 @@ int nonidempotent[NFS_NPROCS] = { }; /* True iff the rpc reply is an nfs status ONLY! */ -static int repliesstatus[NFS_NPROCS] = { +static int nfsv2_repstat[NFS_NPROCS] = { FALSE, FALSE, FALSE, @@ -125,20 +131,17 @@ static int repliesstatus[NFS_NPROCS] = { TRUE, FALSE, FALSE, - FALSE, - FALSE, - FALSE, - FALSE, - TRUE, }; /* * Initialize the server request cache list */ +void nfsrv_initcache() { - rheadhtbl = hashinit(desirednfsrvcache, M_NFSD, &rheadhash); + nfsrvhashtbl = hashinit(desirednfsrvcache, M_NFSD, &nfsrvhash); + TAILQ_INIT(&nfsrvlruhead); } /* @@ -155,24 +158,29 @@ nfsrv_initcache() * return DOIT * Update/add new request at end of lru list */ -nfsrv_getcache(nam, nd, repp) - struct mbuf *nam; - register struct nfsd *nd; +int +nfsrv_getcache(nd, slp, repp) + register struct nfsrv_descript *nd; + struct nfssvc_sock *slp; struct mbuf **repp; { - register struct nfsrvcache *rp, *rq, **rpp; + register struct nfsrvcache *rp; struct mbuf *mb; struct sockaddr_in *saddr; caddr_t bpos; int ret; - if (nd->nd_nqlflag != NQL_NOVAL) + /* + * Don't cache recent requests for reliable transport protocols. + * (Maybe we should for the case of a reconnect, but..) + */ + if (!nd->nd_nam2) return (RC_DOIT); - rpp = &rheadhtbl[NFSRCHASH(nd->nd_retxid)]; loop: - for (rp = *rpp; rp; rp = rp->rc_forw) { + for (rp = NFSRCHASH(nd->nd_retxid)->lh_first; rp != 0; + rp = rp->rc_hash.le_next) { if (nd->nd_retxid == rp->rc_xid && nd->nd_procnum == rp->rc_proc && - netaddr_match(NETFAMILY(rp), &rp->rc_haddr, nam)) { + netaddr_match(NETFAMILY(rp), &rp->rc_haddr, nd->nd_nam)) { if ((rp->rc_flag & RC_LOCKED) != 0) { rp->rc_flag |= RC_WANTED; (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0); @@ -180,15 +188,9 @@ loop: } rp->rc_flag |= RC_LOCKED; /* If not at end of LRU chain, move it there */ - if (rp->rc_next) { - /* remove from LRU chain */ - *rp->rc_prev = rp->rc_next; - rp->rc_next->rc_prev = rp->rc_prev; - /* and replace at end of it */ - rp->rc_next = NULL; - rp->rc_prev = nfsrvlrutail; - *nfsrvlrutail = rp; - nfsrvlrutail = &rp->rc_next; + if (rp->rc_lru.tqe_next) { + TAILQ_REMOVE(&nfsrvlruhead, rp, rc_lru); + TAILQ_INSERT_TAIL(&nfsrvlruhead, rp, rc_lru); } if (rp->rc_state == RC_UNUSED) panic("nfsrv cache"); @@ -197,7 +199,7 @@ loop: ret = RC_DROPIT; } else if (rp->rc_flag & RC_REPSTATUS) { nfsstats.srvcache_nonidemdonehits++; - nfs_rephead(0, nd, rp->rc_status, + nfs_rephead(0, nd, slp, rp->rc_status, 0, (u_quad_t *)0, repp, &mb, &bpos); ret = RC_REPLY; } else if (rp->rc_flag & RC_REPMBUF) { @@ -226,34 +228,25 @@ loop: numnfsrvcache++; rp->rc_flag = RC_LOCKED; } else { - rp = nfsrvlruhead; + rp = nfsrvlruhead.tqh_first; while ((rp->rc_flag & RC_LOCKED) != 0) { rp->rc_flag |= RC_WANTED; (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0); - rp = nfsrvlruhead; + rp = nfsrvlruhead.tqh_first; } rp->rc_flag |= RC_LOCKED; - /* remove from hash chain */ - if (rq = rp->rc_forw) - rq->rc_back = rp->rc_back; - *rp->rc_back = rq; - /* remove from LRU chain */ - *rp->rc_prev = rp->rc_next; - rp->rc_next->rc_prev = rp->rc_prev; + LIST_REMOVE(rp, rc_hash); + TAILQ_REMOVE(&nfsrvlruhead, rp, rc_lru); if (rp->rc_flag & RC_REPMBUF) m_freem(rp->rc_reply); if (rp->rc_flag & RC_NAM) MFREE(rp->rc_nam, mb); rp->rc_flag &= (RC_LOCKED | RC_WANTED); } - /* place at end of LRU list */ - rp->rc_next = NULL; - rp->rc_prev = nfsrvlrutail; - *nfsrvlrutail = rp; - nfsrvlrutail = &rp->rc_next; + TAILQ_INSERT_TAIL(&nfsrvlruhead, rp, rc_lru); rp->rc_state = RC_INPROG; rp->rc_xid = nd->nd_retxid; - saddr = mtod(nam, struct sockaddr_in *); + saddr = mtod(nd->nd_nam, struct sockaddr_in *); switch (saddr->sin_family) { case AF_INET: rp->rc_flag |= RC_INETADDR; @@ -262,16 +255,11 @@ loop: case AF_ISO: default: rp->rc_flag |= RC_NAM; - rp->rc_nam = m_copym(nam, 0, M_COPYALL, M_WAIT); + rp->rc_nam = m_copym(nd->nd_nam, 0, M_COPYALL, M_WAIT); break; }; rp->rc_proc = nd->nd_procnum; - /* insert into hash chain */ - if (rq = *rpp) - rq->rc_back = &rp->rc_forw; - rp->rc_forw = rq; - rp->rc_back = rpp; - *rpp = rp; + LIST_INSERT_HEAD(NFSRCHASH(nd->nd_retxid), rp, rc_hash); rp->rc_flag &= ~RC_LOCKED; if (rp->rc_flag & RC_WANTED) { rp->rc_flag &= ~RC_WANTED; @@ -284,20 +272,20 @@ loop: * Update a request cache entry after the rpc has been done */ void -nfsrv_updatecache(nam, nd, repvalid, repmbuf) - struct mbuf *nam; - register struct nfsd *nd; +nfsrv_updatecache(nd, repvalid, repmbuf) + register struct nfsrv_descript *nd; int repvalid; struct mbuf *repmbuf; { register struct nfsrvcache *rp; - if (nd->nd_nqlflag != NQL_NOVAL) + if (!nd->nd_nam2) return; loop: - for (rp = rheadhtbl[NFSRCHASH(nd->nd_retxid)]; rp; rp = rp->rc_forw) { + for (rp = NFSRCHASH(nd->nd_retxid)->lh_first; rp != 0; + rp = rp->rc_hash.le_next) { if (nd->nd_retxid == rp->rc_xid && nd->nd_procnum == rp->rc_proc && - netaddr_match(NETFAMILY(rp), &rp->rc_haddr, nam)) { + netaddr_match(NETFAMILY(rp), &rp->rc_haddr, nd->nd_nam)) { if ((rp->rc_flag & RC_LOCKED) != 0) { rp->rc_flag |= RC_WANTED; (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0); @@ -310,7 +298,8 @@ loop: * the reply for non-idempotent rpc's. */ if (repvalid && nonidempotent[nd->nd_procnum]) { - if (repliesstatus[nd->nd_procnum]) { + if ((nd->nd_flag & ND_NFSV3) == 0 && + nfsv2_repstat[nfsv2_procid[nd->nd_procnum]]) { rp->rc_status = nd->nd_repstat; rp->rc_flag |= RC_REPSTATUS; } else { @@ -337,12 +326,11 @@ nfsrv_cleancache() { register struct nfsrvcache *rp, *nextrp; - for (rp = nfsrvlruhead; rp; rp = nextrp) { - nextrp = rp->rc_next; + for (rp = nfsrvlruhead.tqh_first; rp != 0; rp = nextrp) { + nextrp = rp->rc_lru.tqe_next; + LIST_REMOVE(rp, rc_hash); + TAILQ_REMOVE(&nfsrvlruhead, rp, rc_lru); free(rp, M_NFSD); } - bzero((char *)rheadhtbl, (rheadhash + 1) * sizeof(void *)); - nfsrvlruhead = NULL; - nfsrvlrutail = &nfsrvlruhead; numnfsrvcache = 0; } diff --git a/sys/nfs/nfs_subs.c b/sys/nfs/nfs_subs.c index 5778f7d..5211c5c 100644 --- a/sys/nfs/nfs_subs.c +++ b/sys/nfs/nfs_subs.c @@ -33,9 +33,10 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfs_subs.c 8.3 (Berkeley) 1/4/94 + * @(#)nfs_subs.c 8.8 (Berkeley) 5/22/95 */ + /* * These functions support the macros and help fiddle mbuf chains for * the nfs op functions. They do things like create the rpc header and @@ -51,9 +52,16 @@ #include #include #include +#include +#ifdef VFS_LKM +#include +#include +#endif + +#include #include -#include +#include #include #include #include @@ -69,32 +77,465 @@ #include #endif -#define TRUE 1 -#define FALSE 0 - /* * Data items converted to xdr at startup, since they are constant * This is kinda hokey, but may save a little time doing byte swaps */ -u_long nfs_procids[NFS_NPROCS]; u_long nfs_xdrneg1; u_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr, - rpc_mismatch, rpc_auth_unix, rpc_msgaccepted, rpc_rejectedcred, + rpc_mismatch, rpc_auth_unix, rpc_msgaccepted, rpc_auth_kerb; -u_long nfs_vers, nfs_prog, nfs_true, nfs_false; +u_long nfs_prog, nqnfs_prog, nfs_true, nfs_false; /* And other global data */ static u_long nfs_xid = 0; -enum vtype ntov_type[7] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON }; +enum vtype nv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON }; +enum vtype nv3tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO }; +int nfs_mount_type; +int nfs_ticks; + +/* + * Mapping of old NFS Version 2 RPC numbers to generic numbers. + */ +int nfsv3_procid[NFS_NPROCS] = { + NFSPROC_NULL, + NFSPROC_GETATTR, + NFSPROC_SETATTR, + NFSPROC_NOOP, + NFSPROC_LOOKUP, + NFSPROC_READLINK, + NFSPROC_READ, + NFSPROC_NOOP, + NFSPROC_WRITE, + NFSPROC_CREATE, + NFSPROC_REMOVE, + NFSPROC_RENAME, + NFSPROC_LINK, + NFSPROC_SYMLINK, + NFSPROC_MKDIR, + NFSPROC_RMDIR, + NFSPROC_READDIR, + NFSPROC_FSSTAT, + NFSPROC_NOOP, + NFSPROC_NOOP, + NFSPROC_NOOP, + NFSPROC_NOOP, + NFSPROC_NOOP, + NFSPROC_NOOP, + NFSPROC_NOOP, + NFSPROC_NOOP +}; + +/* + * and the reverse mapping from generic to Version 2 procedure numbers + */ +int nfsv2_procid[NFS_NPROCS] = { + NFSV2PROC_NULL, + NFSV2PROC_GETATTR, + NFSV2PROC_SETATTR, + NFSV2PROC_LOOKUP, + NFSV2PROC_NOOP, + NFSV2PROC_READLINK, + NFSV2PROC_READ, + NFSV2PROC_WRITE, + NFSV2PROC_CREATE, + NFSV2PROC_MKDIR, + NFSV2PROC_SYMLINK, + NFSV2PROC_CREATE, + NFSV2PROC_REMOVE, + NFSV2PROC_RMDIR, + NFSV2PROC_RENAME, + NFSV2PROC_LINK, + NFSV2PROC_READDIR, + NFSV2PROC_NOOP, + NFSV2PROC_STATFS, + NFSV2PROC_NOOP, + NFSV2PROC_NOOP, + NFSV2PROC_NOOP, + NFSV2PROC_NOOP, + NFSV2PROC_NOOP, + NFSV2PROC_NOOP, + NFSV2PROC_NOOP, +}; + +/* + * Maps errno values to nfs error numbers. + * Use NFSERR_IO as the catch all for ones not specifically defined in + * RFC 1094. + */ +static u_char nfsrv_v2errmap[ELAST] = { + NFSERR_PERM, NFSERR_NOENT, NFSERR_IO, NFSERR_IO, NFSERR_IO, + NFSERR_NXIO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, + NFSERR_IO, NFSERR_IO, NFSERR_ACCES, NFSERR_IO, NFSERR_IO, + NFSERR_IO, NFSERR_EXIST, NFSERR_IO, NFSERR_NODEV, NFSERR_NOTDIR, + NFSERR_ISDIR, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, + NFSERR_IO, NFSERR_FBIG, NFSERR_NOSPC, NFSERR_IO, NFSERR_ROFS, + NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, + NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, + NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, + NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, + NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, + NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, + NFSERR_IO, NFSERR_IO, NFSERR_NAMETOL, NFSERR_IO, NFSERR_IO, + NFSERR_NOTEMPTY, NFSERR_IO, NFSERR_IO, NFSERR_DQUOT, NFSERR_STALE, + NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, + NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, + NFSERR_IO, +}; + +/* + * Maps errno values to nfs error numbers. + * Although it is not obvious whether or not NFS clients really care if + * a returned error value is in the specified list for the procedure, the + * safest thing to do is filter them appropriately. For Version 2, the + * X/Open XNFS document is the only specification that defines error values + * for each RPC (The RFC simply lists all possible error values for all RPCs), + * so I have decided to not do this for Version 2. + * The first entry is the default error return and the rest are the valid + * errors for that RPC in increasing numeric order. + */ +static short nfsv3err_null[] = { + 0, + 0, +}; + +static short nfsv3err_getattr[] = { + NFSERR_IO, + NFSERR_IO, + NFSERR_STALE, + NFSERR_BADHANDLE, + NFSERR_SERVERFAULT, + 0, +}; + +static short nfsv3err_setattr[] = { + NFSERR_IO, + NFSERR_PERM, + NFSERR_IO, + NFSERR_ACCES, + NFSERR_INVAL, + NFSERR_NOSPC, + NFSERR_ROFS, + NFSERR_DQUOT, + NFSERR_STALE, + NFSERR_BADHANDLE, + NFSERR_NOT_SYNC, + NFSERR_SERVERFAULT, + 0, +}; + +static short nfsv3err_lookup[] = { + NFSERR_IO, + NFSERR_NOENT, + NFSERR_IO, + NFSERR_ACCES, + NFSERR_NOTDIR, + NFSERR_NAMETOL, + NFSERR_STALE, + NFSERR_BADHANDLE, + NFSERR_SERVERFAULT, + 0, +}; + +static short nfsv3err_access[] = { + NFSERR_IO, + NFSERR_IO, + NFSERR_STALE, + NFSERR_BADHANDLE, + NFSERR_SERVERFAULT, + 0, +}; + +static short nfsv3err_readlink[] = { + NFSERR_IO, + NFSERR_IO, + NFSERR_ACCES, + NFSERR_INVAL, + NFSERR_STALE, + NFSERR_BADHANDLE, + NFSERR_NOTSUPP, + NFSERR_SERVERFAULT, + 0, +}; + +static short nfsv3err_read[] = { + NFSERR_IO, + NFSERR_IO, + NFSERR_NXIO, + NFSERR_ACCES, + NFSERR_INVAL, + NFSERR_STALE, + NFSERR_BADHANDLE, + NFSERR_SERVERFAULT, + 0, +}; + +static short nfsv3err_write[] = { + NFSERR_IO, + NFSERR_IO, + NFSERR_ACCES, + NFSERR_INVAL, + NFSERR_FBIG, + NFSERR_NOSPC, + NFSERR_ROFS, + NFSERR_DQUOT, + NFSERR_STALE, + NFSERR_BADHANDLE, + NFSERR_SERVERFAULT, + 0, +}; + +static short nfsv3err_create[] = { + NFSERR_IO, + NFSERR_IO, + NFSERR_ACCES, + NFSERR_EXIST, + NFSERR_NOTDIR, + NFSERR_NOSPC, + NFSERR_ROFS, + NFSERR_NAMETOL, + NFSERR_DQUOT, + NFSERR_STALE, + NFSERR_BADHANDLE, + NFSERR_NOTSUPP, + NFSERR_SERVERFAULT, + 0, +}; + +static short nfsv3err_mkdir[] = { + NFSERR_IO, + NFSERR_IO, + NFSERR_ACCES, + NFSERR_EXIST, + NFSERR_NOTDIR, + NFSERR_NOSPC, + NFSERR_ROFS, + NFSERR_NAMETOL, + NFSERR_DQUOT, + NFSERR_STALE, + NFSERR_BADHANDLE, + NFSERR_NOTSUPP, + NFSERR_SERVERFAULT, + 0, +}; + +static short nfsv3err_symlink[] = { + NFSERR_IO, + NFSERR_IO, + NFSERR_ACCES, + NFSERR_EXIST, + NFSERR_NOTDIR, + NFSERR_NOSPC, + NFSERR_ROFS, + NFSERR_NAMETOL, + NFSERR_DQUOT, + NFSERR_STALE, + NFSERR_BADHANDLE, + NFSERR_NOTSUPP, + NFSERR_SERVERFAULT, + 0, +}; + +static short nfsv3err_mknod[] = { + NFSERR_IO, + NFSERR_IO, + NFSERR_ACCES, + NFSERR_EXIST, + NFSERR_NOTDIR, + NFSERR_NOSPC, + NFSERR_ROFS, + NFSERR_NAMETOL, + NFSERR_DQUOT, + NFSERR_STALE, + NFSERR_BADHANDLE, + NFSERR_NOTSUPP, + NFSERR_SERVERFAULT, + NFSERR_BADTYPE, + 0, +}; + +static short nfsv3err_remove[] = { + NFSERR_IO, + NFSERR_NOENT, + NFSERR_IO, + NFSERR_ACCES, + NFSERR_NOTDIR, + NFSERR_ROFS, + NFSERR_NAMETOL, + NFSERR_STALE, + NFSERR_BADHANDLE, + NFSERR_SERVERFAULT, + 0, +}; + +static short nfsv3err_rmdir[] = { + NFSERR_IO, + NFSERR_NOENT, + NFSERR_IO, + NFSERR_ACCES, + NFSERR_EXIST, + NFSERR_NOTDIR, + NFSERR_INVAL, + NFSERR_ROFS, + NFSERR_NAMETOL, + NFSERR_NOTEMPTY, + NFSERR_STALE, + NFSERR_BADHANDLE, + NFSERR_NOTSUPP, + NFSERR_SERVERFAULT, + 0, +}; + +static short nfsv3err_rename[] = { + NFSERR_IO, + NFSERR_NOENT, + NFSERR_IO, + NFSERR_ACCES, + NFSERR_EXIST, + NFSERR_XDEV, + NFSERR_NOTDIR, + NFSERR_ISDIR, + NFSERR_INVAL, + NFSERR_NOSPC, + NFSERR_ROFS, + NFSERR_MLINK, + NFSERR_NAMETOL, + NFSERR_NOTEMPTY, + NFSERR_DQUOT, + NFSERR_STALE, + NFSERR_BADHANDLE, + NFSERR_NOTSUPP, + NFSERR_SERVERFAULT, + 0, +}; + +static short nfsv3err_link[] = { + NFSERR_IO, + NFSERR_IO, + NFSERR_ACCES, + NFSERR_EXIST, + NFSERR_XDEV, + NFSERR_NOTDIR, + NFSERR_INVAL, + NFSERR_NOSPC, + NFSERR_ROFS, + NFSERR_MLINK, + NFSERR_NAMETOL, + NFSERR_DQUOT, + NFSERR_STALE, + NFSERR_BADHANDLE, + NFSERR_NOTSUPP, + NFSERR_SERVERFAULT, + 0, +}; + +static short nfsv3err_readdir[] = { + NFSERR_IO, + NFSERR_IO, + NFSERR_ACCES, + NFSERR_NOTDIR, + NFSERR_STALE, + NFSERR_BADHANDLE, + NFSERR_BAD_COOKIE, + NFSERR_TOOSMALL, + NFSERR_SERVERFAULT, + 0, +}; + +static short nfsv3err_readdirplus[] = { + NFSERR_IO, + NFSERR_IO, + NFSERR_ACCES, + NFSERR_NOTDIR, + NFSERR_STALE, + NFSERR_BADHANDLE, + NFSERR_BAD_COOKIE, + NFSERR_NOTSUPP, + NFSERR_TOOSMALL, + NFSERR_SERVERFAULT, + 0, +}; + +static short nfsv3err_fsstat[] = { + NFSERR_IO, + NFSERR_IO, + NFSERR_STALE, + NFSERR_BADHANDLE, + NFSERR_SERVERFAULT, + 0, +}; + +static short nfsv3err_fsinfo[] = { + NFSERR_STALE, + NFSERR_STALE, + NFSERR_BADHANDLE, + NFSERR_SERVERFAULT, + 0, +}; + +static short nfsv3err_pathconf[] = { + NFSERR_STALE, + NFSERR_STALE, + NFSERR_BADHANDLE, + NFSERR_SERVERFAULT, + 0, +}; + +static short nfsv3err_commit[] = { + NFSERR_IO, + NFSERR_IO, + NFSERR_STALE, + NFSERR_BADHANDLE, + NFSERR_SERVERFAULT, + 0, +}; + +static short *nfsrv_v3errmap[] = { + nfsv3err_null, + nfsv3err_getattr, + nfsv3err_setattr, + nfsv3err_lookup, + nfsv3err_access, + nfsv3err_readlink, + nfsv3err_read, + nfsv3err_write, + nfsv3err_create, + nfsv3err_mkdir, + nfsv3err_symlink, + nfsv3err_mknod, + nfsv3err_remove, + nfsv3err_rmdir, + nfsv3err_rename, + nfsv3err_link, + nfsv3err_readdir, + nfsv3err_readdirplus, + nfsv3err_fsstat, + nfsv3err_fsinfo, + nfsv3err_pathconf, + nfsv3err_commit, +}; + extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; -extern struct nfsreq nfsreqh; -extern int nqnfs_piggy[NFS_NPROCS]; extern struct nfsrtt nfsrtt; extern time_t nqnfsstarttime; -extern u_long nqnfs_prog, nqnfs_vers; extern int nqsrv_clockskew; extern int nqsrv_writeslack; extern int nqsrv_maxlease; +extern struct nfsstats nfsstats; +extern int nqnfs_piggy[NFS_NPROCS]; +extern nfstype nfsv2_type[9]; +extern nfstype nfsv3_type[9]; +extern struct nfsnodehashhead *nfsnodehashtbl; +extern u_long nfsnodehash; + +#ifdef VFS_LKM +struct getfh_args; +extern int getfh(struct proc *, struct getfh_args *, int *); +struct nfssvc_args; +extern int nfssvc(struct proc *, struct nfssvc_args *, int *); +#endif + +LIST_HEAD(nfsnodehashhead, nfsnode); /* * Create the header for an rpc request packet @@ -150,14 +591,16 @@ nfsm_reqh(vp, procid, hsiz, bposp) * Returns the head of the mbuf list. */ struct mbuf * -nfsm_rpchead(cr, nqnfs, procid, auth_type, auth_len, auth_str, mrest, - mrest_len, mbp, xidp) +nfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len, + verf_str, mrest, mrest_len, mbp, xidp) register struct ucred *cr; - int nqnfs; + int nmflag; int procid; int auth_type; int auth_len; char *auth_str; + int verf_len; + char *verf_str; struct mbuf *mrest; int mrest_len; struct mbuf **mbp; @@ -171,15 +614,13 @@ nfsm_rpchead(cr, nqnfs, procid, auth_type, auth_len, auth_str, mrest, int siz, grpsiz, authsiz; authsiz = nfsm_rndup(auth_len); - if (auth_type == RPCAUTH_NQNFS) - authsiz += 2 * NFSX_UNSIGNED; MGETHDR(mb, M_WAIT, MT_DATA); - if ((authsiz + 10*NFSX_UNSIGNED) >= MINCLSIZE) { + if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) { MCLGET(mb, M_WAIT); - } else if ((authsiz + 10*NFSX_UNSIGNED) < MHLEN) { - MH_ALIGN(mb, authsiz + 10*NFSX_UNSIGNED); + } else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) { + MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED); } else { - MH_ALIGN(mb, 8*NFSX_UNSIGNED); + MH_ALIGN(mb, 8 * NFSX_UNSIGNED); } mb->m_len = 0; mreq = mb; @@ -188,20 +629,26 @@ nfsm_rpchead(cr, nqnfs, procid, auth_type, auth_len, auth_str, mrest, /* * First the RPC header. */ - nfsm_build(tl, u_long *, 8*NFSX_UNSIGNED); + nfsm_build(tl, u_long *, 8 * NFSX_UNSIGNED); if (++nfs_xid == 0) nfs_xid++; *tl++ = *xidp = txdr_unsigned(nfs_xid); *tl++ = rpc_call; *tl++ = rpc_vers; - if (nqnfs) { + if (nmflag & NFSMNT_NQNFS) { *tl++ = txdr_unsigned(NQNFS_PROG); - *tl++ = txdr_unsigned(NQNFS_VER1); + *tl++ = txdr_unsigned(NQNFS_VER3); } else { *tl++ = txdr_unsigned(NFS_PROG); - *tl++ = txdr_unsigned(NFS_VER2); + if (nmflag & NFSMNT_NFSV3) + *tl++ = txdr_unsigned(NFS_VER3); + else + *tl++ = txdr_unsigned(NFS_VER2); } - *tl++ = txdr_unsigned(procid); + if (nmflag & NFSMNT_NFSV3) + *tl++ = txdr_unsigned(procid); + else + *tl++ = txdr_unsigned(nfsv2_procid[procid]); /* * And then the authorization cred. @@ -220,10 +667,7 @@ nfsm_rpchead(cr, nqnfs, procid, auth_type, auth_len, auth_str, mrest, for (i = 1; i <= grpsiz; i++) *tl++ = txdr_unsigned(cr->cr_groups[i]); break; - case RPCAUTH_NQNFS: - nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); - *tl++ = txdr_unsigned(cr->cr_uid); - *tl = txdr_unsigned(auth_len); + case RPCAUTH_KERB4: siz = auth_len; while (siz > 0) { if (M_TRAILINGSPACE(mb) == 0) { @@ -249,11 +693,43 @@ nfsm_rpchead(cr, nqnfs, procid, auth_type, auth_len, auth_str, mrest, } break; }; - nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); - *tl++ = txdr_unsigned(RPCAUTH_NULL); - *tl = 0; + + /* + * And the verifier... + */ + nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED); + if (verf_str) { + *tl++ = txdr_unsigned(RPCAUTH_KERB4); + *tl = txdr_unsigned(verf_len); + siz = verf_len; + while (siz > 0) { + if (M_TRAILINGSPACE(mb) == 0) { + MGET(mb2, M_WAIT, MT_DATA); + if (siz >= MINCLSIZE) + MCLGET(mb2, M_WAIT); + mb->m_next = mb2; + mb = mb2; + mb->m_len = 0; + bpos = mtod(mb, caddr_t); + } + i = min(siz, M_TRAILINGSPACE(mb)); + bcopy(verf_str, bpos, i); + mb->m_len += i; + verf_str += i; + bpos += i; + siz -= i; + } + if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) { + for (i = 0; i < siz; i++) + *bpos++ = '\0'; + mb->m_len += siz; + } + } else { + *tl++ = txdr_unsigned(RPCAUTH_NULL); + *tl = 0; + } mb->m_next = mrest; - mreq->m_pkthdr.len = authsiz + 10*NFSX_UNSIGNED + mrest_len; + mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len; mreq->m_pkthdr.rcvif = (struct ifnet *)0; *mbp = mb; return (mreq); @@ -262,6 +738,7 @@ nfsm_rpchead(cr, nqnfs, procid, auth_type, auth_len, auth_str, mrest, /* * copies mbuf chain to the uio scatter/gather list */ +int nfsm_mbuftouio(mrep, uiop, siz, dpos) struct mbuf **mrep; register struct uio *uiop; @@ -336,6 +813,7 @@ nfsm_mbuftouio(mrep, uiop, siz, dpos) /* * copies a uio scatter/gather list to an mbuf chain... */ +int nfsm_uiotombuf(uiop, mq, siz, bpos) register struct uio *uiop; struct mbuf **mq; @@ -423,6 +901,7 @@ nfsm_uiotombuf(uiop, mq, siz, bpos) * This is used by the macros nfsm_dissect and nfsm_dissecton for tough * cases. (The macros use the vars. dpos and dpos2) */ +int nfsm_disct(mdp, dposp, siz, left, cp2) struct mbuf **mdp; caddr_t *dposp; @@ -485,6 +964,7 @@ nfsm_disct(mdp, dposp, siz, left, cp2) /* * Advance the position in the mbuf chain. */ +int nfs_adv(mdp, dposp, offs, left) struct mbuf **mdp; caddr_t *dposp; @@ -511,13 +991,14 @@ nfs_adv(mdp, dposp, offs, left) /* * Copy a string into mbufs for the hard cases... */ +int nfsm_strtmbuf(mb, bpos, cp, siz) struct mbuf **mb; char **bpos; char *cp; long siz; { - register struct mbuf *m1, *m2; + register struct mbuf *m1 = 0, *m2; long left, xfer, len, tlen; u_long *tl; int putsize; @@ -576,10 +1057,32 @@ nfsm_strtmbuf(mb, bpos, cp, siz) /* * Called once to initialize data structures... */ -nfs_init() +int +nfs_init(vfsp) + struct vfsconf *vfsp; { register int i; + /* + * Check to see if major data structures haven't bloated. + */ + if (sizeof (struct nfsnode) > NFS_NODEALLOC) { + printf("struct nfsnode bloated (> %dbytes)\n", NFS_NODEALLOC); + printf("Try reducing NFS_SMALLFH\n"); + } + if (sizeof (struct nfsmount) > NFS_MNTALLOC) { + printf("struct nfsmount bloated (> %dbytes)\n", NFS_MNTALLOC); + printf("Try reducing NFS_MUIDHASHSIZ\n"); + } + if (sizeof (struct nfssvc_sock) > NFS_SVCALLOC) { + printf("struct nfssvc_sock bloated (> %dbytes)\n",NFS_SVCALLOC); + printf("Try reducing NFS_UIDHASHSIZ\n"); + } + if (sizeof (struct nfsuid) > NFS_UIDALLOC) { + printf("struct nfsuid bloated (> %dbytes)\n",NFS_UIDALLOC); + printf("Try unionizing the nu_nickname and nu_flag fields\n"); + } + nfs_mount_type = vfsp->vfc_typenum; nfsrtt.pos = 0; rpc_vers = txdr_unsigned(RPC_VER2); rpc_call = txdr_unsigned(RPC_CALL); @@ -588,21 +1091,20 @@ nfs_init() rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); rpc_mismatch = txdr_unsigned(RPC_MISMATCH); rpc_autherr = txdr_unsigned(RPC_AUTHERR); - rpc_rejectedcred = txdr_unsigned(AUTH_REJECTCRED); rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); - rpc_auth_kerb = txdr_unsigned(RPCAUTH_NQNFS); - nfs_vers = txdr_unsigned(NFS_VER2); + rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4); nfs_prog = txdr_unsigned(NFS_PROG); + nqnfs_prog = txdr_unsigned(NQNFS_PROG); nfs_true = txdr_unsigned(TRUE); nfs_false = txdr_unsigned(FALSE); - /* Loop thru nfs procids */ - for (i = 0; i < NFS_NPROCS; i++) - nfs_procids[i] = txdr_unsigned(i); + nfs_xdrneg1 = txdr_unsigned(-1); + nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000; + if (nfs_ticks < 1) + nfs_ticks = 1; /* Ensure async daemons disabled */ for (i = 0; i < NFS_MAXASYNCDAEMON; i++) nfs_iodwant[i] = (struct proc *)0; TAILQ_INIT(&nfs_bufq); - nfs_xdrneg1 = txdr_unsigned(-1); nfs_nhinit(); /* Init the nfsnode table */ nfsrv_init(0); /* Init server data structures */ nfsrv_initcache(); /* Init the server request cache */ @@ -614,18 +1116,16 @@ nfs_init() nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease + nqsrv_clockskew + nqsrv_writeslack; NQLOADNOVRAM(nqnfsstarttime); - nqnfs_prog = txdr_unsigned(NQNFS_PROG); - nqnfs_vers = txdr_unsigned(NQNFS_VER1); - nqthead.th_head[0] = &nqthead; - nqthead.th_head[1] = &nqthead; - nqfhead = hashinit(NQLCHSZ, M_NQLEASE, &nqfheadhash); + CIRCLEQ_INIT(&nqtimerhead); + nqfhhashtbl = hashinit(NQLCHSZ, M_NQLEASE, &nqfhhash); } /* * Initialize reply list and start timer */ - nfsreqh.r_prev = nfsreqh.r_next = &nfsreqh; - nfs_timer(); + TAILQ_INIT(&nfs_reqq); + nfs_timer(0); + return (0); } /* @@ -642,6 +1142,7 @@ nfs_init() * Iff vap not NULL * copy the attributes to *vaper */ +int nfs_loadattrcache(vpp, mdp, dposp, vaper) struct vnode **vpp; struct mbuf **mdp; @@ -650,37 +1151,47 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper) { register struct vnode *vp = *vpp; register struct vattr *vap; - register struct nfsv2_fattr *fp; + register struct nfs_fattr *fp; extern int (**spec_nfsv2nodeop_p)(); - register struct nfsnode *np, *nq, **nhpp; + register struct nfsnode *np; + register struct nfsnodehashhead *nhpp; register long t1; - caddr_t dpos, cp2; - int error = 0, isnq; + caddr_t cp2; + int error = 0, rdev; struct mbuf *md; enum vtype vtyp; u_short vmode; - long rdev; struct timespec mtime; struct vnode *nvp; + quad_t tval; + int v3 = NFS_ISV3(vp); md = *mdp; - dpos = *dposp; - t1 = (mtod(md, caddr_t) + md->m_len) - dpos; - isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS); - if (error = nfsm_disct(&md, &dpos, NFSX_FATTR(isnq), t1, &cp2)) + t1 = (mtod(md, caddr_t) + md->m_len) - *dposp; + if (error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2)) return (error); - fp = (struct nfsv2_fattr *)cp2; - vtyp = nfstov_type(fp->fa_type); - vmode = fxdr_unsigned(u_short, fp->fa_mode); - if (vtyp == VNON || vtyp == VREG) - vtyp = IFTOVT(vmode); - if (isnq) { - rdev = fxdr_unsigned(long, fp->fa_nqrdev); - fxdr_nqtime(&fp->fa_nqmtime, &mtime); + fp = (struct nfs_fattr *)cp2; + if (v3) { + vtyp = nfsv3tov_type(fp->fa_type); + vmode = fxdr_unsigned(u_short, fp->fa_mode); + rdev = makedev(fxdr_unsigned(u_char, fp->fa3_rdev.specdata1), + fxdr_unsigned(u_char, fp->fa3_rdev.specdata2)); + fxdr_nfsv3time(&fp->fa3_mtime, &mtime); } else { - rdev = fxdr_unsigned(long, fp->fa_nfsrdev); - fxdr_nfstime(&fp->fa_nfsmtime, &mtime); + vtyp = nfsv2tov_type(fp->fa_type); + vmode = fxdr_unsigned(u_short, fp->fa_mode); + if (vtyp == VNON || vtyp == VREG) + vtyp = IFTOVT(vmode); + rdev = fxdr_unsigned(long, fp->fa2_rdev); + fxdr_nfsv2time(&fp->fa2_mtime, &mtime); + + /* + * Really ugly NFSv2 kludge. + */ + if (vtyp == VCHR && rdev == 0xffffffff) + vtyp = VFIFO; } + /* * If v_type == VNON it is a new node, so fill in the v_type, * n_mtime fields. Check to see if it represents a special @@ -690,27 +1201,22 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper) */ np = VTONFS(vp); if (vp->v_type == VNON) { - if (vtyp == VCHR && rdev == 0xffffffff) - vp->v_type = vtyp = VFIFO; - else - vp->v_type = vtyp; + vp->v_type = vtyp; if (vp->v_type == VFIFO) { -#ifdef FIFO extern int (**fifo_nfsv2nodeop_p)(); vp->v_op = fifo_nfsv2nodeop_p; -#else - return (EOPNOTSUPP); -#endif /* FIFO */ } if (vp->v_type == VCHR || vp->v_type == VBLK) { vp->v_op = spec_nfsv2nodeop_p; - if (nvp = checkalias(vp, (dev_t)rdev, vp->v_mount)) { + nvp = checkalias(vp, (dev_t)rdev, vp->v_mount); + if (nvp) { /* * Discard unneeded vnode, but save its nfsnode. + * Since the nfsnode does not have a lock, its + * vnode lock has to be carried over. */ - if (nq = np->n_forw) - nq->n_back = np->n_back; - *np->n_back = nq; + nvp->v_vnlock = vp->v_vnlock; + vp->v_vnlock = NULL; nvp->v_data = vp->v_data; vp->v_data = NULL; vp->v_op = spec_vnodeop_p; @@ -720,12 +1226,6 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper) * Reinitialize aliased node. */ np->n_vnode = nvp; - nhpp = (struct nfsnode **)nfs_hash(&np->n_fh); - if (nq = *nhpp) - nq->n_back = &np->n_forw; - np->n_forw = nq; - np->n_back = nhpp; - *nhpp = np; *vpp = vp = nvp; } } @@ -734,32 +1234,34 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper) vap = &np->n_vattr; vap->va_type = vtyp; vap->va_mode = (vmode & 07777); - vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); - vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); - vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); vap->va_rdev = (dev_t)rdev; vap->va_mtime = mtime; vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; - if (isnq) { - fxdr_hyper(&fp->fa_nqsize, &vap->va_size); - vap->va_blocksize = fxdr_unsigned(long, fp->fa_nqblocksize); - fxdr_hyper(&fp->fa_nqbytes, &vap->va_bytes); - vap->va_fileid = fxdr_unsigned(long, fp->fa_nqfileid); - fxdr_nqtime(&fp->fa_nqatime, &vap->va_atime); - vap->va_flags = fxdr_unsigned(u_long, fp->fa_nqflags); - fxdr_nqtime(&fp->fa_nqctime, &vap->va_ctime); - vap->va_gen = fxdr_unsigned(u_long, fp->fa_nqgen); - fxdr_hyper(&fp->fa_nqfilerev, &vap->va_filerev); + if (v3) { + vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); + vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); + vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); + fxdr_hyper(&fp->fa3_size, &vap->va_size); + vap->va_blocksize = NFS_FABLKSIZE; + fxdr_hyper(&fp->fa3_used, &vap->va_bytes); + vap->va_fileid = fxdr_unsigned(int, fp->fa3_fileid.nfsuquad[1]); + fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime); + fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime); + vap->va_flags = 0; + vap->va_filerev = 0; } else { - vap->va_size = fxdr_unsigned(u_long, fp->fa_nfssize); - vap->va_blocksize = fxdr_unsigned(long, fp->fa_nfsblocksize); - vap->va_bytes = fxdr_unsigned(long, fp->fa_nfsblocks) * NFS_FABLKSIZE; - vap->va_fileid = fxdr_unsigned(long, fp->fa_nfsfileid); - fxdr_nfstime(&fp->fa_nfsatime, &vap->va_atime); + vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); + vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); + vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); + vap->va_size = fxdr_unsigned(u_long, fp->fa2_size); + vap->va_blocksize = fxdr_unsigned(long, fp->fa2_blocksize); + vap->va_bytes = fxdr_unsigned(long, fp->fa2_blocks) * NFS_FABLKSIZE; + vap->va_fileid = fxdr_unsigned(long, fp->fa2_fileid); + fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime); vap->va_flags = 0; - vap->va_ctime.ts_sec = fxdr_unsigned(long, fp->fa_nfsctime.nfs_sec); + vap->va_ctime.ts_sec = fxdr_unsigned(long, fp->fa2_ctime.nfsv2_sec); vap->va_ctime.ts_nsec = 0; - vap->va_gen = fxdr_unsigned(u_long, fp->fa_nfsctime.nfs_usec); + vap->va_gen = fxdr_unsigned(u_long, fp->fa2_ctime.nfsv2_usec); vap->va_filerev = 0; } if (vap->va_size != np->n_size) { @@ -776,26 +1278,13 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper) np->n_size = vap->va_size; } np->n_attrstamp = time.tv_sec; - *dposp = dpos; - *mdp = md; if (vaper != NULL) { bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); -#ifdef notdef - if ((np->n_flag & NMODIFIED) && np->n_size > vap->va_size) - if (np->n_size > vap->va_size) - vaper->va_size = np->n_size; -#endif if (np->n_flag & NCHG) { - if (np->n_flag & NACC) { - vaper->va_atime.ts_sec = np->n_atim.tv_sec; - vaper->va_atime.ts_nsec = - np->n_atim.tv_usec * 1000; - } - if (np->n_flag & NUPD) { - vaper->va_mtime.ts_sec = np->n_mtim.tv_sec; - vaper->va_mtime.ts_nsec = - np->n_mtim.tv_usec * 1000; - } + if (np->n_flag & NACC) + vaper->va_atime = np->n_atim; + if (np->n_flag & NUPD) + vaper->va_mtime = np->n_mtim; } } return (0); @@ -806,6 +1295,7 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper) * If the cache is valid, copy contents to *vap and return 0 * otherwise return an error */ +int nfs_getattrcache(vp, vaper) register struct vnode *vp; struct vattr *vaper; @@ -813,12 +1303,7 @@ nfs_getattrcache(vp, vaper) register struct nfsnode *np = VTONFS(vp); register struct vattr *vap; - if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQLOOKLEASE) { - if (!NQNFS_CKCACHABLE(vp, NQL_READ) || np->n_attrstamp == 0) { - nfsstats.attrcache_misses++; - return (ENOENT); - } - } else if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO(np)) { + if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO(np)) { nfsstats.attrcache_misses++; return (ENOENT); } @@ -838,23 +1323,11 @@ nfs_getattrcache(vp, vaper) np->n_size = vap->va_size; } bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr)); -#ifdef notdef - if ((np->n_flag & NMODIFIED) == 0) { - np->n_size = vaper->va_size; - vnode_pager_setsize(vp, (u_long)np->n_size); - } else if (np->n_size > vaper->va_size) - if (np->n_size > vaper->va_size) - vaper->va_size = np->n_size; -#endif if (np->n_flag & NCHG) { - if (np->n_flag & NACC) { - vaper->va_atime.ts_sec = np->n_atim.tv_sec; - vaper->va_atime.ts_nsec = np->n_atim.tv_usec * 1000; - } - if (np->n_flag & NUPD) { - vaper->va_mtime.ts_sec = np->n_mtim.tv_sec; - vaper->va_mtime.ts_nsec = np->n_mtim.tv_usec * 1000; - } + if (np->n_flag & NACC) + vaper->va_atime = np->n_atim; + if (np->n_flag & NUPD) + vaper->va_mtime = np->n_mtim; } return (0); } @@ -862,7 +1335,8 @@ nfs_getattrcache(vp, vaper) /* * Set up nameidata for a lookup() call and do it */ -nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p) +int +nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag) register struct nameidata *ndp; fhandle_t *fhp; int len; @@ -870,7 +1344,9 @@ nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p) struct mbuf *nam; struct mbuf **mdp; caddr_t *dposp; + struct vnode **retdirp; struct proc *p; + int kerbflag; { register int i, rem; register struct mbuf *md; @@ -879,6 +1355,7 @@ nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p) int error, rdonly; struct componentname *cnp = &ndp->ni_cnd; + *retdirp = (struct vnode *)0; MALLOC(cnp->cn_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK); /* * Copy the name from the mbuf list to ndp->ni_pnbuf @@ -900,7 +1377,7 @@ nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p) rem = md->m_len; } if (*fromcp == '\0' || *fromcp == '/') { - error = EINVAL; + error = EACCES; goto out; } cnp->cn_hash += (unsigned char)*fromcp; @@ -923,13 +1400,15 @@ nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p) * Extract and set starting directory. */ if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, - nam, &rdonly)) + nam, &rdonly, kerbflag)) goto out; if (dp->v_type != VDIR) { vrele(dp); error = ENOTDIR; goto out; } + VREF(dp); + *retdirp = dp; ndp->ni_startdir = dp; if (rdonly) cnp->cn_flags |= (NOCROSSMOUNT | RDONLY); @@ -1024,18 +1503,122 @@ nfsm_adj(mp, len, nul) } count -= m->m_len; } - while (m = m->m_next) + for (m = m->m_next;m;m = m->m_next) m->m_len = 0; } /* + * Make these functions instead of macros, so that the kernel text size + * doesn't get too big... + */ +void +nfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp) + struct nfsrv_descript *nfsd; + int before_ret; + register struct vattr *before_vap; + int after_ret; + struct vattr *after_vap; + struct mbuf **mbp; + char **bposp; +{ + register struct mbuf *mb = *mbp, *mb2; + register char *bpos = *bposp; + register u_long *tl; + + if (before_ret) { + nfsm_build(tl, u_long *, NFSX_UNSIGNED); + *tl = nfs_false; + } else { + nfsm_build(tl, u_long *, 7 * NFSX_UNSIGNED); + *tl++ = nfs_true; + txdr_hyper(&(before_vap->va_size), tl); + tl += 2; + txdr_nfsv3time(&(before_vap->va_mtime), tl); + tl += 2; + txdr_nfsv3time(&(before_vap->va_ctime), tl); + } + *bposp = bpos; + *mbp = mb; + nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp); +} + +void +nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp) + struct nfsrv_descript *nfsd; + int after_ret; + struct vattr *after_vap; + struct mbuf **mbp; + char **bposp; +{ + register struct mbuf *mb = *mbp, *mb2; + register char *bpos = *bposp; + register u_long *tl; + register struct nfs_fattr *fp; + + if (after_ret) { + nfsm_build(tl, u_long *, NFSX_UNSIGNED); + *tl = nfs_false; + } else { + nfsm_build(tl, u_long *, NFSX_UNSIGNED + NFSX_V3FATTR); + *tl++ = nfs_true; + fp = (struct nfs_fattr *)tl; + nfsm_srvfattr(nfsd, after_vap, fp); + } + *mbp = mb; + *bposp = bpos; +} + +void +nfsm_srvfattr(nfsd, vap, fp) + register struct nfsrv_descript *nfsd; + register struct vattr *vap; + register struct nfs_fattr *fp; +{ + + fp->fa_nlink = txdr_unsigned(vap->va_nlink); + fp->fa_uid = txdr_unsigned(vap->va_uid); + fp->fa_gid = txdr_unsigned(vap->va_gid); + if (nfsd->nd_flag & ND_NFSV3) { + fp->fa_type = vtonfsv3_type(vap->va_type); + fp->fa_mode = vtonfsv3_mode(vap->va_mode); + txdr_hyper(&vap->va_size, &fp->fa3_size); + txdr_hyper(&vap->va_bytes, &fp->fa3_used); + fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev)); + fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev)); + fp->fa3_fsid.nfsuquad[0] = 0; + fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid); + fp->fa3_fileid.nfsuquad[0] = 0; + fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid); + txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime); + txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime); + txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime); + } else { + fp->fa_type = vtonfsv2_type(vap->va_type); + fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode); + fp->fa2_size = txdr_unsigned(vap->va_size); + fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize); + if (vap->va_type == VFIFO) + fp->fa2_rdev = 0xffffffff; + else + fp->fa2_rdev = txdr_unsigned(vap->va_rdev); + fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE); + fp->fa2_fsid = txdr_unsigned(vap->va_fsid); + fp->fa2_fileid = txdr_unsigned(vap->va_fileid); + txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime); + txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime); + txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime); + } +} + +/* * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) * - look up fsid in mount list (if not found ret error) * - get vp and export rights by calling VFS_FHTOVP() * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon * - if not lockflag unlock it with VOP_UNLOCK() */ -nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp) +int +nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag) fhandle_t *fhp; int lockflag; struct vnode **vpp; @@ -1043,7 +1626,9 @@ nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp) struct nfssvc_sock *slp; struct mbuf *nam; int *rdonlyp; + int kerbflag; { + struct proc *p = curproc; /* XXX */ register struct mount *mp; register struct nfsuid *uidp; register int i; @@ -1051,39 +1636,35 @@ nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp) int error, exflags; *vpp = (struct vnode *)0; - if ((mp = getvfs(&fhp->fh_fsid)) == NULL) + mp = vfs_getvfs(&fhp->fh_fsid); + if (!mp) return (ESTALE); - if (error = VFS_FHTOVP(mp, &fhp->fh_fid, nam, vpp, &exflags, &credanon)) + error = VFS_FHTOVP(mp, &fhp->fh_fid, nam, vpp, &exflags, &credanon); + if (error) return (error); /* * Check/setup credentials. */ if (exflags & MNT_EXKERB) { - uidp = slp->ns_uidh[NUIDHASH(cred->cr_uid)]; - while (uidp) { - if (uidp->nu_uid == cred->cr_uid) - break; - uidp = uidp->nu_hnext; - } - if (uidp) { - cred->cr_uid = uidp->nu_cr.cr_uid; - for (i = 0; i < uidp->nu_cr.cr_ngroups; i++) - cred->cr_groups[i] = uidp->nu_cr.cr_groups[i]; - } else { + if (!kerbflag) { vput(*vpp); - return (NQNFS_AUTHERR); + return (NFSERR_AUTHERR | AUTH_TOOWEAK); } + } else if (kerbflag) { + vput(*vpp); + return (NFSERR_AUTHERR | AUTH_TOOWEAK); } else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) { cred->cr_uid = credanon->cr_uid; for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++) cred->cr_groups[i] = credanon->cr_groups[i]; + cred->cr_ngroups = i; } if (exflags & MNT_EXRDONLY) *rdonlyp = 1; else *rdonlyp = 0; if (!lockflag) - VOP_UNLOCK(*vpp); + VOP_UNLOCK(*vpp, 0, p); return (0); } @@ -1094,6 +1675,7 @@ nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp) * The AF_INET family is handled as a special case so that address mbufs * don't need to be saved to store "struct in_addr", which is only 4 bytes. */ +int netaddr_match(family, haddr, nam) int family; union nethostaddr *haddr; @@ -1128,3 +1710,142 @@ netaddr_match(family, haddr, nam) }; return (0); } + +static nfsuint64 nfs_nullcookie = { 0, 0 }; +/* + * This function finds the directory cookie that corresponds to the + * logical byte offset given. + */ +nfsuint64 * +nfs_getcookie(np, off, add) + register struct nfsnode *np; + off_t off; + int add; +{ + register struct nfsdmap *dp, *dp2; + register int pos; + + pos = off / NFS_DIRBLKSIZ; + if (pos == 0) { +#ifdef DIAGNOSTIC + if (add) + panic("nfs getcookie add at 0"); +#endif + return (&nfs_nullcookie); + } + pos--; + dp = np->n_cookies.lh_first; + if (!dp) { + if (add) { + MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap), + M_NFSDIROFF, M_WAITOK); + dp->ndm_eocookie = 0; + LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list); + } else + return ((nfsuint64 *)0); + } + while (pos >= NFSNUMCOOKIES) { + pos -= NFSNUMCOOKIES; + if (dp->ndm_list.le_next) { + if (!add && dp->ndm_eocookie < NFSNUMCOOKIES && + pos >= dp->ndm_eocookie) + return ((nfsuint64 *)0); + dp = dp->ndm_list.le_next; + } else if (add) { + MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap), + M_NFSDIROFF, M_WAITOK); + dp2->ndm_eocookie = 0; + LIST_INSERT_AFTER(dp, dp2, ndm_list); + dp = dp2; + } else + return ((nfsuint64 *)0); + } + if (pos >= dp->ndm_eocookie) { + if (add) + dp->ndm_eocookie = pos + 1; + else + return ((nfsuint64 *)0); + } + return (&dp->ndm_cookies[pos]); +} + +/* + * Invalidate cached directory information, except for the actual directory + * blocks (which are invalidated separately). + * Done mainly to avoid the use of stale offset cookies. + */ +void +nfs_invaldir(vp) + register struct vnode *vp; +{ + register struct nfsnode *np = VTONFS(vp); + +#ifdef DIAGNOSTIC + if (vp->v_type != VDIR) + panic("nfs: invaldir not dir"); +#endif + np->n_direofoffset = 0; + np->n_cookieverf.nfsuquad[0] = 0; + np->n_cookieverf.nfsuquad[1] = 0; + if (np->n_cookies.lh_first) + np->n_cookies.lh_first->ndm_eocookie = 0; +} + +/* + * The write verifier has changed (probably due to a server reboot), so all + * B_NEEDCOMMIT blocks will have to be written again. Since they are on the + * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT + * flag. Once done the new write verifier can be set for the mount point. + */ +void +nfs_clearcommit(mp) + struct mount *mp; +{ + register struct vnode *vp, *nvp; + register struct buf *bp, *nbp; + int s; + + s = splbio(); +loop: + for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) { + if (vp->v_mount != mp) /* Paranoia */ + goto loop; + nvp = vp->v_mntvnodes.le_next; + for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) { + nbp = bp->b_vnbufs.le_next; + if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT)) + == (B_DELWRI | B_NEEDCOMMIT)) + bp->b_flags &= ~B_NEEDCOMMIT; + } + } + splx(s); +} + +/* + * Map errnos to NFS error numbers. For Version 3 also filter out error + * numbers not specified for the associated procedure. + */ +int +nfsrv_errmap(nd, err) + struct nfsrv_descript *nd; + register int err; +{ + register short *defaulterrp, *errp; + + if (nd->nd_flag & ND_NFSV3) { + if (nd->nd_procnum <= NFSPROC_COMMIT) { + errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum]; + while (*++errp) { + if (*errp == err) + return (err); + else if (*errp > err) + break; + } + return ((int)*defaulterrp); + } else + return (err & 0xffff); + } + if (err <= ELAST) + return ((int)nfsrv_v2errmap[err - 1]); + return (NFSERR_IO); +} diff --git a/sys/nfs/nfs_syscalls.c b/sys/nfs/nfs_syscalls.c index 5d86b42..aac38e4 100644 --- a/sys/nfs/nfs_syscalls.c +++ b/sys/nfs/nfs_syscalls.c @@ -33,7 +33,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfs_syscalls.c 8.3 (Berkeley) 1/4/94 + * @(#)nfs_syscalls.c 8.5 (Berkeley) 3/30/95 */ #include @@ -60,25 +60,28 @@ #ifdef ISO #include #endif +#include #include -#include +#include #include +#include #include #include #include #include #include +void nfsrv_zapsock __P((struct nfssvc_sock *)); + /* Global defs. */ -extern u_long nfs_prog, nfs_vers; -extern int (*nfsrv_procs[NFS_NPROCS])(); +extern int (*nfsrv3_procs[NFS_NPROCS])(); extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; extern int nfs_numasync; extern time_t nqnfsstarttime; -extern struct nfsrv_req nsrvq_head; -extern struct nfsd nfsd_head; extern int nqsrv_writeslack; extern int nfsrtton; +extern struct nfsstats nfsstats; +extern int nfsrvw_procrastinate; struct nfssvc_sock *nfs_udpsock, *nfs_cltpsock; int nuidhash_max = NFS_MAXUIDHASH; static int nfs_numnfsd = 0; @@ -88,7 +91,7 @@ static int modify_flag = 0; static struct nfsdrt nfsdrt; void nfsrv_cleancache(), nfsrv_rcv(), nfsrv_wakenfsd(), nfs_sndunlock(); static void nfsd_rt(); -void nfsrv_slpderef(), nfsrv_init(); +void nfsrv_slpderef(); #define TRUE 1 #define FALSE 0 @@ -106,6 +109,7 @@ struct getfh_args { char *fname; fhandle_t *fhp; }; +int getfh(p, uap, retval) struct proc *p; register struct getfh_args *uap; @@ -119,10 +123,12 @@ getfh(p, uap, retval) /* * Must be super user */ - if (error = suser(p->p_ucred, &p->p_acflag)) + error = suser(p->p_ucred, &p->p_acflag); + if(error) return (error); NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); - if (error = namei(&nd)) + error = namei(&nd); + if (error) return (error); vp = nd.ni_vp; bzero((caddr_t)&fh, sizeof(fh)); @@ -135,8 +141,6 @@ getfh(p, uap, retval) return (error); } -static struct nfssvc_sock nfssvc_sockhead; - /* * Nfs server psuedo system call for the nfsd's * Based on the flag value it either: @@ -148,6 +152,7 @@ struct nfssvc_args { int flag; caddr_t argp; }; +int nfssvc(p, uap, retval) struct proc *p; register struct nfssvc_args *uap; @@ -161,27 +166,30 @@ nfssvc(p, uap, retval) struct nfsd_cargs ncd; struct nfsd *nfsd; struct nfssvc_sock *slp; - struct nfsuid *nuidp, **nuh; + struct nfsuid *nuidp; struct nfsmount *nmp; int error; /* * Must be super user */ - if (error = suser(p->p_ucred, &p->p_acflag)) + error = suser(p->p_ucred, &p->p_acflag); + if(error) return (error); - while (nfssvc_sockhead.ns_flag & SLP_INIT) { - nfssvc_sockhead.ns_flag |= SLP_WANTINIT; + while (nfssvc_sockhead_flag & SLP_INIT) { + nfssvc_sockhead_flag |= SLP_WANTINIT; (void) tsleep((caddr_t)&nfssvc_sockhead, PSOCK, "nfsd init", 0); } if (uap->flag & NFSSVC_BIOD) error = nfssvc_iod(p); else if (uap->flag & NFSSVC_MNTD) { - if (error = copyin(uap->argp, (caddr_t)&ncd, sizeof (ncd))) + error = copyin(uap->argp, (caddr_t)&ncd, sizeof (ncd)); + if (error) return (error); NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, ncd.ncd_dirp, p); - if (error = namei(&nd)) + error = namei(&nd); + if (error) return (error); if ((nd.ni_vp->v_flag & VROOT) == 0) error = EINVAL; @@ -196,38 +204,48 @@ nfssvc(p, uap, retval) error = nqnfs_clientd(nmp, p->p_ucred, &ncd, uap->flag, uap->argp, p); } else if (uap->flag & NFSSVC_ADDSOCK) { - if (error = copyin(uap->argp, (caddr_t)&nfsdarg, - sizeof(nfsdarg))) + error = copyin(uap->argp, (caddr_t)&nfsdarg, sizeof(nfsdarg)); + if (error) return (error); - if (error = getsock(p->p_fd, nfsdarg.sock, &fp)) + error = getsock(p->p_fd, nfsdarg.sock, &fp); + if (error) return (error); /* * Get the client address for connected sockets. */ if (nfsdarg.name == NULL || nfsdarg.namelen == 0) nam = (struct mbuf *)0; - else if (error = sockargs(&nam, nfsdarg.name, nfsdarg.namelen, - MT_SONAME)) - return (error); + else { + error = sockargs(&nam, nfsdarg.name, nfsdarg.namelen, + MT_SONAME); + if (error) + return (error); + } error = nfssvc_addsock(fp, nam); } else { - if (error = copyin(uap->argp, (caddr_t)nsd, sizeof (*nsd))) + error = copyin(uap->argp, (caddr_t)nsd, sizeof (*nsd)); + if (error) return (error); - if ((uap->flag & NFSSVC_AUTHIN) && (nfsd = nsd->nsd_nfsd) && - (nfsd->nd_slp->ns_flag & SLP_VALID)) { - slp = nfsd->nd_slp; + if ((uap->flag & NFSSVC_AUTHIN) && ((nfsd = nsd->nsd_nfsd)) && + (nfsd->nfsd_slp->ns_flag & SLP_VALID)) { + slp = nfsd->nfsd_slp; /* * First check to see if another nfsd has already * added this credential. */ - nuidp = slp->ns_uidh[NUIDHASH(nsd->nsd_uid)]; - while (nuidp) { - if (nuidp->nu_uid == nsd->nsd_uid) + for (nuidp = NUIDHASH(slp,nsd->nsd_cr.cr_uid)->lh_first; + nuidp != 0; nuidp = nuidp->nu_hash.le_next) { + if (nuidp->nu_cr.cr_uid == nsd->nsd_cr.cr_uid && + (!nfsd->nfsd_nd->nd_nam2 || + netaddr_match(NU_NETFAM(nuidp), + &nuidp->nu_haddr, nfsd->nfsd_nd->nd_nam2))) break; - nuidp = nuidp->nu_hnext; } - if (!nuidp) { + if (nuidp) { + nfsrv_setcred(&nuidp->nu_cr,&nfsd->nfsd_nd->nd_cr); + nfsd->nfsd_nd->nd_flag |= ND_KERBFULL; + } else { /* * Nope, so we will. */ @@ -243,31 +261,57 @@ nfssvc(p, uap, retval) free((caddr_t)nuidp, M_NFSUID); } else { if (nuidp == (struct nfsuid *)0) { - nuidp = slp->ns_lruprev; - remque(nuidp); - if (nuidp->nu_hprev) - nuidp->nu_hprev->nu_hnext = - nuidp->nu_hnext; - if (nuidp->nu_hnext) - nuidp->nu_hnext->nu_hprev = - nuidp->nu_hprev; + nuidp = slp->ns_uidlruhead.tqh_first; + LIST_REMOVE(nuidp, nu_hash); + TAILQ_REMOVE(&slp->ns_uidlruhead, nuidp, + nu_lru); + if (nuidp->nu_flag & NU_NAM) + m_freem(nuidp->nu_nam); } + nuidp->nu_flag = 0; nuidp->nu_cr = nsd->nsd_cr; if (nuidp->nu_cr.cr_ngroups > NGROUPS) - nuidp->nu_cr.cr_ngroups = NGROUPS; + nuidp->nu_cr.cr_ngroups = NGROUPS; nuidp->nu_cr.cr_ref = 1; - nuidp->nu_uid = nsd->nsd_uid; - insque(nuidp, (struct nfsuid *)slp); - nuh = &slp->ns_uidh[NUIDHASH(nsd->nsd_uid)]; - if (nuidp->nu_hnext = *nuh) - nuidp->nu_hnext->nu_hprev = nuidp; - nuidp->nu_hprev = (struct nfsuid *)0; - *nuh = nuidp; + nuidp->nu_timestamp = nsd->nsd_timestamp; + nuidp->nu_expire = time.tv_sec + nsd->nsd_ttl; + /* + * and save the session key in nu_key. + */ + bcopy(nsd->nsd_key, nuidp->nu_key, + sizeof (nsd->nsd_key)); + if (nfsd->nfsd_nd->nd_nam2) { + struct sockaddr_in *saddr; + + saddr = mtod(nfsd->nfsd_nd->nd_nam2, + struct sockaddr_in *); + switch (saddr->sin_family) { + case AF_INET: + nuidp->nu_flag |= NU_INETADDR; + nuidp->nu_inetaddr = + saddr->sin_addr.s_addr; + break; + case AF_ISO: + default: + nuidp->nu_flag |= NU_NAM; + nuidp->nu_nam = m_copym( + nfsd->nfsd_nd->nd_nam2, 0, + M_COPYALL, M_WAIT); + break; + }; + } + TAILQ_INSERT_TAIL(&slp->ns_uidlruhead, nuidp, + nu_lru); + LIST_INSERT_HEAD(NUIDHASH(slp, nsd->nsd_uid), + nuidp, nu_hash); + nfsrv_setcred(&nuidp->nu_cr, + &nfsd->nfsd_nd->nd_cr); + nfsd->nfsd_nd->nd_flag |= ND_KERBFULL; } } } if ((uap->flag & NFSSVC_AUTHINFAIL) && (nfsd = nsd->nsd_nfsd)) - nfsd->nd_flag |= NFSD_AUTHFAIL; + nfsd->nfsd_flag |= NFSD_AUTHFAIL; error = nfssvc_nfsd(nsd, uap->argp, p); } if (error == EINTR || error == ERESTART) @@ -278,6 +322,7 @@ nfssvc(p, uap, retval) /* * Adds a socket to the list for servicing by nfsds. */ +int nfssvc_addsock(fp, mynam) struct file *fp; struct mbuf *mynam; @@ -313,7 +358,8 @@ nfssvc_addsock(fp, mynam) siz = NFS_MAXPACKET + sizeof (u_long); else siz = NFS_MAXPACKET; - if (error = soreserve(so, siz, siz)) { + error = soreserve(so, siz, siz); + if (error) { m_freem(mynam); return (error); } @@ -346,11 +392,8 @@ nfssvc_addsock(fp, mynam) slp = (struct nfssvc_sock *) malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK); bzero((caddr_t)slp, sizeof (struct nfssvc_sock)); - slp->ns_prev = nfssvc_sockhead.ns_prev; - slp->ns_prev->ns_next = slp; - slp->ns_next = &nfssvc_sockhead; - nfssvc_sockhead.ns_prev = slp; - slp->ns_lrunext = slp->ns_lruprev = (struct nfsuid *)slp; + TAILQ_INIT(&slp->ns_uidlruhead); + TAILQ_INSERT_TAIL(&nfssvc_sockhead, slp, ns_chain); } slp->ns_so = so; slp->ns_nam = mynam; @@ -369,65 +412,68 @@ nfssvc_addsock(fp, mynam) * Called by nfssvc() for nfsds. Just loops around servicing rpc requests * until it is killed by a signal. */ +int nfssvc_nfsd(nsd, argp, p) struct nfsd_srvargs *nsd; caddr_t argp; struct proc *p; { - register struct mbuf *m, *nam2; + register struct mbuf *m; register int siz; register struct nfssvc_sock *slp; register struct socket *so; register int *solockp; - struct nfsd *nd = nsd->nsd_nfsd; - struct mbuf *mreq, *nam; - struct timeval starttime; + struct nfsd *nfsd = nsd->nsd_nfsd; + struct nfsrv_descript *nd = NULL; + struct mbuf *mreq; struct nfsuid *uidp; - int error, cacherep, s; - int sotype; + int error = 0, cacherep, s, sotype, writes_todo; + u_quad_t cur_usec; +#ifndef nolint + cacherep = RC_DOIT; + writes_todo = 0; +#endif s = splnet(); - if (nd == (struct nfsd *)0) { - nsd->nsd_nfsd = nd = (struct nfsd *) + if (nfsd == (struct nfsd *)0) { + nsd->nsd_nfsd = nfsd = (struct nfsd *) malloc(sizeof (struct nfsd), M_NFSD, M_WAITOK); - bzero((caddr_t)nd, sizeof (struct nfsd)); - nd->nd_procp = p; - nd->nd_cr.cr_ref = 1; - insque(nd, &nfsd_head); - nd->nd_nqlflag = NQL_NOVAL; + bzero((caddr_t)nfsd, sizeof (struct nfsd)); + nfsd->nfsd_procp = p; + TAILQ_INSERT_TAIL(&nfsd_head, nfsd, nfsd_chain); nfs_numnfsd++; } /* * Loop getting rpc requests until SIGKILL. */ for (;;) { - if ((nd->nd_flag & NFSD_REQINPROG) == 0) { - while (nd->nd_slp == (struct nfssvc_sock *)0 && - (nfsd_head.nd_flag & NFSD_CHECKSLP) == 0) { - nd->nd_flag |= NFSD_WAITING; + if ((nfsd->nfsd_flag & NFSD_REQINPROG) == 0) { + while (nfsd->nfsd_slp == (struct nfssvc_sock *)0 && + (nfsd_head_flag & NFSD_CHECKSLP) == 0) { + nfsd->nfsd_flag |= NFSD_WAITING; nfsd_waiting++; - error = tsleep((caddr_t)nd, PSOCK | PCATCH, "nfsd", 0); + error = tsleep((caddr_t)nfsd, PSOCK | PCATCH, + "nfsd", 0); nfsd_waiting--; if (error) goto done; } - if (nd->nd_slp == (struct nfssvc_sock *)0 && - (nfsd_head.nd_flag & NFSD_CHECKSLP)) { - slp = nfssvc_sockhead.ns_next; - while (slp != &nfssvc_sockhead) { + if (nfsd->nfsd_slp == (struct nfssvc_sock *)0 && + (nfsd_head_flag & NFSD_CHECKSLP) != 0) { + for (slp = nfssvc_sockhead.tqh_first; slp != 0; + slp = slp->ns_chain.tqe_next) { if ((slp->ns_flag & (SLP_VALID | SLP_DOREC)) == (SLP_VALID | SLP_DOREC)) { slp->ns_flag &= ~SLP_DOREC; slp->ns_sref++; - nd->nd_slp = slp; + nfsd->nfsd_slp = slp; break; } - slp = slp->ns_next; } - if (slp == &nfssvc_sockhead) - nfsd_head.nd_flag &= ~NFSD_CHECKSLP; + if (slp == 0) + nfsd_head_flag &= ~NFSD_CHECKSLP; } - if ((slp = nd->nd_slp) == (struct nfssvc_sock *)0) + if ((slp = nfsd->nfsd_slp) == (struct nfssvc_sock *)0) continue; if (slp->ns_flag & SLP_VALID) { if (slp->ns_flag & SLP_DISCONN) @@ -440,86 +486,78 @@ nfssvc_nfsd(nsd, argp, p) M_WAIT); nfs_sndunlock(&slp->ns_solock); } - error = nfsrv_dorec(slp, nd); - nd->nd_flag |= NFSD_REQINPROG; + error = nfsrv_dorec(slp, nfsd, &nd); + cur_usec = (u_quad_t)time.tv_sec * 1000000 + + (u_quad_t)time.tv_usec; + if (error && slp->ns_tq.lh_first && + slp->ns_tq.lh_first->nd_time <= cur_usec) { + error = 0; + cacherep = RC_DOIT; + writes_todo = 1; + } else + writes_todo = 0; + nfsd->nfsd_flag |= NFSD_REQINPROG; } } else { error = 0; - slp = nd->nd_slp; + slp = nfsd->nfsd_slp; } if (error || (slp->ns_flag & SLP_VALID) == 0) { - nd->nd_slp = (struct nfssvc_sock *)0; - nd->nd_flag &= ~NFSD_REQINPROG; + if (nd) { + free((caddr_t)nd, M_NFSRVDESC); + nd = NULL; + } + nfsd->nfsd_slp = (struct nfssvc_sock *)0; + nfsd->nfsd_flag &= ~NFSD_REQINPROG; nfsrv_slpderef(slp); continue; } splx(s); so = slp->ns_so; sotype = so->so_type; - starttime = time; if (so->so_proto->pr_flags & PR_CONNREQUIRED) solockp = &slp->ns_solock; else solockp = (int *)0; - /* - * nam == nam2 for connectionless protocols such as UDP - * nam2 == NULL for connection based protocols to disable - * recent request caching. - */ - if (nam2 = nd->nd_nam) { - nam = nam2; - cacherep = RC_CHECKIT; - } else { - nam = slp->ns_nam; - cacherep = RC_DOIT; - } + if (nd) { + nd->nd_starttime = time; + if (nd->nd_nam2) + nd->nd_nam = nd->nd_nam2; + else + nd->nd_nam = slp->ns_nam; - /* - * Check to see if authorization is needed. - */ - if (nd->nd_flag & NFSD_NEEDAUTH) { - static int logauth = 0; + /* + * Check to see if authorization is needed. + */ + if (nfsd->nfsd_flag & NFSD_NEEDAUTH) { + nfsd->nfsd_flag &= ~NFSD_NEEDAUTH; + nsd->nsd_haddr = mtod(nd->nd_nam, + struct sockaddr_in *)->sin_addr.s_addr; + nsd->nsd_authlen = nfsd->nfsd_authlen; + nsd->nsd_verflen = nfsd->nfsd_verflen; + if (!copyout(nfsd->nfsd_authstr,nsd->nsd_authstr, + nfsd->nfsd_authlen) && + !copyout(nfsd->nfsd_verfstr, nsd->nsd_verfstr, + nfsd->nfsd_verflen) && + !copyout((caddr_t)nsd, argp, sizeof (*nsd))) + return (ENEEDAUTH); + cacherep = RC_DROPIT; + } else + cacherep = nfsrv_getcache(nd, slp, &mreq); - nd->nd_flag &= ~NFSD_NEEDAUTH; - /* - * Check for a mapping already installed. - */ - uidp = slp->ns_uidh[NUIDHASH(nd->nd_cr.cr_uid)]; - while (uidp) { - if (uidp->nu_uid == nd->nd_cr.cr_uid) - break; - uidp = uidp->nu_hnext; - } - if (!uidp) { - nsd->nsd_uid = nd->nd_cr.cr_uid; - if (nam2 && logauth++ == 0) - log(LOG_WARNING, "Kerberized NFS using UDP\n"); - nsd->nsd_haddr = - mtod(nam, struct sockaddr_in *)->sin_addr.s_addr; - nsd->nsd_authlen = nd->nd_authlen; - if (copyout(nd->nd_authstr, nsd->nsd_authstr, - nd->nd_authlen) == 0 && - copyout((caddr_t)nsd, argp, sizeof (*nsd)) == 0) - return (ENEEDAUTH); - cacherep = RC_DROPIT; - } - } - if (cacherep == RC_CHECKIT) - cacherep = nfsrv_getcache(nam2, nd, &mreq); - - /* - * Check for just starting up for NQNFS and send - * fake "try again later" replies to the NQNFS clients. - */ - if (notstarted && nqnfsstarttime <= time.tv_sec) { + /* + * Check for just starting up for NQNFS and send + * fake "try again later" replies to the NQNFS clients. + */ + if (notstarted && nqnfsstarttime <= time.tv_sec) { if (modify_flag) { nqnfsstarttime = time.tv_sec + nqsrv_writeslack; modify_flag = 0; } else notstarted = 0; - } - if (notstarted) { - if (nd->nd_nqlflag == NQL_NOVAL) + } + if (notstarted) { + if ((nd->nd_flag & ND_NQNFS) == 0) cacherep = RC_DROPIT; else if (nd->nd_procnum != NFSPROC_WRITE) { nd->nd_procnum = NFSPROC_NOOP; @@ -527,36 +565,42 @@ nfssvc_nfsd(nsd, argp, p) cacherep = RC_DOIT; } else modify_flag = 1; - } else if (nd->nd_flag & NFSD_AUTHFAIL) { - nd->nd_flag &= ~NFSD_AUTHFAIL; + } else if (nfsd->nfsd_flag & NFSD_AUTHFAIL) { + nfsd->nfsd_flag &= ~NFSD_AUTHFAIL; nd->nd_procnum = NFSPROC_NOOP; - nd->nd_repstat = NQNFS_AUTHERR; + nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK); cacherep = RC_DOIT; + } } - switch (cacherep) { - case RC_DOIT: - error = (*(nfsrv_procs[nd->nd_procnum]))(nd, - nd->nd_mrep, nd->nd_md, nd->nd_dpos, &nd->nd_cr, - nam, &mreq); - if (nd->nd_cr.cr_ref != 1) { - printf("nfssvc cref=%d\n", nd->nd_cr.cr_ref); - panic("nfssvc cref"); - } + /* + * Loop to get all the write rpc relies that have been + * gathered together. + */ + do { + switch (cacherep) { + case RC_DOIT: + if (writes_todo || (nd->nd_procnum == NFSPROC_WRITE && + nfsrvw_procrastinate > 0 && !notstarted)) + error = nfsrv_writegather(&nd, slp, + nfsd->nfsd_procp, &mreq); + else + error = (*(nfsrv3_procs[nd->nd_procnum]))(nd, + slp, nfsd->nfsd_procp, &mreq); + if (mreq == NULL) + break; if (error) { if (nd->nd_procnum != NQNFSPROC_VACATED) nfsstats.srv_errs++; - if (nam2) { - nfsrv_updatecache(nam2, nd, FALSE, mreq); - m_freem(nam2); - } + nfsrv_updatecache(nd, FALSE, mreq); + if (nd->nd_nam2) + m_freem(nd->nd_nam2); break; } nfsstats.srvrpccnt[nd->nd_procnum]++; - if (nam2) - nfsrv_updatecache(nam2, nd, TRUE, mreq); + nfsrv_updatecache(nd, TRUE, mreq); nd->nd_mrep = (struct mbuf *)0; - case RC_REPLY: + case RC_REPLY: m = mreq; siz = 0; while (m) { @@ -581,15 +625,15 @@ nfssvc_nfsd(nsd, argp, p) if (solockp) (void) nfs_sndlock(solockp, (struct nfsreq *)0); if (slp->ns_flag & SLP_VALID) - error = nfs_send(so, nam2, m, (struct nfsreq *)0); + error = nfs_send(so, nd->nd_nam2, m, NULL); else { error = EPIPE; m_freem(m); } if (nfsrtton) - nfsd_rt(&starttime, sotype, nd, nam, cacherep); - if (nam2) - MFREE(nam2, m); + nfsd_rt(sotype, nd, cacherep); + if (nd->nd_nam2) + MFREE(nd->nd_nam2, m); if (nd->nd_mrep) m_freem(nd->nd_mrep); if (error == EPIPE) @@ -597,29 +641,50 @@ nfssvc_nfsd(nsd, argp, p) if (solockp) nfs_sndunlock(solockp); if (error == EINTR || error == ERESTART) { + free((caddr_t)nd, M_NFSRVDESC); nfsrv_slpderef(slp); s = splnet(); goto done; } break; - case RC_DROPIT: + case RC_DROPIT: if (nfsrtton) - nfsd_rt(&starttime, sotype, nd, nam, cacherep); + nfsd_rt(sotype, nd, cacherep); m_freem(nd->nd_mrep); - m_freem(nam2); + m_freem(nd->nd_nam2); break; - }; + }; + if (nd) { + FREE((caddr_t)nd, M_NFSRVDESC); + nd = NULL; + } + + /* + * Check to see if there are outstanding writes that + * need to be serviced. + */ + cur_usec = (u_quad_t)time.tv_sec * 1000000 + + (u_quad_t)time.tv_usec; + s = splsoftclock(); + if (slp->ns_tq.lh_first && + slp->ns_tq.lh_first->nd_time <= cur_usec) { + cacherep = RC_DOIT; + writes_todo = 1; + } else + writes_todo = 0; + splx(s); + } while (writes_todo); s = splnet(); - if (nfsrv_dorec(slp, nd)) { - nd->nd_flag &= ~NFSD_REQINPROG; - nd->nd_slp = (struct nfssvc_sock *)0; + if (nfsrv_dorec(slp, nfsd, &nd)) { + nfsd->nfsd_flag &= ~NFSD_REQINPROG; + nfsd->nfsd_slp = NULL; nfsrv_slpderef(slp); } } done: - remque(nd); + TAILQ_REMOVE(&nfsd_head, nfsd, nfsd_chain); splx(s); - free((caddr_t)nd, M_NFSD); + free((caddr_t)nfsd, M_NFSD); nsd->nsd_nfsd = (struct nfsd *)0; if (--nfs_numnfsd == 0) nfsrv_init(TRUE); /* Reinitialize everything */ @@ -631,12 +696,14 @@ done: * They do read-ahead and write-behind operations on the block I/O cache. * Never returns unless it fails or gets killed. */ +int nfssvc_iod(p) struct proc *p; { - register struct buf *bp; + register struct buf *bp, *nbp; register int i, myiod; - int error = 0; + struct vnode *vp; + int error = 0, s; /* * Assign my position or return error if too many already running @@ -655,24 +722,52 @@ nfssvc_iod(p) * Just loop around doin our stuff until SIGKILL */ for (;;) { - while (nfs_bufq.tqh_first == NULL && error == 0) { - nfs_iodwant[myiod] = p; - error = tsleep((caddr_t)&nfs_iodwant[myiod], - PWAIT | PCATCH, "nfsidl", 0); - } - while ((bp = nfs_bufq.tqh_first) != NULL) { - /* Take one off the front of the list */ - TAILQ_REMOVE(&nfs_bufq, bp, b_freelist); - if (bp->b_flags & B_READ) - (void) nfs_doio(bp, bp->b_rcred, (struct proc *)0); - else - (void) nfs_doio(bp, bp->b_wcred, (struct proc *)0); - } - if (error) { - nfs_asyncdaemon[myiod] = 0; - nfs_numasync--; - return (error); - } + while (nfs_bufq.tqh_first == NULL && error == 0) { + nfs_iodwant[myiod] = p; + error = tsleep((caddr_t)&nfs_iodwant[myiod], + PWAIT | PCATCH, "nfsidl", 0); + } + while ((bp = nfs_bufq.tqh_first) != NULL) { + /* Take one off the front of the list */ + TAILQ_REMOVE(&nfs_bufq, bp, b_freelist); + if (bp->b_flags & B_READ) + (void) nfs_doio(bp, bp->b_rcred, (struct proc *)0); + else do { + /* + * Look for a delayed write for the same vnode, so I can do + * it now. We must grab it before calling nfs_doio() to + * avoid any risk of the vnode getting vclean()'d while + * we are doing the write rpc. + */ + vp = bp->b_vp; + s = splbio(); + for (nbp = vp->v_dirtyblkhd.lh_first; nbp; + nbp = nbp->b_vnbufs.le_next) { + if ((nbp->b_flags & + (B_BUSY|B_DELWRI|B_NEEDCOMMIT|B_NOCACHE))!=B_DELWRI) + continue; + bremfree(nbp); + nbp->b_flags |= (B_BUSY|B_ASYNC); + break; + } + splx(s); + /* + * For the delayed write, do the first part of nfs_bwrite() + * up to, but not including nfs_strategy(). + */ + if (nbp) { + nbp->b_flags &= ~(B_READ|B_DONE|B_ERROR|B_DELWRI); + reassignbuf(nbp, nbp->b_vp); + nbp->b_vp->v_numoutput++; + } + (void) nfs_doio(bp, bp->b_wcred, (struct proc *)0); + } while (bp = nbp); + } + if (error) { + nfs_asyncdaemon[myiod] = 0; + nfs_numasync--; + return (error); + } } } @@ -683,17 +778,20 @@ nfssvc_iod(p) * will stop using it and clear ns_flag at the end so that it will not be * reassigned during cleanup. */ +void nfsrv_zapsock(slp) register struct nfssvc_sock *slp; { - register struct nfsuid *nuidp, *onuidp; - register int i; + register struct nfsuid *nuidp, *nnuidp; + register struct nfsrv_descript *nwp, *nnwp; struct socket *so; struct file *fp; struct mbuf *m; + int s; slp->ns_flag &= ~SLP_ALLFLAGS; - if (fp = slp->ns_fp) { + fp = slp->ns_fp; + if (fp) { slp->ns_fp = (struct file *)0; so = slp->ns_so; so->so_upcall = NULL; @@ -703,15 +801,23 @@ nfsrv_zapsock(slp) MFREE(slp->ns_nam, m); m_freem(slp->ns_raw); m_freem(slp->ns_rec); - nuidp = slp->ns_lrunext; - while (nuidp != (struct nfsuid *)slp) { - onuidp = nuidp; - nuidp = nuidp->nu_lrunext; - free((caddr_t)onuidp, M_NFSUID); + for (nuidp = slp->ns_uidlruhead.tqh_first; nuidp != 0; + nuidp = nnuidp) { + nnuidp = nuidp->nu_lru.tqe_next; + LIST_REMOVE(nuidp, nu_hash); + TAILQ_REMOVE(&slp->ns_uidlruhead, nuidp, nu_lru); + if (nuidp->nu_flag & NU_NAM) + m_freem(nuidp->nu_nam); + free((caddr_t)nuidp, M_NFSUID); + } + s = splsoftclock(); + for (nwp = slp->ns_tq.lh_first; nwp; nwp = nnwp) { + nnwp = nwp->nd_tq.le_next; + LIST_REMOVE(nwp, nd_tq); + free((caddr_t)nwp, M_NFSRVDESC); } - slp->ns_lrunext = slp->ns_lruprev = (struct nfsuid *)slp; - for (i = 0; i < NUIDHASHSIZ; i++) - slp->ns_uidh[i] = (struct nfsuid *)0; + LIST_INIT(&slp->ns_tq); + splx(s); } } @@ -719,13 +825,16 @@ nfsrv_zapsock(slp) * Get an authorization string for the uid by having the mount_nfs sitting * on this mount point porpous out of the kernel and do it. */ -nfs_getauth(nmp, rep, cred, auth_type, auth_str, auth_len) +int +nfs_getauth(nmp, rep, cred, auth_str, auth_len, verf_str, verf_len, key) register struct nfsmount *nmp; struct nfsreq *rep; struct ucred *cred; - int *auth_type; char **auth_str; int *auth_len; + char *verf_str; + int *verf_len; + NFSKERBKEY_T key; /* return session key */ { int error = 0; @@ -733,13 +842,17 @@ nfs_getauth(nmp, rep, cred, auth_type, auth_str, auth_len) nmp->nm_flag |= NFSMNT_WANTAUTH; (void) tsleep((caddr_t)&nmp->nm_authtype, PSOCK, "nfsauth1", 2 * hz); - if (error = nfs_sigintr(nmp, rep, rep->r_procp)) { + error = nfs_sigintr(nmp, rep, rep->r_procp); + if (error) { nmp->nm_flag &= ~NFSMNT_WANTAUTH; return (error); } } nmp->nm_flag &= ~(NFSMNT_WAITAUTH | NFSMNT_WANTAUTH); nmp->nm_authstr = *auth_str = (char *)malloc(RPCAUTH_MAXSIZ, M_TEMP, M_WAITOK); + nmp->nm_authlen = RPCAUTH_MAXSIZ; + nmp->nm_verfstr = verf_str; + nmp->nm_verflen = *verf_len; nmp->nm_authuid = cred->cr_uid; wakeup((caddr_t)&nmp->nm_authstr); @@ -758,8 +871,9 @@ nfs_getauth(nmp, rep, cred, auth_type, auth_str, auth_len) if (error) free((caddr_t)*auth_str, M_TEMP); else { - *auth_type = nmp->nm_authtype; *auth_len = nmp->nm_authlen; + *verf_len = nmp->nm_verflen; + bcopy((caddr_t)nmp->nm_key, (caddr_t)key, sizeof (key)); } nmp->nm_flag &= ~NFSMNT_HASAUTH; nmp->nm_flag |= NFSMNT_WAITAUTH; @@ -771,6 +885,149 @@ nfs_getauth(nmp, rep, cred, auth_type, auth_str, auth_len) } /* + * Get a nickname authenticator and verifier. + */ +int +nfs_getnickauth(nmp, cred, auth_str, auth_len, verf_str, verf_len) + struct nfsmount *nmp; + struct ucred *cred; + char **auth_str; + int *auth_len; + char *verf_str; + int verf_len; +{ + register struct nfsuid *nuidp; + register u_long *nickp, *verfp; + struct timeval ktvin, ktvout; + NFSKERBKEYSCHED_T keys; /* stores key schedule */ + +#ifdef DIAGNOSTIC + if (verf_len < (4 * NFSX_UNSIGNED)) + panic("nfs_getnickauth verf too small"); +#endif + for (nuidp = NMUIDHASH(nmp, cred->cr_uid)->lh_first; + nuidp != 0; nuidp = nuidp->nu_hash.le_next) { + if (nuidp->nu_cr.cr_uid == cred->cr_uid) + break; + } + if (!nuidp || nuidp->nu_expire < time.tv_sec) + return (EACCES); + + /* + * Move to the end of the lru list (end of lru == most recently used). + */ + TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp, nu_lru); + TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp, nu_lru); + + nickp = (u_long *)malloc(2 * NFSX_UNSIGNED, M_TEMP, M_WAITOK); + *nickp++ = txdr_unsigned(RPCAKN_NICKNAME); + *nickp = txdr_unsigned(nuidp->nu_nickname); + *auth_str = (char *)nickp; + *auth_len = 2 * NFSX_UNSIGNED; + + /* + * Now we must encrypt the verifier and package it up. + */ + verfp = (u_long *)verf_str; + *verfp++ = txdr_unsigned(RPCAKN_NICKNAME); + if (time.tv_sec > nuidp->nu_timestamp.tv_sec || + (time.tv_sec == nuidp->nu_timestamp.tv_sec && + time.tv_usec > nuidp->nu_timestamp.tv_usec)) + nuidp->nu_timestamp = time; + else + nuidp->nu_timestamp.tv_usec++; + ktvin.tv_sec = txdr_unsigned(nuidp->nu_timestamp.tv_sec); + ktvin.tv_usec = txdr_unsigned(nuidp->nu_timestamp.tv_usec); + + /* + * Now encrypt the timestamp verifier in ecb mode using the session + * key. + */ +#ifdef NFSKERB + XXX +#endif + + *verfp++ = ktvout.tv_sec; + *verfp++ = ktvout.tv_usec; + *verfp = 0; + return (0); +} + +/* + * Save the current nickname in a hash list entry on the mount point. + */ +int +nfs_savenickauth(nmp, cred, len, key, mdp, dposp, mrep) + register struct nfsmount *nmp; + struct ucred *cred; + int len; + NFSKERBKEY_T key; + struct mbuf **mdp; + char **dposp; + struct mbuf *mrep; +{ + register struct nfsuid *nuidp; + register u_long *tl; + register long t1; + struct mbuf *md = *mdp; + struct timeval ktvin, ktvout; + u_long nick; + NFSKERBKEYSCHED_T keys; + char *dpos = *dposp, *cp2; + int deltasec, error = 0; + + if (len == (3 * NFSX_UNSIGNED)) { + nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED); + ktvin.tv_sec = *tl++; + ktvin.tv_usec = *tl++; + nick = fxdr_unsigned(u_long, *tl); + + /* + * Decrypt the timestamp in ecb mode. + */ +#ifdef NFSKERB + XXX +#endif + ktvout.tv_sec = fxdr_unsigned(long, ktvout.tv_sec); + ktvout.tv_usec = fxdr_unsigned(long, ktvout.tv_usec); + deltasec = time.tv_sec - ktvout.tv_sec; + if (deltasec < 0) + deltasec = -deltasec; + /* + * If ok, add it to the hash list for the mount point. + */ + if (deltasec <= NFS_KERBCLOCKSKEW) { + if (nmp->nm_numuids < nuidhash_max) { + nmp->nm_numuids++; + nuidp = (struct nfsuid *) + malloc(sizeof (struct nfsuid), M_NFSUID, + M_WAITOK); + } else { + nuidp = nmp->nm_uidlruhead.tqh_first; + LIST_REMOVE(nuidp, nu_hash); + TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp, + nu_lru); + } + nuidp->nu_flag = 0; + nuidp->nu_cr.cr_uid = cred->cr_uid; + nuidp->nu_expire = time.tv_sec + NFS_KERBTTL; + nuidp->nu_timestamp = ktvout; + nuidp->nu_nickname = nick; + bcopy(key, nuidp->nu_key, sizeof (key)); + TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp, + nu_lru); + LIST_INSERT_HEAD(NMUIDHASH(nmp, cred->cr_uid), + nuidp, nu_hash); + } + } else + nfsm_adv(nfsm_rndup(len)); +nfsmout: + *mdp = md; + *dposp = dpos; + return (error); +} + +/* * Derefence a server socket structure. If it has no more references and * is no longer valid, you can throw it away. */ @@ -779,8 +1036,7 @@ nfsrv_slpderef(slp) register struct nfssvc_sock *slp; { if (--(slp->ns_sref) == 0 && (slp->ns_flag & SLP_VALID) == 0) { - slp->ns_prev->ns_next = slp->ns_next; - slp->ns_next->ns_prev = slp->ns_prev; + TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain); free((caddr_t)slp, M_NFSSVC); } } @@ -794,59 +1050,52 @@ void nfsrv_init(terminating) int terminating; { - register struct nfssvc_sock *slp; - struct nfssvc_sock *oslp; + register struct nfssvc_sock *slp, *nslp; - if (nfssvc_sockhead.ns_flag & SLP_INIT) + if (nfssvc_sockhead_flag & SLP_INIT) panic("nfsd init"); - nfssvc_sockhead.ns_flag |= SLP_INIT; + nfssvc_sockhead_flag |= SLP_INIT; if (terminating) { - slp = nfssvc_sockhead.ns_next; - while (slp != &nfssvc_sockhead) { + for (slp = nfssvc_sockhead.tqh_first; slp != 0; slp = nslp) { + nslp = slp->ns_chain.tqe_next; if (slp->ns_flag & SLP_VALID) nfsrv_zapsock(slp); - slp->ns_next->ns_prev = slp->ns_prev; - slp->ns_prev->ns_next = slp->ns_next; - oslp = slp; - slp = slp->ns_next; - free((caddr_t)oslp, M_NFSSVC); + TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain); + free((caddr_t)slp, M_NFSSVC); } nfsrv_cleancache(); /* And clear out server cache */ } + + TAILQ_INIT(&nfssvc_sockhead); + nfssvc_sockhead_flag &= ~SLP_INIT; + if (nfssvc_sockhead_flag & SLP_WANTINIT) { + nfssvc_sockhead_flag &= ~SLP_WANTINIT; + wakeup((caddr_t)&nfssvc_sockhead); + } + + TAILQ_INIT(&nfsd_head); + nfsd_head_flag &= ~NFSD_CHECKSLP; + nfs_udpsock = (struct nfssvc_sock *) malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK); bzero((caddr_t)nfs_udpsock, sizeof (struct nfssvc_sock)); + TAILQ_INIT(&nfs_udpsock->ns_uidlruhead); + TAILQ_INSERT_HEAD(&nfssvc_sockhead, nfs_udpsock, ns_chain); + nfs_cltpsock = (struct nfssvc_sock *) malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK); bzero((caddr_t)nfs_cltpsock, sizeof (struct nfssvc_sock)); - nfssvc_sockhead.ns_next = nfs_udpsock; - nfs_udpsock->ns_next = nfs_cltpsock; - nfs_cltpsock->ns_next = &nfssvc_sockhead; - nfssvc_sockhead.ns_prev = nfs_cltpsock; - nfs_cltpsock->ns_prev = nfs_udpsock; - nfs_udpsock->ns_prev = &nfssvc_sockhead; - nfs_udpsock->ns_lrunext = nfs_udpsock->ns_lruprev = - (struct nfsuid *)nfs_udpsock; - nfs_cltpsock->ns_lrunext = nfs_cltpsock->ns_lruprev = - (struct nfsuid *)nfs_cltpsock; - nfsd_head.nd_next = nfsd_head.nd_prev = &nfsd_head; - nfsd_head.nd_flag = 0; - nfssvc_sockhead.ns_flag &= ~SLP_INIT; - if (nfssvc_sockhead.ns_flag & SLP_WANTINIT) { - nfssvc_sockhead.ns_flag &= ~SLP_WANTINIT; - wakeup((caddr_t)&nfssvc_sockhead); - } + TAILQ_INIT(&nfs_cltpsock->ns_uidlruhead); + TAILQ_INSERT_TAIL(&nfssvc_sockhead, nfs_cltpsock, ns_chain); } /* * Add entries to the server monitor log. */ static void -nfsd_rt(startp, sotype, nd, nam, cacherep) - struct timeval *startp; +nfsd_rt(sotype, nd, cacherep) int sotype; - register struct nfsd *nd; - struct mbuf *nam; + register struct nfsrv_descript *nd; int cacherep; { register struct drt *rt; @@ -860,15 +1109,17 @@ nfsd_rt(startp, sotype, nd, nam, cacherep) rt->flag = DRT_CACHEDROP; if (sotype == SOCK_STREAM) rt->flag |= DRT_TCP; - if (nd->nd_nqlflag != NQL_NOVAL) + if (nd->nd_flag & ND_NQNFS) rt->flag |= DRT_NQNFS; + else if (nd->nd_flag & ND_NFSV3) + rt->flag |= DRT_NFSV3; rt->proc = nd->nd_procnum; - if (mtod(nam, struct sockaddr *)->sa_family == AF_INET) - rt->ipadr = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr; + if (mtod(nd->nd_nam, struct sockaddr *)->sa_family == AF_INET) + rt->ipadr = mtod(nd->nd_nam, struct sockaddr_in *)->sin_addr.s_addr; else - rt->ipadr = INADDR_ANY; - rt->resptime = ((time.tv_sec - startp->tv_sec) * 1000000) + - (time.tv_usec - startp->tv_usec); + rt->ipadr = INADDR_ANY; + rt->resptime = ((time.tv_sec - nd->nd_starttime.tv_sec) * 1000000) + + (time.tv_usec - nd->nd_starttime.tv_usec); rt->tstamp = time; nfsdrt.pos = (nfsdrt.pos + 1) % NFSRTTLOGSIZ; } diff --git a/sys/nfs/nfs_vfsops.c b/sys/nfs/nfs_vfsops.c index 1f18676..54e2a71 100644 --- a/sys/nfs/nfs_vfsops.c +++ b/sys/nfs/nfs_vfsops.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1989, 1993 + * 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 @@ -33,7 +33,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfs_vfsops.c 8.3 (Berkeley) 1/4/94 + * @(#)nfs_vfsops.c 8.12 (Berkeley) 5/20/95 */ #include @@ -48,6 +48,7 @@ #include #include #include +#include #include #include @@ -55,15 +56,20 @@ #include #include -#include +#include #include -#include #include +#include #include #include #include #include +struct nfsstats nfsstats; +static int nfs_sysctl(int *, u_int, void *, size_t *, void *, size_t, + struct proc *); +extern int nfs_ticks; + /* * nfs vfs operations. */ @@ -79,6 +85,7 @@ struct vfsops nfs_vfsops = { nfs_fhtovp, nfs_vptofh, nfs_init, + nfs_sysctl }; /* @@ -87,16 +94,14 @@ struct vfsops nfs_vfsops = { * to ensure that it is allocated to initialized data (.data not .bss). */ struct nfs_diskless nfs_diskless = { 0 }; +int nfs_diskless_valid = 0; -extern u_long nfs_procids[NFS_NPROCS]; -extern u_long nfs_prog, nfs_vers; void nfs_disconnect __P((struct nfsmount *)); void nfsargs_ntoh __P((struct nfs_args *)); -static struct mount *nfs_mountdiskless __P((char *, char *, int, - struct sockaddr_in *, struct nfs_args *, register struct vnode **)); - -#define TRUE 1 -#define FALSE 0 +int nfs_fsinfo __P((struct nfsmount *, struct vnode *, struct ucred *, + struct proc *)); +static int nfs_mountdiskless __P((char *, char *, int, struct sockaddr_in *, + struct nfs_args *, struct proc *, struct vnode **, struct mount **)); /* * nfs statfs call @@ -108,39 +113,55 @@ nfs_statfs(mp, sbp, p) struct proc *p; { register struct vnode *vp; - register struct nfsv2_statfs *sfp; + register struct nfs_statfs *sfp; register caddr_t cp; - register long t1; + register u_long *tl; + register long t1, t2; caddr_t bpos, dpos, cp2; - int error = 0, isnq; + struct nfsmount *nmp = VFSTONFS(mp); + int error = 0, v3 = (nmp->nm_flag & NFSMNT_NFSV3), retattr; struct mbuf *mreq, *mrep, *md, *mb, *mb2; - struct nfsmount *nmp; struct ucred *cred; struct nfsnode *np; + u_quad_t tquad; - nmp = VFSTONFS(mp); - isnq = (nmp->nm_flag & NFSMNT_NQNFS); - if (error = nfs_nget(mp, &nmp->nm_fh, &np)) +#ifndef nolint + sfp = (struct nfs_statfs *)0; +#endif + error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np); + if (error) return (error); vp = NFSTOV(np); - nfsstats.rpccnt[NFSPROC_STATFS]++; cred = crget(); cred->cr_ngroups = 1; - nfsm_reqhead(vp, NFSPROC_STATFS, NFSX_FH); - nfsm_fhtom(vp); - nfsm_request(vp, NFSPROC_STATFS, p, cred); - nfsm_dissect(sfp, struct nfsv2_statfs *, NFSX_STATFS(isnq)); - sbp->f_type = MOUNT_NFS; - sbp->f_flags = nmp->nm_flag; - sbp->f_iosize = NFS_MAXDGRAMDATA; - 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 (isnq) { - sbp->f_files = fxdr_unsigned(long, sfp->sf_files); - sbp->f_ffree = fxdr_unsigned(long, sfp->sf_ffree); + 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_fhtom(vp, v3); + nfsm_request(vp, NFSPROC_FSSTAT, p, cred); + if (v3) + nfsm_postop_attr(vp, retattr); + if (!error) + nfsm_dissect(sfp, struct nfs_statfs *, NFSX_STATFS(v3)); + sbp->f_iosize = min(nmp->nm_rsize, nmp->nm_wsize); + if (v3) { + 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]) + & 0x7fffffff); + sbp->f_ffree = (fxdr_unsigned(long, sfp->sf_ffiles.nfsuquad[1]) + & 0x7fffffff); } else { + 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); sbp->f_files = 0; sbp->f_ffree = 0; } @@ -155,6 +176,66 @@ nfs_statfs(mp, sbp, p) } /* + * nfs version 3 fsinfo rpc call + */ +int +nfs_fsinfo(nmp, vp, cred, p) + register struct nfsmount *nmp; + register struct vnode *vp; + struct ucred *cred; + struct proc *p; +{ + register struct nfsv3_fsinfo *fsp; + register caddr_t cp; + register long t1, t2; + register u_long *tl, pref, max; + caddr_t bpos, dpos, cp2; + int error = 0, retattr; + struct mbuf *mreq, *mrep, *md, *mb, *mb2; + + nfsstats.rpccnt[NFSPROC_FSINFO]++; + nfsm_reqhead(vp, NFSPROC_FSINFO, NFSX_FH(1)); + nfsm_fhtom(vp, 1); + nfsm_request(vp, NFSPROC_FSINFO, p, cred); + nfsm_postop_attr(vp, retattr); + if (!error) { + 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) & + ~(NFS_FABLKSIZE - 1); + max = fxdr_unsigned(u_long, fsp->fs_wtmax); + if (max < nmp->nm_wsize) { + nmp->nm_wsize = max & ~(NFS_FABLKSIZE - 1); + if (nmp->nm_wsize == 0) + nmp->nm_wsize = max; + } + pref = fxdr_unsigned(u_long, fsp->fs_rtpref); + if (pref < nmp->nm_rsize) + nmp->nm_rsize = (pref + NFS_FABLKSIZE - 1) & + ~(NFS_FABLKSIZE - 1); + max = fxdr_unsigned(u_long, fsp->fs_rtmax); + if (max < nmp->nm_rsize) { + nmp->nm_rsize = max & ~(NFS_FABLKSIZE - 1); + if (nmp->nm_rsize == 0) + nmp->nm_rsize = max; + } + pref = fxdr_unsigned(u_long, fsp->fs_dtpref); + if (pref < nmp->nm_readdirsize) + nmp->nm_readdirsize = (pref + NFS_DIRBLKSIZ - 1) & + ~(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; + } + nfsm_reqdone; + return (error); +} + +/* * 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 * bootstrap. @@ -170,12 +251,14 @@ nfs_statfs(mp, sbp, p) int nfs_mountroot() { - register struct mount *mp; - register struct nfs_diskless *nd = &nfs_diskless; + struct mount *mp, *swap_mp; + struct nfs_diskless *nd = &nfs_diskless; struct socket *so; struct vnode *vp; struct proc *p = curproc; /* XXX */ int error, i; + u_long l; + char buf[128]; /* * XXX time must be non-zero when we init the interface or else @@ -184,6 +267,11 @@ nfs_mountroot() if (time.tv_sec == 0) time.tv_sec = 1; + /* + * XXX splnet, so networks will receive... + */ + splnet(); + #ifdef notyet /* Set up swap credentials. */ proc0.p_ucred->cr_uid = ntohl(nd->swap_ucred.cr_uid); @@ -199,10 +287,31 @@ nfs_mountroot() * Do enough of ifconfig(8) so that the critical net interface can * talk to the server. */ - if (error = socreate(nd->myif.ifra_addr.sa_family, &so, SOCK_DGRAM, 0)) - panic("nfs_mountroot: socreate: %d", error); - if (error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, p)) - panic("nfs_mountroot: SIOCAIFADDR: %d", error); + error = socreate(nd->myif.ifra_addr.sa_family, &so, SOCK_DGRAM, 0); + if (error) { + printf("nfs_mountroot: socreate(%04x): %d", + nd->myif.ifra_addr.sa_family, error); + return (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); + if(!error) + break; + } + if (error) { + printf("nfs_mountroot: SIOCAIFADDR: %d", error); + return (error); + } soclose(so); /* @@ -215,23 +324,40 @@ nfs_mountroot() sin = mask; sin.sin_family = AF_INET; sin.sin_len = sizeof(sin); - if (error = rtrequest(RTM_ADD, (struct sockaddr *)&sin, + error = rtrequest(RTM_ADD, (struct sockaddr *)&sin, (struct sockaddr *)&nd->mygateway, (struct sockaddr *)&mask, - RTF_UP | RTF_GATEWAY, (struct rtentry **)0)) - panic("nfs_mountroot: RTM_ADD: %d", error); + RTF_UP | RTF_GATEWAY, (struct rtentry **)0); + if (error) { + printf("nfs_mountroot: RTM_ADD: %d", error); + return (error); + } } - /* - * If swapping to an nfs node (indicated by swdevt[0].sw_dev == NODEV): - * Create a fake mount point just for the swap vnode so that the - * swap file can be on a different server from the rootfs. - */ - if (swdevt[0].sw_dev == NODEV) { - nd->swap_args.fh = (nfsv2fh_t *)nd->swap_fh; - (void) nfs_mountdiskless(nd->swap_hostnam, "/swap", 0, - &nd->swap_saddr, &nd->swap_args, &vp); - + swap_mp = NULL; + if (nd->swap_nblks) { + /* + * 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_fhsize. + */ + 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)) + return (error); + vfs_unbusy(swap_mp, p); + + 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. @@ -240,25 +366,44 @@ nfs_mountroot() vp->v_flag = 0; swapdev_vp = vp; VREF(vp); - swdevt[0].sw_vp = vp; - swdevt[0].sw_nblks = ntohl(nd->swap_nblks); - } else if (bdevvp(swapdev, &swapdev_vp)) - panic("nfs_mountroot: can't setup swapdev_vp"); + swdevt[i].sw_vp = vp; + swdevt[i].sw_nblks = nd->swap_nblks*2; + + if (!swdevt[i].sw_nblks) { + swdevt[i].sw_nblks = 2048; + printf("defaulting to %d kbyte.\n", + swdevt[i].sw_nblks/2); + } else + printf("using %d kbyte.\n",swdevt[i].sw_nblks/2); + } /* * Create the rootfs mount point. */ - nd->root_args.fh = (nfsv2fh_t *)nd->root_fh; - mp = nfs_mountdiskless(nd->root_hostnam, "/", MNT_RDONLY, - &nd->root_saddr, &nd->root_args, &vp); - - if (vfs_lock(mp)) - panic("nfs_mountroot: vfs_lock"); - TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); - mp->mnt_flag |= MNT_ROOTFS; - mp->mnt_vnodecovered = NULLVP; - vfs_unlock(mp); + 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)) { + if (swap_mp) { + mp->mnt_vfc->vfc_refcount--; + free(swap_mp, M_MOUNT); + } + return (error); + } + + simple_lock(&mountlist_slock); + CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); + simple_unlock(&mountlist_slock); rootvp = vp; + vfs_unbusy(mp, p); /* * This is not really an nfs issue, but it is much easier to @@ -278,59 +423,39 @@ nfs_mountroot() /* * Internal version of mount system call for diskless setup. */ -static struct mount * -nfs_mountdiskless(path, which, mountflag, sin, args, vpp) +static int +nfs_mountdiskless(path, which, mountflag, sin, args, p, vpp, mpp) char *path; char *which; int mountflag; struct sockaddr_in *sin; struct nfs_args *args; - register struct vnode **vpp; + struct proc *p; + struct vnode **vpp; + struct mount **mpp; { - register struct mount *mp; - register struct mbuf *m; - register int error; - - mp = (struct mount *)malloc((u_long)sizeof(struct mount), - M_MOUNT, M_NOWAIT); - if (mp == NULL) - panic("nfs_mountroot: %s mount malloc", which); - bzero((char *)mp, (u_long)sizeof(struct mount)); - mp->mnt_op = &nfs_vfsops; - mp->mnt_flag = mountflag; + struct mount *mp; + struct mbuf *m; + int error; - MGET(m, MT_SONAME, M_DONTWAIT); - if (m == NULL) - panic("nfs_mountroot: %s mount mbuf", which); + if (error = vfs_rootmountalloc("nfs", path, &mp)) { + printf("nfs_mountroot: NFS not configured"); + return (error); + } + mp->mnt_flag = mountflag; + MGET(m, MT_SONAME, M_WAITOK); bcopy((caddr_t)sin, mtod(m, caddr_t), sin->sin_len); m->m_len = sin->sin_len; - nfsargs_ntoh(args); - if (error = mountnfs(args, mp, m, which, path, vpp)) - panic("nfs_mountroot: mount %s on %s: %d", path, which, error); - - return (mp); -} - -/* - * Convert the integer fields of the nfs_args structure from net byte order - * to host byte order. Called by nfs_mountroot() above. - */ -void -nfsargs_ntoh(nfsp) - register struct nfs_args *nfsp; -{ - - NTOHL(nfsp->sotype); - NTOHL(nfsp->proto); - NTOHL(nfsp->flags); - NTOHL(nfsp->wsize); - NTOHL(nfsp->rsize); - NTOHL(nfsp->timeo); - NTOHL(nfsp->retrans); - NTOHL(nfsp->maxgrouplist); - NTOHL(nfsp->readahead); - NTOHL(nfsp->leaseterm); - NTOHL(nfsp->deadthresh); + 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--; + vfs_unbusy(mp, p); + free(mp, M_MOUNT); + return (error); + } + (void) copystr(which, mp->mnt_stat.f_mntonname, MNAMELEN - 1, 0); + *mpp = mp; + return (0); } /* @@ -357,23 +482,29 @@ nfs_mount(mp, path, data, ndp, p) struct vnode *vp; char pth[MNAMELEN], hst[MNAMELEN]; u_int len; - nfsv2fh_t nfh; + u_char nfh[NFSX_V3FHMAX]; - if (error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args))) + error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args)); + if (error) return (error); - if (error = copyin((caddr_t)args.fh, (caddr_t)&nfh, sizeof (nfsv2fh_t))) + if (args.version != NFS_ARGSVERSION) + return (EPROGMISMATCH); + error = copyin((caddr_t)args.fh, (caddr_t)nfh, args.fhsize); + if (error) return (error); - if (error = copyinstr(path, pth, MNAMELEN-1, &len)) + error = copyinstr(path, pth, MNAMELEN-1, &len); + if (error) return (error); bzero(&pth[len], MNAMELEN - len); - if (error = copyinstr(args.hostname, hst, MNAMELEN-1, &len)) + error = copyinstr(args.hostname, hst, MNAMELEN-1, &len); + if (error) return (error); bzero(&hst[len], MNAMELEN - len); /* sockargs() call must be after above copyin() calls */ - if (error = sockargs(&nam, (caddr_t)args.addr, - args.addrlen, MT_SONAME)) + error = sockargs(&nam, (caddr_t)args.addr, args.addrlen, MT_SONAME); + if (error) return (error); - args.fh = &nfh; + args.fh = nfh; error = mountnfs(&args, mp, nam, pth, hst, &vp); return (error); } @@ -391,7 +522,7 @@ mountnfs(argp, mp, nam, pth, hst, vpp) { register struct nfsmount *nmp; struct nfsnode *np; - int error; + int error, maxio; if (mp->mnt_flag & MNT_UPDATE) { nmp = VFSTONFS(mp); @@ -402,16 +533,12 @@ mountnfs(argp, mp, nam, pth, hst, vpp) MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount), M_NFSMNT, M_WAITOK); bzero((caddr_t)nmp, sizeof (struct nfsmount)); + TAILQ_INIT(&nmp->nm_uidlruhead); mp->mnt_data = (qaddr_t)nmp; } - getnewfsid(mp, MOUNT_NFS); + vfs_getnewfsid(mp); nmp->nm_mountp = mp; nmp->nm_flag = argp->flags; - if ((nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_MYWRITE)) == - (NFSMNT_NQNFS | NFSMNT_MYWRITE)) { - error = EPERM; - goto bad; - } if (nmp->nm_flag & NFSMNT_NQNFS) /* * We have to set mnt_maxsymlink to a non-zero value so @@ -424,15 +551,15 @@ mountnfs(argp, mp, nam, pth, hst, vpp) 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; - nmp->nm_tnext = (struct nfsnode *)nmp; - nmp->nm_tprev = (struct nfsnode *)nmp; + CIRCLEQ_INIT(&nmp->nm_timerhead); nmp->nm_inprog = NULLVP; - bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t)); - mp->mnt_stat.f_type = MOUNT_NFS; + 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); nmp->nm_nam = nam; @@ -451,29 +578,48 @@ mountnfs(argp, mp, nam, pth, hst, vpp) nmp->nm_retry = NFS_MAXREXMIT; } + if (argp->flags & NFSMNT_NFSV3) { + if (argp->sotype == SOCK_DGRAM) + maxio = NFS_MAXDGRAMDATA; + else + maxio = NFS_MAXDATA; + } else + maxio = NFS_V2MAXDATA; + if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) { nmp->nm_wsize = argp->wsize; /* Round down to multiple of blocksize */ - nmp->nm_wsize &= ~0x1ff; + nmp->nm_wsize &= ~(NFS_FABLKSIZE - 1); if (nmp->nm_wsize <= 0) - nmp->nm_wsize = 512; - else if (nmp->nm_wsize > NFS_MAXDATA) - nmp->nm_wsize = NFS_MAXDATA; + nmp->nm_wsize = NFS_FABLKSIZE; } + if (nmp->nm_wsize > maxio) + 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 &= ~0x1ff; + nmp->nm_rsize &= ~(NFS_FABLKSIZE - 1); if (nmp->nm_rsize <= 0) - nmp->nm_rsize = 512; - else if (nmp->nm_rsize > NFS_MAXDATA) - nmp->nm_rsize = NFS_MAXDATA; + nmp->nm_rsize = NFS_FABLKSIZE; } + if (nmp->nm_rsize > maxio) + 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; @@ -513,7 +659,8 @@ mountnfs(argp, mp, nam, pth, hst, vpp) * this problem, because one can identify root inodes by their * number == ROOTINO (2). */ - if (error = nfs_nget(mp, &nmp->nm_fh, &np)) + error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np); + if (error) goto bad; *vpp = NFSTOV(np); @@ -538,13 +685,9 @@ nfs_unmount(mp, mntflags, p) struct nfsnode *np; struct vnode *vp; int error, flags = 0; - extern int doforce; - if (mntflags & MNT_FORCE) { - if (!doforce || (mp->mnt_flag & MNT_ROOTFS)) - return (EINVAL); + if (mntflags & MNT_FORCE) flags |= FORCECLOSE; - } nmp = VFSTONFS(mp); /* * Goes something like this.. @@ -560,7 +703,8 @@ nfs_unmount(mp, mntflags, p) * the remote root. See comment in mountnfs(). The VFS unmount() * has done vput on this vnode, otherwise we would get deadlock! */ - if (error = nfs_nget(mp, &nmp->nm_fh, &np)) + error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np); + if (error) return(error); vp = NFSTOV(np); if (vp->v_usecount > 2) { @@ -574,7 +718,8 @@ nfs_unmount(mp, mntflags, p) nmp->nm_flag |= NFSMNT_DISMINPROG; while (nmp->nm_inprog != NULLVP) (void) tsleep((caddr_t)&lbolt, PSOCK, "nfsdism", 0); - if (error = vflush(mp, vp, flags)) { + error = vflush(mp, vp, flags); + if (error) { vput(vp); nmp->nm_flag &= ~NFSMNT_DISMINPROG; return (error); @@ -615,7 +760,8 @@ nfs_root(mp, vpp) int error; nmp = VFSTONFS(mp); - if (error = nfs_nget(mp, &nmp->nm_fh, &np)) + error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np); + if (error) return (error); vp = NFSTOV(np); vp->v_type = VDIR; @@ -655,9 +801,10 @@ loop: goto loop; if (VOP_ISLOCKED(vp) || vp->v_dirtyblkhd.lh_first == NULL) continue; - if (vget(vp, 1)) + if (vget(vp, LK_EXCLUSIVE, p)) goto loop; - if (error = VOP_FSYNC(vp, cred, waitfor, p)) + error = VOP_FSYNC(vp, cred, waitfor, p); + if (error) allerror = error; vput(vp); } @@ -738,3 +885,47 @@ nfs_quotactl(mp, cmd, uid, arg, p) return (EOPNOTSUPP); } + +/* + * Do that sysctl thang... + */ +static int +nfs_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, + size_t newlen, struct proc *p) +{ + int rv; + + /* + * All names at this level are terminal. + */ + if(namelen > 1) + return ENOTDIR; /* overloaded */ + + switch(name[0]) { + case NFS_NFSSTATS: + if(!oldp) { + *oldlenp = sizeof nfsstats; + return 0; + } + + if(*oldlenp < sizeof nfsstats) { + *oldlenp = sizeof nfsstats; + return ENOMEM; + } + + rv = copyout(&nfsstats, oldp, sizeof nfsstats); + if(rv) return rv; + + if(newp && newlen != sizeof nfsstats) + return EINVAL; + + if(newp) { + return copyin(newp, &nfsstats, sizeof nfsstats); + } + return 0; + + default: + return EOPNOTSUPP; + } +} + diff --git a/sys/nfs/nfs_vnops.c b/sys/nfs/nfs_vnops.c index a909b48..c72f573 100644 --- a/sys/nfs/nfs_vnops.c +++ b/sys/nfs/nfs_vnops.c @@ -33,17 +33,19 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfs_vnops.c 8.5 (Berkeley) 2/13/94 + * @(#)nfs_vnops.c 8.16 (Berkeley) 5/27/95 */ + /* - * vnode op calls for sun nfs version 2 + * vnode op calls for Sun NFS version 2 and 3 */ #include -#include #include #include +#include +#include #include #include #include @@ -51,8 +53,9 @@ #include #include #include -#include #include +#include +#include #include @@ -60,7 +63,7 @@ #include #include -#include +#include #include #include #include @@ -68,6 +71,10 @@ #include #include +#include +#include +#include + /* Defs */ #define TRUE 1 #define FALSE 0 @@ -88,8 +95,10 @@ struct vnodeopv_entry_desc nfsv2_vnodeop_entries[] = { { &vop_setattr_desc, nfs_setattr }, /* setattr */ { &vop_read_desc, nfs_read }, /* read */ { &vop_write_desc, nfs_write }, /* write */ + { &vop_lease_desc, nfs_lease_check }, /* lease */ { &vop_ioctl_desc, nfs_ioctl }, /* ioctl */ { &vop_select_desc, nfs_select }, /* select */ + { &vop_revoke_desc, nfs_revoke }, /* revoke */ { &vop_mmap_desc, nfs_mmap }, /* mmap */ { &vop_fsync_desc, nfs_fsync }, /* fsync */ { &vop_seek_desc, nfs_seek }, /* seek */ @@ -118,7 +127,7 @@ struct vnodeopv_entry_desc nfsv2_vnodeop_entries[] = { { &vop_vfree_desc, nfs_vfree }, /* vfree */ { &vop_truncate_desc, nfs_truncate }, /* truncate */ { &vop_update_desc, nfs_update }, /* update */ - { &vop_bwrite_desc, vn_bwrite }, + { &vop_bwrite_desc, nfs_bwrite }, { (struct vnodeop_desc*)NULL, (int(*)())NULL } }; struct vnodeopv_desc nfsv2_vnodeop_opv_desc = @@ -140,8 +149,10 @@ struct vnodeopv_entry_desc spec_nfsv2nodeop_entries[] = { { &vop_setattr_desc, nfs_setattr }, /* setattr */ { &vop_read_desc, nfsspec_read }, /* read */ { &vop_write_desc, nfsspec_write }, /* write */ + { &vop_lease_desc, spec_lease_check }, /* lease */ { &vop_ioctl_desc, spec_ioctl }, /* ioctl */ { &vop_select_desc, spec_select }, /* select */ + { &vop_revoke_desc, spec_revoke }, /* revoke */ { &vop_mmap_desc, spec_mmap }, /* mmap */ { &vop_fsync_desc, nfs_fsync }, /* fsync */ { &vop_seek_desc, spec_seek }, /* seek */ @@ -176,7 +187,6 @@ struct vnodeopv_entry_desc spec_nfsv2nodeop_entries[] = { struct vnodeopv_desc spec_nfsv2nodeop_opv_desc = { &spec_nfsv2nodeop_p, spec_nfsv2nodeop_entries }; -#ifdef FIFO int (**fifo_nfsv2nodeop_p)(); struct vnodeopv_entry_desc fifo_nfsv2nodeop_entries[] = { { &vop_default_desc, vn_default_error }, @@ -190,8 +200,10 @@ struct vnodeopv_entry_desc fifo_nfsv2nodeop_entries[] = { { &vop_setattr_desc, nfs_setattr }, /* setattr */ { &vop_read_desc, nfsfifo_read }, /* read */ { &vop_write_desc, nfsfifo_write }, /* write */ + { &vop_lease_desc, fifo_lease_check }, /* lease */ { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */ { &vop_select_desc, fifo_select }, /* select */ + { &vop_revoke_desc, fifo_revoke }, /* revoke */ { &vop_mmap_desc, fifo_mmap }, /* mmap */ { &vop_fsync_desc, nfs_fsync }, /* fsync */ { &vop_seek_desc, fifo_seek }, /* seek */ @@ -225,16 +237,16 @@ struct vnodeopv_entry_desc fifo_nfsv2nodeop_entries[] = { }; struct vnodeopv_desc fifo_nfsv2nodeop_opv_desc = { &fifo_nfsv2nodeop_p, fifo_nfsv2nodeop_entries }; -#endif /* FIFO */ void nqnfs_clientlease(); +int nfs_commit(); /* * Global variables */ -extern u_long nfs_procids[NFS_NPROCS]; -extern u_long nfs_prog, nfs_vers, nfs_true, nfs_false; -extern char nfsiobuf[MAXPHYS+NBPG]; +extern u_long nfs_true, nfs_false; +extern struct nfsstats nfsstats; +extern nfstype nfsv3_type[9]; struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; int nfs_numasync = 0; #define DIRHDSIZ (sizeof (struct dirent) - (MAXNAMLEN + 1)) @@ -260,9 +272,9 @@ nfs_null(vp, cred, procp) /* * nfs access vnode op. - * For nfs, just return ok. File accesses may fail later. - * For nqnfs, use the access rpc to check accessibility. If file modes are - * changed on the server, accesses might still fail later. + * For nfs version 2, just return ok. File accesses may fail later. + * For nfs version 3, use the access rpc to check accessibility. If file modes + * are changed on the server, accesses might still fail later. */ int nfs_access(ap) @@ -276,36 +288,67 @@ nfs_access(ap) register struct vnode *vp = ap->a_vp; register u_long *tl; register caddr_t cp; - caddr_t bpos, dpos; - int error = 0; + register int t1, t2; + caddr_t bpos, dpos, cp2; + int error = 0, attrflag; struct mbuf *mreq, *mrep, *md, *mb, *mb2; + u_long mode, rmode; + int v3 = NFS_ISV3(vp); /* - * For nqnfs, do an access rpc, otherwise you are stuck emulating + * Disallow write attempts on filesystems mounted read-only; + * unless the file is a socket, fifo, or a block or character + * device resident on the filesystem. + */ + if ((ap->a_mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) { + switch (vp->v_type) { + case VREG: case VDIR: case VLNK: + return (EROFS); + } + } + /* + * For nfs v3, do an access rpc, otherwise you are stuck emulating * ufs_access() locally using the vattr. This may not be correct, * since the server may apply other access criteria such as * client uid-->server uid mapping that we do not know about, but * this is better than just returning anything that is lying about * in the cache. */ - if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) { - nfsstats.rpccnt[NQNFSPROC_ACCESS]++; - nfsm_reqhead(vp, NQNFSPROC_ACCESS, NFSX_FH + 3 * NFSX_UNSIGNED); - nfsm_fhtom(vp); - nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED); + if (v3) { + nfsstats.rpccnt[NFSPROC_ACCESS]++; + nfsm_reqhead(vp, NFSPROC_ACCESS, NFSX_FH(v3) + NFSX_UNSIGNED); + nfsm_fhtom(vp, v3); + nfsm_build(tl, u_long *, NFSX_UNSIGNED); if (ap->a_mode & VREAD) - *tl++ = nfs_true; - else - *tl++ = nfs_false; - if (ap->a_mode & VWRITE) - *tl++ = nfs_true; - else - *tl++ = nfs_false; - if (ap->a_mode & VEXEC) - *tl = nfs_true; + mode = NFSV3ACCESS_READ; else - *tl = nfs_false; - nfsm_request(vp, NQNFSPROC_ACCESS, ap->a_p, ap->a_cred); + mode = 0; + if (vp->v_type == VDIR) { + if (ap->a_mode & VWRITE) + mode |= (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND | + NFSV3ACCESS_DELETE); + if (ap->a_mode & VEXEC) + mode |= NFSV3ACCESS_LOOKUP; + } else { + if (ap->a_mode & VWRITE) + mode |= (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND); + if (ap->a_mode & VEXEC) + mode |= NFSV3ACCESS_EXECUTE; + } + *tl = txdr_unsigned(mode); + nfsm_request(vp, NFSPROC_ACCESS, ap->a_p, ap->a_cred); + nfsm_postop_attr(vp, attrflag); + if (!error) { + nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); + rmode = fxdr_unsigned(u_long, *tl); + /* + * The NFS V3 spec does not clarify whether or not + * the returned access bits can be a superset of + * the ones requested, so... + */ + if ((rmode & mode) != mode) + error = EACCES; + } nfsm_reqdone; return (error); } else @@ -336,15 +379,17 @@ nfs_open(ap) int error; if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK) +{ printf("open eacces vtyp=%d\n",vp->v_type); return (EACCES); - if (vp->v_flag & VTEXT) { - /* - * Get a valid lease. If cached data is stale, flush it. - */ - if (nmp->nm_flag & NFSMNT_NQNFS) { - if (NQNFS_CKINVALID(vp, np, NQL_READ)) { +} + /* + * Get a valid lease. If cached data is stale, flush it. + */ + if (nmp->nm_flag & NFSMNT_NQNFS) { + if (NQNFS_CKINVALID(vp, np, ND_READ)) { do { - error = nqnfs_getlease(vp, NQL_READ, ap->a_cred, ap->a_p); + error = nqnfs_getlease(vp, ND_READ, ap->a_cred, + ap->a_p); } while (error == NQNFS_EXPIRED); if (error) return (error); @@ -357,22 +402,26 @@ nfs_open(ap) np->n_brev = np->n_lrev; } } - } else { + } else { if (np->n_flag & NMODIFIED) { if ((error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 1)) == EINTR) return (error); (void) vnode_pager_uncache(vp); np->n_attrstamp = 0; - np->n_direofoffset = 0; - if (error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p)) + if (vp->v_type == VDIR) + np->n_direofoffset = 0; + error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p); + if (error) return (error); np->n_mtime = vattr.va_mtime.ts_sec; } else { - if (error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p)) + error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p); + if (error) return (error); if (np->n_mtime != vattr.va_mtime.ts_sec) { - np->n_direofoffset = 0; + if (vp->v_type == VDIR) + np->n_direofoffset = 0; if ((error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 1)) == EINTR) return (error); @@ -380,15 +429,41 @@ nfs_open(ap) np->n_mtime = vattr.va_mtime.ts_sec; } } - } - } else if ((nmp->nm_flag & NFSMNT_NQNFS) == 0) + } + if ((nmp->nm_flag & NFSMNT_NQNFS) == 0) np->n_attrstamp = 0; /* For Open/Close consistency */ return (0); } /* * nfs close vnode op - * For reg files, invalidate any buffer cache entries. + * What an NFS client should do upon close after writing is a debatable issue. + * Most NFS clients push delayed writes to the server upon close, basically for + * two reasons: + * 1 - So that any write errors may be reported back to the client process + * doing the close system call. By far the two most likely errors are + * NFSERR_NOSPC and NFSERR_DQUOT to indicate space allocation failure. + * 2 - To put a worst case upper bound on cache inconsistency between + * multiple clients for the file. + * There is also a consistency problem for Version 2 of the protocol w.r.t. + * not being able to tell if other clients are writing a file concurrently, + * since there is no way of knowing if the changed modify time in the reply + * is only due to the write for this client. + * (NFS Version 3 provides weak cache consistency data in the reply that + * should be sufficient to detect and handle this case.) + * + * The current code does the following: + * for NFS Version 2 - play it safe and flush/invalidate all dirty buffers + * for NFS Version 3 - flush dirty buffers to the server but don't invalidate + * or commit them (this satisfies 1 and 2 except for the + * case where the server crashes after this close but + * before the commit RPC, which is felt to be "good + * enough". Changing the last argument to nfs_flush() to + * a 1 would force a commit operation, if it is felt a + * commit is necessary now. + * for NQNFS - do nothing now, since 2 is dealt with via leases and + * 1 should be dealt with via an fsync() system call for + * cases where write errors are important. */ /* ARGSUSED */ int @@ -408,7 +483,10 @@ nfs_close(ap) if (vp->v_type == VREG) { if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0 && (np->n_flag & NMODIFIED)) { - error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 1); + if (NFS_ISV3(vp)) + error = nfs_flush(vp, ap->a_cred, MNT_WAIT, ap->a_p, 0); + else + error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 1); np->n_attrstamp = 0; } if (np->n_flag & NWRITEERR) { @@ -434,9 +512,12 @@ nfs_getattr(ap) register struct vnode *vp = ap->a_vp; register struct nfsnode *np = VTONFS(vp); register caddr_t cp; + register u_long *tl; + register int t1, t2; caddr_t bpos, dpos; int error = 0; struct mbuf *mreq, *mrep, *md, *mb, *mb2; + int v3 = NFS_ISV3(vp); /* * Update local times for special files. @@ -449,10 +530,11 @@ nfs_getattr(ap) if (nfs_getattrcache(vp, ap->a_vap) == 0) return (0); nfsstats.rpccnt[NFSPROC_GETATTR]++; - nfsm_reqhead(vp, NFSPROC_GETATTR, NFSX_FH); - nfsm_fhtom(vp); + nfsm_reqhead(vp, NFSPROC_GETATTR, NFSX_FH(v3)); + nfsm_fhtom(vp, v3); nfsm_request(vp, NFSPROC_GETATTR, ap->a_p, ap->a_cred); - nfsm_loadattr(vp, ap->a_vap); + if (!error) + nfsm_loadattr(vp, ap->a_vap); nfsm_reqdone; return (error); } @@ -470,81 +552,182 @@ nfs_setattr(ap) struct proc *a_p; } */ *ap; { + register struct vnode *vp = ap->a_vp; + register struct nfsnode *np = VTONFS(vp); + register struct vattr *vap = ap->a_vap; + int error = 0; + u_quad_t tsize; + +#ifndef nolint + tsize = (u_quad_t)0; +#endif + /* + * Disallow write attempts if the filesystem is mounted read-only. + */ + if ((vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL || + vap->va_gid != (gid_t)VNOVAL || vap->va_atime.ts_sec != VNOVAL || + vap->va_mtime.ts_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL) && + (vp->v_mount->mnt_flag & MNT_RDONLY)) + return (EROFS); + if (vap->va_size != VNOVAL) { + switch (vp->v_type) { + case VDIR: + return (EISDIR); + case VCHR: + case VBLK: + case VSOCK: + case VFIFO: + if (vap->va_mtime.ts_sec == VNOVAL && + vap->va_atime.ts_sec == VNOVAL && + vap->va_mode == (u_short)VNOVAL && + vap->va_uid == (uid_t)VNOVAL && + vap->va_gid == (gid_t)VNOVAL) + return (0); + vap->va_size = VNOVAL; + break; + default: + /* + * Disallow write attempts if the filesystem is + * mounted read-only. + */ + if (vp->v_mount->mnt_flag & MNT_RDONLY) + return (EROFS); + if (np->n_flag & NMODIFIED) { + if (vap->va_size == 0) + error = nfs_vinvalbuf(vp, 0, + ap->a_cred, ap->a_p, 1); + else + error = nfs_vinvalbuf(vp, V_SAVE, + ap->a_cred, ap->a_p, 1); + if (error) + return (error); + } + tsize = np->n_size; + np->n_size = np->n_vattr.va_size = vap->va_size; + vnode_pager_setsize(vp, (u_long)np->n_size); + }; + } else if ((vap->va_mtime.ts_sec != VNOVAL || + vap->va_atime.ts_sec != VNOVAL) && (np->n_flag & NMODIFIED) && + vp->v_type == VREG && + (error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, + ap->a_p, 1)) == EINTR) + return (error); + error = nfs_setattrrpc(vp, vap, ap->a_cred, ap->a_p); + if (error) { + np->n_size = np->n_vattr.va_size = tsize; + vnode_pager_setsize(vp, (u_long)np->n_size); + } + return (error); +} + +/* + * Do an nfs setattr rpc. + */ +int +nfs_setattrrpc(vp, vap, cred, procp) + register struct vnode *vp; + register struct vattr *vap; + struct ucred *cred; + struct proc *procp; +{ register struct nfsv2_sattr *sp; register caddr_t cp; - register long t1; + register long t1, t2; caddr_t bpos, dpos, cp2; u_long *tl; - int error = 0, isnq; + int error = 0, wccflag = NFSV3_WCCRATTR; struct mbuf *mreq, *mrep, *md, *mb, *mb2; - register struct vnode *vp = ap->a_vp; - register struct nfsnode *np = VTONFS(vp); - register struct vattr *vap = ap->a_vap; - u_quad_t frev, tsize; + u_quad_t frev; + int v3 = NFS_ISV3(vp); - if (vap->va_size != VNOVAL || vap->va_mtime.ts_sec != VNOVAL || - vap->va_atime.ts_sec != VNOVAL) { + nfsstats.rpccnt[NFSPROC_SETATTR]++; + nfsm_reqhead(vp, NFSPROC_SETATTR, NFSX_FH(v3) + NFSX_SATTR(v3)); + nfsm_fhtom(vp, v3); + if (v3) { + if (vap->va_mode != (u_short)VNOVAL) { + nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED); + *tl++ = nfs_true; + *tl = txdr_unsigned(vap->va_mode); + } else { + nfsm_build(tl, u_long *, NFSX_UNSIGNED); + *tl = nfs_false; + } + if (vap->va_uid != (uid_t)VNOVAL) { + nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED); + *tl++ = nfs_true; + *tl = txdr_unsigned(vap->va_uid); + } else { + nfsm_build(tl, u_long *, NFSX_UNSIGNED); + *tl = nfs_false; + } + if (vap->va_gid != (gid_t)VNOVAL) { + nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED); + *tl++ = nfs_true; + *tl = txdr_unsigned(vap->va_gid); + } else { + nfsm_build(tl, u_long *, NFSX_UNSIGNED); + *tl = nfs_false; + } if (vap->va_size != VNOVAL) { - if (np->n_flag & NMODIFIED) { - if (vap->va_size == 0) - error = nfs_vinvalbuf(vp, 0, ap->a_cred, - ap->a_p, 1); - else - error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, - ap->a_p, 1); - if (error) - return (error); + nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED); + *tl++ = nfs_true; + txdr_hyper(&vap->va_size, tl); + } else { + nfsm_build(tl, u_long *, NFSX_UNSIGNED); + *tl = nfs_false; + } + if (vap->va_atime.ts_sec != VNOVAL) { + if (vap->va_atime.ts_sec != time.tv_sec) { + nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED); + *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT); + txdr_nfsv3time(&vap->va_atime, tl); + } else { + nfsm_build(tl, u_long *, NFSX_UNSIGNED); + *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER); } - tsize = np->n_size; - np->n_size = np->n_vattr.va_size = vap->va_size; - vnode_pager_setsize(vp, (u_long)np->n_size); - } else if ((np->n_flag & NMODIFIED) && - (error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, - ap->a_p, 1)) == EINTR) - return (error); - } - nfsstats.rpccnt[NFSPROC_SETATTR]++; - isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS); - nfsm_reqhead(vp, NFSPROC_SETATTR, NFSX_FH+NFSX_SATTR(isnq)); - nfsm_fhtom(vp); - nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq)); - if (vap->va_mode == (u_short)-1) - sp->sa_mode = VNOVAL; - else - sp->sa_mode = vtonfs_mode(vp->v_type, vap->va_mode); - if (vap->va_uid == (uid_t)-1) - sp->sa_uid = VNOVAL; - else - sp->sa_uid = txdr_unsigned(vap->va_uid); - if (vap->va_gid == (gid_t)-1) - sp->sa_gid = VNOVAL; - else - sp->sa_gid = txdr_unsigned(vap->va_gid); - if (isnq) { - txdr_hyper(&vap->va_size, &sp->sa_nqsize); - txdr_nqtime(&vap->va_atime, &sp->sa_nqatime); - txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime); - sp->sa_nqflags = txdr_unsigned(vap->va_flags); - sp->sa_nqrdev = VNOVAL; + } else { + nfsm_build(tl, u_long *, NFSX_UNSIGNED); + *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE); + } + if (vap->va_mtime.ts_sec != VNOVAL) { + if (vap->va_mtime.ts_sec != time.tv_sec) { + nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED); + *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT); + txdr_nfsv3time(&vap->va_atime, tl); + } else { + nfsm_build(tl, u_long *, NFSX_UNSIGNED); + *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER); + } + } else { + nfsm_build(tl, u_long *, NFSX_UNSIGNED); + *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE); + } + nfsm_build(tl, u_long *, NFSX_UNSIGNED); + *tl = nfs_false; } else { - sp->sa_nfssize = txdr_unsigned(vap->va_size); - txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime); - txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime); - } - nfsm_request(vp, NFSPROC_SETATTR, ap->a_p, ap->a_cred); - nfsm_loadattr(vp, (struct vattr *)0); - if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) && - NQNFS_CKCACHABLE(vp, NQL_WRITE)) { - nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); - fxdr_hyper(tl, &frev); - if (frev > np->n_brev) - np->n_brev = frev; + nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR); + if (vap->va_mode == (u_short)VNOVAL) + sp->sa_mode = VNOVAL; + else + sp->sa_mode = vtonfsv2_mode(vp->v_type, vap->va_mode); + if (vap->va_uid == (uid_t)VNOVAL) + sp->sa_uid = VNOVAL; + else + sp->sa_uid = txdr_unsigned(vap->va_uid); + if (vap->va_gid == (gid_t)VNOVAL) + sp->sa_gid = VNOVAL; + else + sp->sa_gid = txdr_unsigned(vap->va_gid); + sp->sa_size = txdr_unsigned(vap->va_size); + txdr_nfsv2time(&vap->va_atime, &sp->sa_atime); + txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime); } + nfsm_request(vp, NFSPROC_SETATTR, procp, cred); + if (v3) { + nfsm_wcc_data(vp, wccflag); + } else + nfsm_loadattr(vp, (struct vattr *)0); nfsm_reqdone; - if (error) { - np->n_size = np->n_vattr.va_size = tsize; - vnode_pager_setsize(vp, (u_long)np->n_size); - } return (error); } @@ -566,23 +749,24 @@ nfs_lookup(ap) register struct vnode *dvp = ap->a_dvp; register struct vnode **vpp = ap->a_vpp; register int flags = cnp->cn_flags; - register struct vnode *vdp; + register struct proc *p = cnp->cn_proc; + register struct vnode *newvp; register u_long *tl; register caddr_t cp; register long t1, t2; struct nfsmount *nmp; caddr_t bpos, dpos, cp2; - time_t reqtime; struct mbuf *mreq, *mrep, *md, *mb, *mb2; - struct vnode *newvp; long len; - nfsv2fh_t *fhp; + nfsfh_t *fhp; struct nfsnode *np; - int lockparent, wantparent, error = 0; - int nqlflag, cachable; - u_quad_t frev; + int lockparent, wantparent, error = 0, attrflag, fhsize; + int v3 = NFS_ISV3(dvp); - *vpp = NULL; + if ((flags & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) && + (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) + return (EROFS); + *vpp = NULLVP; if (dvp->v_type != VDIR) return (ENOTDIR); lockparent = flags & LOCKPARENT; @@ -593,158 +777,112 @@ nfs_lookup(ap) struct vattr vattr; int vpid; - vdp = *vpp; - vpid = vdp->v_id; + newvp = *vpp; + vpid = newvp->v_id; /* * See the comment starting `Step through' in ufs/ufs_lookup.c * for an explanation of the locking protocol */ - if (dvp == vdp) { - VREF(vdp); + if (dvp == newvp) { + VREF(newvp); error = 0; } else - error = vget(vdp, 1); + error = vget(newvp, LK_EXCLUSIVE, p); if (!error) { - if (vpid == vdp->v_id) { - if (nmp->nm_flag & NFSMNT_NQNFS) { - if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) == 0) { - nfsstats.lookupcache_hits++; - if (cnp->cn_nameiop != LOOKUP && - (flags & ISLASTCN)) - cnp->cn_flags |= SAVENAME; - return (0); - } else if (NQNFS_CKCACHABLE(dvp, NQL_READ)) { - if (np->n_lrev != np->n_brev || - (np->n_flag & NMODIFIED)) { - np->n_direofoffset = 0; - cache_purge(dvp); - error = nfs_vinvalbuf(dvp, 0, - cnp->cn_cred, cnp->cn_proc, - 1); - if (error == EINTR) - return (error); - np->n_brev = np->n_lrev; - } else { - nfsstats.lookupcache_hits++; - if (cnp->cn_nameiop != LOOKUP && - (flags & ISLASTCN)) - cnp->cn_flags |= SAVENAME; - return (0); - } - } - } else if (!VOP_GETATTR(vdp, &vattr, cnp->cn_cred, cnp->cn_proc) && - vattr.va_ctime.ts_sec == VTONFS(vdp)->n_ctime) { + if (vpid == newvp->v_id) { + if (!VOP_GETATTR(newvp, &vattr, cnp->cn_cred, cnp->cn_proc) + && vattr.va_ctime.ts_sec == VTONFS(newvp)->n_ctime) { nfsstats.lookupcache_hits++; if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN)) cnp->cn_flags |= SAVENAME; return (0); } - cache_purge(vdp); + cache_purge(newvp); } - vrele(vdp); + vrele(newvp); } *vpp = NULLVP; } error = 0; + newvp = NULLVP; nfsstats.lookupcache_misses++; nfsstats.rpccnt[NFSPROC_LOOKUP]++; len = cnp->cn_namelen; - nfsm_reqhead(dvp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); - - /* - * For nqnfs optionally piggyback a getlease request for the name - * being looked up. - */ - if (nmp->nm_flag & NFSMNT_NQNFS) { - nfsm_build(tl, u_long *, NFSX_UNSIGNED); - if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) && - ((cnp->cn_flags & MAKEENTRY) && - (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN)))) - *tl = txdr_unsigned(nmp->nm_leaseterm); - else - *tl = 0; - } - nfsm_fhtom(dvp); + nfsm_reqhead(dvp, NFSPROC_LOOKUP, + NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len)); + nfsm_fhtom(dvp, v3); nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN); - reqtime = time.tv_sec; nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred); -nfsmout: if (error) { - if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) && - (flags & ISLASTCN) && error == ENOENT) - error = EJUSTRETURN; - if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN)) - cnp->cn_flags |= SAVENAME; - return (error); - } - if (nmp->nm_flag & NFSMNT_NQNFS) { - nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); - if (*tl) { - nqlflag = fxdr_unsigned(int, *tl); - nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED); - cachable = fxdr_unsigned(int, *tl++); - reqtime += fxdr_unsigned(int, *tl++); - fxdr_hyper(tl, &frev); - } else - nqlflag = 0; + nfsm_postop_attr(dvp, attrflag); + m_freem(mrep); + goto nfsmout; } - nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH); + nfsm_getfh(fhp, fhsize, v3); /* * Handle RENAME case... */ if (cnp->cn_nameiop == RENAME && wantparent && (flags & ISLASTCN)) { - if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { + if (NFS_CMPFH(np, fhp, fhsize)) { m_freem(mrep); return (EISDIR); } - if (error = nfs_nget(dvp->v_mount, fhp, &np)) { + if (error = nfs_nget(dvp->v_mount, fhp, fhsize, &np)) { m_freem(mrep); return (error); } newvp = NFSTOV(np); - if (error = - nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) { - vrele(newvp); - m_freem(mrep); - return (error); - } + if (v3) { + nfsm_postop_attr(newvp, attrflag); + nfsm_postop_attr(dvp, attrflag); + } else + nfsm_loadattr(newvp, (struct vattr *)0); *vpp = newvp; m_freem(mrep); cnp->cn_flags |= SAVENAME; return (0); } - if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { + if (NFS_CMPFH(np, fhp, fhsize)) { VREF(dvp); newvp = dvp; } else { - if (error = nfs_nget(dvp->v_mount, fhp, &np)) { + if (error = nfs_nget(dvp->v_mount, fhp, fhsize, &np)) { m_freem(mrep); return (error); } newvp = NFSTOV(np); } - if (error = nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) { - vrele(newvp); - m_freem(mrep); - return (error); - } - m_freem(mrep); - *vpp = newvp; + if (v3) { + nfsm_postop_attr(newvp, attrflag); + nfsm_postop_attr(dvp, attrflag); + } else + nfsm_loadattr(newvp, (struct vattr *)0); if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN)) cnp->cn_flags |= SAVENAME; if ((cnp->cn_flags & MAKEENTRY) && (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))) { - if ((nmp->nm_flag & NFSMNT_NQNFS) == 0) - np->n_ctime = np->n_vattr.va_ctime.ts_sec; - else if (nqlflag && reqtime > time.tv_sec) - nqnfs_clientlease(nmp, np, nqlflag, cachable, reqtime, - frev); - cache_enter(dvp, *vpp, cnp); + np->n_ctime = np->n_vattr.va_ctime.ts_sec; + cache_enter(dvp, newvp, cnp); } - return (0); + *vpp = newvp; + nfsm_reqdone; + if (error) { + if (newvp != NULLVP) + vrele(newvp); + if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) && + (flags & ISLASTCN) && error == ENOENT) { + if (dvp->v_mount->mnt_flag & MNT_RDONLY) + error = EROFS; + else + error = EJUSTRETURN; + } + if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN)) + cnp->cn_flags |= SAVENAME; + } + return (error); } /* @@ -797,18 +935,22 @@ nfs_readlinkrpc(vp, uiop, cred) { register u_long *tl; register caddr_t cp; - register long t1; + register long t1, t2; caddr_t bpos, dpos, cp2; - int error = 0; + int error = 0, len, attrflag; struct mbuf *mreq, *mrep, *md, *mb, *mb2; - long len; + int v3 = NFS_ISV3(vp); nfsstats.rpccnt[NFSPROC_READLINK]++; - nfsm_reqhead(vp, NFSPROC_READLINK, NFSX_FH); - nfsm_fhtom(vp); + nfsm_reqhead(vp, NFSPROC_READLINK, NFSX_FH(v3)); + nfsm_fhtom(vp, v3); nfsm_request(vp, NFSPROC_READLINK, uiop->uio_procp, cred); - nfsm_strsiz(len, NFS_MAXPATHLEN); - nfsm_mtouio(uiop, len); + if (v3) + nfsm_postop_attr(vp, attrflag); + if (!error) { + nfsm_strsiz(len, NFS_MAXPATHLEN); + nfsm_mtouio(uiop, len); + } nfsm_reqdone; return (error); } @@ -825,25 +967,27 @@ nfs_readrpc(vp, uiop, cred) { register u_long *tl; register caddr_t cp; - register long t1; + register long t1, t2; caddr_t bpos, dpos, cp2; - int error = 0; struct mbuf *mreq, *mrep, *md, *mb, *mb2; struct nfsmount *nmp; - long len, retlen, tsiz; + int error = 0, len, retlen, tsiz, eof, attrflag; + int v3 = NFS_ISV3(vp); +#ifndef nolint + eof = 0; +#endif nmp = VFSTONFS(vp->v_mount); tsiz = uiop->uio_resid; - if (uiop->uio_offset + tsiz > 0xffffffff && - (nmp->nm_flag & NFSMNT_NQNFS) == 0) + if (uiop->uio_offset + tsiz > 0xffffffff && !v3) return (EFBIG); while (tsiz > 0) { nfsstats.rpccnt[NFSPROC_READ]++; len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz; - nfsm_reqhead(vp, NFSPROC_READ, NFSX_FH+NFSX_UNSIGNED*3); - nfsm_fhtom(vp); - nfsm_build(tl, u_long *, NFSX_UNSIGNED*3); - if (nmp->nm_flag & NFSMNT_NQNFS) { + nfsm_reqhead(vp, NFSPROC_READ, NFSX_FH(v3) + NFSX_UNSIGNED * 3); + nfsm_fhtom(vp, v3); + nfsm_build(tl, u_long *, NFSX_UNSIGNED * 3); + if (v3) { txdr_hyper(&uiop->uio_offset, tl); *(tl + 2) = txdr_unsigned(len); } else { @@ -852,14 +996,25 @@ nfs_readrpc(vp, uiop, cred) *tl = 0; } nfsm_request(vp, NFSPROC_READ, uiop->uio_procp, cred); - nfsm_loadattr(vp, (struct vattr *)0); + if (v3) { + nfsm_postop_attr(vp, attrflag); + if (error) { + m_freem(mrep); + goto nfsmout; + } + nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); + eof = fxdr_unsigned(int, *(tl + 1)); + } else + nfsm_loadattr(vp, (struct vattr *)0); nfsm_strsiz(retlen, nmp->nm_rsize); nfsm_mtouio(uiop, retlen); m_freem(mrep); - if (retlen < len) + tsiz -= retlen; + if (v3) { + if (eof || retlen == 0) + tsiz = 0; + } else if (retlen < len) tsiz = 0; - else - tsiz -= len; } nfsmout: return (error); @@ -869,105 +1024,136 @@ nfsmout: * nfs write call */ int -nfs_writerpc(vp, uiop, cred, ioflags) +nfs_writerpc(vp, uiop, cred, iomode, must_commit) register struct vnode *vp; - struct uio *uiop; + register struct uio *uiop; struct ucred *cred; - int ioflags; + int *iomode, *must_commit; { register u_long *tl; register caddr_t cp; - register long t1; + register int t1, t2, backup; caddr_t bpos, dpos, cp2; - int error = 0; struct mbuf *mreq, *mrep, *md, *mb, *mb2; - struct nfsmount *nmp; + struct nfsmount *nmp = VFSTONFS(vp->v_mount); struct nfsnode *np = VTONFS(vp); u_quad_t frev; - long len, tsiz; + int error = 0, len, tsiz, wccflag = NFSV3_WCCRATTR, rlen, commit; + int v3 = NFS_ISV3(vp), committed = NFSV3WRITE_FILESYNC; - nmp = VFSTONFS(vp->v_mount); +#ifndef DIAGNOSTIC + if (uiop->uio_iovcnt != 1) + panic("nfs: writerpc iovcnt > 1"); +#endif + *must_commit = 0; tsiz = uiop->uio_resid; - if (uiop->uio_offset + tsiz > 0xffffffff && - (nmp->nm_flag & NFSMNT_NQNFS) == 0) + if (uiop->uio_offset + tsiz > 0xffffffff && !v3) return (EFBIG); while (tsiz > 0) { nfsstats.rpccnt[NFSPROC_WRITE]++; len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz; nfsm_reqhead(vp, NFSPROC_WRITE, - NFSX_FH+NFSX_UNSIGNED*4+nfsm_rndup(len)); - nfsm_fhtom(vp); - nfsm_build(tl, u_long *, NFSX_UNSIGNED * 4); - if (nmp->nm_flag & NFSMNT_NQNFS) { + NFSX_FH(v3) + 5 * NFSX_UNSIGNED + nfsm_rndup(len)); + nfsm_fhtom(vp, v3); + if (v3) { + nfsm_build(tl, u_long *, 5 * NFSX_UNSIGNED); txdr_hyper(&uiop->uio_offset, tl); tl += 2; - if (ioflags & IO_APPEND) - *tl++ = txdr_unsigned(1); - else - *tl++ = 0; + *tl++ = txdr_unsigned(len); + *tl++ = txdr_unsigned(*iomode); } else { + nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED); *++tl = txdr_unsigned(uiop->uio_offset); tl += 2; } *tl = txdr_unsigned(len); nfsm_uiotom(uiop, len); nfsm_request(vp, NFSPROC_WRITE, uiop->uio_procp, cred); - nfsm_loadattr(vp, (struct vattr *)0); - if (nmp->nm_flag & NFSMNT_MYWRITE) - VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr.va_mtime.ts_sec; - else if ((nmp->nm_flag & NFSMNT_NQNFS) && - NQNFS_CKCACHABLE(vp, NQL_WRITE)) { - nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); - fxdr_hyper(tl, &frev); - if (frev > np->n_brev) - np->n_brev = frev; - } + if (v3) { + wccflag = NFSV3_WCCCHK; + nfsm_wcc_data(vp, wccflag); + if (!error) { + nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED + + NFSX_V3WRITEVERF); + rlen = fxdr_unsigned(int, *tl++); + if (rlen == 0) { + error = NFSERR_IO; + break; + } else if (rlen < len) { + backup = len - rlen; + uiop->uio_iov->iov_base -= backup; + uiop->uio_iov->iov_len += backup; + uiop->uio_offset -= backup; + uiop->uio_resid += backup; + len = rlen; + } + commit = fxdr_unsigned(int, *tl++); + + /* + * Return the lowest committment level + * obtained by any of the RPCs. + */ + if (committed == NFSV3WRITE_FILESYNC) + committed = commit; + else if (committed == NFSV3WRITE_DATASYNC && + commit == NFSV3WRITE_UNSTABLE) + committed = commit; + if ((nmp->nm_flag & NFSMNT_HASWRITEVERF) == 0) { + bcopy((caddr_t)tl, (caddr_t)nmp->nm_verf, + NFSX_V3WRITEVERF); + nmp->nm_flag |= NFSMNT_HASWRITEVERF; + } else if (bcmp((caddr_t)tl, + (caddr_t)nmp->nm_verf, NFSX_V3WRITEVERF)) { + *must_commit = 1; + bcopy((caddr_t)tl, (caddr_t)nmp->nm_verf, + NFSX_V3WRITEVERF); + } + } + } else + nfsm_loadattr(vp, (struct vattr *)0); + if (wccflag) + VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr.va_mtime.ts_sec; m_freem(mrep); tsiz -= len; } nfsmout: + *iomode = committed; if (error) uiop->uio_resid = tsiz; return (error); } /* - * nfs mknod call - * This is a kludge. Use a create rpc but with the IFMT bits of the mode - * set to specify the file type and the size field for rdev. + * nfs mknod rpc + * For NFS v2 this is a kludge. Use a create rpc but with the IFMT bits of the + * mode set to specify the file type and the size field for rdev. */ -/* ARGSUSED */ int -nfs_mknod(ap) - struct vop_mknod_args /* { - struct vnode *a_dvp; - struct vnode **a_vpp; - struct componentname *a_cnp; - struct vattr *a_vap; - } */ *ap; +nfs_mknodrpc(dvp, vpp, cnp, vap) + register struct vnode *dvp; + register struct vnode **vpp; + register struct componentname *cnp; + register struct vattr *vap; { - register struct vnode *dvp = ap->a_dvp; - register struct vattr *vap = ap->a_vap; - register struct componentname *cnp = ap->a_cnp; register struct nfsv2_sattr *sp; + register struct nfsv3_sattr *sp3; register u_long *tl; register caddr_t cp; register long t1, t2; - struct vnode *newvp; + struct vnode *newvp = (struct vnode *)0; + struct nfsnode *np; struct vattr vattr; char *cp2; caddr_t bpos, dpos; - int error = 0, isnq; + int error = 0, wccflag = NFSV3_WCCRATTR, gotvp = 0; struct mbuf *mreq, *mrep, *md, *mb, *mb2; u_long rdev; + int v3 = NFS_ISV3(dvp); - isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS); if (vap->va_type == VCHR || vap->va_type == VBLK) rdev = txdr_unsigned(vap->va_rdev); -#ifdef FIFO - else if (vap->va_type == VFIFO) + else if (vap->va_type == VFIFO || vap->va_type == VSOCK) rdev = 0xffffffff; -#endif /* FIFO */ else { VOP_ABORTOP(dvp, cnp); vput(dvp); @@ -978,38 +1164,88 @@ nfs_mknod(ap) vput(dvp); return (error); } - nfsstats.rpccnt[NFSPROC_CREATE]++; - nfsm_reqhead(dvp, NFSPROC_CREATE, - NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR(isnq)); - nfsm_fhtom(dvp); + nfsstats.rpccnt[NFSPROC_MKNOD]++; + nfsm_reqhead(dvp, NFSPROC_MKNOD, NFSX_FH(v3) + 4 * NFSX_UNSIGNED + + + nfsm_rndup(cnp->cn_namelen) + NFSX_SATTR(v3)); + nfsm_fhtom(dvp, v3); nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); - nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq)); - sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode); - sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid); - sp->sa_gid = txdr_unsigned(vattr.va_gid); - if (isnq) { - sp->sa_nqrdev = rdev; - sp->sa_nqflags = 0; - txdr_nqtime(&vap->va_atime, &sp->sa_nqatime); - txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime); + if (v3) { + nfsm_build(tl, u_long *, NFSX_UNSIGNED + NFSX_V3SRVSATTR); + *tl++ = vtonfsv3_type(vap->va_type); + sp3 = (struct nfsv3_sattr *)tl; + nfsm_v3sattr(sp3, vap, cnp->cn_cred->cr_uid, vattr.va_gid); + if (vap->va_type == VCHR || vap->va_type == VBLK) { + nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED); + *tl++ = txdr_unsigned(major(vap->va_rdev)); + *tl = txdr_unsigned(minor(vap->va_rdev)); + } } else { - sp->sa_nfssize = rdev; - txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime); - txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime); + nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR); + sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode); + sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid); + sp->sa_gid = txdr_unsigned(vattr.va_gid); + sp->sa_size = rdev; + txdr_nfsv2time(&vap->va_atime, &sp->sa_atime); + txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime); } - nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred); - nfsm_mtofh(dvp, newvp); + nfsm_request(dvp, NFSPROC_MKNOD, cnp->cn_proc, cnp->cn_cred); + if (!error) { + nfsm_mtofh(dvp, newvp, v3, gotvp); + if (!gotvp) { + if (newvp) { + vrele(newvp); + newvp = (struct vnode *)0; + } + error = nfs_lookitup(dvp, cnp->cn_nameptr, + cnp->cn_namelen, cnp->cn_cred, cnp->cn_proc, &np); + if (!error) + newvp = NFSTOV(np); + } + } + if (v3) + nfsm_wcc_data(dvp, wccflag); nfsm_reqdone; - if (!error && (cnp->cn_flags & MAKEENTRY)) - cache_enter(dvp, newvp, cnp); + if (error) { + if (newvp) + vrele(newvp); + } else { + if (cnp->cn_flags & MAKEENTRY) + cache_enter(dvp, newvp, cnp); + *vpp = newvp; + } FREE(cnp->cn_pnbuf, M_NAMEI); VTONFS(dvp)->n_flag |= NMODIFIED; - VTONFS(dvp)->n_attrstamp = 0; + if (!wccflag) + VTONFS(dvp)->n_attrstamp = 0; vrele(dvp); return (error); } /* + * nfs mknod vop + * just call nfs_mknodrpc() to do the work. + */ +/* ARGSUSED */ +int +nfs_mknod(ap) + struct vop_mknod_args /* { + struct vnode *a_dvp; + struct vnode **a_vpp; + struct componentname *a_cnp; + struct vattr *a_vap; + } */ *ap; +{ + struct vnode *newvp; + int error; + + error = nfs_mknodrpc(ap->a_dvp, &newvp, ap->a_cnp, ap->a_vap); + if (!error) + vrele(newvp); + return (error); +} + +static u_long create_verf; +/* * nfs file create call */ int @@ -1025,50 +1261,97 @@ nfs_create(ap) register struct vattr *vap = ap->a_vap; register struct componentname *cnp = ap->a_cnp; register struct nfsv2_sattr *sp; + register struct nfsv3_sattr *sp3; register u_long *tl; register caddr_t cp; register long t1, t2; + struct nfsnode *np = (struct nfsnode *)0; + struct vnode *newvp = (struct vnode *)0; caddr_t bpos, dpos, cp2; - int error = 0, isnq; + int error = 0, wccflag = NFSV3_WCCRATTR, gotvp = 0, fmode = 0; struct mbuf *mreq, *mrep, *md, *mb, *mb2; struct vattr vattr; + int v3 = NFS_ISV3(dvp); + + /* + * Oops, not for me.. + */ + if (vap->va_type == VSOCK) + return (nfs_mknodrpc(dvp, ap->a_vpp, cnp, vap)); if (error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc)) { VOP_ABORTOP(dvp, cnp); vput(dvp); return (error); } + if (vap->va_vaflags & VA_EXCLUSIVE) + fmode |= O_EXCL; +again: nfsstats.rpccnt[NFSPROC_CREATE]++; - isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS); - nfsm_reqhead(dvp, NFSPROC_CREATE, - NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR(isnq)); - nfsm_fhtom(dvp); + nfsm_reqhead(dvp, NFSPROC_CREATE, NFSX_FH(v3) + 2 * NFSX_UNSIGNED + + nfsm_rndup(cnp->cn_namelen) + NFSX_SATTR(v3)); + nfsm_fhtom(dvp, v3); nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); - nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq)); - sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode); - sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid); - sp->sa_gid = txdr_unsigned(vattr.va_gid); - if (isnq) { - u_quad_t qval = 0; - - txdr_hyper(&qval, &sp->sa_nqsize); - sp->sa_nqflags = 0; - sp->sa_nqrdev = -1; - txdr_nqtime(&vap->va_atime, &sp->sa_nqatime); - txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime); + if (v3) { + nfsm_build(tl, u_long *, NFSX_UNSIGNED); + if (fmode & O_EXCL) { + *tl = txdr_unsigned(NFSV3CREATE_EXCLUSIVE); + nfsm_build(tl, u_long *, NFSX_V3CREATEVERF); + if (in_ifaddr) + *tl++ = IA_SIN(in_ifaddr)->sin_addr.s_addr; + else + *tl++ = create_verf; + *tl = ++create_verf; + } else { + *tl = txdr_unsigned(NFSV3CREATE_UNCHECKED); + nfsm_build(tl, u_long *, NFSX_V3SRVSATTR); + sp3 = (struct nfsv3_sattr *)tl; + nfsm_v3sattr(sp3, vap, cnp->cn_cred->cr_uid, vattr.va_gid); + } } else { - sp->sa_nfssize = 0; - txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime); - txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime); + nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR); + sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode); + sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid); + sp->sa_gid = txdr_unsigned(vattr.va_gid); + sp->sa_size = 0; + txdr_nfsv2time(&vap->va_atime, &sp->sa_atime); + txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime); } nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred); - nfsm_mtofh(dvp, *ap->a_vpp); + if (!error) { + nfsm_mtofh(dvp, newvp, v3, gotvp); + if (!gotvp) { + if (newvp) { + vrele(newvp); + newvp = (struct vnode *)0; + } + error = nfs_lookitup(dvp, cnp->cn_nameptr, + cnp->cn_namelen, cnp->cn_cred, cnp->cn_proc, &np); + if (!error) + newvp = NFSTOV(np); + } + } + if (v3) + nfsm_wcc_data(dvp, wccflag); nfsm_reqdone; - if (!error && (cnp->cn_flags & MAKEENTRY)) - cache_enter(dvp, *ap->a_vpp, cnp); + if (error) { + if (v3 && (fmode & O_EXCL) && error == NFSERR_NOTSUPP) { + fmode &= ~O_EXCL; + goto again; + } + if (newvp) + vrele(newvp); + } else if (v3 && (fmode & O_EXCL)) + error = nfs_setattrrpc(newvp, vap, cnp->cn_cred, cnp->cn_proc); + if (!error) { + if (cnp->cn_flags & MAKEENTRY) + cache_enter(dvp, newvp, cnp); + *ap->a_vpp = newvp; + } FREE(cnp->cn_pnbuf, M_NAMEI); VTONFS(dvp)->n_flag |= NMODIFIED; - VTONFS(dvp)->n_attrstamp = 0; + if (!wccflag) + VTONFS(dvp)->n_attrstamp = 0; vrele(dvp); return (error); } @@ -1103,11 +1386,18 @@ nfs_remove(ap) caddr_t bpos, dpos; int error = 0; struct mbuf *mreq, *mrep, *md, *mb, *mb2; + struct vattr vattr; + int v3 = NFS_ISV3(dvp); - if (vp->v_usecount > 1) { - if (!np->n_sillyrename) - error = nfs_sillyrename(dvp, vp, cnp); - } else { +#ifndef DIAGNOSTIC + if ((cnp->cn_flags & HASBUF) == 0) + panic("nfs_remove: no name"); + if (vp->v_usecount < 1) + panic("nfs_remove: bad v_usecount"); +#endif + if (vp->v_usecount == 1 || (np->n_sillyrename && + VOP_GETATTR(vp, &vattr, cnp->cn_cred, cnp->cn_proc) == 0 && + vattr.va_nlink > 1)) { /* * Purge the name cache so that the chance of a lookup for * the name succeeding while the remove is in progress is @@ -1117,23 +1407,14 @@ nfs_remove(ap) */ cache_purge(vp); /* - * Throw away biocache buffers. Mainly to avoid - * unnecessary delayed writes. + * throw away biocache buffers, mainly to avoid + * unnecessary delayed writes later. */ error = nfs_vinvalbuf(vp, 0, cnp->cn_cred, cnp->cn_proc, 1); - if (error == EINTR) - return (error); /* Do the rpc */ - nfsstats.rpccnt[NFSPROC_REMOVE]++; - nfsm_reqhead(dvp, NFSPROC_REMOVE, - NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)); - nfsm_fhtom(dvp); - nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); - nfsm_request(dvp, NFSPROC_REMOVE, cnp->cn_proc, cnp->cn_cred); - nfsm_reqdone; - FREE(cnp->cn_pnbuf, M_NAMEI); - VTONFS(dvp)->n_flag |= NMODIFIED; - VTONFS(dvp)->n_attrstamp = 0; + if (error != EINTR) + error = nfs_removerpc(dvp, cnp->cn_nameptr, + cnp->cn_namelen, cnp->cn_cred, cnp->cn_proc); /* * Kludge City: If the first reply to the remove rpc is lost.. * the reply to the retransmitted request will be ENOENT @@ -1142,7 +1423,9 @@ nfs_remove(ap) */ if (error == ENOENT) error = 0; - } + } else if (!np->n_sillyrename) + error = nfs_sillyrename(dvp, vp, cnp); + FREE(cnp->cn_pnbuf, M_NAMEI); np->n_attrstamp = 0; vrele(dvp); vrele(vp); @@ -1156,22 +1439,42 @@ int nfs_removeit(sp) register struct sillyrename *sp; { + + return (nfs_removerpc(sp->s_dvp, sp->s_name, sp->s_namlen, sp->s_cred, + (struct proc *)0)); +} + +/* + * Nfs remove rpc, called from nfs_remove() and nfs_removeit(). + */ +int +nfs_removerpc(dvp, name, namelen, cred, proc) + register struct vnode *dvp; + char *name; + int namelen; + struct ucred *cred; + struct proc *proc; +{ register u_long *tl; register caddr_t cp; - register long t2; - caddr_t bpos, dpos; - int error = 0; + register long t1, t2; + caddr_t bpos, dpos, cp2; + int error = 0, wccflag = NFSV3_WCCRATTR; struct mbuf *mreq, *mrep, *md, *mb, *mb2; + int v3 = NFS_ISV3(dvp); nfsstats.rpccnt[NFSPROC_REMOVE]++; - nfsm_reqhead(sp->s_dvp, NFSPROC_REMOVE, - NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(sp->s_namlen)); - nfsm_fhtom(sp->s_dvp); - nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN); - nfsm_request(sp->s_dvp, NFSPROC_REMOVE, NULL, sp->s_cred); + nfsm_reqhead(dvp, NFSPROC_REMOVE, + NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(namelen)); + nfsm_fhtom(dvp, v3); + nfsm_strtom(name, namelen, NFS_MAXNAMLEN); + nfsm_request(dvp, NFSPROC_REMOVE, proc, cred); + if (v3) + nfsm_wcc_data(dvp, wccflag); nfsm_reqdone; - VTONFS(sp->s_dvp)->n_flag |= NMODIFIED; - VTONFS(sp->s_dvp)->n_attrstamp = 0; + VTONFS(dvp)->n_flag |= NMODIFIED; + if (!wccflag) + VTONFS(dvp)->n_attrstamp = 0; return (error); } @@ -1195,13 +1498,13 @@ nfs_rename(ap) register struct vnode *tdvp = ap->a_tdvp; register struct componentname *tcnp = ap->a_tcnp; register struct componentname *fcnp = ap->a_fcnp; - register u_long *tl; - register caddr_t cp; - register long t2; - caddr_t bpos, dpos; - int error = 0; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; + int error; +#ifndef DIAGNOSTIC + if ((tcnp->cn_flags & HASBUF) == 0 || + (fcnp->cn_flags & HASBUF) == 0) + panic("nfs_rename: no name"); +#endif /* Check for cross-device rename */ if ((fvp->v_mount != tdvp->v_mount) || (tvp && (fvp->v_mount != tvp->v_mount))) { @@ -1209,21 +1512,20 @@ nfs_rename(ap) goto out; } + /* + * If the tvp exists and is in use, sillyrename it before doing the + * rename of the new file over it. + */ + if (tvp && tvp->v_usecount > 1 && !VTONFS(tvp)->n_sillyrename && + !nfs_sillyrename(tdvp, tvp, tcnp)) { + vrele(tvp); + tvp = NULL; + } + + error = nfs_renamerpc(fdvp, fcnp->cn_nameptr, fcnp->cn_namelen, + tdvp, tcnp->cn_nameptr, tcnp->cn_namelen, tcnp->cn_cred, + tcnp->cn_proc); - nfsstats.rpccnt[NFSPROC_RENAME]++; - nfsm_reqhead(fdvp, NFSPROC_RENAME, - (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(fcnp->cn_namelen)+ - nfsm_rndup(fcnp->cn_namelen)); /* or fcnp->cn_cred?*/ - nfsm_fhtom(fdvp); - nfsm_strtom(fcnp->cn_nameptr, fcnp->cn_namelen, NFS_MAXNAMLEN); - nfsm_fhtom(tdvp); - nfsm_strtom(tcnp->cn_nameptr, tcnp->cn_namelen, NFS_MAXNAMLEN); - nfsm_request(fdvp, NFSPROC_RENAME, tcnp->cn_proc, tcnp->cn_cred); - nfsm_reqdone; - VTONFS(fdvp)->n_flag |= NMODIFIED; - VTONFS(fdvp)->n_attrstamp = 0; - VTONFS(tdvp)->n_flag |= NMODIFIED; - VTONFS(tdvp)->n_attrstamp = 0; if (fvp->v_type == VDIR) { if (tvp != NULL && tvp->v_type == VDIR) cache_purge(tdvp); @@ -1255,26 +1557,52 @@ nfs_renameit(sdvp, scnp, sp) struct componentname *scnp; register struct sillyrename *sp; { + return (nfs_renamerpc(sdvp, scnp->cn_nameptr, scnp->cn_namelen, + sdvp, sp->s_name, sp->s_namlen, scnp->cn_cred, scnp->cn_proc)); +} + +/* + * Do an nfs rename rpc. Called from nfs_rename() and nfs_renameit(). + */ +int +nfs_renamerpc(fdvp, fnameptr, fnamelen, tdvp, tnameptr, tnamelen, cred, proc) + register struct vnode *fdvp; + char *fnameptr; + int fnamelen; + register struct vnode *tdvp; + char *tnameptr; + int tnamelen; + struct ucred *cred; + struct proc *proc; +{ register u_long *tl; register caddr_t cp; - register long t2; - caddr_t bpos, dpos; - int error = 0; + register long t1, t2; + caddr_t bpos, dpos, cp2; + int error = 0, fwccflag = NFSV3_WCCRATTR, twccflag = NFSV3_WCCRATTR; struct mbuf *mreq, *mrep, *md, *mb, *mb2; + int v3 = NFS_ISV3(fdvp); nfsstats.rpccnt[NFSPROC_RENAME]++; - nfsm_reqhead(sdvp, NFSPROC_RENAME, - (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(scnp->cn_namelen)+ - nfsm_rndup(sp->s_namlen)); - nfsm_fhtom(sdvp); - nfsm_strtom(scnp->cn_nameptr, scnp->cn_namelen, NFS_MAXNAMLEN); - nfsm_fhtom(sdvp); - nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN); - nfsm_request(sdvp, NFSPROC_RENAME, scnp->cn_proc, scnp->cn_cred); + nfsm_reqhead(fdvp, NFSPROC_RENAME, + (NFSX_FH(v3) + NFSX_UNSIGNED)*2 + nfsm_rndup(fnamelen) + + nfsm_rndup(tnamelen)); + nfsm_fhtom(fdvp, v3); + nfsm_strtom(fnameptr, fnamelen, NFS_MAXNAMLEN); + nfsm_fhtom(tdvp, v3); + nfsm_strtom(tnameptr, tnamelen, NFS_MAXNAMLEN); + nfsm_request(fdvp, NFSPROC_RENAME, proc, cred); + if (v3) { + nfsm_wcc_data(fdvp, fwccflag); + nfsm_wcc_data(tdvp, twccflag); + } nfsm_reqdone; - FREE(scnp->cn_pnbuf, M_NAMEI); - VTONFS(sdvp)->n_flag |= NMODIFIED; - VTONFS(sdvp)->n_attrstamp = 0; + VTONFS(fdvp)->n_flag |= NMODIFIED; + VTONFS(tdvp)->n_flag |= NMODIFIED; + if (!fwccflag) + VTONFS(fdvp)->n_attrstamp = 0; + if (!twccflag) + VTONFS(tdvp)->n_attrstamp = 0; return (error); } @@ -1294,33 +1622,47 @@ nfs_link(ap) register struct componentname *cnp = ap->a_cnp; register u_long *tl; register caddr_t cp; - register long t2; - caddr_t bpos, dpos; - int error = 0; + register long t1, t2; + caddr_t bpos, dpos, cp2; + int error = 0, wccflag = NFSV3_WCCRATTR, attrflag = 0; struct mbuf *mreq, *mrep, *md, *mb, *mb2; + int v3 = NFS_ISV3(vp); if (vp->v_mount != tdvp->v_mount) { /*VOP_ABORTOP(vp, cnp);*/ if (tdvp == vp) - vrele(vp); + vrele(tdvp); else - vput(vp); + vput(tdvp); return (EXDEV); } + /* + * Push all writes to the server, so that the attribute cache + * doesn't get "out of sync" with the server. + * XXX There should be a better way! + */ + VOP_FSYNC(vp, cnp->cn_cred, MNT_WAIT, cnp->cn_proc); + nfsstats.rpccnt[NFSPROC_LINK]++; - nfsm_reqhead(tdvp, NFSPROC_LINK, - NFSX_FH*2+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)); - nfsm_fhtom(tdvp); - nfsm_fhtom(vp); + nfsm_reqhead(vp, NFSPROC_LINK, + NFSX_FH(v3)*2 + NFSX_UNSIGNED + nfsm_rndup(cnp->cn_namelen)); + nfsm_fhtom(vp, v3); + nfsm_fhtom(tdvp, v3); nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); - nfsm_request(tdvp, NFSPROC_LINK, cnp->cn_proc, cnp->cn_cred); + nfsm_request(vp, NFSPROC_LINK, cnp->cn_proc, cnp->cn_cred); + if (v3) { + nfsm_postop_attr(vp, attrflag); + nfsm_wcc_data(tdvp, wccflag); + } nfsm_reqdone; FREE(cnp->cn_pnbuf, M_NAMEI); - VTONFS(tdvp)->n_attrstamp = 0; VTONFS(tdvp)->n_flag |= NMODIFIED; - VTONFS(vp)->n_attrstamp = 0; - vrele(vp); + if (!attrflag) + VTONFS(vp)->n_attrstamp = 0; + if (!wccflag) + VTONFS(tdvp)->n_attrstamp = 0; + vrele(tdvp); /* * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. */ @@ -1332,7 +1674,6 @@ nfs_link(ap) /* * nfs symbolic link create call */ -/* start here */ int nfs_symlink(ap) struct vop_symlink_args /* { @@ -1347,42 +1688,50 @@ nfs_symlink(ap) register struct vattr *vap = ap->a_vap; register struct componentname *cnp = ap->a_cnp; register struct nfsv2_sattr *sp; + register struct nfsv3_sattr *sp3; register u_long *tl; register caddr_t cp; - register long t2; - caddr_t bpos, dpos; - int slen, error = 0, isnq; + register long t1, t2; + caddr_t bpos, dpos, cp2; + int slen, error = 0, wccflag = NFSV3_WCCRATTR, gotvp; struct mbuf *mreq, *mrep, *md, *mb, *mb2; + struct vnode *newvp = (struct vnode *)0; + int v3 = NFS_ISV3(dvp); nfsstats.rpccnt[NFSPROC_SYMLINK]++; slen = strlen(ap->a_target); - isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS); - nfsm_reqhead(dvp, NFSPROC_SYMLINK, NFSX_FH+2*NFSX_UNSIGNED+ - nfsm_rndup(cnp->cn_namelen)+nfsm_rndup(slen)+NFSX_SATTR(isnq)); - nfsm_fhtom(dvp); + nfsm_reqhead(dvp, NFSPROC_SYMLINK, NFSX_FH(v3) + 2*NFSX_UNSIGNED + + nfsm_rndup(cnp->cn_namelen) + nfsm_rndup(slen) + NFSX_SATTR(v3)); + nfsm_fhtom(dvp, v3); nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); + if (v3) { + nfsm_build(sp3, struct nfsv3_sattr *, NFSX_V3SRVSATTR); + nfsm_v3sattr(sp3, vap, cnp->cn_cred->cr_uid, + cnp->cn_cred->cr_gid); + } nfsm_strtom(ap->a_target, slen, NFS_MAXPATHLEN); - nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq)); - sp->sa_mode = vtonfs_mode(VLNK, vap->va_mode); - sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid); - sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid); - if (isnq) { - quad_t qval = -1; - - txdr_hyper(&qval, &sp->sa_nqsize); - sp->sa_nqflags = 0; - txdr_nqtime(&vap->va_atime, &sp->sa_nqatime); - txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime); - } else { - sp->sa_nfssize = -1; - txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime); - txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime); + if (!v3) { + nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR); + sp->sa_mode = vtonfsv2_mode(VLNK, vap->va_mode); + sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid); + sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid); + sp->sa_size = -1; + txdr_nfsv2time(&vap->va_atime, &sp->sa_atime); + txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime); } nfsm_request(dvp, NFSPROC_SYMLINK, cnp->cn_proc, cnp->cn_cred); + if (v3) { + if (!error) + nfsm_mtofh(dvp, newvp, v3, gotvp); + nfsm_wcc_data(dvp, wccflag); + } nfsm_reqdone; + if (newvp) + vrele(newvp); FREE(cnp->cn_pnbuf, M_NAMEI); VTONFS(dvp)->n_flag |= NMODIFIED; - VTONFS(dvp)->n_attrstamp = 0; + if (!wccflag) + VTONFS(dvp)->n_attrstamp = 0; vrele(dvp); /* * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. @@ -1407,16 +1756,21 @@ nfs_mkdir(ap) register struct vnode *dvp = ap->a_dvp; register struct vattr *vap = ap->a_vap; register struct componentname *cnp = ap->a_cnp; - register struct vnode **vpp = ap->a_vpp; register struct nfsv2_sattr *sp; + register struct nfsv3_sattr *sp3; register u_long *tl; register caddr_t cp; register long t1, t2; register int len; + struct nfsnode *np = (struct nfsnode *)0; + struct vnode *newvp = (struct vnode *)0; caddr_t bpos, dpos, cp2; - int error = 0, firsttry = 1, isnq; + nfsfh_t *fhp; + int error = 0, wccflag = NFSV3_WCCRATTR, attrflag; + int fhsize, gotvp = 0; struct mbuf *mreq, *mrep, *md, *mb, *mb2; struct vattr vattr; + int v3 = NFS_ISV3(dvp); if (error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc)) { VOP_ABORTOP(dvp, cnp); @@ -1424,56 +1778,54 @@ nfs_mkdir(ap) return (error); } len = cnp->cn_namelen; - isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS); nfsstats.rpccnt[NFSPROC_MKDIR]++; nfsm_reqhead(dvp, NFSPROC_MKDIR, - NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)+NFSX_SATTR(isnq)); - nfsm_fhtom(dvp); + NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len) + NFSX_SATTR(v3)); + nfsm_fhtom(dvp, v3); nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN); - nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq)); - sp->sa_mode = vtonfs_mode(VDIR, vap->va_mode); - sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid); - sp->sa_gid = txdr_unsigned(vattr.va_gid); - if (isnq) { - quad_t qval = -1; - - txdr_hyper(&qval, &sp->sa_nqsize); - sp->sa_nqflags = 0; - txdr_nqtime(&vap->va_atime, &sp->sa_nqatime); - txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime); + if (v3) { + nfsm_build(sp3, struct nfsv3_sattr *, NFSX_V3SRVSATTR); + nfsm_v3sattr(sp3, vap, cnp->cn_cred->cr_uid, vattr.va_gid); } else { - sp->sa_nfssize = -1; - txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime); - txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime); + nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR); + sp->sa_mode = vtonfsv2_mode(VDIR, vap->va_mode); + sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid); + sp->sa_gid = txdr_unsigned(vattr.va_gid); + sp->sa_size = -1; + txdr_nfsv2time(&vap->va_atime, &sp->sa_atime); + txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime); } nfsm_request(dvp, NFSPROC_MKDIR, cnp->cn_proc, cnp->cn_cred); - nfsm_mtofh(dvp, *vpp); + if (!error) + nfsm_mtofh(dvp, newvp, v3, gotvp); + if (v3) + nfsm_wcc_data(dvp, wccflag); nfsm_reqdone; VTONFS(dvp)->n_flag |= NMODIFIED; - VTONFS(dvp)->n_attrstamp = 0; + if (!wccflag) + VTONFS(dvp)->n_attrstamp = 0; /* * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry * if we can succeed in looking up the directory. - * "firsttry" is necessary since the macros may "goto nfsmout" which - * is above the if on errors. (Ugh) */ - if (error == EEXIST && firsttry) { - firsttry = 0; - error = 0; - nfsstats.rpccnt[NFSPROC_LOOKUP]++; - *vpp = NULL; - nfsm_reqhead(dvp, NFSPROC_LOOKUP, - NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); - nfsm_fhtom(dvp); - nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN); - nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred); - nfsm_mtofh(dvp, *vpp); - if ((*vpp)->v_type != VDIR) { - vput(*vpp); - error = EEXIST; + if (error == EEXIST || (!error && !gotvp)) { + if (newvp) { + vrele(newvp); + newvp = (struct vnode *)0; + } + error = nfs_lookitup(dvp, cnp->cn_nameptr, len, cnp->cn_cred, + cnp->cn_proc, &np); + if (!error) { + newvp = NFSTOV(np); + if (newvp->v_type != VDIR) + error = EEXIST; } - m_freem(mrep); } + if (error) { + if (newvp) + vrele(newvp); + } else + *ap->a_vpp = newvp; FREE(cnp->cn_pnbuf, M_NAMEI); vrele(dvp); return (error); @@ -1495,10 +1847,11 @@ nfs_rmdir(ap) register struct componentname *cnp = ap->a_cnp; register u_long *tl; register caddr_t cp; - register long t2; - caddr_t bpos, dpos; - int error = 0; + register long t1, t2; + caddr_t bpos, dpos, cp2; + int error = 0, wccflag = NFSV3_WCCRATTR; struct mbuf *mreq, *mrep, *md, *mb, *mb2; + int v3 = NFS_ISV3(dvp); if (dvp == vp) { vrele(dvp); @@ -1508,14 +1861,17 @@ nfs_rmdir(ap) } nfsstats.rpccnt[NFSPROC_RMDIR]++; nfsm_reqhead(dvp, NFSPROC_RMDIR, - NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)); - nfsm_fhtom(dvp); + NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(cnp->cn_namelen)); + nfsm_fhtom(dvp, v3); nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); nfsm_request(dvp, NFSPROC_RMDIR, cnp->cn_proc, cnp->cn_cred); + if (v3) + nfsm_wcc_data(dvp, wccflag); nfsm_reqdone; FREE(cnp->cn_pnbuf, M_NAMEI); VTONFS(dvp)->n_flag |= NMODIFIED; - VTONFS(dvp)->n_attrstamp = 0; + if (!wccflag) + VTONFS(dvp)->n_attrstamp = 0; cache_purge(dvp); cache_purge(vp); vrele(vp); @@ -1530,9 +1886,6 @@ nfs_rmdir(ap) /* * nfs readdir call - * Although cookie is defined as opaque, I translate it to/from net byte - * order so that it looks more sensible. This appears consistent with the - * Ultrix implementation of NFS. */ int nfs_readdir(ap) @@ -1553,10 +1906,10 @@ nfs_readdir(ap) /* * First, check for hit on the EOF offset cache */ - if (uio->uio_offset != 0 && uio->uio_offset == np->n_direofoffset && + if (np->n_direofoffset > 0 && uio->uio_offset >= np->n_direofoffset && (np->n_flag & NMODIFIED) == 0) { if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) { - if (NQNFS_CKCACHABLE(vp, NQL_READ)) { + if (NQNFS_CKCACHABLE(vp, ND_READ)) { nfsstats.direofcache_hits++; return (0); } @@ -1584,90 +1937,147 @@ nfs_readdir(ap) */ int nfs_readdirrpc(vp, uiop, cred) - register struct vnode *vp; - struct uio *uiop; + struct vnode *vp; + register struct uio *uiop; struct ucred *cred; { - register long len; + register int len, left; register struct dirent *dp; register u_long *tl; register caddr_t cp; - register long t1; - long tlen, lastlen; + register long t1, t2; + register nfsuint64 *cookiep; caddr_t bpos, dpos, cp2; - int error = 0; struct mbuf *mreq, *mrep, *md, *mb, *mb2; - struct mbuf *md2; - caddr_t dpos2; - int siz; - int more_dirs = 1; - u_long off, savoff; - struct dirent *savdp; - struct nfsmount *nmp; - struct nfsnode *np = VTONFS(vp); - long tresid; + nfsuint64 cookie; + struct nfsmount *nmp = VFSTONFS(vp->v_mount); + struct nfsnode *dnp = VTONFS(vp); + nfsfh_t *fhp; + u_quad_t frev, fileno; + int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1, i; + int cachable, attrflag, fhsize; + int v3 = NFS_ISV3(vp); + +#ifndef nolint + dp = (struct dirent *)0; +#endif +#ifndef DIAGNOSTIC + if (uiop->uio_iovcnt != 1 || (uiop->uio_offset & (NFS_DIRBLKSIZ - 1)) || + (uiop->uio_resid & (NFS_DIRBLKSIZ - 1))) + panic("nfs readdirrpc bad uio"); +#endif - nmp = VFSTONFS(vp->v_mount); - tresid = uiop->uio_resid; /* - * Loop around doing readdir rpc's of size uio_resid or nm_rsize, - * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ. + * If there is no cookie, assume end of directory. + */ + cookiep = nfs_getcookie(dnp, uiop->uio_offset, 0); + if (cookiep) + cookie = *cookiep; + else + return (0); + /* + * Loop around doing readdir rpc's of size nm_readdirsize + * truncated to a multiple of DIRBLKSIZ. * The stopping criteria is EOF or buffer full. */ - while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) { + while (more_dirs && bigenough) { nfsstats.rpccnt[NFSPROC_READDIR]++; - nfsm_reqhead(vp, NFSPROC_READDIR, - NFSX_FH + 2 * NFSX_UNSIGNED); - nfsm_fhtom(vp); - nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED); - off = (u_long)uiop->uio_offset; - *tl++ = txdr_unsigned(off); - *tl = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ? - nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1)); + nfsm_reqhead(vp, NFSPROC_READDIR, NFSX_FH(v3) + + NFSX_READDIR(v3)); + nfsm_fhtom(vp, v3); + if (v3) { + nfsm_build(tl, u_long *, 5 * NFSX_UNSIGNED); + *tl++ = cookie.nfsuquad[0]; + *tl++ = cookie.nfsuquad[1]; + *tl++ = dnp->n_cookieverf.nfsuquad[0]; + *tl++ = dnp->n_cookieverf.nfsuquad[1]; + } else { + nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED); + *tl++ = cookie.nfsuquad[0]; + } + *tl = txdr_unsigned(nmp->nm_readdirsize); nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, cred); - siz = 0; + if (v3) { + nfsm_postop_attr(vp, attrflag); + if (!error) { + nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); + dnp->n_cookieverf.nfsuquad[0] = *tl++; + dnp->n_cookieverf.nfsuquad[1] = *tl; + } else { + m_freem(mrep); + goto nfsmout; + } + } nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); more_dirs = fxdr_unsigned(int, *tl); - /* Save the position so that we can do nfsm_mtouio() later */ - dpos2 = dpos; - md2 = md; - /* loop thru the dir entries, doctoring them to 4bsd form */ -#ifdef lint - dp = (struct dirent *)0; -#endif /* lint */ - while (more_dirs && siz < uiop->uio_resid) { - savoff = off; /* Hold onto offset and dp */ - savdp = dp; - nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); - dp = (struct dirent *)tl; - dp->d_fileno = fxdr_unsigned(u_long, *tl++); - len = fxdr_unsigned(int, *tl); + while (more_dirs && bigenough) { + if (v3) { + nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED); + fxdr_hyper(tl, &fileno); + len = fxdr_unsigned(int, *(tl + 2)); + } else { + nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); + fileno = fxdr_unsigned(u_quad_t, *tl++); + len = fxdr_unsigned(int, *tl); + } if (len <= 0 || len > NFS_MAXNAMLEN) { error = EBADRPC; m_freem(mrep); goto nfsmout; } - dp->d_namlen = (u_char)len; - dp->d_type = DT_UNKNOWN; - nfsm_adv(len); /* Point past name */ tlen = nfsm_rndup(len); - /* - * This should not be necessary, but some servers have - * broken XDR such that these bytes are not null filled. - */ - if (tlen != len) { - *dpos = '\0'; /* Null-terminate */ - nfsm_adv(tlen - len); - len = tlen; + if (tlen == len) + tlen += 4; /* To ensure null termination */ + left = DIRBLKSIZ - blksiz; + if ((tlen + DIRHDSIZ) > left) { + dp->d_reclen += left; + uiop->uio_iov->iov_base += left; + uiop->uio_iov->iov_len -= left; + uiop->uio_offset += left; + uiop->uio_resid -= left; + blksiz = 0; } - nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); - off = fxdr_unsigned(u_long, *tl); - *tl++ = 0; /* Ensures null termination of name */ + if ((tlen + DIRHDSIZ) > uiop->uio_resid) + bigenough = 0; + if (bigenough) { + dp = (struct dirent *)uiop->uio_iov->iov_base; + dp->d_fileno = (int)fileno; + dp->d_namlen = len; + dp->d_reclen = tlen + DIRHDSIZ; + dp->d_type = DT_UNKNOWN; + blksiz += dp->d_reclen; + if (blksiz == DIRBLKSIZ) + blksiz = 0; + uiop->uio_offset += DIRHDSIZ; + uiop->uio_resid -= DIRHDSIZ; + uiop->uio_iov->iov_base += DIRHDSIZ; + uiop->uio_iov->iov_len -= DIRHDSIZ; + nfsm_mtouio(uiop, len); + cp = uiop->uio_iov->iov_base; + tlen -= len; + *cp = '\0'; /* null terminate */ + uiop->uio_iov->iov_base += tlen; + uiop->uio_iov->iov_len -= tlen; + uiop->uio_offset += tlen; + uiop->uio_resid -= tlen; + } else + nfsm_adv(nfsm_rndup(len)); + if (v3) { + nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED); + } else { + nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); + } + if (bigenough) { + cookie.nfsuquad[0] = *tl++; + if (v3) + cookie.nfsuquad[1] = *tl++; + } else if (v3) + tl += 2; + else + tl++; more_dirs = fxdr_unsigned(int, *tl); - dp->d_reclen = len + 4 * NFSX_UNSIGNED; - siz += dp->d_reclen; } /* * If at end of rpc data, get the eof boolean @@ -1675,187 +2085,224 @@ nfs_readdirrpc(vp, uiop, cred) if (!more_dirs) { nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); more_dirs = (fxdr_unsigned(int, *tl) == 0); - - /* - * If at EOF, cache directory offset - */ - if (!more_dirs) - np->n_direofoffset = off; - } - /* - * If there is too much to fit in the data buffer, use savoff and - * savdp to trim off the last record. - * --> we are not at eof - */ - if (siz > uiop->uio_resid) { - off = savoff; - siz -= dp->d_reclen; - dp = savdp; - more_dirs = 0; /* Paranoia */ } - if (siz > 0) { - lastlen = dp->d_reclen; - md = md2; - dpos = dpos2; - nfsm_mtouio(uiop, siz); - uiop->uio_offset = (off_t)off; - } else - more_dirs = 0; /* Ugh, never happens, but in case.. */ m_freem(mrep); } /* - * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ + * Fill last record, iff any, out to a multiple of DIRBLKSIZ * by increasing d_reclen for the last record. */ - if (uiop->uio_resid < tresid) { - len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1); - if (len > 0) { - dp = (struct dirent *) - (uiop->uio_iov->iov_base - lastlen); - dp->d_reclen += len; - uiop->uio_iov->iov_base += len; - uiop->uio_iov->iov_len -= len; - uiop->uio_resid -= len; - } + if (blksiz > 0) { + left = DIRBLKSIZ - blksiz; + dp->d_reclen += left; + uiop->uio_iov->iov_base += left; + uiop->uio_iov->iov_len -= left; + uiop->uio_offset += left; + uiop->uio_resid -= left; + } + + /* + * We are now either at the end of the directory or have filled the + * block. + */ + if (bigenough) + dnp->n_direofoffset = uiop->uio_offset; + else { + if (uiop->uio_resid > 0) + printf("EEK! readdirrpc resid > 0\n"); + cookiep = nfs_getcookie(dnp, uiop->uio_offset, 1); + *cookiep = cookie; } nfsmout: return (error); } /* - * Nqnfs readdir_and_lookup RPC. Used in place of nfs_readdirrpc(). + * NFS V3 readdir plus RPC. Used in place of nfs_readdirrpc(). */ int -nfs_readdirlookrpc(vp, uiop, cred) +nfs_readdirplusrpc(vp, uiop, cred) struct vnode *vp; register struct uio *uiop; struct ucred *cred; { - register int len; + register int len, left; register struct dirent *dp; register u_long *tl; register caddr_t cp; - register long t1; - caddr_t bpos, dpos, cp2; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; + register long t1, t2; + register struct vnode *newvp; + register nfsuint64 *cookiep; + caddr_t bpos, dpos, cp2, dpossav1, dpossav2; + struct mbuf *mreq, *mrep, *md, *mb, *mb2, *mdsav1, *mdsav2; struct nameidata nami, *ndp = &nami; struct componentname *cnp = &ndp->ni_cnd; - u_long off, endoff, fileno; - time_t reqtime, ltime; - struct nfsmount *nmp; - struct nfsnode *np; - struct vnode *newvp; - nfsv2fh_t *fhp; - u_quad_t frev; - int error = 0, tlen, more_dirs = 1, tresid, doit, bigenough, i; - int cachable; - - if (uiop->uio_iovcnt != 1) - panic("nfs rdirlook"); - nmp = VFSTONFS(vp->v_mount); - tresid = uiop->uio_resid; + nfsuint64 cookie; + struct nfsmount *nmp = VFSTONFS(vp->v_mount); + struct nfsnode *dnp = VTONFS(vp), *np; + nfsfh_t *fhp; + u_quad_t frev, fileno; + int error = 0, tlen, more_dirs = 1, blksiz = 0, doit, bigenough = 1, i; + int cachable, attrflag, fhsize; + +#ifndef nolint + dp = (struct dirent *)0; +#endif +#ifndef DIAGNOSTIC + if (uiop->uio_iovcnt != 1 || (uiop->uio_offset & (DIRBLKSIZ - 1)) || + (uiop->uio_resid & (DIRBLKSIZ - 1))) + panic("nfs readdirplusrpc bad uio"); +#endif ndp->ni_dvp = vp; newvp = NULLVP; + + /* + * If there is no cookie, assume end of directory. + */ + cookiep = nfs_getcookie(dnp, uiop->uio_offset, 0); + if (cookiep) + cookie = *cookiep; + else + return (0); /* - * Loop around doing readdir rpc's of size uio_resid or nm_rsize, - * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ. + * Loop around doing readdir rpc's of size nm_readdirsize + * truncated to a multiple of DIRBLKSIZ. * The stopping criteria is EOF or buffer full. */ - while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) { - nfsstats.rpccnt[NQNFSPROC_READDIRLOOK]++; - nfsm_reqhead(vp, NQNFSPROC_READDIRLOOK, - NFSX_FH + 3 * NFSX_UNSIGNED); - nfsm_fhtom(vp); - nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED); - off = (u_long)uiop->uio_offset; - *tl++ = txdr_unsigned(off); - *tl++ = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ? - nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1)); - if (nmp->nm_flag & NFSMNT_NQLOOKLEASE) - *tl = txdr_unsigned(nmp->nm_leaseterm); - else - *tl = 0; - reqtime = time.tv_sec; - nfsm_request(vp, NQNFSPROC_READDIRLOOK, uiop->uio_procp, cred); - nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); + while (more_dirs && bigenough) { + nfsstats.rpccnt[NFSPROC_READDIRPLUS]++; + nfsm_reqhead(vp, NFSPROC_READDIRPLUS, + NFSX_FH(1) + 6 * NFSX_UNSIGNED); + nfsm_fhtom(vp, 1); + nfsm_build(tl, u_long *, 6 * NFSX_UNSIGNED); + *tl++ = cookie.nfsuquad[0]; + *tl++ = cookie.nfsuquad[1]; + *tl++ = dnp->n_cookieverf.nfsuquad[0]; + *tl++ = dnp->n_cookieverf.nfsuquad[1]; + *tl++ = txdr_unsigned(nmp->nm_readdirsize); + *tl = txdr_unsigned(nmp->nm_rsize); + nfsm_request(vp, NFSPROC_READDIRPLUS, uiop->uio_procp, cred); + nfsm_postop_attr(vp, attrflag); + if (error) { + m_freem(mrep); + goto nfsmout; + } + nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED); + dnp->n_cookieverf.nfsuquad[0] = *tl++; + dnp->n_cookieverf.nfsuquad[1] = *tl++; more_dirs = fxdr_unsigned(int, *tl); /* loop thru the dir entries, doctoring them to 4bsd form */ - bigenough = 1; while (more_dirs && bigenough) { - doit = 1; - nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED); - if (nmp->nm_flag & NFSMNT_NQLOOKLEASE) { - cachable = fxdr_unsigned(int, *tl++); - ltime = reqtime + fxdr_unsigned(int, *tl++); - fxdr_hyper(tl, &frev); - } - nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH); - if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) { - VREF(vp); - newvp = vp; - np = VTONFS(vp); - } else { - if (error = nfs_nget(vp->v_mount, fhp, &np)) - doit = 0; - newvp = NFSTOV(np); - } - if (error = nfs_loadattrcache(&newvp, &md, &dpos, - (struct vattr *)0)) - doit = 0; - nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); - fileno = fxdr_unsigned(u_long, *tl++); - len = fxdr_unsigned(int, *tl); + nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED); + fxdr_hyper(tl, &fileno); + len = fxdr_unsigned(int, *(tl + 2)); if (len <= 0 || len > NFS_MAXNAMLEN) { error = EBADRPC; m_freem(mrep); goto nfsmout; } - tlen = (len + 4) & ~0x3; + tlen = nfsm_rndup(len); + if (tlen == len) + tlen += 4; /* To ensure null termination*/ + left = DIRBLKSIZ - blksiz; + if ((tlen + DIRHDSIZ) > left) { + dp->d_reclen += left; + uiop->uio_iov->iov_base += left; + uiop->uio_iov->iov_len -= left; + uiop->uio_offset += left; + uiop->uio_resid -= left; + blksiz = 0; + } if ((tlen + DIRHDSIZ) > uiop->uio_resid) bigenough = 0; - if (bigenough && doit) { + if (bigenough) { dp = (struct dirent *)uiop->uio_iov->iov_base; - dp->d_fileno = fileno; + dp->d_fileno = (int)fileno; dp->d_namlen = len; dp->d_reclen = tlen + DIRHDSIZ; - dp->d_type = - IFTODT(VTTOIF(np->n_vattr.va_type)); + dp->d_type = DT_UNKNOWN; + blksiz += dp->d_reclen; + if (blksiz == DIRBLKSIZ) + blksiz = 0; + uiop->uio_offset += DIRHDSIZ; uiop->uio_resid -= DIRHDSIZ; uiop->uio_iov->iov_base += DIRHDSIZ; uiop->uio_iov->iov_len -= DIRHDSIZ; cnp->cn_nameptr = uiop->uio_iov->iov_base; cnp->cn_namelen = len; - ndp->ni_vp = newvp; nfsm_mtouio(uiop, len); cp = uiop->uio_iov->iov_base; tlen -= len; - for (i = 0; i < tlen; i++) - *cp++ = '\0'; + *cp = '\0'; uiop->uio_iov->iov_base += tlen; uiop->uio_iov->iov_len -= tlen; + uiop->uio_offset += tlen; uiop->uio_resid -= tlen; + } else + nfsm_adv(nfsm_rndup(len)); + nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED); + if (bigenough) { + cookie.nfsuquad[0] = *tl++; + cookie.nfsuquad[1] = *tl++; + } else + tl += 2; + + /* + * Since the attributes are before the file handle + * (sigh), we must skip over the attributes and then + * come back and get them. + */ + attrflag = fxdr_unsigned(int, *tl); + if (attrflag) { + dpossav1 = dpos; + mdsav1 = md; + nfsm_adv(NFSX_V3FATTR); + nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); + doit = fxdr_unsigned(int, *tl); + if (doit) { + nfsm_getfh(fhp, fhsize, 1); + if (NFS_CMPFH(dnp, fhp, fhsize)) { + VREF(vp); + newvp = vp; + np = dnp; + } else { + if (error = nfs_nget(vp->v_mount, fhp, + fhsize, &np)) + doit = 0; + else + newvp = NFSTOV(np); + } + } + if (doit) { + dpossav2 = dpos; + dpos = dpossav1; + mdsav2 = md; + md = mdsav1; + nfsm_loadattr(newvp, (struct vattr *)0); + dpos = dpossav2; + md = mdsav2; + dp->d_type = + IFTODT(VTTOIF(np->n_vattr.va_type)); + ndp->ni_vp = newvp; cnp->cn_hash = 0; - for (cp = cnp->cn_nameptr, i = 1; i <= len; i++, cp++) - cnp->cn_hash += (unsigned char)*cp * i; - if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) && - ltime > time.tv_sec) - nqnfs_clientlease(nmp, np, NQL_READ, - cachable, ltime, frev); + for (cp = cnp->cn_nameptr, i = 1; i <= len; + i++, cp++) + cnp->cn_hash += (unsigned char)*cp * i; if (cnp->cn_namelen <= NCHNAMLEN) cache_enter(ndp->ni_dvp, ndp->ni_vp, cnp); + } } else { - nfsm_adv(nfsm_rndup(len)); + /* Just skip over the file handle */ + nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); + i = fxdr_unsigned(int, *tl); + nfsm_adv(nfsm_rndup(i)); } if (newvp != NULLVP) { - vrele(newvp); - newvp = NULLVP; + vrele(newvp); + newvp = NULLVP; } - nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); - if (bigenough) - endoff = off = fxdr_unsigned(u_long, *tl++); - else - endoff = fxdr_unsigned(u_long, *tl++); + nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); more_dirs = fxdr_unsigned(int, *tl); } /* @@ -1864,31 +2311,33 @@ nfs_readdirlookrpc(vp, uiop, cred) if (!more_dirs) { nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); more_dirs = (fxdr_unsigned(int, *tl) == 0); - - /* - * If at EOF, cache directory offset - */ - if (!more_dirs) - VTONFS(vp)->n_direofoffset = endoff; } - if (uiop->uio_resid < tresid) - uiop->uio_offset = (off_t)off; - else - more_dirs = 0; m_freem(mrep); } /* * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ * by increasing d_reclen for the last record. */ - if (uiop->uio_resid < tresid) { - len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1); - if (len > 0) { - dp->d_reclen += len; - uiop->uio_iov->iov_base += len; - uiop->uio_iov->iov_len -= len; - uiop->uio_resid -= len; - } + if (blksiz > 0) { + left = DIRBLKSIZ - blksiz; + dp->d_reclen += left; + uiop->uio_iov->iov_base += left; + uiop->uio_iov->iov_len -= left; + uiop->uio_offset += left; + uiop->uio_resid -= left; + } + + /* + * We are now either at the end of the directory or have filled the + * block. + */ + if (bigenough) + dnp->n_direofoffset = uiop->uio_offset; + else { + if (uiop->uio_resid > 0) + printf("EEK! readdirplusrpc resid > 0\n"); + cookiep = nfs_getcookie(dnp, uiop->uio_offset, 1); + *cookiep = cookie; } nfsmout: if (newvp != NULLVP) @@ -1910,19 +2359,19 @@ nfs_sillyrename(dvp, vp, cnp) struct vnode *dvp, *vp; struct componentname *cnp; { - register struct nfsnode *np; register struct sillyrename *sp; + struct nfsnode *np; int error; short pid; cache_purge(dvp); np = VTONFS(vp); -#ifdef SILLYSEPARATE +#ifndef DIAGNOSTIC + if (vp->v_type == VDIR) + panic("nfs: sillyrename dir"); +#endif MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename), M_NFSREQ, M_WAITOK); -#else - sp = &np->n_silly; -#endif sp->s_cred = crdup(cnp->cn_cred); sp->s_dvp = dvp; VREF(dvp); @@ -1937,7 +2386,8 @@ nfs_sillyrename(dvp, vp, cnp) sp->s_name[5] = hextoasc[(pid >> 12) & 0xf]; /* Try lookitups until we get one that isn't there */ - while (nfs_lookitup(sp, (nfsv2fh_t *)0, cnp->cn_proc) == 0) { + while (nfs_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred, + cnp->cn_proc, (struct nfsnode **)0) == 0) { sp->s_name[4]++; if (sp->s_name[4] > 'z') { error = EINVAL; @@ -1946,55 +2396,133 @@ nfs_sillyrename(dvp, vp, cnp) } if (error = nfs_renameit(dvp, cnp, sp)) goto bad; - nfs_lookitup(sp, &np->n_fh, cnp->cn_proc); + error = nfs_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred, + cnp->cn_proc, &np); np->n_sillyrename = sp; return (0); bad: vrele(sp->s_dvp); crfree(sp->s_cred); -#ifdef SILLYSEPARATE free((caddr_t)sp, M_NFSREQ); -#endif return (error); } /* - * Look up a file name for silly rename stuff. - * Just like nfs_lookup() except that it doesn't load returned values - * into the nfsnode table. - * If fhp != NULL it copies the returned file handle out + * Look up a file name and optionally either update the file handle or + * allocate an nfsnode, depending on the value of npp. + * npp == NULL --> just do the lookup + * *npp == NULL --> allocate a new nfsnode and make sure attributes are + * handled too + * *npp != NULL --> update the file handle in the vnode */ int -nfs_lookitup(sp, fhp, procp) - register struct sillyrename *sp; - nfsv2fh_t *fhp; +nfs_lookitup(dvp, name, len, cred, procp, npp) + register struct vnode *dvp; + char *name; + int len; + struct ucred *cred; struct proc *procp; + struct nfsnode **npp; { - register struct vnode *vp = sp->s_dvp; register u_long *tl; register caddr_t cp; register long t1, t2; + struct vnode *newvp = (struct vnode *)0; + struct nfsnode *np, *dnp = VTONFS(dvp); caddr_t bpos, dpos, cp2; - int error = 0, isnq; + int error = 0, fhlen, attrflag; struct mbuf *mreq, *mrep, *md, *mb, *mb2; - long len; + nfsfh_t *nfhp; + int v3 = NFS_ISV3(dvp); - isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS); nfsstats.rpccnt[NFSPROC_LOOKUP]++; - len = sp->s_namlen; - nfsm_reqhead(vp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)); - if (isnq) { - nfsm_build(tl, u_long *, NFSX_UNSIGNED); - *tl = 0; + nfsm_reqhead(dvp, NFSPROC_LOOKUP, + NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len)); + nfsm_fhtom(dvp, v3); + nfsm_strtom(name, len, NFS_MAXNAMLEN); + nfsm_request(dvp, NFSPROC_LOOKUP, procp, cred); + if (npp && !error) { + nfsm_getfh(nfhp, fhlen, v3); + if (*npp) { + np = *npp; + if (np->n_fhsize > NFS_SMALLFH && fhlen <= NFS_SMALLFH) { + free((caddr_t)np->n_fhp, M_NFSBIGFH); + np->n_fhp = &np->n_fh; + } else if (np->n_fhsize <= NFS_SMALLFH && fhlen>NFS_SMALLFH) + np->n_fhp =(nfsfh_t *)malloc(fhlen,M_NFSBIGFH,M_WAITOK); + bcopy((caddr_t)nfhp, (caddr_t)np->n_fhp, fhlen); + np->n_fhsize = fhlen; + newvp = NFSTOV(np); + } else if (NFS_CMPFH(dnp, nfhp, fhlen)) { + VREF(dvp); + newvp = dvp; + } else { + error = nfs_nget(dvp->v_mount, nfhp, fhlen, &np); + if (error) { + m_freem(mrep); + return (error); + } + newvp = NFSTOV(np); + } + if (v3) { + nfsm_postop_attr(newvp, attrflag); + if (!attrflag && *npp == NULL) { + m_freem(mrep); + vrele(newvp); + return (ENOENT); + } + } else + nfsm_loadattr(newvp, (struct vattr *)0); } - nfsm_fhtom(vp); - nfsm_strtom(sp->s_name, len, NFS_MAXNAMLEN); - nfsm_request(vp, NFSPROC_LOOKUP, procp, sp->s_cred); - if (fhp != NULL) { - if (isnq) - nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); - nfsm_dissect(cp, caddr_t, NFSX_FH); - bcopy(cp, (caddr_t)fhp, NFSX_FH); + nfsm_reqdone; + if (npp && *npp == NULL) { + if (error) { + if (newvp) + vrele(newvp); + } else + *npp = np; + } + return (error); +} + +/* + * Nfs Version 3 commit rpc + */ +int +nfs_commit(vp, offset, cnt, cred, procp) + register struct vnode *vp; + u_quad_t offset; + int cnt; + struct ucred *cred; + struct proc *procp; +{ + register caddr_t cp; + register u_long *tl; + register int t1, t2; + register struct nfsmount *nmp = VFSTONFS(vp->v_mount); + caddr_t bpos, dpos, cp2; + int error = 0, wccflag = NFSV3_WCCRATTR; + struct mbuf *mreq, *mrep, *md, *mb, *mb2; + + if ((nmp->nm_flag & NFSMNT_HASWRITEVERF) == 0) + return (0); + nfsstats.rpccnt[NFSPROC_COMMIT]++; + nfsm_reqhead(vp, NFSPROC_COMMIT, NFSX_FH(1)); + nfsm_fhtom(vp, 1); + nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED); + txdr_hyper(&offset, tl); + tl += 2; + *tl = txdr_unsigned(cnt); + nfsm_request(vp, NFSPROC_COMMIT, procp, cred); + nfsm_wcc_data(vp, wccflag); + if (!error) { + nfsm_dissect(tl, u_long *, NFSX_V3WRITEVERF); + if (bcmp((caddr_t)nmp->nm_verf, (caddr_t)tl, + NFSX_V3WRITEVERF)) { + bcopy((caddr_t)tl, (caddr_t)nmp->nm_verf, + NFSX_V3WRITEVERF); + error = NFSERR_STALEWRITEVERF; + } } nfsm_reqdone; return (error); @@ -2003,9 +2531,7 @@ nfs_lookitup(sp, fhp, procp) /* * Kludge City.. * - make nfs_bmap() essentially a no-op that does no translation - * - do nfs_strategy() by faking physical I/O with nfs_readrpc/nfs_writerpc - * after mapping the physical addresses into Kernel Virtual space in the - * nfsiobuf area. + * - do nfs_strategy() by doing I/O with nfs_readrpc/nfs_writerpc * (Maybe I could use the process's page mapping, but I was concerned that * Kernel Write might not be enabled and also figured copyout() would do * a lot more work than bcopy() and also it currently happens in the @@ -2086,9 +2612,7 @@ nfs_mmap(ap) } /* - * Flush all the blocks associated with a vnode. - * Walk through the buffer pool and push any dirty pages - * associated with the vnode. + * fsync vnode op. Just call nfs_flush() with commit == 1. */ /* ARGSUSED */ int @@ -2101,29 +2625,122 @@ nfs_fsync(ap) struct proc * a_p; } */ *ap; { - register struct vnode *vp = ap->a_vp; + + return (nfs_flush(ap->a_vp, ap->a_cred, ap->a_waitfor, ap->a_p, 1)); +} + +/* + * Flush all the blocks associated with a vnode. + * Walk through the buffer pool and push any dirty pages + * associated with the vnode. + */ +int +nfs_flush(vp, cred, waitfor, p, commit) + register struct vnode *vp; + struct ucred *cred; + int waitfor; + struct proc *p; + int commit; +{ register struct nfsnode *np = VTONFS(vp); register struct buf *bp; + register int i; struct buf *nbp; - struct nfsmount *nmp; - int s, error = 0, slptimeo = 0, slpflag = 0; + struct nfsmount *nmp = VFSTONFS(vp->v_mount); + int s, error = 0, slptimeo = 0, slpflag = 0, retv, bvecpos; + int passone = 1; + u_quad_t off = (u_quad_t)-1, endoff = 0, toff; +#ifndef NFS_COMMITBVECSIZ +#define NFS_COMMITBVECSIZ 20 +#endif + struct buf *bvec[NFS_COMMITBVECSIZ]; - nmp = VFSTONFS(vp->v_mount); if (nmp->nm_flag & NFSMNT_INT) slpflag = PCATCH; + if (!commit) + passone = 0; + /* + * A b_flags == (B_DELWRI | B_NEEDCOMMIT) block has been written to the + * server, but nas not been committed to stable storage on the server + * yet. On the first pass, the byte range is worked out and the commit + * rpc is done. On the second pass, nfs_writebp() is called to do the + * job. + */ +again: + bvecpos = 0; + if (NFS_ISV3(vp) && commit) { + s = splbio(); + for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) { + nbp = bp->b_vnbufs.le_next; + if (bvecpos >= NFS_COMMITBVECSIZ) + break; + if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT)) + != (B_DELWRI | B_NEEDCOMMIT)) + continue; + bremfree(bp); + bp->b_flags |= (B_BUSY | B_WRITEINPROG); + /* + * A list of these buffers is kept so that the + * second loop knows which buffers have actually + * been committed. This is necessary, since there + * may be a race between the commit rpc and new + * uncommitted writes on the file. + */ + bvec[bvecpos++] = bp; + toff = ((u_quad_t)bp->b_blkno) * DEV_BSIZE + + bp->b_dirtyoff; + if (toff < off) + off = toff; + toff += (u_quad_t)(bp->b_dirtyend - bp->b_dirtyoff); + if (toff > endoff) + endoff = toff; + } + splx(s); + } + if (bvecpos > 0) { + /* + * Commit data on the server, as required. + */ + retv = nfs_commit(vp, off, (int)(endoff - off), cred, p); + if (retv == NFSERR_STALEWRITEVERF) + nfs_clearcommit(vp->v_mount); + /* + * Now, either mark the blocks I/O done or mark the + * blocks dirty, depending on whether the commit + * succeeded. + */ + for (i = 0; i < bvecpos; i++) { + bp = bvec[i]; + bp->b_flags &= ~(B_NEEDCOMMIT | B_WRITEINPROG); + if (retv) { + brelse(bp); + } else { + vp->v_numoutput++; + bp->b_flags |= B_ASYNC; + bp->b_flags &= ~(B_READ|B_DONE|B_ERROR|B_DELWRI); + bp->b_dirtyoff = bp->b_dirtyend = 0; + reassignbuf(bp, vp); + biodone(bp); + } + } + } + + /* + * Start/do any write(s) that are required. + */ loop: s = splbio(); for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) { nbp = bp->b_vnbufs.le_next; if (bp->b_flags & B_BUSY) { - if (ap->a_waitfor != MNT_WAIT) + if (waitfor != MNT_WAIT || passone) continue; bp->b_flags |= B_WANTED; error = tsleep((caddr_t)bp, slpflag | (PRIBIO + 1), "nfsfsync", slptimeo); splx(s); if (error) { - if (nfs_sigintr(nmp, (struct nfsreq *)0, ap->a_p)) + if (nfs_sigintr(nmp, (struct nfsreq *)0, p)) return (EINTR); if (slpflag == PCATCH) { slpflag = 0; @@ -2134,21 +2751,29 @@ loop: } if ((bp->b_flags & B_DELWRI) == 0) panic("nfs_fsync: not dirty"); + if ((passone || !commit) && (bp->b_flags & B_NEEDCOMMIT)) + continue; bremfree(bp); - bp->b_flags |= B_BUSY; + if (passone || !commit) + bp->b_flags |= (B_BUSY|B_ASYNC); + else + bp->b_flags |= (B_BUSY|B_ASYNC|B_WRITEINPROG|B_NEEDCOMMIT); splx(s); - bp->b_flags |= B_ASYNC; VOP_BWRITE(bp); goto loop; } splx(s); - if (ap->a_waitfor == MNT_WAIT) { + if (passone) { + passone = 0; + goto again; + } + if (waitfor == MNT_WAIT) { while (vp->v_numoutput) { vp->v_flag |= VBWAIT; error = tsleep((caddr_t)&vp->v_numoutput, slpflag | (PRIBIO + 1), "nfsfsync", slptimeo); if (error) { - if (nfs_sigintr(nmp, (struct nfsreq *)0, ap->a_p)) + if (nfs_sigintr(nmp, (struct nfsreq *)0, p)) return (EINTR); if (slpflag == PCATCH) { slpflag = 0; @@ -2156,8 +2781,8 @@ loop: } } } - if (vp->v_dirtyblkhd.lh_first) { -#ifdef DIAGNOSTIC + if (vp->v_dirtyblkhd.lh_first && commit) { +#ifndef DIAGNOSTIC vprint("nfs_fsync: dirty", vp); #endif goto loop; @@ -2173,10 +2798,11 @@ loop: /* * Return POSIX pathconf information applicable to nfs. * - * Currently the NFS protocol does not support getting such - * information from the remote server. + * The NFS V2 protocol doesn't support this, so just return EINVAL + * for V2. */ /* ARGSUSED */ +int nfs_pathconf(ap) struct vop_pathconf_args /* { struct vnode *a_vp; @@ -2218,13 +2844,12 @@ nfs_print(ap) register struct vnode *vp = ap->a_vp; register struct nfsnode *np = VTONFS(vp); - printf("tag VT_NFS, fileid %d fsid 0x%x", + printf("tag VT_NFS, fileid %ld fsid 0x%lx", np->n_vattr.va_fileid, np->n_vattr.va_fsid); -#ifdef FIFO if (vp->v_type == VFIFO) fifo_printinfo(vp); -#endif /* FIFO */ printf("\n"); + return (0); } /* @@ -2315,6 +2940,84 @@ nfs_update(ap) } /* + * Just call nfs_writebp() with the force argument set to 1. + */ +int +nfs_bwrite(ap) + struct vop_bwrite_args /* { + struct vnode *a_bp; + } */ *ap; +{ + + return (nfs_writebp(ap->a_bp, 1)); +} + +/* + * This is a clone of vn_bwrite(), except that B_WRITEINPROG isn't set unless + * the force flag is one and it also handles the B_NEEDCOMMIT flag. + */ +int +nfs_writebp(bp, force) + register struct buf *bp; + int force; +{ + register int oldflags = bp->b_flags, retv = 1; + register struct proc *p = curproc; /* XXX */ + off_t off; + + if(!(bp->b_flags & B_BUSY)) + panic("bwrite: buffer is not busy???"); + + bp->b_flags &= ~(B_READ|B_DONE|B_ERROR|B_DELWRI); + + if (oldflags & B_ASYNC) { + if (oldflags & B_DELWRI) { + reassignbuf(bp, bp->b_vp); + } else if (p) { + ++p->p_stats->p_ru.ru_oublock; + } + } + bp->b_vp->v_numoutput++; + + /* + * If B_NEEDCOMMIT is set, a commit rpc may do the trick. If not + * an actual write will have to be scheduled via. VOP_STRATEGY(). + * If B_WRITEINPROG is already set, then push it with a write anyhow. + */ + if (oldflags & (B_NEEDCOMMIT | B_WRITEINPROG) == B_NEEDCOMMIT) { + off = ((u_quad_t)bp->b_blkno) * DEV_BSIZE + bp->b_dirtyoff; + bp->b_flags |= B_WRITEINPROG; + retv = nfs_commit(bp->b_vp, off, bp->b_dirtyend-bp->b_dirtyoff, + bp->b_wcred, bp->b_proc); + bp->b_flags &= ~B_WRITEINPROG; + if (!retv) { + bp->b_dirtyoff = bp->b_dirtyend = 0; + bp->b_flags &= ~B_NEEDCOMMIT; + biodone(bp); + } else if (retv == NFSERR_STALEWRITEVERF) + nfs_clearcommit(bp->b_vp->v_mount); + } + if (retv) { + if (force) + bp->b_flags |= B_WRITEINPROG; + VOP_STRATEGY(bp); + } + + if( (oldflags & B_ASYNC) == 0) { + int rtval = biowait(bp); + if (oldflags & B_DELWRI) { + reassignbuf(bp, bp->b_vp); + } else if (p) { + ++p->p_stats->p_ru.ru_oublock; + } + brelse(bp); + return (rtval); + } + + return (0); +} + +/* * nfs special file access vnode op. * Essentially just get vattr and then imitate iaccess() since the device is * local to the client. @@ -2331,19 +3034,32 @@ nfsspec_access(ap) register struct vattr *vap; register gid_t *gp; register struct ucred *cred = ap->a_cred; + struct vnode *vp = ap->a_vp; mode_t mode = ap->a_mode; struct vattr vattr; register int i; int error; /* + * Disallow write attempts on filesystems mounted read-only; + * unless the file is a socket, fifo, or a block or character + * device resident on the filesystem. + */ + if ((mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) { + switch (vp->v_type) { + case VREG: case VDIR: case VLNK: + return (EROFS); + } + } + /* * If you're the super-user, * you always get access. */ if (cred->cr_uid == 0) return (0); vap = &vattr; - if (error = VOP_GETATTR(ap->a_vp, vap, cred, ap->a_p)) + error = VOP_GETATTR(vp, vap, cred, ap->a_p); + if (error) return (error); /* * Access check is based on only one of owner, group, public. @@ -2360,7 +3076,8 @@ nfsspec_access(ap) found: ; } - return ((vap->va_mode & mode) == mode ? 0 : EACCES); + error = (vap->va_mode & mode) == mode ? 0 : EACCES; + return (error); } /* @@ -2381,7 +3098,8 @@ nfsspec_read(ap) * Set access flag. */ np->n_flag |= NACC; - np->n_atim = time; + np->n_atim.ts_sec = time.tv_sec; + np->n_atim.ts_nsec = time.tv_usec * 1000; return (VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap)); } @@ -2403,7 +3121,8 @@ nfsspec_write(ap) * Set update flag. */ np->n_flag |= NUPD; - np->n_mtim = time; + np->n_mtim.ts_sec = time.tv_sec; + np->n_mtim.ts_nsec = time.tv_usec * 1000; return (VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap)); } @@ -2430,23 +3149,16 @@ nfsspec_close(ap) if (vp->v_usecount == 1 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { VATTR_NULL(&vattr); - if (np->n_flag & NACC) { - vattr.va_atime.ts_sec = np->n_atim.tv_sec; - vattr.va_atime.ts_nsec = - np->n_atim.tv_usec * 1000; - } - if (np->n_flag & NUPD) { - vattr.va_mtime.ts_sec = np->n_mtim.tv_sec; - vattr.va_mtime.ts_nsec = - np->n_mtim.tv_usec * 1000; - } + if (np->n_flag & NACC) + vattr.va_atime = np->n_atim; + if (np->n_flag & NUPD) + vattr.va_mtime = np->n_mtim; (void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p); } } return (VOCALL(spec_vnodeop_p, VOFFSET(vop_close), ap)); } -#ifdef FIFO /* * Read wrapper for fifos. */ @@ -2466,7 +3178,8 @@ nfsfifo_read(ap) * Set access flag. */ np->n_flag |= NACC; - np->n_atim = time; + np->n_atim.ts_sec = time.tv_sec; + np->n_atim.ts_nsec = time.tv_usec * 1000; return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap)); } @@ -2489,7 +3202,8 @@ nfsfifo_write(ap) * Set update flag. */ np->n_flag |= NUPD; - np->n_mtim = time; + np->n_mtim.ts_sec = time.tv_sec; + np->n_mtim.ts_nsec = time.tv_usec * 1000; return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap)); } @@ -2513,27 +3227,24 @@ nfsfifo_close(ap) extern int (**fifo_vnodeop_p)(); if (np->n_flag & (NACC | NUPD)) { - if (np->n_flag & NACC) - np->n_atim = time; - if (np->n_flag & NUPD) - np->n_mtim = time; + if (np->n_flag & NACC) { + np->n_atim.ts_sec = time.tv_sec; + np->n_atim.ts_nsec = time.tv_usec * 1000; + } + if (np->n_flag & NUPD) { + np->n_mtim.ts_sec = time.tv_sec; + np->n_mtim.ts_nsec = time.tv_usec * 1000; + } np->n_flag |= NCHG; if (vp->v_usecount == 1 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { VATTR_NULL(&vattr); - if (np->n_flag & NACC) { - vattr.va_atime.ts_sec = np->n_atim.tv_sec; - vattr.va_atime.ts_nsec = - np->n_atim.tv_usec * 1000; - } - if (np->n_flag & NUPD) { - vattr.va_mtime.ts_sec = np->n_mtim.tv_sec; - vattr.va_mtime.ts_nsec = - np->n_mtim.tv_usec * 1000; - } + if (np->n_flag & NACC) + vattr.va_atime = np->n_atim; + if (np->n_flag & NUPD) + vattr.va_mtime = np->n_mtim; (void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p); } } return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap)); } -#endif /* FIFO */ diff --git a/sys/nfs/nfsdiskless.h b/sys/nfs/nfsdiskless.h index 74e6b7b..9f864a4 100644 --- a/sys/nfs/nfsdiskless.h +++ b/sys/nfs/nfsdiskless.h @@ -33,34 +33,68 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfsdiskless.h 8.1 (Berkeley) 6/10/93 + * @(#)nfsdiskless.h 8.2 (Berkeley) 3/30/95 */ + +#ifndef _NFS_NFSDISKLESS_H_ +#define _NFS_NFSDISKLESS_H_ + /* * Structure that must be initialized for a diskless nfs client. * This structure is used by nfs_mountroot() to set up the root and swap * vnodes plus do a partial ifconfig(8) and route(8) so that the critical net * interface can communicate with the server. * The primary bootstrap is expected to fill in the appropriate fields before - * starting vmunix. Whether or not the swap area is nfs mounted is determined - * by the value in swdevt[0]. (equal to NODEV --> swap over nfs) + * starting the kernel. Whether or not the swap area is nfs mounted is + * determined by the value in swdevt[0]. (equal to NODEV --> swap over nfs) * Currently only works for AF_INET protocols. * NB: All fields are stored in net byte order to avoid hassles with * client/server byte ordering differences. */ + +/* + * I have defined a new structure that can handle an NFS Version 3 file handle + * but the kernel still expects the old Version 2 one to be provided. The + * changes required in nfs_vfsops.c for using the new are documented there in + * comments. (I felt that breaking network booting code by changing this + * structure would not be prudent at this time, since almost all servers are + * still Version 2 anyhow.) + */ +struct nfsv3_diskless { + struct ifaliasreq myif; /* Default interface */ + struct sockaddr_in mygateway; /* Default gateway */ + struct nfs_args swap_args; /* Mount args for swap file */ + int swap_fhsize; /* Size of file handle */ + u_char swap_fh[NFSX_V3FHMAX]; /* Swap file's file handle */ + struct sockaddr_in swap_saddr; /* Address of swap server */ + char swap_hostnam[MNAMELEN]; /* Host name for mount pt */ + int swap_nblks; /* Size of server swap file */ + struct ucred swap_ucred; /* Swap credentials */ + struct nfs_args root_args; /* Mount args for root fs */ + int root_fhsize; /* Size of root file handle */ + u_char root_fh[NFSX_V3FHMAX]; /* File handle of root dir */ + struct sockaddr_in root_saddr; /* Address of root server */ + char root_hostnam[MNAMELEN]; /* Host name for mount pt */ + long root_time; /* Timestamp of root fs */ + char my_hostnam[MAXHOSTNAMELEN]; /* Client host name */ +}; + struct nfs_diskless { struct ifaliasreq myif; /* Default interface */ struct sockaddr_in mygateway; /* Default gateway */ struct nfs_args swap_args; /* Mount args for swap file */ - u_char swap_fh[NFS_FHSIZE]; /* Swap file's file handle */ + u_char swap_fh[NFSX_V2FH]; /* Swap file's file handle */ struct sockaddr_in swap_saddr; /* Address of swap server */ char swap_hostnam[MNAMELEN]; /* Host name for mount pt */ int swap_nblks; /* Size of server swap file */ struct ucred swap_ucred; /* Swap credentials */ struct nfs_args root_args; /* Mount args for root fs */ - u_char root_fh[NFS_FHSIZE]; /* File handle of root dir */ + u_char root_fh[NFSX_V2FH]; /* File handle of root dir */ struct sockaddr_in root_saddr; /* Address of root server */ char root_hostnam[MNAMELEN]; /* Host name for mount pt */ long root_time; /* Timestamp of root fs */ char my_hostnam[MAXHOSTNAMELEN]; /* Client host name */ }; + +#endif diff --git a/sys/nfs/nfsm_subs.h b/sys/nfs/nfsm_subs.h index 879db36..95c1646 100644 --- a/sys/nfs/nfsm_subs.h +++ b/sys/nfs/nfsm_subs.h @@ -33,9 +33,14 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfsm_subs.h 8.1 (Berkeley) 6/16/93 + * @(#)nfsm_subs.h 8.2 (Berkeley) 3/30/95 */ + +#ifndef _NFS_NFSM_SUBS_H_ +#define _NFS_NFSM_SUBS_H_ + + /* * These macros do strange and peculiar things to mbuf chains for * the assistance of the nfs code. To attempt to use them for any @@ -86,44 +91,153 @@ extern struct mbuf *nfsm_reqh(); mb->m_len += (s); \ bpos += (s); } -#define nfsm_dissect(a,c,s) \ +#define nfsm_dissect(a, c, s) \ { t1 = mtod(md, caddr_t)+md->m_len-dpos; \ if (t1 >= (s)) { \ (a) = (c)(dpos); \ dpos += (s); \ - } else if (error = nfsm_disct(&md, &dpos, (s), t1, &cp2)) { \ + } else if (t1 = nfsm_disct(&md, &dpos, (s), t1, &cp2)) { \ + error = t1; \ m_freem(mrep); \ goto nfsmout; \ } else { \ (a) = (c)cp2; \ } } -#define nfsm_fhtom(v) \ - nfsm_build(cp,caddr_t,NFSX_FH); \ - bcopy((caddr_t)&(VTONFS(v)->n_fh), cp, NFSX_FH) +#define nfsm_fhtom(v, v3) \ + { if (v3) { \ + t2 = nfsm_rndup(VTONFS(v)->n_fhsize) + NFSX_UNSIGNED; \ + if (t2 <= M_TRAILINGSPACE(mb)) { \ + nfsm_build(tl, u_long *, t2); \ + *tl++ = txdr_unsigned(VTONFS(v)->n_fhsize); \ + *(tl + ((t2>>2) - 2)) = 0; \ + bcopy((caddr_t)VTONFS(v)->n_fhp,(caddr_t)tl, \ + VTONFS(v)->n_fhsize); \ + } else if (t2 = nfsm_strtmbuf(&mb, &bpos, \ + (caddr_t)VTONFS(v)->n_fhp, VTONFS(v)->n_fhsize)) { \ + error = t2; \ + m_freem(mreq); \ + goto nfsmout; \ + } \ + } else { \ + nfsm_build(cp, caddr_t, NFSX_V2FH); \ + bcopy((caddr_t)VTONFS(v)->n_fhp, cp, NFSX_V2FH); \ + } } -#define nfsm_srvfhtom(f) \ - nfsm_build(cp,caddr_t,NFSX_FH); \ - bcopy((caddr_t)(f), cp, NFSX_FH) +#define nfsm_srvfhtom(f, v3) \ + { if (v3) { \ + nfsm_build(tl, u_long *, NFSX_UNSIGNED + NFSX_V3FH); \ + *tl++ = txdr_unsigned(NFSX_V3FH); \ + bcopy((caddr_t)(f), (caddr_t)tl, NFSX_V3FH); \ + } else { \ + nfsm_build(cp, caddr_t, NFSX_V2FH); \ + bcopy((caddr_t)(f), cp, NFSX_V2FH); \ + } } -#define nfsm_mtofh(d,v) \ - { struct nfsnode *np; nfsv2fh_t *fhp; \ - nfsm_dissect(fhp,nfsv2fh_t *,NFSX_FH); \ - if (error = nfs_nget((d)->v_mount, fhp, &np)) { \ - m_freem(mrep); \ - goto nfsmout; \ +#define nfsm_srvpostop_fh(f) \ + { nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED + NFSX_V3FH); \ + *tl++ = nfs_true; \ + *tl++ = txdr_unsigned(NFSX_V3FH); \ + bcopy((caddr_t)(f), (caddr_t)tl, NFSX_V3FH); \ + } + +#define nfsm_mtofh(d, v, v3, f) \ + { struct nfsnode *ttnp; nfsfh_t *ttfhp; int ttfhsize; \ + if (v3) { \ + nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \ + (f) = fxdr_unsigned(int, *tl); \ + } else \ + (f) = 1; \ + if (f) { \ + nfsm_getfh(ttfhp, ttfhsize, (v3)); \ + if (t1 = nfs_nget((d)->v_mount, ttfhp, ttfhsize, \ + &ttnp)) { \ + error = t1; \ + m_freem(mrep); \ + goto nfsmout; \ + } \ + (v) = NFSTOV(ttnp); \ + } \ + if (v3) { \ + nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \ + if (f) \ + (f) = fxdr_unsigned(int, *tl); \ + else if (fxdr_unsigned(int, *tl)) \ + nfsm_adv(NFSX_V3FATTR); \ } \ - (v) = NFSTOV(np); \ - nfsm_loadattr(v, (struct vattr *)0); \ + if (f) \ + nfsm_loadattr((v), (struct vattr *)0); \ } -#define nfsm_loadattr(v,a) \ - { struct vnode *tvp = (v); \ - if (error = nfs_loadattrcache(&tvp, &md, &dpos, (a))) { \ +#define nfsm_getfh(f, s, v3) \ + { if (v3) { \ + nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \ + if (((s) = fxdr_unsigned(int, *tl)) <= 0 || \ + (s) > NFSX_V3FHMAX) { \ + m_freem(mrep); \ + error = EBADRPC; \ + goto nfsmout; \ + } \ + } else \ + (s) = NFSX_V2FH; \ + nfsm_dissect((f), nfsfh_t *, nfsm_rndup(s)); } + +#define nfsm_loadattr(v, a) \ + { struct vnode *ttvp = (v); \ + if (t1 = nfs_loadattrcache(&ttvp, &md, &dpos, (a))) { \ + error = t1; \ m_freem(mrep); \ goto nfsmout; \ } \ - (v) = tvp; } + (v) = ttvp; } + +#define nfsm_postop_attr(v, f) \ + { struct vnode *ttvp = (v); \ + nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \ + if ((f) = fxdr_unsigned(int, *tl)) { \ + if (t1 = nfs_loadattrcache(&ttvp, &md, &dpos, \ + (struct vattr *)0)) { \ + error = t1; \ + (f) = 0; \ + m_freem(mrep); \ + goto nfsmout; \ + } \ + (v) = ttvp; \ + } } + +/* Used as (f) for nfsm_wcc_data() */ +#define NFSV3_WCCRATTR 0 +#define NFSV3_WCCCHK 1 + +#define nfsm_wcc_data(v, f) \ + { int ttattrf, ttretf = 0; \ + nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \ + if (*tl == nfs_true) { \ + nfsm_dissect(tl, u_long *, 6 * NFSX_UNSIGNED); \ + if (f) \ + ttretf = (VTONFS(v)->n_mtime == \ + fxdr_unsigned(u_long, *(tl + 2))); \ + } \ + nfsm_postop_attr((v), ttattrf); \ + if (f) { \ + (f) = ttretf; \ + } else { \ + (f) = ttattrf; \ + } } + +#define nfsm_v3sattr(s, a, u, g) \ + { (s)->sa_modetrue = nfs_true; \ + (s)->sa_mode = vtonfsv3_mode((a)->va_mode); \ + (s)->sa_uidtrue = nfs_true; \ + (s)->sa_uid = txdr_unsigned(u); \ + (s)->sa_gidtrue = nfs_true; \ + (s)->sa_gid = txdr_unsigned(g); \ + (s)->sa_sizefalse = nfs_false; \ + (s)->sa_atimetype = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT); \ + txdr_nfsv3time(&(a)->va_atime, &(s)->sa_atime); \ + (s)->sa_mtimetype = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT); \ + txdr_nfsv3time(&(a)->va_mtime, &(s)->sa_mtime); \ + } #define nfsm_strsiz(s,m) \ { nfsm_dissect(tl,u_long *,NFSX_UNSIGNED); \ @@ -140,15 +254,27 @@ extern struct mbuf *nfsm_reqh(); nfsm_reply(0); \ } } +#define nfsm_srvnamesiz(s) \ + { nfsm_dissect(tl,u_long *,NFSX_UNSIGNED); \ + if (((s) = fxdr_unsigned(long,*tl)) > NFS_MAXNAMLEN) \ + error = NFSERR_NAMETOL; \ + if ((s) <= 0) \ + error = EBADRPC; \ + if (error) \ + nfsm_reply(0); \ + } + #define nfsm_mtouio(p,s) \ if ((s) > 0 && \ - (error = nfsm_mbuftouio(&md,(p),(s),&dpos))) { \ + (t1 = nfsm_mbuftouio(&md,(p),(s),&dpos))) { \ + error = t1; \ m_freem(mrep); \ goto nfsmout; \ } #define nfsm_uiotom(p,s) \ - if (error = nfsm_uiotombuf((p),&mb,(s),&bpos)) { \ + if (t1 = nfsm_uiotombuf((p),&mb,(s),&bpos)) { \ + error = t1; \ m_freem(mreq); \ goto nfsmout; \ } @@ -163,8 +289,12 @@ extern struct mbuf *nfsm_reqh(); #define nfsm_request(v, t, p, c) \ if (error = nfs_request((v), mreq, (t), (p), \ - (c), &mrep, &md, &dpos)) \ - goto nfsmout + (c), &mrep, &md, &dpos)) { \ + if (error & NFSERR_RETERR) \ + error &= ~NFSERR_RETERR; \ + else \ + goto nfsmout; \ + } #define nfsm_strtom(a,s,m) \ if ((s) > (m)) { \ @@ -178,7 +308,8 @@ extern struct mbuf *nfsm_reqh(); *tl++ = txdr_unsigned(s); \ *(tl+((t2>>2)-2)) = 0; \ bcopy((caddr_t)(a), (caddr_t)tl, (s)); \ - } else if (error = nfsm_strtmbuf(&mb, &bpos, (a), (s))) { \ + } else if (t2 = nfsm_strtmbuf(&mb, &bpos, (a), (s))) { \ + error = t2; \ m_freem(mreq); \ goto nfsmout; \ } @@ -190,30 +321,53 @@ extern struct mbuf *nfsm_reqh(); #define nfsm_reply(s) \ { \ nfsd->nd_repstat = error; \ - if (error) \ - (void) nfs_rephead(0, nfsd, error, cache, &frev, \ + if (error && !(nfsd->nd_flag & ND_NFSV3)) \ + (void) nfs_rephead(0, nfsd, slp, error, cache, &frev, \ mrq, &mb, &bpos); \ else \ - (void) nfs_rephead((s), nfsd, error, cache, &frev, \ + (void) nfs_rephead((s), nfsd, slp, error, cache, &frev, \ mrq, &mb, &bpos); \ m_freem(mrep); \ mreq = *mrq; \ - if (error) \ + if (error && (!(nfsd->nd_flag & ND_NFSV3) || \ + error == EBADRPC)) \ return(0); \ } +#define nfsm_writereply(s, v3) \ + { \ + nfsd->nd_repstat = error; \ + if (error && !(v3)) \ + (void) nfs_rephead(0, nfsd, slp, error, cache, &frev, \ + &mreq, &mb, &bpos); \ + else \ + (void) nfs_rephead((s), nfsd, slp, error, cache, &frev, \ + &mreq, &mb, &bpos); \ + } + #define nfsm_adv(s) \ - t1 = mtod(md, caddr_t)+md->m_len-dpos; \ + { t1 = mtod(md, caddr_t)+md->m_len-dpos; \ if (t1 >= (s)) { \ dpos += (s); \ - } else if (error = nfs_adv(&md, &dpos, (s), t1)) { \ + } else if (t1 = nfs_adv(&md, &dpos, (s), t1)) { \ + error = t1; \ m_freem(mrep); \ goto nfsmout; \ - } + } } #define nfsm_srvmtofh(f) \ - nfsm_dissect(tl, u_long *, NFSX_FH); \ - bcopy((caddr_t)tl, (caddr_t)f, NFSX_FH) + { if (nfsd->nd_flag & ND_NFSV3) { \ + nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \ + if (fxdr_unsigned(int, *tl) != NFSX_V3FH) { \ + error = EBADRPC; \ + nfsm_reply(0); \ + } \ + } \ + nfsm_dissect(tl, u_long *, NFSX_V3FH); \ + bcopy((caddr_t)tl, (caddr_t)(f), NFSX_V3FH); \ + if ((nfsd->nd_flag & ND_NFSV3) == 0) \ + nfsm_adv(NFSX_V2FH - NFSX_V3FH); \ + } #define nfsm_clget \ if (bp >= be) { \ @@ -229,41 +383,57 @@ extern struct mbuf *nfsm_reqh(); } \ tl = (u_long *)bp -#define nfsm_srvfillattr \ - fp->fa_type = vtonfs_type(vap->va_type); \ - fp->fa_mode = vtonfs_mode(vap->va_type, vap->va_mode); \ - fp->fa_nlink = txdr_unsigned(vap->va_nlink); \ - fp->fa_uid = txdr_unsigned(vap->va_uid); \ - fp->fa_gid = txdr_unsigned(vap->va_gid); \ - if (nfsd->nd_nqlflag == NQL_NOVAL) { \ - fp->fa_nfsblocksize = txdr_unsigned(vap->va_blocksize); \ - if (vap->va_type == VFIFO) \ - fp->fa_nfsrdev = 0xffffffff; \ - else \ - fp->fa_nfsrdev = txdr_unsigned(vap->va_rdev); \ - fp->fa_nfsfsid = txdr_unsigned(vap->va_fsid); \ - fp->fa_nfsfileid = txdr_unsigned(vap->va_fileid); \ - fp->fa_nfssize = txdr_unsigned(vap->va_size); \ - fp->fa_nfsblocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE); \ - txdr_nfstime(&vap->va_atime, &fp->fa_nfsatime); \ - txdr_nfstime(&vap->va_mtime, &fp->fa_nfsmtime); \ - fp->fa_nfsctime.nfs_sec = txdr_unsigned(vap->va_ctime.ts_sec); \ - fp->fa_nfsctime.nfs_usec = txdr_unsigned(vap->va_gen); \ - } else { \ - fp->fa_nqblocksize = txdr_unsigned(vap->va_blocksize); \ - if (vap->va_type == VFIFO) \ - fp->fa_nqrdev = 0xffffffff; \ - else \ - fp->fa_nqrdev = txdr_unsigned(vap->va_rdev); \ - fp->fa_nqfsid = txdr_unsigned(vap->va_fsid); \ - fp->fa_nqfileid = txdr_unsigned(vap->va_fileid); \ - txdr_hyper(&vap->va_size, &fp->fa_nqsize); \ - txdr_hyper(&vap->va_bytes, &fp->fa_nqbytes); \ - txdr_nqtime(&vap->va_atime, &fp->fa_nqatime); \ - txdr_nqtime(&vap->va_mtime, &fp->fa_nqmtime); \ - txdr_nqtime(&vap->va_ctime, &fp->fa_nqctime); \ - fp->fa_nqflags = txdr_unsigned(vap->va_flags); \ - fp->fa_nqgen = txdr_unsigned(vap->va_gen); \ - txdr_hyper(&vap->va_filerev, &fp->fa_nqfilerev); \ - } +#define nfsm_srvfillattr(a, f) \ + nfsm_srvfattr(nfsd, (a), (f)) + +#define nfsm_srvwcc_data(br, b, ar, a) \ + nfsm_srvwcc(nfsd, (br), (b), (ar), (a), &mb, &bpos) + +#define nfsm_srvpostop_attr(r, a) \ + nfsm_srvpostopattr(nfsd, (r), (a), &mb, &bpos) + +#define nfsm_srvsattr(a) \ + { nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \ + if (*tl == nfs_true) { \ + nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \ + (a)->va_mode = nfstov_mode(*tl); \ + } \ + nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \ + if (*tl == nfs_true) { \ + nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \ + (a)->va_uid = fxdr_unsigned(uid_t, *tl); \ + } \ + nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \ + if (*tl == nfs_true) { \ + nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \ + (a)->va_gid = fxdr_unsigned(gid_t, *tl); \ + } \ + nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \ + if (*tl == nfs_true) { \ + nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); \ + fxdr_hyper(tl, &(a)->va_size); \ + } \ + nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \ + switch (fxdr_unsigned(int, *tl)) { \ + case NFSV3SATTRTIME_TOCLIENT: \ + nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); \ + fxdr_nfsv3time(tl, &(a)->va_atime); \ + break; \ + case NFSV3SATTRTIME_TOSERVER: \ + (a)->va_atime.ts_sec = time.tv_sec; \ + (a)->va_atime.ts_nsec = time.tv_usec * 1000; \ + break; \ + }; \ + nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \ + switch (fxdr_unsigned(int, *tl)) { \ + case NFSV3SATTRTIME_TOCLIENT: \ + nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); \ + fxdr_nfsv3time(tl, &(a)->va_mtime); \ + break; \ + case NFSV3SATTRTIME_TOSERVER: \ + (a)->va_mtime.ts_sec = time.tv_sec; \ + (a)->va_mtime.ts_nsec = time.tv_usec * 1000; \ + break; \ + }; } +#endif diff --git a/sys/nfs/nfsmount.h b/sys/nfs/nfsmount.h index 4d74acb..78fe04a 100644 --- a/sys/nfs/nfsmount.h +++ b/sys/nfs/nfsmount.h @@ -33,9 +33,13 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfsmount.h 8.1 (Berkeley) 6/10/93 + * @(#)nfsmount.h 8.3 (Berkeley) 3/30/95 */ + +#ifndef _NFS_NFSMOUNT_H_ +#define _NFS_NFSMOUNT_H_ + /* * Mount structure. * One allocated on every NFS mount. @@ -45,7 +49,8 @@ struct nfsmount { int nm_flag; /* Flags for soft/hard... */ struct mount *nm_mountp; /* Vfs structure for this filesystem */ int nm_numgrps; /* Max. size of groupslist */ - nfsv2fh_t nm_fh; /* File handle of root dir */ + u_char nm_fh[NFSX_V3FHMAX]; /* File handle of root dir */ + int nm_fhsize; /* Size of root file handle */ struct socket *nm_so; /* Rpc socket */ int nm_sotype; /* Type of socket */ int nm_soproto; /* and protocol */ @@ -61,15 +66,22 @@ struct nfsmount { int nm_deadthresh; /* Threshold of timeouts-->dead server*/ int nm_rsize; /* Max size of read rpc */ int nm_wsize; /* Max size of write rpc */ + int nm_readdirsize; /* Size of a readdir rpc */ int nm_readahead; /* Num. of blocks to readahead */ int nm_leaseterm; /* Term (sec) for NQNFS lease */ - struct nfsnode *nm_tnext; /* Head of lease timer queue */ - struct nfsnode *nm_tprev; + CIRCLEQ_HEAD(, nfsnode) nm_timerhead; /* Head of lease timer queue */ struct vnode *nm_inprog; /* Vnode in prog by nqnfs_clientd() */ uid_t nm_authuid; /* Uid for authenticator */ int nm_authtype; /* Authenticator type */ int nm_authlen; /* and length */ char *nm_authstr; /* Authenticator string */ + char *nm_verfstr; /* and the verifier */ + int nm_verflen; + u_char nm_verf[NFSX_V3WRITEVERF]; /* V3 write verifier */ + NFSKERBKEY_T nm_key; /* and the session key */ + int nm_numuids; /* Number of nfsuid mappings */ + TAILQ_HEAD(, nfsuid) nm_uidlruhead; /* Lists of nfsuid mappings */ + LIST_HEAD(, nfsuid) nm_uidhashtbl[NFS_MUIDHASHSIZ]; }; #ifdef KERNEL @@ -125,3 +137,5 @@ int nfs_vptofh __P(( struct vnode *vp, struct fid *fhp)); int nfs_init __P(()); + +#endif diff --git a/sys/nfs/nfsnode.h b/sys/nfs/nfsnode.h index f5fee5b..06107d5 100644 --- a/sys/nfs/nfsnode.h +++ b/sys/nfs/nfsnode.h @@ -33,9 +33,17 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfsnode.h 8.4 (Berkeley) 2/13/94 + * @(#)nfsnode.h 8.9 (Berkeley) 5/14/95 */ + +#ifndef _NFS_NFSNODE_H_ +#define _NFS_NFSNODE_H_ + +#ifndef _NFS_NFS_H_ +#include +#endif + /* * Silly rename structure that hangs off the nfsnode until the name * can be removed by nfs_inactive() @@ -48,38 +56,73 @@ struct sillyrename { }; /* + * This structure is used to save the logical directory offset to + * NFS cookie mappings. + * The mappings are stored in a list headed + * by n_cookies, as required. + * There is one mapping for each NFS_DIRBLKSIZ bytes of directory information + * stored in increasing logical offset byte order. + */ +#define NFSNUMCOOKIES 31 + +struct nfsdmap { + LIST_ENTRY(nfsdmap) ndm_list; + int ndm_eocookie; + nfsuint64 ndm_cookies[NFSNUMCOOKIES]; +}; + +/* * The nfsnode is the nfs equivalent to ufs's inode. Any similarity * is purely coincidental. * There is a unique nfsnode allocated for each active file, * each current directory, each mounted-on file, text file, and the root. * An nfsnode is 'named' by its file handle. (nget/nfs_node.c) + * If this structure exceeds 256 bytes (it is currently 256 using 4.4BSD-Lite + * type definitions), file handles of > 32 bytes should probably be split out + * into a separate MALLOC()'d data structure. (Reduce the size of nfsfh_t by + * changing the definition in sys/mount.h of NFS_SMALLFH.) + * NB: Hopefully the current order of the fields is such that everything will + * be well aligned and, therefore, tightly packed. */ - struct nfsnode { - struct nfsnode *n_forw; /* hash, forward */ - struct nfsnode **n_back; /* hash, backward */ - nfsv2fh_t n_fh; /* NFS File Handle */ - long n_flag; /* Flag for locking.. */ - struct vnode *n_vnode; /* vnode associated with this node */ - struct vattr n_vattr; /* Vnode attribute cache */ - time_t n_attrstamp; /* Time stamp for cached attributes */ - struct sillyrename *n_sillyrename; /* Ptr to silly rename struct */ - u_quad_t n_size; /* Current size of file */ - int n_error; /* Save write error value */ - u_long n_direofoffset; /* Dir. EOF offset cache */ - time_t n_mtime; /* Prev modify time. */ - time_t n_ctime; /* Prev create time. */ - u_quad_t n_brev; /* Modify rev when cached */ - u_quad_t n_lrev; /* Modify rev for lease */ - time_t n_expiry; /* Lease expiry time */ - struct nfsnode *n_tnext; /* Nqnfs timer chain */ - struct nfsnode *n_tprev; - long spare1; /* To 8 byte boundary */ - struct sillyrename n_silly; /* Silly rename struct */ - struct timeval n_atim; /* Special file times */ - struct timeval n_mtim; + LIST_ENTRY(nfsnode) n_hash; /* Hash chain */ + CIRCLEQ_ENTRY(nfsnode) n_timer; /* Nqnfs timer chain */ + u_quad_t n_size; /* Current size of file */ + u_quad_t n_brev; /* Modify rev when cached */ + u_quad_t n_lrev; /* Modify rev for lease */ + struct vattr n_vattr; /* Vnode attribute cache */ + time_t n_attrstamp; /* Attr. cache timestamp */ + time_t n_mtime; /* Prev modify time. */ + time_t n_ctime; /* Prev create time. */ + time_t n_expiry; /* Lease expiry time */ + nfsfh_t *n_fhp; /* NFS File Handle */ + struct vnode *n_vnode; /* associated vnode */ + struct lockf *n_lockf; /* Locking record of file */ + int n_error; /* Save write error value */ + union { + struct timespec nf_atim; /* Special file times */ + nfsuint64 nd_cookieverf; /* Cookie verifier (dir only) */ + } n_un1; + union { + struct timespec nf_mtim; + off_t nd_direof; /* Dir. EOF offset cache */ + } n_un2; + union { + struct sillyrename *nf_silly; /* Ptr to silly rename struct */ + LIST_HEAD(, nfsdmap) nd_cook; /* cookies */ + } n_un3; + short n_fhsize; /* size in bytes, of fh */ + short n_flag; /* Flag for locking.. */ + nfsfh_t n_fh; /* Small File Handle */ }; +#define n_atim n_un1.nf_atim +#define n_mtim n_un2.nf_mtim +#define n_sillyrename n_un3.nf_silly +#define n_cookieverf n_un1.nd_cookieverf +#define n_direofoffset n_un2.nd_direof +#define n_cookies n_un3.nd_cook + /* * Flags for n_flag */ @@ -103,7 +146,7 @@ struct nfsnode { /* * Queue head for nfsiod's */ -TAILQ_HEAD(nfsbufs, buf) nfs_bufq; +TAILQ_HEAD(, buf) nfs_bufq; #ifdef KERNEL /* @@ -115,23 +158,22 @@ int nfs_mknod __P((struct vop_mknod_args *)); int nfs_open __P((struct vop_open_args *)); int nfs_close __P((struct vop_close_args *)); int nfsspec_close __P((struct vop_close_args *)); -#ifdef FIFO int nfsfifo_close __P((struct vop_close_args *)); -#endif int nfs_access __P((struct vop_access_args *)); int nfsspec_access __P((struct vop_access_args *)); int nfs_getattr __P((struct vop_getattr_args *)); int nfs_setattr __P((struct vop_setattr_args *)); int nfs_read __P((struct vop_read_args *)); int nfs_write __P((struct vop_write_args *)); +#define nfs_lease_check ((int (*) __P((struct vop_lease_args *)))nullop) +#define nqnfs_vop_lease_check lease_check int nfsspec_read __P((struct vop_read_args *)); int nfsspec_write __P((struct vop_write_args *)); -#ifdef FIFO int nfsfifo_read __P((struct vop_read_args *)); int nfsfifo_write __P((struct vop_write_args *)); -#endif #define nfs_ioctl ((int (*) __P((struct vop_ioctl_args *)))enoioctl) #define nfs_select ((int (*) __P((struct vop_select_args *)))seltrue) +#define nfs_revoke vop_revoke int nfs_mmap __P((struct vop_mmap_args *)); int nfs_fsync __P((struct vop_fsync_args *)); #define nfs_seek ((int (*) __P((struct vop_seek_args *)))nullop) @@ -146,15 +188,16 @@ int nfs_readlink __P((struct vop_readlink_args *)); int nfs_abortop __P((struct vop_abortop_args *)); int nfs_inactive __P((struct vop_inactive_args *)); int nfs_reclaim __P((struct vop_reclaim_args *)); -int nfs_lock __P((struct vop_lock_args *)); -int nfs_unlock __P((struct vop_unlock_args *)); +#define nfs_lock ((int (*) __P((struct vop_lock_args *)))vop_nolock) +#define nfs_unlock ((int (*) __P((struct vop_unlock_args *)))vop_nounlock) +#define nfs_islocked ((int (*) __P((struct vop_islocked_args *)))vop_noislocked) int nfs_bmap __P((struct vop_bmap_args *)); int nfs_strategy __P((struct vop_strategy_args *)); int nfs_print __P((struct vop_print_args *)); -int nfs_islocked __P((struct vop_islocked_args *)); int nfs_pathconf __P((struct vop_pathconf_args *)); int nfs_advlock __P((struct vop_advlock_args *)); int nfs_blkatoff __P((struct vop_blkatoff_args *)); +int nfs_bwrite __P((struct vop_bwrite_args *)); int nfs_vget __P((struct mount *, ino_t, struct vnode **)); int nfs_valloc __P((struct vop_valloc_args *)); #define nfs_reallocblks \ @@ -162,5 +205,16 @@ int nfs_valloc __P((struct vop_valloc_args *)); int nfs_vfree __P((struct vop_vfree_args *)); int nfs_truncate __P((struct vop_truncate_args *)); int nfs_update __P((struct vop_update_args *)); -int nfs_bwrite __P((struct vop_bwrite_args *)); + +/* other stuff */ +int nfs_removeit __P((struct sillyrename *)); +int nfs_nget __P((struct mount *,nfsfh_t *,int,struct nfsnode **)); +int nfs_lookitup __P((struct vnode *,char *,int,struct ucred *,struct proc *,struct nfsnode **)); +int nfs_sillyrename __P((struct vnode *,struct vnode *,struct componentname *)); +nfsuint64 *nfs_getcookie __P((struct nfsnode *, off_t, int)); +void nfs_invaldir __P((struct vnode *)); +#define nqnfs_lease_updatetime lease_updatetime + #endif /* KERNEL */ + +#endif diff --git a/sys/nfs/nfsproto.h b/sys/nfs/nfsproto.h index ac1a090..7dd9090 100644 --- a/sys/nfs/nfsproto.h +++ b/sys/nfs/nfsproto.h @@ -33,13 +33,13 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfsproto.h 8.1 (Berkeley) 6/10/93 - * $Id: nfsproto.h,v 1.4 1994/08/21 06:50:13 paul Exp $ + * @(#)nfsproto.h 8.2 (Berkeley) 3/30/95 */ #ifndef _NFS_NFSPROTO_H_ #define _NFS_NFSPROTO_H_ + /* * nfs definitions as per the Version 2 and 3 specs */ diff --git a/sys/nfs/nfsrtt.h b/sys/nfs/nfsrtt.h index 0d23880..da15ece 100644 --- a/sys/nfs/nfsrtt.h +++ b/sys/nfs/nfsrtt.h @@ -33,9 +33,13 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfsrtt.h 8.1 (Berkeley) 6/10/93 + * @(#)nfsrtt.h 8.2 (Berkeley) 3/30/95 */ + +#ifndef _NFS_NFSRTT_H_ +#define _NFS_NFSRTT_H_ + /* * Definitions for performance monitor. * The client and server logging are turned on by setting the global @@ -78,6 +82,7 @@ struct nfsrtt { #define DRT_TCP 0x02 /* Client used TCP transport */ #define DRT_CACHEREPLY 0x04 /* Reply was from recent request cache */ #define DRT_CACHEDROP 0x08 /* Rpc request dropped, due to recent reply */ +#define DRT_NFSV3 0x10 /* Rpc used NFS Version 3 */ /* * Server log structure @@ -94,3 +99,5 @@ struct nfsdrt { struct timeval tstamp; /* Timestamp of log entry */ } drt[NFSRTTLOGSIZ]; }; + +#endif diff --git a/sys/nfs/nfsrvcache.h b/sys/nfs/nfsrvcache.h index 26da2c2..15f0c1b 100644 --- a/sys/nfs/nfsrvcache.h +++ b/sys/nfs/nfsrvcache.h @@ -33,20 +33,22 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nfsrvcache.h 8.1 (Berkeley) 6/10/93 + * @(#)nfsrvcache.h 8.3 (Berkeley) 3/30/95 */ + +#ifndef _NFS_NFSRVCACHE_H_ +#define _NFS_NFSRVCACHE_H_ + /* * Definitions for the server recent request cache */ -#define NFSRVCACHESIZ 256 +#define NFSRVCACHESIZ 64 struct nfsrvcache { - struct nfsrvcache *rc_forw; /* Hash chain links */ - struct nfsrvcache **rc_back; /* Hash chain links */ - struct nfsrvcache *rc_next; /* Lru list */ - struct nfsrvcache **rc_prev; /* Lru list */ + TAILQ_ENTRY(nfsrvcache) rc_lru; /* LRU chain */ + LIST_ENTRY(nfsrvcache) rc_hash; /* Hash chain */ u_long rc_xid; /* rpc id number */ union { struct mbuf *ru_repmb; /* Reply mbuf list OR */ @@ -82,3 +84,5 @@ struct nfsrvcache { #define RC_NQNFS 0x10 #define RC_INETADDR 0x20 #define RC_NAM 0x40 + +#endif diff --git a/sys/nfs/nqnfs.h b/sys/nfs/nqnfs.h index 730741a..254d5c4 100644 --- a/sys/nfs/nqnfs.h +++ b/sys/nfs/nqnfs.h @@ -33,9 +33,13 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nqnfs.h 8.1 (Berkeley) 6/10/93 + * @(#)nqnfs.h 8.3 (Berkeley) 3/30/95 */ + +#ifndef _NFS_NQNFS_H_ +#define _NFS_NQNFS_H_ + /* * Definitions for NQNFS (Not Quite NFS) cache consistency protocol. */ @@ -54,7 +58,7 @@ #define NQLCHSZ 256 /* Server hash table size */ #define NQNFS_PROG 300105 /* As assigned by Sun */ -#define NQNFS_VER1 1 +#define NQNFS_VER3 3 #define NQNFS_EVICTSIZ 156 /* Size of eviction request in bytes */ /* @@ -62,6 +66,9 @@ * RAM on the server. The default definitions below assume that NOVRAM is not * available. */ +#ifdef HASNVRAM +# undef HASNVRAM +#endif #define NQSTORENOVRAM(t) #define NQLOADNOVRAM(t) @@ -105,9 +112,8 @@ struct nqhost { #define lph_slp lph_un.un_conn.conn_slp struct nqlease { - struct nqlease *lc_chain1[2]; /* Timer queue list (must be first) */ - struct nqlease *lc_fhnext; /* Fhandle hash list */ - struct nqlease **lc_fhprev; + LIST_ENTRY(nqlease) lc_hash; /* Fhandle hash list */ + CIRCLEQ_ENTRY(nqlease) lc_timer; /* Timer queue list */ time_t lc_expiry; /* Expiry time (sec) */ struct nqhost lc_host; /* Host that got lease */ struct nqm *lc_morehosts; /* Other hosts that share read lease */ @@ -137,14 +143,6 @@ struct nqm { }; /* - * Flag bits for flags argument to nqsrv_getlease. - */ -#define NQL_READ LEASE_READ /* Read Request */ -#define NQL_WRITE LEASE_WRITE /* Write Request */ -#define NQL_CHECK 0x4 /* Check for lease */ -#define NQL_NOVAL 0xffffffff /* Invalid */ - -/* * Special value for slp for local server calls. */ #define NQLOCALSLP ((struct nfssvc_sock *) -1) @@ -154,9 +152,9 @@ struct nqm { */ #define nqsrv_getl(v, l) \ (void) nqsrv_getlease((v), &nfsd->nd_duration, \ - ((nfsd->nd_nqlflag != 0 && nfsd->nd_nqlflag != NQL_NOVAL) ? nfsd->nd_nqlflag : \ - ((l) | NQL_CHECK)), \ - nfsd, nam, &cache, &frev, cred) + ((nfsd->nd_flag & ND_LEASE) ? (nfsd->nd_flag & ND_LEASE) : \ + ((l) | ND_CHECK)), \ + slp, procp, nfsd->nd_nam, &cache, &frev, cred) /* * Client side macros that check for a valid lease. @@ -164,13 +162,13 @@ struct nqm { #define NQNFS_CKINVALID(v, n, f) \ ((time.tv_sec > (n)->n_expiry && \ VFSTONFS((v)->v_mount)->nm_timeouts < VFSTONFS((v)->v_mount)->nm_deadthresh) \ - || ((f) == NQL_WRITE && ((n)->n_flag & NQNFSWRITE) == 0)) + || ((f) == ND_WRITE && ((n)->n_flag & NQNFSWRITE) == 0)) #define NQNFS_CKCACHABLE(v, f) \ ((time.tv_sec <= VTONFS(v)->n_expiry || \ VFSTONFS((v)->v_mount)->nm_timeouts >= VFSTONFS((v)->v_mount)->nm_deadthresh) \ && (VTONFS(v)->n_flag & NQNFSNONCACHE) == 0 && \ - ((f) == NQL_READ || (VTONFS(v)->n_flag & NQNFSWRITE))) + ((f) == ND_READ || (VTONFS(v)->n_flag & NQNFSWRITE))) #define NQNFS_NEEDLEASE(v, p) \ (time.tv_sec > VTONFS(v)->n_expiry ? \ @@ -178,21 +176,38 @@ struct nqm { (((time.tv_sec + NQ_RENEWAL) > VTONFS(v)->n_expiry && \ nqnfs_piggy[p]) ? \ ((VTONFS(v)->n_flag & NQNFSWRITE) ? \ - NQL_WRITE : nqnfs_piggy[p]) : 0)) + ND_WRITE : nqnfs_piggy[p]) : 0)) /* * List head for timer queue. */ -extern union nqsrvthead { - union nqsrvthead *th_head[2]; - struct nqlease *th_chain[2]; -} nqthead; -extern struct nqlease **nqfhead; -extern u_long nqfheadhash; +CIRCLEQ_HEAD(, nqlease) nqtimerhead; + +/* + * List head for the file handle hash table. + */ +#define NQFHHASH(f) \ + (&nqfhhashtbl[(*((u_long *)(f))) & nqfhhash]) +LIST_HEAD(nqfhhashhead, nqlease) *nqfhhashtbl; +u_long nqfhhash; /* * Nqnfs return status numbers. */ #define NQNFS_EXPIRED 500 #define NQNFS_TRYLATER 501 -#define NQNFS_AUTHERR 502 + +#ifdef KERNEL +void nqnfs_lease_updatetime __P((int)); +int nqsrv_cmpnam __P((struct nfssvc_sock *,struct mbuf *,struct nqhost *)); +int nqsrv_getlease __P((struct vnode *, u_long *, int, + struct nfssvc_sock *, struct proc *, struct mbuf *, int *, + u_quad_t *, struct ucred *)); +int nqnfs_getlease __P((struct vnode *, int, struct ucred *,struct proc *)); +int nqnfs_callback __P((struct nfsmount *, struct mbuf *, struct mbuf *, + caddr_t)); +int nqnfs_clientd __P((struct nfsmount *, struct ucred *, + struct nfsd_cargs *, int, caddr_t, struct proc *)); +#endif + +#endif diff --git a/sys/nfs/rpcv2.h b/sys/nfs/rpcv2.h index 9c793a7..bb6cd3d 100644 --- a/sys/nfs/rpcv2.h +++ b/sys/nfs/rpcv2.h @@ -33,9 +33,13 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)rpcv2.h 8.1 (Berkeley) 6/10/93 + * @(#)rpcv2.h 8.2 (Berkeley) 3/30/95 */ + +#ifndef _NFS_RPCV2_H_ +#define _NFS_RPCV2_H_ + /* * Definitions for Sun RPC Version 2, from * "RPC: Remote Procedure Call Protocol Specification" RFC1057 @@ -48,10 +52,18 @@ #define RPCAUTH_NULL 0 #define RPCAUTH_UNIX 1 #define RPCAUTH_SHORT 2 +#define RPCAUTH_KERB4 4 #define RPCAUTH_NQNFS 300000 #define RPCAUTH_MAXSIZ 400 +#define RPCVERF_MAXSIZ 12 /* For Kerb, can actually be 400 */ #define RPCAUTH_UNIXGIDS 16 +/* + * Constants associated with authentication flavours. + */ +#define RPCAKN_FULLNAME 0 +#define RPCAKN_NICKNAME 1 + /* Rpc Constants */ #define RPC_CALL 0 #define RPC_REPLY 1 @@ -86,3 +98,44 @@ #define RPCMNT_NAMELEN 255 #define RPCMNT_PATHLEN 1024 #define RPCPROG_NFS 100003 + +/* + * Structures used for RPCAUTH_KERB4. + */ +struct nfsrpc_fullverf { + u_long t1; + u_long t2; + u_long w2; +}; + +struct nfsrpc_fullblock { + u_long t1; + u_long t2; + u_long w1; + u_long w2; +}; + +struct nfsrpc_nickverf { + u_long kind; + struct nfsrpc_fullverf verf; +}; + +/* + * and their sizes in bytes.. If sizeof (struct nfsrpc_xx) != these + * constants, well then things will break in mount_nfs and nfsd. + */ +#define RPCX_FULLVERF 12 +#define RPCX_FULLBLOCK 16 +#define RPCX_NICKVERF 16 + +#ifdef NFSKERB +XXX +#else +typedef u_char NFSKERBKEY_T[2]; +typedef u_char NFSKERBKEYSCHED_T[2]; +#endif +#define NFS_KERBSRV "rcmd" /* Kerberos Service for NFS */ +#define NFS_KERBTTL (30 * 60) /* Credential ttl (sec) */ +#define NFS_KERBCLOCKSKEW (5 * 60) /* Clock skew (sec) */ +#define NFS_KERBW1(t) (*((u_long *)(&((t).dat[((t).length + 3) & ~0x3])))) +#endif diff --git a/sys/nfs/xdr_subs.h b/sys/nfs/xdr_subs.h index c2aa4f3..2c433a6 100644 --- a/sys/nfs/xdr_subs.h +++ b/sys/nfs/xdr_subs.h @@ -33,9 +33,13 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)xdr_subs.h 8.1 (Berkeley) 6/10/93 + * @(#)xdr_subs.h 8.3 (Berkeley) 3/30/95 */ + +#ifndef _NFS_XDR_SUBS_H_ +#define _NFS_XDR_SUBS_H_ + /* * Macros used for conversion to/from xdr representation by nfs... * These use the MACHINE DEPENDENT routines ntohl, htonl @@ -50,22 +54,28 @@ #define fxdr_unsigned(t, v) ((t)ntohl((long)(v))) #define txdr_unsigned(v) (htonl((long)(v))) -#define fxdr_nfstime(f, t) { \ - (t)->ts_sec = ntohl(((struct nfsv2_time *)(f))->nfs_sec); \ - (t)->ts_nsec = 1000 * ntohl(((struct nfsv2_time *)(f))->nfs_usec); \ +#define fxdr_nfsv2time(f, t) { \ + (t)->ts_sec = ntohl(((struct nfsv2_time *)(f))->nfsv2_sec); \ + if (((struct nfsv2_time *)(f))->nfsv2_usec != 0xffffffff) \ + (t)->ts_nsec = 1000 * ntohl(((struct nfsv2_time *)(f))->nfsv2_usec); \ + else \ + (t)->ts_nsec = 0; \ } -#define txdr_nfstime(f, t) { \ - ((struct nfsv2_time *)(t))->nfs_sec = htonl((f)->ts_sec); \ - ((struct nfsv2_time *)(t))->nfs_usec = htonl((f)->ts_nsec) / 1000; \ +#define txdr_nfsv2time(f, t) { \ + ((struct nfsv2_time *)(t))->nfsv2_sec = htonl((f)->ts_sec); \ + if ((f)->ts_nsec != -1) \ + ((struct nfsv2_time *)(t))->nfsv2_usec = htonl((f)->ts_nsec / 1000); \ + else \ + ((struct nfsv2_time *)(t))->nfsv2_usec = 0xffffffff; \ } -#define fxdr_nqtime(f, t) { \ - (t)->ts_sec = ntohl(((struct nqnfs_time *)(f))->nq_sec); \ - (t)->ts_nsec = ntohl(((struct nqnfs_time *)(f))->nq_nsec); \ +#define fxdr_nfsv3time(f, t) { \ + (t)->ts_sec = ntohl(((struct nfsv3_time *)(f))->nfsv3_sec); \ + (t)->ts_nsec = ntohl(((struct nfsv3_time *)(f))->nfsv3_nsec); \ } -#define txdr_nqtime(f, t) { \ - ((struct nqnfs_time *)(t))->nq_sec = htonl((f)->ts_sec); \ - ((struct nqnfs_time *)(t))->nq_nsec = htonl((f)->ts_nsec); \ +#define txdr_nfsv3time(f, t) { \ + ((struct nfsv3_time *)(t))->nfsv3_sec = htonl((f)->ts_sec); \ + ((struct nfsv3_time *)(t))->nfsv3_nsec = htonl((f)->ts_nsec); \ } #define fxdr_hyper(f, t) { \ @@ -76,3 +86,5 @@ ((long *)(t))[0] = htonl(((long *)(f))[_QUAD_HIGHWORD]); \ ((long *)(t))[1] = htonl(((long *)(f))[_QUAD_LOWWORD]); \ } + +#endif -- cgit v1.1 From 73a498e93ef77f792f958b4a1ea0d9ad0490888a Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 11 Mar 1996 19:39:40 +0000 Subject: Import 4.4BSD-Lite2 onto the vendor branch, note that in the kernel, all files are off the vendor branch, so this should not change anything. A "U" marker generally means that the file was not changed in between the 4.4Lite and Lite-2 releases, and does not need a merge. "C" generally means that there was a change. [new sys/syscallargs.h file, to be "cvs rm"ed] --- sys/sys/acct.h | 41 +-- sys/sys/buf.h | 15 +- sys/sys/cdefs.h | 5 +- sys/sys/conf.h | 36 ++- sys/sys/dirent.h | 11 +- sys/sys/disk.h | 4 +- sys/sys/disklabel.h | 133 ++++---- sys/sys/dkbad.h | 14 +- sys/sys/exec.h | 11 +- sys/sys/file.h | 16 +- sys/sys/ioccom.h | 17 +- sys/sys/ipc.h | 4 +- sys/sys/ktrace.h | 8 +- sys/sys/malloc.h | 14 +- sys/sys/mbuf.h | 20 +- sys/sys/mman.h | 7 +- sys/sys/mount.h | 322 +++++++------------ sys/sys/namei.h | 14 +- sys/sys/param.h | 4 +- sys/sys/proc.h | 65 ++-- sys/sys/queue.h | 30 +- sys/sys/reboot.h | 29 +- sys/sys/resource.h | 10 +- sys/sys/resourcevar.h | 5 +- sys/sys/signal.h | 12 +- sys/sys/signalvar.h | 16 +- sys/sys/socket.h | 6 +- sys/sys/socketvar.h | 60 +++- sys/sys/stat.h | 73 +++-- sys/sys/syscall.h | 77 ++--- sys/sys/syscallargs.h | 862 ++++++++++++++++++++++++++++++++++++++++++++++++++ sys/sys/sysctl.h | 6 +- sys/sys/systm.h | 9 +- sys/sys/tablet.h | 27 +- sys/sys/time.h | 12 +- sys/sys/tty.h | 6 +- sys/sys/types.h | 48 +-- sys/sys/ucred.h | 15 +- sys/sys/un.h | 23 +- sys/sys/vmmeter.h | 112 +++---- sys/sys/vnioctl.h | 2 +- sys/sys/vnode.h | 84 +++-- sys/sys/wait.h | 6 +- 43 files changed, 1635 insertions(+), 656 deletions(-) create mode 100644 sys/sys/syscallargs.h (limited to 'sys') diff --git a/sys/sys/acct.h b/sys/sys/acct.h index edc5bdb..bf72100 100644 --- a/sys/sys/acct.h +++ b/sys/sys/acct.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1990, 1993 + * Copyright (c) 1990, 1993, 1994 * The Regents of the University of California. All rights reserved. * (c) UNIX System Laboratories, Inc. * All or some portions of this file are derived from material licensed @@ -35,7 +35,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)acct.h 8.2 (Berkeley) 1/21/94 + * @(#)acct.h 8.4 (Berkeley) 1/9/95 */ /* @@ -43,25 +43,26 @@ * exponent, 13 bit fraction ``floating point'' number. Units are 1/AHZ * seconds. */ -typedef u_short comp_t; +typedef u_int16_t comp_t; struct acct { - char ac_comm[10]; /* command name */ - comp_t ac_utime; /* user time */ - comp_t ac_stime; /* system time */ - comp_t ac_etime; /* elapsed time */ - time_t ac_btime; /* starting time */ - uid_t ac_uid; /* user id */ - gid_t ac_gid; /* group id */ - short ac_mem; /* average memory usage */ - comp_t ac_io; /* count of IO blocks */ - dev_t ac_tty; /* controlling tty */ -#define AFORK 0x01 /* forked but not execed */ -#define ASU 0x02 /* used super-user permissions */ -#define ACOMPAT 0x04 /* used compatibility mode */ -#define ACORE 0x08 /* dumped core */ -#define AXSIG 0x10 /* killed by a signal */ - char ac_flag; /* accounting flags */ + char ac_comm[10]; /* command name */ + comp_t ac_utime; /* user time */ + comp_t ac_stime; /* system time */ + comp_t ac_etime; /* elapsed time */ + time_t ac_btime; /* starting time */ + uid_t ac_uid; /* user id */ + gid_t ac_gid; /* group id */ + u_int16_t ac_mem; /* average memory usage */ + comp_t ac_io; /* count of IO blocks */ + dev_t ac_tty; /* controlling tty */ + +#define AFORK 0x01 /* fork'd but not exec'd */ +#define ASU 0x02 /* used super-user permissions */ +#define ACOMPAT 0x04 /* used compatibility mode */ +#define ACORE 0x08 /* dumped core */ +#define AXSIG 0x10 /* killed by a signal */ + u_int8_t ac_flag; /* accounting flags */ }; /* @@ -72,4 +73,6 @@ struct acct { #ifdef KERNEL struct vnode *acctp; + +int acct_process __P((struct proc *p)); #endif diff --git a/sys/sys/buf.h b/sys/sys/buf.h index e6c329f..dcf7246 100644 --- a/sys/sys/buf.h +++ b/sys/sys/buf.h @@ -35,7 +35,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)buf.h 8.7 (Berkeley) 1/21/94 + * @(#)buf.h 8.9 (Berkeley) 3/30/95 */ #ifndef _SYS_BUF_H_ @@ -68,7 +68,8 @@ struct buf { /* Function to call upon completion. */ void (*b_iodone) __P((struct buf *)); struct vnode *b_vp; /* Device vnode. */ - int b_pfcent; /* Center page when swapping cluster. */ + long b_pfcent; /* Center page when swapping cluster. */ + /* XXX pfcent should be int; overld. */ int b_dirtyoff; /* Offset in buffer of dirty region. */ int b_dirtyend; /* Offset of end of dirty region. */ struct ucred *b_rcred; /* Read credentials reference. */ @@ -88,7 +89,7 @@ struct buf { * These flags are kept in b_flags. */ #define B_AGE 0x00000001 /* Move to age queue when I/O done. */ -#define B_APPENDWRITE 0x00000002 /* Append-write in progress. */ +#define B_NEEDCOMMIT 0x00000002 /* Append-write in progress. */ #define B_ASYNC 0x00000004 /* Start I/O, do not wait. */ #define B_BAD 0x00000008 /* Bad block revectoring in progress. */ #define B_BUSY 0x00000010 /* I/O in progress. */ @@ -133,7 +134,7 @@ struct cluster_save { * Zero out the buffer's data area. */ #define clrbuf(bp) { \ - blkclr((bp)->b_data, (u_int)(bp)->b_bcount); \ + bzero((bp)->b_data, (u_int)(bp)->b_bcount); \ (bp)->b_resid = 0; \ } @@ -153,15 +154,15 @@ struct buf *bclnlist; /* Head of cleaned page list. */ __BEGIN_DECLS int allocbuf __P((struct buf *, int)); -int bawrite __P((struct buf *)); -int bdwrite __P((struct buf *)); +void bawrite __P((struct buf *)); +void bdwrite __P((struct buf *)); void biodone __P((struct buf *)); int biowait __P((struct buf *)); int bread __P((struct vnode *, daddr_t, int, struct ucred *, struct buf **)); int breadn __P((struct vnode *, daddr_t, int, daddr_t *, int *, int, struct ucred *, struct buf **)); -int brelse __P((struct buf *)); +void brelse __P((struct buf *)); void bufinit __P((void)); int bwrite __P((struct buf *)); void cluster_callback __P((struct buf *)); diff --git a/sys/sys/cdefs.h b/sys/sys/cdefs.h index c104b9e..e586cbf 100644 --- a/sys/sys/cdefs.h +++ b/sys/sys/cdefs.h @@ -33,7 +33,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)cdefs.h 8.7 (Berkeley) 1/21/94 + * @(#)cdefs.h 8.8 (Berkeley) 1/9/95 */ #ifndef _CDEFS_H_ @@ -105,7 +105,8 @@ * these work for GNU C++ (modulo a slight glitch in the C++ grammar * in the distribution version of 2.5.5). */ -#if !defined(__GNUC__) || __GNUC__ < 2 || __GNUC_MINOR__ < 5 +#if !defined(__GNUC__) || __GNUC__ < 2 || \ + (__GNUC__ == 2 && __GNUC_MINOR__ < 5) #define __attribute__(x) /* delete __attribute__ if non-gcc or gcc1 */ #if defined(__GNUC__) && !defined(__STRICT_ANSI__) #define __dead __volatile diff --git a/sys/sys/conf.h b/sys/sys/conf.h index 58cb6fa..317f40a 100644 --- a/sys/sys/conf.h +++ b/sys/sys/conf.h @@ -35,7 +35,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)conf.h 8.3 (Berkeley) 1/21/94 + * @(#)conf.h 8.5 (Berkeley) 1/9/95 */ /* @@ -48,23 +48,36 @@ struct tty; struct uio; struct vnode; +/* + * Types for d_type. + */ +#define D_TAPE 1 +#define D_DISK 2 +#define D_TTY 3 + +/* + * Block device switch table + */ struct bdevsw { int (*d_open) __P((dev_t dev, int oflags, int devtype, struct proc *p)); int (*d_close) __P((dev_t dev, int fflag, int devtype, struct proc *p)); - int (*d_strategy) __P((struct buf *bp)); - int (*d_ioctl) __P((dev_t dev, int cmd, caddr_t data, + void (*d_strategy) __P((struct buf *bp)); + int (*d_ioctl) __P((dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p)); int (*d_dump) (); /* parameters vary by architecture */ int (*d_psize) __P((dev_t dev)); - int d_flags; + int d_type; }; #ifdef KERNEL extern struct bdevsw bdevsw[]; #endif +/* + * Character device switch table + */ struct cdevsw { int (*d_open) __P((dev_t dev, int oflags, int devtype, struct proc *p)); @@ -72,14 +85,15 @@ struct cdevsw { struct proc *)); int (*d_read) __P((dev_t dev, struct uio *uio, int ioflag)); int (*d_write) __P((dev_t dev, struct uio *uio, int ioflag)); - int (*d_ioctl) __P((dev_t dev, int cmd, caddr_t data, + int (*d_ioctl) __P((dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p)); int (*d_stop) __P((struct tty *tp, int rw)); int (*d_reset) __P((int uban)); /* XXX */ struct tty *d_ttys; int (*d_select) __P((dev_t dev, int which, struct proc *p)); int (*d_mmap) __P(()); - int (*d_strategy) __P((struct buf *bp)); + void (*d_strategy) __P((struct buf *bp)); + int d_type; }; #ifdef KERNEL @@ -90,6 +104,9 @@ extern char devopn[], devio[], devwait[], devin[], devout[]; extern char devioc[], devcls[]; #endif +/* + * Line discipline switch table + */ struct linesw { int (*l_open) __P((dev_t dev, struct tty *tp)); int (*l_close) __P((struct tty *tp, int flag)); @@ -97,7 +114,7 @@ struct linesw { int flag)); int (*l_write) __P((struct tty *tp, struct uio *uio, int flag)); - int (*l_ioctl) __P((struct tty *tp, int cmd, caddr_t data, + int (*l_ioctl) __P((struct tty *tp, u_long cmd, caddr_t data, int flag, struct proc *p)); int (*l_rint) __P((int c, struct tty *tp)); int (*l_start) __P((struct tty *tp)); @@ -108,6 +125,9 @@ struct linesw { extern struct linesw linesw[]; #endif +/* + * Swap device table + */ struct swdevt { dev_t sw_dev; int sw_flags; @@ -116,7 +136,7 @@ struct swdevt { }; #define SW_FREED 0x01 #define SW_SEQUENTIAL 0x02 -#define sw_freed sw_flags /* XXX compat */ +#define sw_freed sw_flags /* XXX compat */ #ifdef KERNEL extern struct swdevt swdevt[]; diff --git a/sys/sys/dirent.h b/sys/sys/dirent.h index 1c4b96aa..d407ad2 100644 --- a/sys/sys/dirent.h +++ b/sys/sys/dirent.h @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)dirent.h 8.1 (Berkeley) 6/2/93 + * @(#)dirent.h 8.3 (Berkeley) 8/10/94 */ /* @@ -45,10 +45,10 @@ */ struct dirent { - unsigned long d_fileno; /* file number of entry */ - unsigned short d_reclen; /* length of this record */ - unsigned char d_type; /* file type, see below */ - unsigned char d_namlen; /* length of string in d_name */ + u_int32_t d_fileno; /* file number of entry */ + u_int16_t d_reclen; /* length of this record */ + u_int8_t d_type; /* file type, see below */ + u_int8_t d_namlen; /* length of string in d_name */ #ifdef _POSIX_SOURCE char d_name[255 + 1]; /* name must be no longer than this */ #else @@ -68,6 +68,7 @@ struct dirent { #define DT_REG 8 #define DT_LNK 10 #define DT_SOCK 12 +#define DT_WHT 14 /* * Convert between stat structure types and directory types. diff --git a/sys/sys/disk.h b/sys/sys/disk.h index 352ecf0..74e191e 100644 --- a/sys/sys/disk.h +++ b/sys/sys/disk.h @@ -39,7 +39,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)disk.h 8.1 (Berkeley) 6/2/93 + * @(#)disk.h 8.2 (Berkeley) 1/9/95 * * from: $Header: disk.h,v 1.5 92/11/19 04:33:03 torek Exp $ (LBL) */ @@ -72,7 +72,7 @@ struct dkdriver { #ifdef notyet int (*d_open) __P((dev_t dev, int ifmt, int, struct proc *)); int (*d_close) __P((dev_t dev, int, int ifmt, struct proc *)); - int (*d_ioctl) __P((dev_t dev, int cmd, caddr_t data, int fflag, + int (*d_ioctl) __P((dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *)); int (*d_dump) __P((dev_t)); void (*d_start) __P((struct buf *, daddr_t)); diff --git a/sys/sys/disklabel.h b/sys/sys/disklabel.h index a25ee29..50a06dc 100644 --- a/sys/sys/disklabel.h +++ b/sys/sys/disklabel.h @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)disklabel.h 8.1 (Berkeley) 6/2/93 + * @(#)disklabel.h 8.2 (Berkeley) 7/10/94 */ /* @@ -60,7 +60,7 @@ #define LABELOFFSET 64 /* offset of label in sector */ #endif -#define DISKMAGIC ((u_long) 0x82564557) /* The disk magic number */ +#define DISKMAGIC ((u_int32_t)0x82564557) /* The disk magic number */ #ifndef MAXPARTITIONS #define MAXPARTITIONS 8 #endif @@ -68,10 +68,11 @@ #ifndef LOCORE struct disklabel { - u_long d_magic; /* the magic number */ - short d_type; /* drive type */ - short d_subtype; /* controller/d_type specific */ - char d_typename[16]; /* type name, e.g. "eagle" */ + u_int32_t d_magic; /* the magic number */ + u_int16_t d_type; /* drive type */ + u_int16_t d_subtype; /* controller/d_type specific */ + char d_typename[16]; /* type name, e.g. "eagle" */ + /* * d_packname contains the pack identifier and is returned when * the disklabel is read off the disk or in-core copy. @@ -81,7 +82,7 @@ struct disklabel { * getdiskbyname(3) to retrieve the values from /etc/disktab. */ #if defined(KERNEL) || defined(STANDALONE) - char d_packname[16]; /* pack identifier */ + char d_packname[16]; /* pack identifier */ #else union { char un_d_packname[16]; /* pack identifier */ @@ -94,71 +95,73 @@ struct disklabel { #define d_boot0 d_un.un_b.un_d_boot0 #define d_boot1 d_un.un_b.un_d_boot1 #endif /* ! KERNEL or STANDALONE */ + /* disk geometry: */ - u_long d_secsize; /* # of bytes per sector */ - u_long d_nsectors; /* # of data sectors per track */ - u_long d_ntracks; /* # of tracks per cylinder */ - u_long d_ncylinders; /* # of data cylinders per unit */ - u_long d_secpercyl; /* # of data sectors per cylinder */ - u_long d_secperunit; /* # of data sectors per unit */ + u_int32_t d_secsize; /* # of bytes per sector */ + u_int32_t d_nsectors; /* # of data sectors per track */ + u_int32_t d_ntracks; /* # of tracks per cylinder */ + u_int32_t d_ncylinders; /* # of data cylinders per unit */ + u_int32_t d_secpercyl; /* # of data sectors per cylinder */ + u_int32_t d_secperunit; /* # of data sectors per unit */ + /* - * Spares (bad sector replacements) below - * are not counted in d_nsectors or d_secpercyl. - * Spare sectors are assumed to be physical sectors - * which occupy space at the end of each track and/or cylinder. + * Spares (bad sector replacements) below are not counted in + * d_nsectors or d_secpercyl. Spare sectors are assumed to + * be physical sectors which occupy space at the end of each + * track and/or cylinder. */ - u_short d_sparespertrack; /* # of spare sectors per track */ - u_short d_sparespercyl; /* # of spare sectors per cylinder */ + u_int16_t d_sparespertrack; /* # of spare sectors per track */ + u_int16_t d_sparespercyl; /* # of spare sectors per cylinder */ /* - * Alternate cylinders include maintenance, replacement, - * configuration description areas, etc. + * Alternate cylinders include maintenance, replacement, configuration + * description areas, etc. */ - u_long d_acylinders; /* # of alt. cylinders per unit */ + u_int32_t d_acylinders; /* # of alt. cylinders per unit */ /* hardware characteristics: */ /* * d_interleave, d_trackskew and d_cylskew describe perturbations * in the media format used to compensate for a slow controller. - * Interleave is physical sector interleave, set up by the formatter - * or controller when formatting. When interleaving is in use, - * logically adjacent sectors are not physically contiguous, - * but instead are separated by some number of sectors. - * It is specified as the ratio of physical sectors traversed - * per logical sector. Thus an interleave of 1:1 implies contiguous - * layout, while 2:1 implies that logical sector 0 is separated - * by one sector from logical sector 1. - * d_trackskew is the offset of sector 0 on track N - * relative to sector 0 on track N-1 on the same cylinder. - * Finally, d_cylskew is the offset of sector 0 on cylinder N - * relative to sector 0 on cylinder N-1. + * Interleave is physical sector interleave, set up by the + * formatter or controller when formatting. When interleaving is + * in use, logically adjacent sectors are not physically + * contiguous, but instead are separated by some number of + * sectors. It is specified as the ratio of physical sectors + * traversed per logical sector. Thus an interleave of 1:1 + * implies contiguous layout, while 2:1 implies that logical + * sector 0 is separated by one sector from logical sector 1. + * d_trackskew is the offset of sector 0 on track N relative to + * sector 0 on track N-1 on the same cylinder. Finally, d_cylskew + * is the offset of sector 0 on cylinder N relative to sector 0 + * on cylinder N-1. */ - u_short d_rpm; /* rotational speed */ - u_short d_interleave; /* hardware sector interleave */ - u_short d_trackskew; /* sector 0 skew, per track */ - u_short d_cylskew; /* sector 0 skew, per cylinder */ - u_long d_headswitch; /* head switch time, usec */ - u_long d_trkseek; /* track-to-track seek, usec */ - u_long d_flags; /* generic flags */ + u_int16_t d_rpm; /* rotational speed */ + u_int16_t d_interleave; /* hardware sector interleave */ + u_int16_t d_trackskew; /* sector 0 skew, per track */ + u_int16_t d_cylskew; /* sector 0 skew, per cylinder */ + u_int32_t d_headswitch; /* head switch time, usec */ + u_int32_t d_trkseek; /* track-to-track seek, usec */ + u_int32_t d_flags; /* generic flags */ #define NDDATA 5 - u_long d_drivedata[NDDATA]; /* drive-type specific information */ + u_int32_t d_drivedata[NDDATA]; /* drive-type specific information */ #define NSPARE 5 - u_long d_spare[NSPARE]; /* reserved for future use */ - u_long d_magic2; /* the magic number (again) */ - u_short d_checksum; /* xor of data incl. partitions */ + u_int32_t d_spare[NSPARE]; /* reserved for future use */ + u_int32_t d_magic2; /* the magic number (again) */ + u_int16_t d_checksum; /* xor of data incl. partitions */ /* filesystem and partition information: */ - u_short d_npartitions; /* number of partitions in following */ - u_long d_bbsize; /* size of boot area at sn0, bytes */ - u_long d_sbsize; /* max size of fs superblock, bytes */ + u_int16_t d_npartitions; /* number of partitions in following */ + u_int32_t d_bbsize; /* size of boot area at sn0, bytes */ + u_int32_t d_sbsize; /* max size of fs superblock, bytes */ struct partition { /* the partition table */ - u_long p_size; /* number of sectors in partition */ - u_long p_offset; /* starting sector */ - u_long p_fsize; /* filesystem basic fragment size */ - u_char p_fstype; /* filesystem type, see below */ - u_char p_frag; /* filesystem fragments per block */ + u_int32_t p_size; /* number of sectors in partition */ + u_int32_t p_offset; /* starting sector */ + u_int32_t p_fsize; /* filesystem basic fragment size */ + u_int8_t p_fstype; /* filesystem type, see below */ + u_int8_t p_frag; /* filesystem fragments per block */ union { - u_short cpg; /* UFS: FS cylinders per group */ - u_short sgs; /* LFS: FS segment shift */ + u_int16_t cpg; /* UFS: FS cylinders per group */ + u_int16_t sgs; /* LFS: FS segment shift */ } __partition_u1; #define p_cpg __partition_u1.cpg #define p_sgs __partition_u1.sgs @@ -201,7 +204,7 @@ static char *dktypenames[] = { "HP-FL", "type 9", "floppy", - 0 + NULL }; #define DKMAXTYPES (sizeof(dktypenames) / sizeof(dktypenames[0]) - 1) #endif @@ -242,7 +245,7 @@ static char *fstypenames[] = { "HPFS", "ISO9660", "boot", - 0 + NULL }; #define FSMAXTYPES (sizeof(fstypenames) / sizeof(fstypenames[0]) - 1) #endif @@ -278,22 +281,20 @@ static char *fstypenames[] = { #ifndef LOCORE /* - * Structure used to perform a format - * or other raw operation, returning data - * and/or register values. - * Register identification and format + * Structure used to perform a format or other raw operation, returning + * data and/or register values. Register identification and format * are device- and driver-dependent. */ struct format_op { char *df_buf; - int df_count; /* value-result */ - daddr_t df_startblk; - int df_reg[8]; /* result */ + int df_count; /* value-result */ + daddr_t df_startblk; + int df_reg[8]; /* result */ }; /* - * Structure used internally to retrieve - * information about a partition on a disk. + * Structure used internally to retrieve information about a partition + * on a disk. */ struct partinfo { struct disklabel *disklab; diff --git a/sys/sys/dkbad.h b/sys/sys/dkbad.h index c574000..476b7bd 100644 --- a/sys/sys/dkbad.h +++ b/sys/sys/dkbad.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1982, 1986, 1993 + * Copyright (c) 1982, 1986, 1993, 1994 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)dkbad.h 8.1 (Berkeley) 6/2/93 + * @(#)dkbad.h 8.2 (Berkeley) 7/10/94 */ /* @@ -53,12 +53,12 @@ * replacement sectors. */ struct dkbad { - long bt_csn; /* cartridge serial number */ - u_short bt_mbz; /* unused; should be 0 */ - u_short bt_flag; /* -1 => alignment cartridge */ + int32_t bt_csn; /* cartridge serial number */ + u_int16_t bt_mbz; /* unused; should be 0 */ + u_int16_t bt_flag; /* -1 => alignment cartridge */ struct bt_bad { - u_short bt_cyl; /* cylinder number of bad sector */ - u_short bt_trksec; /* track and sector number */ + u_int16_t bt_cyl; /* cylinder number of bad sector */ + u_int16_t bt_trksec; /* track and sector number */ } bt_bad[126]; }; diff --git a/sys/sys/exec.h b/sys/sys/exec.h index 443e144..781b21a 100644 --- a/sys/sys/exec.h +++ b/sys/sys/exec.h @@ -35,7 +35,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)exec.h 8.3 (Berkeley) 1/21/94 + * @(#)exec.h 8.4 (Berkeley) 2/19/95 */ #include @@ -60,12 +60,3 @@ struct ps_strings { */ #define PS_STRINGS \ ((struct ps_strings *)(USRSTACK - sizeof(struct ps_strings))) - -/* - * Arguments to the exec system call. - */ -struct execve_args { - char *fname; - char **argp; - char **envp; -}; diff --git a/sys/sys/file.h b/sys/sys/file.h index 3d82190..f3d59a1 100644 --- a/sys/sys/file.h +++ b/sys/sys/file.h @@ -30,13 +30,15 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)file.h 8.1 (Berkeley) 6/2/93 + * @(#)file.h 8.3 (Berkeley) 1/9/95 */ #include #include #ifdef KERNEL +#include + struct proc; struct uio; @@ -45,8 +47,7 @@ struct uio; * One entry for each open kernel vnode and socket. */ struct file { - struct file *f_filef; /* list of active files */ - struct file **f_fileb; /* list of active files */ + LIST_ENTRY(file) f_list;/* list of active files */ short f_flag; /* see fcntl.h */ #define DTYPE_VNODE 1 /* file */ #define DTYPE_SOCKET 2 /* communications endpoint */ @@ -59,7 +60,7 @@ struct file { struct ucred *cred)); int (*fo_write) __P((struct file *fp, struct uio *uio, struct ucred *cred)); - int (*fo_ioctl) __P((struct file *fp, int com, + int (*fo_ioctl) __P((struct file *fp, u_long com, caddr_t data, struct proc *p)); int (*fo_select) __P((struct file *fp, int which, struct proc *p)); @@ -69,8 +70,9 @@ struct file { caddr_t f_data; /* vnode or socket */ }; -extern struct file *filehead; /* head of list of open files */ -extern int maxfiles; /* kernel limit on number of open files */ -extern int nfiles; /* actual number of open files */ +LIST_HEAD(filelist, file); +extern struct filelist filehead; /* head of list of open files */ +extern int maxfiles; /* kernel limit on number of open files */ +extern int nfiles; /* actual number of open files */ #endif /* KERNEL */ diff --git a/sys/sys/ioccom.h b/sys/sys/ioccom.h index 5bc11b3..da117df 100644 --- a/sys/sys/ioccom.h +++ b/sys/sys/ioccom.h @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)ioccom.h 8.2 (Berkeley) 3/28/94 + * @(#)ioccom.h 8.3 (Berkeley) 1/9/95 */ #ifndef _SYS_IOCCOM_H_ @@ -46,12 +46,17 @@ #define IOCBASECMD(x) ((x) & ~(IOCPARM_MASK << 16)) #define IOCGROUP(x) (((x) >> 8) & 0xff) -#define IOCPARM_MAX NBPG /* max size of ioctl, mult. of NBPG */ -#define IOC_VOID 0x20000000 /* no parameters */ -#define IOC_OUT 0x40000000 /* copy out parameters */ -#define IOC_IN 0x80000000 /* copy in parameters */ +#define IOCPARM_MAX NBPG /* max size of ioctl args, mult. of NBPG */ + /* no parameters */ +#define IOC_VOID (unsigned long)0x20000000 + /* copy parameters out */ +#define IOC_OUT (unsigned long)0x40000000 + /* copy parameters in */ +#define IOC_IN (unsigned long)0x80000000 + /* copy paramters in and out */ #define IOC_INOUT (IOC_IN|IOC_OUT) -#define IOC_DIRMASK 0xe0000000 /* mask for IN/OUT/VOID */ + /* mask for IN/OUT/VOID */ +#define IOC_DIRMASK (unsigned long)0xe0000000 #define _IOC(inout,group,num,len) \ (inout | ((len & IOCPARM_MASK) << 16) | ((group) << 8) | (num)) diff --git a/sys/sys/ipc.h b/sys/sys/ipc.h index cc036a8..908ed52 100644 --- a/sys/sys/ipc.h +++ b/sys/sys/ipc.h @@ -40,7 +40,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)ipc.h 8.3 (Berkeley) 1/21/94 + * @(#)ipc.h 8.4 (Berkeley) 2/19/95 */ /* @@ -49,8 +49,6 @@ #ifndef _SYS_IPC_H_ #define _SYS_IPC_H_ -typedef long key_t; /* XXX should be in types.h */ - struct ipc_perm { ushort cuid; /* creator user id */ ushort cgid; /* creator group id */ diff --git a/sys/sys/ktrace.h b/sys/sys/ktrace.h index 1623c35..5a44885 100644 --- a/sys/sys/ktrace.h +++ b/sys/sys/ktrace.h @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)ktrace.h 8.1 (Berkeley) 6/2/93 + * @(#)ktrace.h 8.2 (Berkeley) 2/19/95 */ /* @@ -72,10 +72,10 @@ struct ktr_header { */ #define KTR_SYSCALL 1 struct ktr_syscall { - short ktr_code; /* syscall number */ - short ktr_narg; /* number of arguments */ + int ktr_code; /* syscall number */ + int ktr_argsize; /* size of arguments */ /* - * followed by ktr_narg ints + * followed by ktr_argsize/sizeof(register_t) 'register_t's */ }; diff --git a/sys/sys/malloc.h b/sys/sys/malloc.h index ba67bda..c72edb2 100644 --- a/sys/sys/malloc.h +++ b/sys/sys/malloc.h @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)malloc.h 8.3 (Berkeley) 1/12/94 + * @(#)malloc.h 8.5 (Berkeley) 5/3/95 */ #ifndef _SYS_MALLOC_H_ @@ -106,6 +106,9 @@ #define M_MRTABLE 56 /* multicast routing tables */ #define M_ISOFSMNT 57 /* ISOFS mount structure */ #define M_ISOFSNODE 58 /* ISOFS vnode private part */ +#define M_NFSRVDESC 59 /* NFS server socket descriptor */ +#define M_NFSDIROFF 60 /* NFS directory offset data */ +#define M_NFSBIGFH 61 /* NFS version 3 file handle */ #define M_TEMP 74 /* misc temporary data buffers */ #define M_LAST 75 /* Must be last type + 1 */ @@ -169,7 +172,10 @@ "mrt", /* 56 M_MRTABLE */ \ "ISOFS mount", /* 57 M_ISOFSMNT */ \ "ISOFS node", /* 58 M_ISOFSNODE */ \ - NULL, NULL, NULL, NULL, NULL, \ + "NFSV3 srvdesc",/* 59 M_NFSRVDESC */ \ + "NFSV3 diroff", /* 60 M_NFSDIROFF */ \ + "NFSV3 bigfh", /* 61 M_NFSBIGFH */ \ + NULL, NULL, \ NULL, NULL, NULL, NULL, NULL, \ NULL, NULL, NULL, NULL, NULL, \ "temp", /* 74 M_TEMP */ \ @@ -217,7 +223,7 @@ struct kmembuckets { #ifdef KERNEL #define MINALLOCSIZE (1 << MINBUCKET) #define BUCKETINDX(size) \ - (size) <= (MINALLOCSIZE * 128) \ + ((size) <= (MINALLOCSIZE * 128) \ ? (size) <= (MINALLOCSIZE * 8) \ ? (size) <= (MINALLOCSIZE * 2) \ ? (size) <= (MINALLOCSIZE * 1) \ @@ -247,7 +253,7 @@ struct kmembuckets { : (MINBUCKET + 13) \ : (size) <= (MINALLOCSIZE * 16384) \ ? (MINBUCKET + 14) \ - : (MINBUCKET + 15) + : (MINBUCKET + 15)) /* * Turn virtual addresses into kmem map indicies diff --git a/sys/sys/mbuf.h b/sys/sys/mbuf.h index f3ea7ed..2f32d88 100644 --- a/sys/sys/mbuf.h +++ b/sys/sys/mbuf.h @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)mbuf.h 8.3 (Berkeley) 1/21/94 + * @(#)mbuf.h 8.5 (Berkeley) 2/19/95 */ #ifndef M_WAITOK @@ -58,25 +58,25 @@ * mtocl(x) - convert pointer within cluster to cluster index # * cltom(x) - convert cluster # to ptr to beginning of cluster */ -#define mtod(m,t) ((t)((m)->m_data)) -#define dtom(x) ((struct mbuf *)((int)(x) & ~(MSIZE-1))) -#define mtocl(x) (((u_int)(x) - (u_int)mbutl) >> MCLSHIFT) -#define cltom(x) ((caddr_t)((u_int)mbutl + ((u_int)(x) << MCLSHIFT))) +#define mtod(m,t) ((t)((m)->m_data)) +#define dtom(x) ((struct mbuf *)((long)(x) & ~(MSIZE-1))) +#define mtocl(x) (((u_long)(x) - (u_long)mbutl) >> MCLSHIFT) +#define cltom(x) ((caddr_t)((u_long)mbutl + ((u_long)(x) << MCLSHIFT))) /* header at beginning of each mbuf: */ struct m_hdr { struct mbuf *mh_next; /* next buffer in chain */ struct mbuf *mh_nextpkt; /* next chain in queue/record */ - int mh_len; /* amount of data in this mbuf */ caddr_t mh_data; /* location of data */ + int mh_len; /* amount of data in this mbuf */ short mh_type; /* type of data in this mbuf */ short mh_flags; /* flags; see below */ }; /* record/packet header in first mbuf of chain; valid if M_PKTHDR set */ struct pkthdr { - int len; /* total packet length */ - struct ifnet *rcvif; /* rcv interface */ + struct ifnet *rcvif; /* rcv interface */ + int len; /* total packet length */ }; /* description of external storage mapped into mbuf, valid if M_EXT set */ @@ -214,7 +214,7 @@ union mcluster { MBUFLOCK( \ if (mclfree == 0) \ (void)m_clalloc(1, (how)); \ - if ((p) = (caddr_t)mclfree) { \ + if (((p) = (caddr_t)mclfree) != 0) { \ ++mclrefcnt[mtocl(p)]; \ mbstat.m_clfree--; \ mclfree = ((union mcluster *)(p))->mcl_next; \ @@ -372,9 +372,11 @@ struct mbuf *m_prepend __P((struct mbuf *, int, int)); struct mbuf *m_pullup __P((struct mbuf *, int)); struct mbuf *m_retry __P((int, int)); struct mbuf *m_retryhdr __P((int, int)); +void m_adj __P((struct mbuf *, int)); int m_clalloc __P((int, int)); void m_copyback __P((struct mbuf *, int, int, caddr_t)); void m_freem __P((struct mbuf *)); +void m_reclaim __P((void)); #ifdef MBTYPES int mbtypes[] = { /* XXX */ diff --git a/sys/sys/mman.h b/sys/sys/mman.h index b3951c2..33ed934 100644 --- a/sys/sys/mman.h +++ b/sys/sys/mman.h @@ -30,12 +30,13 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)mman.h 8.1 (Berkeley) 6/2/93 + * @(#)mman.h 8.2 (Berkeley) 1/9/95 */ /* * Protections are chosen from these bits, or-ed together */ +#define PROT_NONE 0x00 /* no permissions */ #define PROT_READ 0x01 /* pages can be read */ #define PROT_WRITE 0x02 /* pages can be written */ #define PROT_EXEC 0x04 /* pages can be executed */ @@ -59,8 +60,9 @@ #define MAP_HASSEMAPHORE 0x0200 /* region may contain semaphores */ /* - * Mapping type; default is map from file. + * Mapping type */ +#define MAP_FILE 0x0000 /* map from file (default) */ #define MAP_ANON 0x1000 /* allocated from memory, swap space */ /* @@ -84,6 +86,7 @@ int munmap __P((caddr_t, size_t)); int msync __P((caddr_t, size_t)); int mlock __P((caddr_t, size_t)); int munlock __P((caddr_t, size_t)); +int madvise __P((caddr_t, size_t, int)); __END_DECLS #endif /* !KERNEL */ diff --git a/sys/sys/mount.h b/sys/sys/mount.h index 4561675..4805be2 100644 --- a/sys/sys/mount.h +++ b/sys/sys/mount.h @@ -30,15 +30,18 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)mount.h 8.13 (Berkeley) 3/27/94 + * @(#)mount.h 8.21 (Berkeley) 5/20/95 */ #ifndef KERNEL #include #endif #include +#include +#include +#include /* XXX for AF_MAX */ -typedef struct { long val[2]; } fsid_t; /* file system id type */ +typedef struct { int32_t val[2]; } fsid_t; /* file system id type */ /* * File identifier. @@ -56,10 +59,11 @@ struct fid { * file system statistics */ -#define MNAMELEN 90 /* length of buffer for returned name */ +#define MFSNAMELEN 16 /* length of fs type name, including null */ +#define MNAMELEN 90 /* length of buffer for returned name */ struct statfs { - short f_type; /* type of filesystem (see below) */ + short f_type; /* filesystem type number */ short f_flags; /* copy of mount flags */ long f_bsize; /* fundamental file system block size */ long f_iosize; /* optimal transfer block size */ @@ -69,53 +73,14 @@ struct statfs { long f_files; /* total file nodes in file system */ long f_ffree; /* free file nodes in fs */ fsid_t f_fsid; /* file system id */ - long f_spare[9]; /* spare for later */ + uid_t f_owner; /* user that mounted the filesystem */ + long f_spare[4]; /* spare for later */ + char f_fstypename[MFSNAMELEN]; /* fs type name */ char f_mntonname[MNAMELEN]; /* directory on which mounted */ char f_mntfromname[MNAMELEN];/* mounted filesystem */ }; /* - * File system types. - */ -#define MOUNT_NONE 0 -#define MOUNT_UFS 1 /* Fast Filesystem */ -#define MOUNT_NFS 2 /* Sun-compatible Network Filesystem */ -#define MOUNT_MFS 3 /* Memory-based Filesystem */ -#define MOUNT_MSDOS 4 /* MS/DOS Filesystem */ -#define MOUNT_LFS 5 /* Log-based Filesystem */ -#define MOUNT_LOFS 6 /* Loopback Filesystem */ -#define MOUNT_FDESC 7 /* File Descriptor Filesystem */ -#define MOUNT_PORTAL 8 /* Portal Filesystem */ -#define MOUNT_NULL 9 /* Minimal Filesystem Layer */ -#define MOUNT_UMAP 10 /* User/Group Identifer Remapping Filesystem */ -#define MOUNT_KERNFS 11 /* Kernel Information Filesystem */ -#define MOUNT_PROCFS 12 /* /proc Filesystem */ -#define MOUNT_AFS 13 /* Andrew Filesystem */ -#define MOUNT_CD9660 14 /* ISO9660 (aka CDROM) Filesystem */ -#define MOUNT_UNION 15 /* Union (translucent) Filesystem */ -#define MOUNT_MAXTYPE 15 - -#define INITMOUNTNAMES { \ - "none", /* 0 MOUNT_NONE */ \ - "ufs", /* 1 MOUNT_UFS */ \ - "nfs", /* 2 MOUNT_NFS */ \ - "mfs", /* 3 MOUNT_MFS */ \ - "msdos", /* 4 MOUNT_MSDOS */ \ - "lfs", /* 5 MOUNT_LFS */ \ - "lofs", /* 6 MOUNT_LOFS */ \ - "fdesc", /* 7 MOUNT_FDESC */ \ - "portal", /* 8 MOUNT_PORTAL */ \ - "null", /* 9 MOUNT_NULL */ \ - "umap", /* 10 MOUNT_UMAP */ \ - "kernfs", /* 11 MOUNT_KERNFS */ \ - "procfs", /* 12 MOUNT_PROCFS */ \ - "afs", /* 13 MOUNT_AFS */ \ - "iso9660fs", /* 14 MOUNT_CD9660 */ \ - "union", /* 15 MOUNT_UNION */ \ - 0, /* 16 MOUNT_SPARE */ \ -} - -/* * Structure per mounted file system. Each mounted file system has an * array of operations and an instance record. The file systems are * put on a doubly linked list. @@ -123,10 +88,12 @@ struct statfs { LIST_HEAD(vnodelst, vnode); struct mount { - TAILQ_ENTRY(mount) mnt_list; /* mount list */ + CIRCLEQ_ENTRY(mount) mnt_list; /* mount list */ struct vfsops *mnt_op; /* operations on fs */ + struct vfsconf *mnt_vfc; /* configuration info */ struct vnode *mnt_vnodecovered; /* vnode we mounted on */ struct vnodelst mnt_vnodelist; /* list of vnodes this mount */ + struct lock mnt_lock; /* mount structure lock */ int mnt_flag; /* flags */ int mnt_maxsymlinklen; /* max size of short symlink */ struct statfs mnt_stat; /* cache of filesystem stats */ @@ -161,7 +128,6 @@ struct mount { #define MNT_LOCAL 0x00001000 /* filesystem is stored locally */ #define MNT_QUOTA 0x00002000 /* quotas are enabled on filesystem */ #define MNT_ROOTFS 0x00004000 /* identifies the root filesystem */ -#define MNT_USER 0x00008000 /* mounted by a user */ /* * Mask of flags that are visible to statfs() @@ -169,27 +135,92 @@ struct mount { #define MNT_VISFLAGMASK 0x0000ffff /* - * filesystem control flags. - * - * MNT_MLOCK lock the mount entry so that name lookup cannot proceed - * past the mount point. This keeps the subtree stable during mounts - * and unmounts. + * External filesystem control flags. */ #define MNT_UPDATE 0x00010000 /* not a real mount, just an update */ #define MNT_DELEXPORT 0x00020000 /* delete export host lists */ #define MNT_RELOAD 0x00040000 /* reload filesystem data */ #define MNT_FORCE 0x00080000 /* force unmount or readonly change */ -#define MNT_MLOCK 0x00100000 /* lock so that subtree is stable */ -#define MNT_MWAIT 0x00200000 /* someone is waiting for lock */ -#define MNT_MPBUSY 0x00400000 /* scan of mount point in progress */ -#define MNT_MPWANT 0x00800000 /* waiting for mount point */ +/* + * Internal filesystem control flags. + * + * MNT_UNMOUNT locks the mount entry so that name lookup cannot proceed + * past the mount point. This keeps the subtree stable during mounts + * and unmounts. + */ #define MNT_UNMOUNT 0x01000000 /* unmount in progress */ -#define MNT_WANTRDWR 0x02000000 /* want upgrade to read/write */ +#define MNT_MWAIT 0x02000000 /* waiting for unmount to finish */ +#define MNT_WANTRDWR 0x04000000 /* upgrade to read/write requested */ /* - * Operations supported on mounted file system. + * Sysctl CTL_VFS definitions. + * + * Second level identifier specifies which filesystem. Second level + * identifier VFS_GENERIC returns information about all filesystems. */ +#define VFS_GENERIC 0 /* generic filesystem information */ +/* + * Third level identifiers for VFS_GENERIC are given below; third + * level identifiers for specific filesystems are given in their + * mount specific header files. + */ +#define VFS_MAXTYPENUM 1 /* int: highest defined filesystem type */ +#define VFS_CONF 2 /* struct: vfsconf for filesystem given + as next argument */ + +/* + * Flags for various system call interfaces. + * + * waitfor flags to vfs_sync() and getfsstat() + */ +#define MNT_WAIT 1 +#define MNT_NOWAIT 2 + +/* + * Generic file handle + */ +struct fhandle { + fsid_t fh_fsid; /* File system id of mount point */ + struct fid fh_fid; /* File sys specific id */ +}; +typedef struct fhandle fhandle_t; + +/* + * Export arguments for local filesystem mount calls. + */ +struct export_args { + int ex_flags; /* export related flags */ + uid_t ex_root; /* mapping for root uid */ + struct ucred ex_anon; /* mapping for anonymous user */ + struct sockaddr *ex_addr; /* net address to which exported */ + int ex_addrlen; /* and the net address length */ + struct sockaddr *ex_mask; /* mask of valid bits in saddr */ + int ex_masklen; /* and the smask length */ +}; + +/* + * Filesystem configuration information. One of these exists for each + * type of filesystem supported by the kernel. These are searched at + * mount time to identify the requested filesystem. + */ +struct vfsconf { + struct vfsops *vfc_vfsops; /* filesystem operations vector */ + char vfc_name[MFSNAMELEN]; /* filesystem type name */ + int vfc_typenum; /* historic filesystem type number */ + int vfc_refcount; /* number mounted of this type */ + int vfc_flags; /* permanent flags */ + int (*vfc_mountroot)(void); /* if != NULL, routine to mount root */ + struct vfsconf *vfc_next; /* next in list */ +}; + #ifdef KERNEL + +extern int maxvfsconf; /* highest defined filesystem type */ +extern struct vfsconf *vfsconf; /* head of list of filesystem types */ + +/* + * Operations supported on mounted file system. + */ #ifdef __STDC__ struct nameidata; struct mbuf; @@ -215,7 +246,9 @@ struct vfsops { struct mbuf *nam, struct vnode **vpp, int *exflagsp, struct ucred **credanonp)); int (*vfs_vptofh) __P((struct vnode *vp, struct fid *fhp)); - int (*vfs_init) __P((void)); + int (*vfs_init) __P((struct vfsconf *)); + int (*vfs_sysctl) __P((int *, u_int, void *, size_t *, void *, + size_t, struct proc *)); }; #define VFS_MOUNT(MP, PATH, DATA, NDP, P) \ @@ -230,28 +263,6 @@ struct vfsops { #define VFS_FHTOVP(MP, FIDP, NAM, VPP, EXFLG, CRED) \ (*(MP)->mnt_op->vfs_fhtovp)(MP, FIDP, NAM, VPP, EXFLG, CRED) #define VFS_VPTOFH(VP, FIDP) (*(VP)->v_mount->mnt_op->vfs_vptofh)(VP, FIDP) -#endif /* KERNEL */ - -/* - * Flags for various system call interfaces. - * - * waitfor flags to vfs_sync() and getfsstat() - */ -#define MNT_WAIT 1 -#define MNT_NOWAIT 2 - -/* - * Generic file handle - */ -struct fhandle { - fsid_t fh_fsid; /* File system id of mount point */ - struct fid fh_fid; /* File sys specific id */ -}; -typedef struct fhandle fhandle_t; - -#ifdef KERNEL -#include -#include /* XXX for AF_MAX */ /* * Network address lookup element @@ -269,139 +280,26 @@ struct netexport { struct netcred ne_defexported; /* Default export */ struct radix_node_head *ne_rtable[AF_MAX+1]; /* Individual exports */ }; -#endif /* KERNEL */ - -/* - * Export arguments for local filesystem mount calls. - */ -struct export_args { - int ex_flags; /* export related flags */ - uid_t ex_root; /* mapping for root uid */ - struct ucred ex_anon; /* mapping for anonymous user */ - struct sockaddr *ex_addr; /* net address to which exported */ - int ex_addrlen; /* and the net address length */ - struct sockaddr *ex_mask; /* mask of valid bits in saddr */ - int ex_masklen; /* and the smask length */ -}; - -/* - * Arguments to mount UFS-based filesystems - */ -struct ufs_args { - char *fspec; /* block special device to mount */ - struct export_args export; /* network export information */ -}; - -#ifdef MFS -/* - * Arguments to mount MFS - */ -struct mfs_args { - char *fspec; /* name to export for statfs */ - struct export_args export; /* if exported MFSes are supported */ - caddr_t base; /* base of file system in memory */ - u_long size; /* size of file system */ -}; -#endif /* MFS */ - -#ifdef CD9660 -/* - * Arguments to mount ISO 9660 filesystems. - */ -struct iso_args { - char *fspec; /* block special device to mount */ - struct export_args export; /* network export info */ - int flags; /* mounting flags, see below */ - -}; -#define ISOFSMNT_NORRIP 0x00000001 /* disable Rock Ridge Ext.*/ -#define ISOFSMNT_GENS 0x00000002 /* enable generation numbers */ -#define ISOFSMNT_EXTATT 0x00000004 /* enable extended attributes */ -#endif /* CD9660 */ - -#ifdef NFS -/* - * File Handle (32 bytes for version 2), variable up to 1024 for version 3 - */ -union nfsv2fh { - fhandle_t fh_generic; - u_char fh_bytes[32]; -}; -typedef union nfsv2fh nfsv2fh_t; /* - * Arguments to mount NFS - */ -struct nfs_args { - struct sockaddr *addr; /* file server address */ - int addrlen; /* length of address */ - int sotype; /* Socket type */ - int proto; /* and Protocol */ - nfsv2fh_t *fh; /* File handle to be mounted */ - int flags; /* flags */ - int wsize; /* write size in bytes */ - int rsize; /* read size in bytes */ - int timeo; /* initial timeout in .1 secs */ - int retrans; /* times to retry send */ - int maxgrouplist; /* Max. size of group list */ - int readahead; /* # of blocks to readahead */ - int leaseterm; /* Term (sec) of lease */ - int deadthresh; /* Retrans threshold */ - char *hostname; /* server's name */ -}; - - -/* - * NFS mount option flags - */ -#define NFSMNT_SOFT 0x00000001 /* soft mount (hard is default) */ -#define NFSMNT_WSIZE 0x00000002 /* set write size */ -#define NFSMNT_RSIZE 0x00000004 /* set read size */ -#define NFSMNT_TIMEO 0x00000008 /* set initial timeout */ -#define NFSMNT_RETRANS 0x00000010 /* set number of request retrys */ -#define NFSMNT_MAXGRPS 0x00000020 /* set maximum grouplist size */ -#define NFSMNT_INT 0x00000040 /* allow interrupts on hard mount */ -#define NFSMNT_NOCONN 0x00000080 /* Don't Connect the socket */ -#define NFSMNT_NQNFS 0x00000100 /* Use Nqnfs protocol */ -#define NFSMNT_MYWRITE 0x00000200 /* Assume writes were mine */ -#define NFSMNT_KERB 0x00000400 /* Use Kerberos authentication */ -#define NFSMNT_DUMBTIMR 0x00000800 /* Don't estimate rtt dynamically */ -#define NFSMNT_RDIRALOOK 0x00001000 /* Do lookup with readdir (nqnfs) */ -#define NFSMNT_LEASETERM 0x00002000 /* set lease term (nqnfs) */ -#define NFSMNT_READAHEAD 0x00004000 /* set read ahead */ -#define NFSMNT_DEADTHRESH 0x00008000 /* set dead server retry thresh */ -#define NFSMNT_NQLOOKLEASE 0x00010000 /* Get lease for lookup */ -#define NFSMNT_RESVPORT 0x00020000 /* Allocate a reserved port */ -#define NFSMNT_INTERNAL 0xffe00000 /* Bits set internally */ -#define NFSMNT_MNTD 0x00200000 /* Mnt server for mnt point */ -#define NFSMNT_DISMINPROG 0x00400000 /* Dismount in progress */ -#define NFSMNT_DISMNT 0x00800000 /* Dismounted */ -#define NFSMNT_SNDLOCK 0x01000000 /* Send socket lock */ -#define NFSMNT_WANTSND 0x02000000 /* Want above */ -#define NFSMNT_RCVLOCK 0x04000000 /* Rcv socket lock */ -#define NFSMNT_WANTRCV 0x08000000 /* Want above */ -#define NFSMNT_WAITAUTH 0x10000000 /* Wait for authentication */ -#define NFSMNT_HASAUTH 0x20000000 /* Has authenticator */ -#define NFSMNT_WANTAUTH 0x40000000 /* Wants an authenticator */ -#define NFSMNT_AUTHERR 0x80000000 /* Authentication error */ -#endif /* NFS */ - -#ifdef KERNEL -/* * exported vnode operations */ -struct mount *getvfs __P((fsid_t *)); /* return vfs given fsid */ -int vfs_export /* process mount export info */ - __P((struct mount *, struct netexport *, struct export_args *)); -struct netcred *vfs_export_lookup /* lookup host in fs export list */ - __P((struct mount *, struct netexport *, struct mbuf *)); -int vfs_lock __P((struct mount *)); /* lock a vfs */ -int vfs_mountedon __P((struct vnode *));/* is a vfs mounted on vp */ -void vfs_unlock __P((struct mount *)); /* unlock a vfs */ -extern TAILQ_HEAD(mntlist, mount) mountlist; /* mounted filesystem list */ -extern struct vfsops *vfssw[]; /* filesystem type table */ - -#else /* KERNEL */ +int vfs_busy __P((struct mount *, int, struct simplelock *, struct proc *)); +int vfs_export __P((struct mount *, struct netexport *, + struct export_args *)); +struct netcred *vfs_export_lookup __P((struct mount *, struct netexport *, + struct mbuf *)); +void vfs_getnewfsid __P((struct mount *)); +struct mount *vfs_getvfs __P((fsid_t *)); +int vfs_mountedon __P((struct vnode *)); +int vfs_mountroot __P((void)); +int vfs_rootmountalloc __P((char *, char *, struct mount **)); +void vfs_unbusy __P((struct mount *, struct proc *)); +void vfs_unmountall __P((void)); +extern CIRCLEQ_HEAD(mntlist, mount) mountlist; +extern struct simplelock mountlist_slock; + +#else /* !KERNEL */ #include @@ -410,7 +308,7 @@ int fstatfs __P((int, struct statfs *)); int getfh __P((const char *, fhandle_t *)); int getfsstat __P((struct statfs *, long, int)); int getmntinfo __P((struct statfs **, int)); -int mount __P((int, const char *, int, void *)); +int mount __P((const char *, const char *, int, void *)); int statfs __P((const char *, struct statfs *)); int unmount __P((const char *, int)); __END_DECLS diff --git a/sys/sys/namei.h b/sys/sys/namei.h index 74ff360..77d35b2 100644 --- a/sys/sys/namei.h +++ b/sys/sys/namei.h @@ -30,12 +30,14 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)namei.h 8.2 (Berkeley) 1/4/94 + * @(#)namei.h 8.5 (Berkeley) 1/9/95 */ #ifndef _SYS_NAMEI_H_ #define _SYS_NAMEI_H_ +#include + /* * Encapsulation of namei parameters. */ @@ -131,6 +133,8 @@ struct nameidata { #define MAKEENTRY 0x04000 /* entry is to be added to name cache */ #define ISLASTCN 0x08000 /* this is last component of pathname */ #define ISSYMLINK 0x10000 /* symlink needs interpretation */ +#define ISWHITEOUT 0x20000 /* found whiteout */ +#define DOWHITEOUT 0x40000 /* do whiteouts */ #define PARAMASK 0xfff00 /* mask of parameter descriptors */ /* * Initialization of an nameidata structure. @@ -154,10 +158,8 @@ struct nameidata { #define NCHNAMLEN 31 /* maximum name segment length we bother with */ struct namecache { - struct namecache *nc_forw; /* hash chain */ - struct namecache **nc_back; /* hash chain */ - struct namecache *nc_nxt; /* LRU chain */ - struct namecache **nc_prev; /* LRU chain */ + LIST_ENTRY(namecache) nc_hash; /* hash chain */ + TAILQ_ENTRY(namecache) nc_lru; /* LRU chain */ struct vnode *nc_dvp; /* vnode of parent of name */ u_long nc_dvpid; /* capability number of nc_dvp */ struct vnode *nc_vp; /* vnode the name refers to */ @@ -170,6 +172,8 @@ struct namecache { u_long nextvnodeid; int namei __P((struct nameidata *ndp)); int lookup __P((struct nameidata *ndp)); +int relookup __P((struct vnode *dvp, struct vnode **vpp, + struct componentname *cnp)); #endif /* diff --git a/sys/sys/param.h b/sys/sys/param.h index 91bdfd8..a68bfc2 100644 --- a/sys/sys/param.h +++ b/sys/sys/param.h @@ -35,10 +35,10 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)param.h 8.2 (Berkeley) 1/21/94 + * @(#)param.h 8.3 (Berkeley) 4/4/95 */ -#define BSD 199306 /* System version (year & month). */ +#define BSD 199506 /* System version (year & month). */ #define BSD4_3 1 #define BSD4_4 1 diff --git a/sys/sys/proc.h b/sys/sys/proc.h index bbe60cd..6e2b1ff 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -35,7 +35,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)proc.h 8.8 (Berkeley) 1/21/94 + * @(#)proc.h 8.15 (Berkeley) 5/19/95 */ #ifndef _SYS_PROC_H_ @@ -43,6 +43,7 @@ #include /* Machine-dependent proc substruct. */ #include /* For struct selinfo. */ +#include /* * One structure allocated per session. @@ -59,8 +60,8 @@ struct session { * One structure allocated per process group. */ struct pgrp { - struct pgrp *pg_hforw; /* Forward link in hash bucket. */ - struct proc *pg_mem; /* Pointer to pgrp members. */ + LIST_ENTRY(pgrp) pg_hash; /* Hash chain. */ + LIST_HEAD(, proc) pg_members; /* Pointer to pgrp members. */ struct session *pg_session; /* Pointer to session. */ pid_t pg_id; /* Pgrp id. */ int pg_jobc; /* # procs qualifying pgrp for job control */ @@ -80,8 +81,7 @@ struct pgrp { struct proc { struct proc *p_forw; /* Doubly-linked run/sleep queue. */ struct proc *p_back; - struct proc *p_next; /* Linked list of active procs */ - struct proc **p_prev; /* and zombies. */ + LIST_ENTRY(proc) p_list; /* List of all processes. */ /* substructures: */ struct pcred *p_cred; /* Process owner's identity. */ @@ -99,15 +99,14 @@ struct proc { char p_pad1[3]; pid_t p_pid; /* Process identifier. */ - struct proc *p_hash; /* Hashed based on p_pid for kill+exit+... */ - struct proc *p_pgrpnxt; /* Pointer to next process in process group. */ - struct proc *p_pptr; /* Pointer to process structure of parent. */ - struct proc *p_osptr; /* Pointer to older sibling processes. */ + LIST_ENTRY(proc) p_pglist; /* List of processes in pgrp. */ + struct proc *p_pptr; /* Pointer to parent process. */ + LIST_ENTRY(proc) p_sibling; /* List of sibling processes. */ + LIST_HEAD(, proc) p_children; /* Pointer to list of children. */ /* The following fields are all zeroed upon creation in fork. */ -#define p_startzero p_ysptr - struct proc *p_ysptr; /* Pointer to younger siblings. */ - struct proc *p_cptr; /* Pointer to youngest living child. */ +#define p_startzero p_oppid + pid_t p_oppid; /* Save parent pid during ptrace. XXX */ int p_dupfd; /* Sideways return value from fdopen. XXX */ @@ -133,10 +132,18 @@ struct proc { struct vnode *p_textvp; /* Vnode of executable. */ - long p_spare[5]; /* pad to 256, avoid shifting eproc. */ + short p_locks; /* DEBUG: lockmgr count of held locks */ + short p_simple_locks; /* DEBUG: count of held simple locks */ + long p_spare[2]; /* pad to 256, avoid shifting eproc. */ /* End area that is zeroed on creation. */ -#define p_endzero p_startcopy +#define p_endzero p_hash.le_next + + /* + * Not copied, not zero'ed. + * Belongs after p_pid, but here to avoid shifting proc elements. + */ + LIST_ENTRY(proc) p_hash; /* Hash chain. */ /* The following fields are all copied upon creation in fork. */ #define p_startcopy p_sigmask @@ -154,14 +161,14 @@ struct proc { /* End area that is copied on creation. */ #define p_endcopy p_thread - int p_thread; /* Id for this "thread"; Mach glue. XXX */ + + void *p_thread; /* Id for this "thread"; Mach glue. XXX */ struct user *p_addr; /* Kernel virtual addr of u-area (PROC ONLY). */ struct mdproc p_md; /* Any machine-dependent fields. */ u_short p_xstat; /* Exit status for wait; also stop signal. */ u_short p_acflag; /* Accounting flags. */ struct rusage *p_ru; /* Exit information. XXX */ - }; #define p_session p_pgrp->pg_session @@ -189,7 +196,7 @@ struct proc { #define P_TRACED 0x00800 /* Debugged process being traced. */ #define P_WAITED 0x01000 /* Debugging process has waited for child. */ #define P_WEXIT 0x02000 /* Working on exiting. */ -#define P_EXEC 0x04000 /* Process called exec. */ +#define P_EXEC 0x04000 /* Process called exec. */ /* Should probably be changed into a hold count. */ #define P_NOSWAP 0x08000 /* Another flag to prevent swap out. */ @@ -221,7 +228,6 @@ struct pcred { */ #define PID_MAX 30000 #define NO_PID 30001 -#define PIDHASH(pid) ((pid) & pidhashmask) #define SESS_LEADER(p) ((p)->p_session->s_leader == (p)) #define SESSHOLD(s) ((s)->s_count++) @@ -230,15 +236,21 @@ struct pcred { FREE(s, M_SESSION); \ } -extern struct proc *pidhash[]; /* In param.c. */ -extern struct pgrp *pgrphash[]; /* In param.c. */ +#define PIDHASH(pid) (&pidhashtbl[(pid) & pidhash]) +extern LIST_HEAD(pidhashhead, proc) *pidhashtbl; +extern u_long pidhash; + +#define PGRPHASH(pgid) (&pgrphashtbl[(pgid) & pgrphash]) +extern LIST_HEAD(pgrphashhead, pgrp) *pgrphashtbl; +extern u_long pgrphash; + extern struct proc *curproc; /* Current running proc. */ extern struct proc proc0; /* Process slot for swapper. */ extern int nprocs, maxproc; /* Current and max number of procs. */ -extern int pidhashmask; /* In param.c. */ -volatile struct proc *allproc; /* List of active procs. */ -struct proc *zombproc; /* List of zombie procs. */ +LIST_HEAD(proclist, proc); +extern struct proclist allproc; /* List of all processes. */ +extern struct proclist zombproc; /* List of zombie processes. */ struct proc *initproc, *pageproc; /* Process slots for init, pager. */ #define NQS 32 /* 32 run queues. */ @@ -251,7 +263,14 @@ struct prochd { struct proc *pfind __P((pid_t)); /* Find process by id. */ struct pgrp *pgfind __P((pid_t)); /* Find process group by id. */ +int chgproccnt __P((uid_t uid, int diff)); +int enterpgrp __P((struct proc *p, pid_t pgid, int mksess)); +void fixjobc __P((struct proc *p, struct pgrp *pgrp, int entering)); +int inferior __P((struct proc *p)); +int leavepgrp __P((struct proc *p)); void mi_switch __P((void)); +void pgdelete __P((struct pgrp *pgrp)); +void procinit __P((void)); void resetpriority __P((struct proc *)); void setrunnable __P((struct proc *)); void setrunqueue __P((struct proc *)); diff --git a/sys/sys/queue.h b/sys/sys/queue.h index c200c9f..cbd7586 100644 --- a/sys/sys/queue.h +++ b/sys/sys/queue.h @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)queue.h 8.4 (Berkeley) 1/4/94 + * @(#)queue.h 8.5 (Berkeley) 8/20/94 */ #ifndef _SYS_QUEUE_H_ @@ -43,16 +43,16 @@ * A list is headed by a single forward pointer (or an array of forward * pointers for a hash table header). The elements are doubly linked * so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list after - * an existing element or at the head of the list. A list may only be - * traversed in the forward direction. + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. * * A tail queue is headed by a pair of pointers, one to the head of the * list and the other to the tail of the list. The elements are doubly * linked so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list after - * an existing element, at the head of the list, or at the end of the - * list. A tail queue may only be traversed in the forward direction. + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may only be traversed in the forward direction. * * A circle queue is headed by a pair of pointers, one to the head of the * list and the other to the tail of the list. The elements are doubly @@ -94,6 +94,13 @@ struct { \ (elm)->field.le_prev = &(listelm)->field.le_next; \ } +#define LIST_INSERT_BEFORE(listelm, elm, field) { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + (elm)->field.le_next = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &(elm)->field.le_next; \ +} + #define LIST_INSERT_HEAD(head, elm, field) { \ if (((elm)->field.le_next = (head)->lh_first) != NULL) \ (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ @@ -133,7 +140,7 @@ struct { \ #define TAILQ_INSERT_HEAD(head, elm, field) { \ if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ - (elm)->field.tqe_next->field.tqe_prev = \ + (head)->tqh_first->field.tqe_prev = \ &(elm)->field.tqe_next; \ else \ (head)->tqh_last = &(elm)->field.tqe_next; \ @@ -158,6 +165,13 @@ struct { \ (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ } +#define TAILQ_INSERT_BEFORE(listelm, elm, field) { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + (elm)->field.tqe_next = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ +} + #define TAILQ_REMOVE(head, elm, field) { \ if (((elm)->field.tqe_next) != NULL) \ (elm)->field.tqe_next->field.tqe_prev = \ diff --git a/sys/sys/reboot.h b/sys/sys/reboot.h index c3c957e..a4fc1b6 100644 --- a/sys/sys/reboot.h +++ b/sys/sys/reboot.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1982, 1986, 1988, 1993 + * Copyright (c) 1982, 1986, 1988, 1993, 1994 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,24 +30,23 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)reboot.h 8.1 (Berkeley) 6/2/93 + * @(#)reboot.h 8.3 (Berkeley) 12/13/94 */ /* - * Arguments to reboot system call. - * These are passed to boot program in r11, - * and on to init. + * Arguments to reboot system call. These are passed to + * the boot program and on to init. */ #define RB_AUTOBOOT 0 /* flags for system auto-booting itself */ -#define RB_ASKNAME 0x01 /* ask for file name to reboot from */ -#define RB_SINGLE 0x02 /* reboot to single user only */ -#define RB_NOSYNC 0x04 /* dont sync before reboot */ -#define RB_HALT 0x08 /* don't reboot, just halt */ -#define RB_INITNAME 0x10 /* name given for /etc/init (unused) */ -#define RB_DFLTROOT 0x20 /* use compiled-in rootdev */ -#define RB_KDB 0x40 /* give control to kernel debugger */ -#define RB_RDONLY 0x80 /* mount root fs read-only */ +#define RB_ASKNAME 0x001 /* ask for file name to reboot from */ +#define RB_SINGLE 0x002 /* reboot to single user only */ +#define RB_NOSYNC 0x004 /* dont sync before reboot */ +#define RB_HALT 0x008 /* don't reboot, just halt */ +#define RB_INITNAME 0x010 /* name given for /etc/init (unused) */ +#define RB_DFLTROOT 0x020 /* use compiled-in rootdev */ +#define RB_KDB 0x040 /* give control to kernel debugger */ +#define RB_RDONLY 0x080 /* mount root fs read-only */ #define RB_DUMP 0x100 /* dump kernel memory before reboot */ #define RB_MINIROOT 0x200 /* mini-root present in memory at boot time */ @@ -79,8 +78,8 @@ #define B_TYPEMASK 0xff #define B_TYPE(val) (((val) >> B_TYPESHIFT) & B_TYPEMASK) -#define B_MAGICMASK ((u_long)0xf0000000) -#define B_DEVMAGIC ((u_long)0xa0000000) +#define B_MAGICMASK 0xf0000000 +#define B_DEVMAGIC 0xa0000000 #define MAKEBOOTDEV(type, adaptor, controller, unit, partition) \ (((type) << B_TYPESHIFT) | ((adaptor) << B_ADAPTORSHIFT) | \ diff --git a/sys/sys/resource.h b/sys/sys/resource.h index 559f1ac..2e3941d 100644 --- a/sys/sys/resource.h +++ b/sys/sys/resource.h @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)resource.h 8.2 (Berkeley) 1/4/94 + * @(#)resource.h 8.4 (Berkeley) 1/9/95 */ #ifndef _SYS_RESOURCE_H_ @@ -92,8 +92,8 @@ struct rusage { #define RLIM_INFINITY (((u_quad_t)1 << 63) - 1) struct orlimit { - long rlim_cur; /* current (soft) limit */ - long rlim_max; /* maximum value for rlim_cur */ + int32_t rlim_cur; /* current (soft) limit */ + int32_t rlim_max; /* maximum value for rlim_cur */ }; struct rlimit { @@ -103,8 +103,8 @@ struct rlimit { /* Load average structure. */ struct loadavg { - fixpt_t ldavg[3]; - long fscale; + fixpt_t ldavg[3]; + long fscale; }; #ifdef KERNEL diff --git a/sys/sys/resourcevar.h b/sys/sys/resourcevar.h index 0f8d5e3..7c4f50e 100644 --- a/sys/sys/resourcevar.h +++ b/sys/sys/resourcevar.h @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)resourcevar.h 8.3 (Berkeley) 2/22/94 + * @(#)resourcevar.h 8.4 (Berkeley) 1/9/95 */ #ifndef _SYS_RESOURCEVAR_H_ @@ -84,7 +84,10 @@ struct plimit { #ifdef KERNEL void addupc_intr __P((struct proc *p, u_long pc, u_int ticks)); void addupc_task __P((struct proc *p, u_long pc, u_int ticks)); +void calcru __P((struct proc *p, struct timeval *up, struct timeval *sp, + struct timeval *ip)); struct plimit *limcopy __P((struct plimit *lim)); +void ruadd __P((struct rusage *ru, struct rusage *ru2)); #endif #endif /* !_SYS_RESOURCEVAR_H_ */ diff --git a/sys/sys/signal.h b/sys/sys/signal.h index 8ccded4..9e8d401 100644 --- a/sys/sys/signal.h +++ b/sys/sys/signal.h @@ -35,17 +35,17 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)signal.h 8.2 (Berkeley) 1/21/94 + * @(#)signal.h 8.4 (Berkeley) 5/4/95 */ #ifndef _SYS_SIGNAL_H_ #define _SYS_SIGNAL_H_ +#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE) #define NSIG 32 /* counting 0; could be 33 (mask is 1-32) */ +#endif -#ifndef _ANSI_SOURCE #include /* sigcontext; codes for SIGILL, SIGFPE */ -#endif #define SIGHUP 1 /* hangup */ #define SIGINT 2 /* interrupt */ @@ -113,7 +113,7 @@ typedef unsigned int sigset_t; * Signal vector "template" used in sigaction call. */ struct sigaction { - void (*sa_handler)(); /* signal handler */ + void (*sa_handler)(int); /* signal handler */ sigset_t sa_mask; /* signal mask to apply */ int sa_flags; /* see signal options below */ }; @@ -134,7 +134,7 @@ struct sigaction { #define SIG_UNBLOCK 2 /* unblock specified signal set */ #define SIG_SETMASK 3 /* set specified signal set */ -#ifndef _POSIX_SOURCE +#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE) #ifndef KERNEL #include #endif @@ -156,7 +156,7 @@ struct sigaltstack { * Signal vector "template" used in sigvec call. */ struct sigvec { - void (*sv_handler)(); /* signal handler */ + void (*sv_handler)(int); /* signal handler */ int sv_mask; /* signal mask to apply */ int sv_flags; /* see signal options below */ }; diff --git a/sys/sys/signalvar.h b/sys/sys/signalvar.h index 3d7e68b..191ff4a 100644 --- a/sys/sys/signalvar.h +++ b/sys/sys/signalvar.h @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)signalvar.h 8.3 (Berkeley) 1/4/94 + * @(#)signalvar.h 8.6 (Berkeley) 2/19/95 */ #ifndef _SYS_SIGNALVAR_H_ /* tmp for user.h */ @@ -54,8 +54,8 @@ struct sigacts { int ps_flags; /* signal flags, below */ struct sigaltstack ps_sigstk; /* sp & on stack state variable */ int ps_sig; /* for core dump/debugger XXX */ - int ps_code; /* for core dump/debugger XXX */ - int ps_addr; /* for core dump/debugger XXX */ + long ps_code; /* for core dump/debugger XXX */ + long ps_addr; /* for core dump/debugger XXX */ sigset_t ps_usertramp; /* SunOS compat; libc sigtramp XXX */ }; @@ -75,7 +75,7 @@ struct sigacts { /* * Determine signal that should be delivered to process p, the current * process, 0 if none. If there is a pending stop signal with default - * action, the process stops in issig(). + * action, the process stops in issignal(). */ #define CURSIG(p) \ (((p)->p_siglist == 0 || \ @@ -152,16 +152,18 @@ int sigprop[NSIG + 1] = { int coredump __P((struct proc *p)); void execsigs __P((struct proc *p)); void gsignal __P((int pgid, int sig)); -int issig __P((struct proc *p)); +int issignal __P((struct proc *p)); void pgsignal __P((struct pgrp *pgrp, int sig, int checkctty)); void postsig __P((int sig)); void psignal __P((struct proc *p, int sig)); +void setsigvec __P((struct proc *p, int signum, struct sigaction *sa)); +void sigexit __P((struct proc *p, int signum)); void siginit __P((struct proc *p)); -void trapsignal __P((struct proc *p, int sig, unsigned code)); +void trapsignal __P((struct proc *p, int sig, u_long code)); /* * Machine-dependent functions: */ -void sendsig __P((sig_t action, int sig, int returnmask, unsigned code)); +void sendsig __P((sig_t action, int sig, int returnmask, u_long code)); #endif /* KERNEL */ #endif /* !_SYS_SIGNALVAR_H_ */ diff --git a/sys/sys/socket.h b/sys/sys/socket.h index f6728e9..be6163f 100644 --- a/sys/sys/socket.h +++ b/sys/sys/socket.h @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)socket.h 8.4 (Berkeley) 2/21/94 + * @(#)socket.h 8.6 (Berkeley) 5/3/95 */ #ifndef _SYS_SOCKET_H_ @@ -80,7 +80,7 @@ */ struct linger { int l_onoff; /* option on/off */ - int l_linger; /* linger time */ + int l_linger; /* linger time in seconds */ }; /* @@ -187,7 +187,7 @@ struct sockproto { #define CTL_NET_NAMES { \ { 0, 0 }, \ - { "unix", CTLTYPE_NODE }, \ + { "local", CTLTYPE_NODE }, \ { "inet", CTLTYPE_NODE }, \ { "implink", CTLTYPE_NODE }, \ { "pup", CTLTYPE_NODE }, \ diff --git a/sys/sys/socketvar.h b/sys/sys/socketvar.h index ff10404..317c280 100644 --- a/sys/sys/socketvar.h +++ b/sys/sys/socketvar.h @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)socketvar.h 8.1 (Berkeley) 6/2/93 + * @(#)socketvar.h 8.3 (Berkeley) 2/19/95 */ #include /* for struct selinfo */ @@ -201,7 +201,61 @@ extern char netio[], netcon[], netcls[]; */ int soo_read __P((struct file *fp, struct uio *uio, struct ucred *cred)); int soo_write __P((struct file *fp, struct uio *uio, struct ucred *cred)); -int soo_ioctl __P((struct file *fp, int com, caddr_t data, struct proc *p)); +int soo_ioctl __P((struct file *fp, u_long cmd, caddr_t data, + struct proc *p)); int soo_select __P((struct file *fp, int which, struct proc *p)); int soo_close __P((struct file *fp, struct proc *p)); -#endif + +struct mbuf; +struct sockaddr; + +void sbappend __P((struct sockbuf *sb, struct mbuf *m)); +int sbappendaddr __P((struct sockbuf *sb, struct sockaddr *asa, + struct mbuf *m0, struct mbuf *control)); +int sbappendcontrol __P((struct sockbuf *sb, struct mbuf *m0, + struct mbuf *control)); +void sbappendrecord __P((struct sockbuf *sb, struct mbuf *m0)); +void sbcheck __P((struct sockbuf *sb)); +void sbcompress __P((struct sockbuf *sb, struct mbuf *m, struct mbuf *n)); +void sbdrop __P((struct sockbuf *sb, int len)); +void sbdroprecord __P((struct sockbuf *sb)); +void sbflush __P((struct sockbuf *sb)); +void sbinsertoob __P((struct sockbuf *sb, struct mbuf *m0)); +void sbrelease __P((struct sockbuf *sb)); +int sbreserve __P((struct sockbuf *sb, u_long cc)); +int sbwait __P((struct sockbuf *sb)); +int sb_lock __P((struct sockbuf *sb)); +int soabort __P((struct socket *so)); +int soaccept __P((struct socket *so, struct mbuf *nam)); +int sobind __P((struct socket *so, struct mbuf *nam)); +void socantrcvmore __P((struct socket *so)); +void socantsendmore __P((struct socket *so)); +int soclose __P((struct socket *so)); +int soconnect __P((struct socket *so, struct mbuf *nam)); +int soconnect2 __P((struct socket *so1, struct socket *so2)); +int socreate __P((int dom, struct socket **aso, int type, int proto)); +int sodisconnect __P((struct socket *so)); +int sofree __P((struct socket *so)); +int sogetopt __P((struct socket *so, int level, int optname, + struct mbuf **mp)); +void sohasoutofband __P((struct socket *so)); +void soisconnected __P((struct socket *so)); +void soisconnecting __P((struct socket *so)); +void soisdisconnected __P((struct socket *so)); +void soisdisconnecting __P((struct socket *so)); +int solisten __P((struct socket *so, int backlog)); +struct socket * + sonewconn1 __P((struct socket *head, int connstatus)); +void soqinsque __P((struct socket *head, struct socket *so, int q)); +int soqremque __P((struct socket *so, int q)); +int soreceive __P((struct socket *so, struct mbuf **paddr, struct uio *uio, + struct mbuf **mp0, struct mbuf **controlp, int *flagsp)); +int soreserve __P((struct socket *so, u_long sndcc, u_long rcvcc)); +void sorflush __P((struct socket *so)); +int sosend __P((struct socket *so, struct mbuf *addr, struct uio *uio, + struct mbuf *top, struct mbuf *control, int flags)); +int sosetopt __P((struct socket *so, int level, int optname, + struct mbuf *m0)); +int soshutdown __P((struct socket *so, int how)); +void sowakeup __P((struct socket *so, struct sockbuf *sb)); +#endif /* KERNEL */ diff --git a/sys/sys/stat.h b/sys/sys/stat.h index 07020c3..c471bdc 100644 --- a/sys/sys/stat.h +++ b/sys/sys/stat.h @@ -35,7 +35,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)stat.h 8.6 (Berkeley) 3/8/94 + * @(#)stat.h 8.12 (Berkeley) 6/16/95 */ #ifndef _SYS_STAT_H_ @@ -45,46 +45,57 @@ #ifndef _POSIX_SOURCE struct ostat { - unsigned short st_dev; /* inode's device */ - ino_t st_ino; /* inode's number */ - mode_t st_mode; /* inode protection mode */ - nlink_t st_nlink; /* number of hard links */ - unsigned short st_uid; /* user ID of the file's owner */ - unsigned short st_gid; /* group ID of the file's group */ - unsigned short st_rdev; /* device type */ - long st_size; /* file size, in bytes */ + u_int16_t st_dev; /* inode's device */ + ino_t st_ino; /* inode's number */ + mode_t st_mode; /* inode protection mode */ + nlink_t st_nlink; /* number of hard links */ + u_int16_t st_uid; /* user ID of the file's owner */ + u_int16_t st_gid; /* group ID of the file's group */ + u_int16_t st_rdev; /* device type */ + int32_t st_size; /* file size, in bytes */ struct timespec st_atimespec; /* time of last access */ struct timespec st_mtimespec; /* time of last data modification */ struct timespec st_ctimespec; /* time of last file status change */ - long st_blksize; /* optimal blocksize for I/O */ - long st_blocks; /* blocks allocated for file */ - unsigned long st_flags; /* user defined flags for file */ - unsigned long st_gen; /* file generation number */ + int32_t st_blksize; /* optimal blocksize for I/O */ + int32_t st_blocks; /* blocks allocated for file */ + u_int32_t st_flags; /* user defined flags for file */ + u_int32_t st_gen; /* file generation number */ }; #endif /* !_POSIX_SOURCE */ struct stat { - dev_t st_dev; /* inode's device */ - ino_t st_ino; /* inode's number */ - mode_t st_mode; /* inode protection mode */ - nlink_t st_nlink; /* number of hard links */ - uid_t st_uid; /* user ID of the file's owner */ - gid_t st_gid; /* group ID of the file's group */ - dev_t st_rdev; /* device type */ + dev_t st_dev; /* inode's device */ + ino_t st_ino; /* inode's number */ + mode_t st_mode; /* inode protection mode */ + nlink_t st_nlink; /* number of hard links */ + uid_t st_uid; /* user ID of the file's owner */ + gid_t st_gid; /* group ID of the file's group */ + dev_t st_rdev; /* device type */ +#ifndef _POSIX_SOURCE struct timespec st_atimespec; /* time of last access */ struct timespec st_mtimespec; /* time of last data modification */ struct timespec st_ctimespec; /* time of last file status change */ - off_t st_size; /* file size, in bytes */ - quad_t st_blocks; /* blocks allocated for file */ - unsigned long st_blksize; /* optimal blocksize for I/O */ - unsigned long st_flags; /* user defined flags for file */ - unsigned long st_gen; /* file generation number */ - long st_lspare; - quad_t st_qspare[2]; +#else + time_t st_atime; /* time of last access */ + long st_atimensec; /* nsec of last access */ + time_t st_mtime; /* time of last data modification */ + long st_mtimensec; /* nsec of last data modification */ + time_t st_ctime; /* time of last file status change */ + long st_ctimensec; /* nsec of last file status change */ +#endif + off_t st_size; /* file size, in bytes */ + int64_t st_blocks; /* blocks allocated for file */ + u_int32_t st_blksize; /* optimal blocksize for I/O */ + u_int32_t st_flags; /* user defined flags for file */ + u_int32_t st_gen; /* file generation number */ + int32_t st_lspare; + int64_t st_qspare[2]; }; +#ifndef _POSIX_SOURCE #define st_atime st_atimespec.ts_sec #define st_mtime st_mtimespec.ts_sec #define st_ctime st_ctimespec.ts_sec +#endif #define S_ISUID 0004000 /* set user id on execution */ #define S_ISGID 0002000 /* set group id on execution */ @@ -122,6 +133,7 @@ struct stat { #define S_IFREG 0100000 /* regular */ #define S_IFLNK 0120000 /* symbolic link */ #define S_IFSOCK 0140000 /* socket */ +#define S_IFWHT 0160000 /* whiteout */ #define S_ISVTX 0001000 /* save swapped text even after use */ #endif @@ -129,12 +141,13 @@ struct stat { #define S_ISCHR(m) ((m & 0170000) == 0020000) /* char special */ #define S_ISBLK(m) ((m & 0170000) == 0060000) /* block special */ #define S_ISREG(m) ((m & 0170000) == 0100000) /* regular file */ -#define S_ISFIFO(m) ((m & 0170000) == 0100000 || \ +#define S_ISFIFO(m) ((m & 0170000) == 0010000 || \ (m & 0170000) == 0140000) /* fifo or socket */ #ifndef _POSIX_SOURCE #define S_ISLNK(m) ((m & 0170000) == 0120000) /* symbolic link */ -#define S_ISSOCK(m) ((m & 0170000) == 0100000 || \ +#define S_ISSOCK(m) ((m & 0170000) == 0010000 || \ (m & 0170000) == 0140000) /* fifo or socket */ +#define S_ISWHT(m) ((m & 0170000) == 0160000) /* whiteout */ #endif #ifndef _POSIX_SOURCE @@ -155,6 +168,7 @@ struct stat { #define UF_NODUMP 0x00000001 /* do not dump file */ #define UF_IMMUTABLE 0x00000002 /* file may not be changed */ #define UF_APPEND 0x00000004 /* writes to file may only append */ +#define UF_OPAQUE 0x00000008 /* directory is opaque wrt. union */ /* * Super-user changeable flags. */ @@ -167,6 +181,7 @@ struct stat { /* * Shorthand abbreviations of above. */ +#define OPAQUE (UF_OPAQUE) #define APPEND (UF_APPEND | SF_APPEND) #define IMMUTABLE (UF_IMMUTABLE | SF_IMMUTABLE) #endif diff --git a/sys/sys/syscall.h b/sys/sys/syscall.h index 8df8eb4..b08c304 100644 --- a/sys/sys/syscall.h +++ b/sys/sys/syscall.h @@ -2,7 +2,7 @@ * System call numbers. * * DO NOT EDIT-- this file is automatically generated. - * created from @(#)syscalls.master 8.2 (Berkeley) 1/13/94 + * created from @(#)syscalls.master 8.6 (Berkeley) 3/30/95 */ #define SYS_syscall 0 @@ -13,7 +13,7 @@ #define SYS_open 5 #define SYS_close 6 #define SYS_wait4 7 - /* 8 is old creat */ + /* 8 is compat_43 creat */ #define SYS_link 9 #define SYS_unlink 10 /* 11 is obsolete execv */ @@ -24,7 +24,7 @@ #define SYS_chown 16 #define SYS_break 17 #define SYS_getfsstat 18 - /* 19 is old lseek */ + /* 19 is compat_43 lseek */ #define SYS_getpid 20 #define SYS_mount 21 #define SYS_unmount 22 @@ -43,9 +43,9 @@ #define SYS_fchflags 35 #define SYS_sync 36 #define SYS_kill 37 - /* 38 is old stat */ + /* 38 is compat_43 stat */ #define SYS_getppid 39 - /* 40 is old lstat */ + /* 40 is compat_43 lstat */ #define SYS_dup 41 #define SYS_pipe 42 #define SYS_getegid 43 @@ -67,16 +67,16 @@ #define SYS_execve 59 #define SYS_umask 60 #define SYS_chroot 61 - /* 62 is old fstat */ - /* 63 is old getkerninfo */ - /* 64 is old getpagesize */ + /* 62 is compat_43 fstat */ + /* 63 is compat_43 getkerninfo */ + /* 64 is compat_43 getpagesize */ #define SYS_msync 65 #define SYS_vfork 66 /* 67 is obsolete vread */ /* 68 is obsolete vwrite */ #define SYS_sbrk 69 #define SYS_sstk 70 - /* 71 is old mmap */ + /* 71 is compat_43 mmap */ #define SYS_vadvise 72 #define SYS_munmap 73 #define SYS_mprotect 74 @@ -89,11 +89,11 @@ #define SYS_getpgrp 81 #define SYS_setpgid 82 #define SYS_setitimer 83 - /* 84 is old wait */ + /* 84 is compat_43 wait */ #define SYS_swapon 85 #define SYS_getitimer 86 - /* 87 is old gethostname */ - /* 88 is old sethostname */ + /* 87 is compat_43 gethostname */ + /* 88 is compat_43 sethostname */ #define SYS_getdtablesize 89 #define SYS_dup2 90 #define SYS_fcntl 92 @@ -102,22 +102,22 @@ #define SYS_setpriority 96 #define SYS_socket 97 #define SYS_connect 98 - /* 99 is old accept */ + /* 99 is compat_43 accept */ #define SYS_getpriority 100 - /* 101 is old send */ - /* 102 is old recv */ + /* 101 is compat_43 send */ + /* 102 is compat_43 recv */ #define SYS_sigreturn 103 #define SYS_bind 104 #define SYS_setsockopt 105 #define SYS_listen 106 /* 107 is obsolete vtimes */ - /* 108 is old sigvec */ - /* 109 is old sigblock */ - /* 110 is old sigsetmask */ + /* 108 is compat_43 sigvec */ + /* 109 is compat_43 sigblock */ + /* 110 is compat_43 sigsetmask */ #define SYS_sigsuspend 111 - /* 112 is old sigstack */ - /* 113 is old recvmsg */ - /* 114 is old sendmsg */ + /* 112 is compat_43 sigstack */ + /* 113 is compat_43 recvmsg */ + /* 114 is compat_43 sendmsg */ #define SYS_vtrace 115 /* 115 is obsolete vtrace */ #define SYS_gettimeofday 116 @@ -129,12 +129,12 @@ #define SYS_settimeofday 122 #define SYS_fchown 123 #define SYS_fchmod 124 - /* 125 is old recvfrom */ - /* 126 is old setreuid */ - /* 127 is old setregid */ + /* 125 is compat_43 recvfrom */ + /* 126 is compat_43 setreuid */ + /* 127 is compat_43 setregid */ #define SYS_rename 128 - /* 129 is old truncate */ - /* 130 is old ftruncate */ + /* 129 is compat_43 truncate */ + /* 130 is compat_43 ftruncate */ #define SYS_flock 131 #define SYS_mkfifo 132 #define SYS_sendto 133 @@ -145,22 +145,22 @@ #define SYS_utimes 138 /* 139 is obsolete 4.2 sigreturn */ #define SYS_adjtime 140 - /* 141 is old getpeername */ - /* 142 is old gethostid */ - /* 143 is old sethostid */ - /* 144 is old getrlimit */ - /* 145 is old setrlimit */ - /* 146 is old killpg */ + /* 141 is compat_43 getpeername */ + /* 142 is compat_43 gethostid */ + /* 143 is compat_43 sethostid */ + /* 144 is compat_43 getrlimit */ + /* 145 is compat_43 setrlimit */ + /* 146 is compat_43 killpg */ #define SYS_setsid 147 #define SYS_quotactl 148 - /* 149 is old quota */ - /* 150 is old getsockname */ + /* 149 is compat_43 quota */ + /* 150 is compat_43 getsockname */ #define SYS_nfssvc 155 - /* 156 is old getdirentries */ + /* 156 is compat_43 getdirentries */ #define SYS_statfs 157 #define SYS_fstatfs 158 #define SYS_getfh 161 -#define SYS_shmsys 171 + /* 171 is compat_43 shmsys */ #define SYS_setgid 181 #define SYS_setegid 182 #define SYS_seteuid 183 @@ -184,3 +184,8 @@ #define SYS___sysctl 202 #define SYS_mlock 203 #define SYS_munlock 204 +#define SYS_undelete 205 +#define SYS_shmat 228 +#define SYS_shmctl 229 +#define SYS_shmdt 230 +#define SYS_shmget 231 diff --git a/sys/sys/syscallargs.h b/sys/sys/syscallargs.h new file mode 100644 index 0000000..44589aa --- /dev/null +++ b/sys/sys/syscallargs.h @@ -0,0 +1,862 @@ +/* + * System call argument lists. + * + * DO NOT EDIT-- this file is automatically generated. + * created from @(#)syscalls.master 8.6 (Berkeley) 3/30/95 + */ + +#define syscallarg(x) union { x datum; register_t pad; } + +struct exit_args { + syscallarg(int) rval; +}; + +struct read_args { + syscallarg(int) fd; + syscallarg(char *) buf; + syscallarg(u_int) nbyte; +}; + +struct write_args { + syscallarg(int) fd; + syscallarg(char *) buf; + syscallarg(u_int) nbyte; +}; + +struct open_args { + syscallarg(char *) path; + syscallarg(int) flags; + syscallarg(int) mode; +}; + +struct close_args { + syscallarg(int) fd; +}; + +struct wait4_args { + syscallarg(int) pid; + syscallarg(int *) status; + syscallarg(int) options; + syscallarg(struct rusage *) rusage; +}; + +struct compat_43_creat_args { + syscallarg(char *) path; + syscallarg(int) mode; +}; + +struct link_args { + syscallarg(char *) path; + syscallarg(char *) link; +}; + +struct unlink_args { + syscallarg(char *) path; +}; + +struct chdir_args { + syscallarg(char *) path; +}; + +struct fchdir_args { + syscallarg(int) fd; +}; + +struct mknod_args { + syscallarg(char *) path; + syscallarg(int) mode; + syscallarg(int) dev; +}; + +struct chmod_args { + syscallarg(char *) path; + syscallarg(int) mode; +}; + +struct chown_args { + syscallarg(char *) path; + syscallarg(int) uid; + syscallarg(int) gid; +}; + +struct obreak_args { + syscallarg(char *) nsize; +}; + +struct getfsstat_args { + syscallarg(struct statfs *) buf; + syscallarg(long) bufsize; + syscallarg(int) flags; +}; + +struct compat_43_lseek_args { + syscallarg(int) fd; + syscallarg(long) offset; + syscallarg(int) whence; +}; + +struct mount_args { + syscallarg(char *) type; + syscallarg(char *) path; + syscallarg(int) flags; + syscallarg(caddr_t) data; +}; + +struct unmount_args { + syscallarg(char *) path; + syscallarg(int) flags; +}; + +struct setuid_args { + syscallarg(uid_t) uid; +}; + +struct ptrace_args { + syscallarg(int) req; + syscallarg(pid_t) pid; + syscallarg(caddr_t) addr; + syscallarg(int) data; +}; + +struct recvmsg_args { + syscallarg(int) s; + syscallarg(struct msghdr *) msg; + syscallarg(int) flags; +}; + +struct sendmsg_args { + syscallarg(int) s; + syscallarg(caddr_t) msg; + syscallarg(int) flags; +}; + +struct recvfrom_args { + syscallarg(int) s; + syscallarg(caddr_t) buf; + syscallarg(size_t) len; + syscallarg(int) flags; + syscallarg(caddr_t) from; + syscallarg(int *) fromlenaddr; +}; + +struct accept_args { + syscallarg(int) s; + syscallarg(caddr_t) name; + syscallarg(int *) anamelen; +}; + +struct getpeername_args { + syscallarg(int) fdes; + syscallarg(caddr_t) asa; + syscallarg(int *) alen; +}; + +struct getsockname_args { + syscallarg(int) fdes; + syscallarg(caddr_t) asa; + syscallarg(int *) alen; +}; + +struct access_args { + syscallarg(char *) path; + syscallarg(int) flags; +}; + +struct chflags_args { + syscallarg(char *) path; + syscallarg(int) flags; +}; + +struct fchflags_args { + syscallarg(int) fd; + syscallarg(int) flags; +}; + +struct kill_args { + syscallarg(int) pid; + syscallarg(int) signum; +}; + +struct compat_43_stat_args { + syscallarg(char *) path; + syscallarg(struct ostat *) ub; +}; + +struct compat_43_lstat_args { + syscallarg(char *) path; + syscallarg(struct ostat *) ub; +}; + +struct dup_args { + syscallarg(u_int) fd; +}; + +struct profil_args { + syscallarg(caddr_t) samples; + syscallarg(u_int) size; + syscallarg(u_int) offset; + syscallarg(u_int) scale; +}; + +struct ktrace_args { + syscallarg(char *) fname; + syscallarg(int) ops; + syscallarg(int) facs; + syscallarg(int) pid; +}; + +struct sigaction_args { + syscallarg(int) signum; + syscallarg(struct sigaction *) nsa; + syscallarg(struct sigaction *) osa; +}; + +struct sigprocmask_args { + syscallarg(int) how; + syscallarg(sigset_t) mask; +}; + +struct getlogin_args { + syscallarg(char *) namebuf; + syscallarg(u_int) namelen; +}; + +struct setlogin_args { + syscallarg(char *) namebuf; +}; + +struct acct_args { + syscallarg(char *) path; +}; + +struct sigaltstack_args { + syscallarg(struct sigaltstack *) nss; + syscallarg(struct sigaltstack *) oss; +}; + +struct ioctl_args { + syscallarg(int) fd; + syscallarg(u_long) com; + syscallarg(caddr_t) data; +}; + +struct reboot_args { + syscallarg(int) opt; +}; + +struct revoke_args { + syscallarg(char *) path; +}; + +struct symlink_args { + syscallarg(char *) path; + syscallarg(char *) link; +}; + +struct readlink_args { + syscallarg(char *) path; + syscallarg(char *) buf; + syscallarg(int) count; +}; + +struct execve_args { + syscallarg(char *) path; + syscallarg(char **) argp; + syscallarg(char **) envp; +}; + +struct umask_args { + syscallarg(int) newmask; +}; + +struct chroot_args { + syscallarg(char *) path; +}; + +struct compat_43_fstat_args { + syscallarg(int) fd; + syscallarg(struct ostat *) sb; +}; + +struct compat_43_getkerninfo_args { + syscallarg(int) op; + syscallarg(char *) where; + syscallarg(int *) size; + syscallarg(int) arg; +}; + +struct msync_args { + syscallarg(caddr_t) addr; + syscallarg(int) len; +}; + +struct sbrk_args { + syscallarg(int) incr; +}; + +struct sstk_args { + syscallarg(int) incr; +}; + +struct compat_43_mmap_args { + syscallarg(caddr_t) addr; + syscallarg(int) len; + syscallarg(int) prot; + syscallarg(int) flags; + syscallarg(int) fd; + syscallarg(long) pos; +}; + +struct ovadvise_args { + syscallarg(int) anom; +}; + +struct munmap_args { + syscallarg(caddr_t) addr; + syscallarg(int) len; +}; + +struct mprotect_args { + syscallarg(caddr_t) addr; + syscallarg(int) len; + syscallarg(int) prot; +}; + +struct madvise_args { + syscallarg(caddr_t) addr; + syscallarg(int) len; + syscallarg(int) behav; +}; + +struct mincore_args { + syscallarg(caddr_t) addr; + syscallarg(int) len; + syscallarg(char *) vec; +}; + +struct getgroups_args { + syscallarg(u_int) gidsetsize; + syscallarg(gid_t *) gidset; +}; + +struct setgroups_args { + syscallarg(u_int) gidsetsize; + syscallarg(gid_t *) gidset; +}; + +struct setpgid_args { + syscallarg(int) pid; + syscallarg(int) pgid; +}; + +struct setitimer_args { + syscallarg(u_int) which; + syscallarg(struct itimerval *) itv; + syscallarg(struct itimerval *) oitv; +}; + +struct swapon_args { + syscallarg(char *) name; +}; + +struct getitimer_args { + syscallarg(u_int) which; + syscallarg(struct itimerval *) itv; +}; + +struct compat_43_gethostname_args { + syscallarg(char *) hostname; + syscallarg(u_int) len; +}; + +struct compat_43_sethostname_args { + syscallarg(char *) hostname; + syscallarg(u_int) len; +}; + +struct dup2_args { + syscallarg(u_int) from; + syscallarg(u_int) to; +}; + +struct fcntl_args { + syscallarg(int) fd; + syscallarg(int) cmd; + syscallarg(void *) arg; +}; + +struct select_args { + syscallarg(u_int) nd; + syscallarg(fd_set *) in; + syscallarg(fd_set *) ou; + syscallarg(fd_set *) ex; + syscallarg(struct timeval *) tv; +}; + +struct fsync_args { + syscallarg(int) fd; +}; + +struct setpriority_args { + syscallarg(int) which; + syscallarg(int) who; + syscallarg(int) prio; +}; + +struct socket_args { + syscallarg(int) domain; + syscallarg(int) type; + syscallarg(int) protocol; +}; + +struct connect_args { + syscallarg(int) s; + syscallarg(caddr_t) name; + syscallarg(int) namelen; +}; + +struct compat_43_accept_args { + syscallarg(int) s; + syscallarg(caddr_t) name; + syscallarg(int *) anamelen; +}; + +struct getpriority_args { + syscallarg(int) which; + syscallarg(int) who; +}; + +struct compat_43_send_args { + syscallarg(int) s; + syscallarg(caddr_t) buf; + syscallarg(int) len; + syscallarg(int) flags; +}; + +struct compat_43_recv_args { + syscallarg(int) s; + syscallarg(caddr_t) buf; + syscallarg(int) len; + syscallarg(int) flags; +}; + +struct sigreturn_args { + syscallarg(struct sigcontext *) sigcntxp; +}; + +struct bind_args { + syscallarg(int) s; + syscallarg(caddr_t) name; + syscallarg(int) namelen; +}; + +struct setsockopt_args { + syscallarg(int) s; + syscallarg(int) level; + syscallarg(int) name; + syscallarg(caddr_t) val; + syscallarg(int) valsize; +}; + +struct listen_args { + syscallarg(int) s; + syscallarg(int) backlog; +}; + +struct compat_43_sigvec_args { + syscallarg(int) signum; + syscallarg(struct sigvec *) nsv; + syscallarg(struct sigvec *) osv; +}; + +struct compat_43_sigblock_args { + syscallarg(int) mask; +}; + +struct compat_43_sigsetmask_args { + syscallarg(int) mask; +}; + +struct sigsuspend_args { + syscallarg(int) mask; +}; + +struct compat_43_sigstack_args { + syscallarg(struct sigstack *) nss; + syscallarg(struct sigstack *) oss; +}; + +struct compat_43_recvmsg_args { + syscallarg(int) s; + syscallarg(struct omsghdr *) msg; + syscallarg(int) flags; +}; + +struct compat_43_sendmsg_args { + syscallarg(int) s; + syscallarg(caddr_t) msg; + syscallarg(int) flags; +}; + +struct vtrace_args { + syscallarg(int) request; + syscallarg(int) value; +}; + +struct gettimeofday_args { + syscallarg(struct timeval *) tp; + syscallarg(struct timezone *) tzp; +}; + +struct getrusage_args { + syscallarg(int) who; + syscallarg(struct rusage *) rusage; +}; + +struct getsockopt_args { + syscallarg(int) s; + syscallarg(int) level; + syscallarg(int) name; + syscallarg(caddr_t) val; + syscallarg(int *) avalsize; +}; + +struct resuba_args { + syscallarg(int) value; +}; + +struct readv_args { + syscallarg(int) fd; + syscallarg(struct iovec *) iovp; + syscallarg(u_int) iovcnt; +}; + +struct writev_args { + syscallarg(int) fd; + syscallarg(struct iovec *) iovp; + syscallarg(u_int) iovcnt; +}; + +struct settimeofday_args { + syscallarg(struct timeval *) tv; + syscallarg(struct timezone *) tzp; +}; + +struct fchown_args { + syscallarg(int) fd; + syscallarg(int) uid; + syscallarg(int) gid; +}; + +struct fchmod_args { + syscallarg(int) fd; + syscallarg(int) mode; +}; + +struct compat_43_recvfrom_args { + syscallarg(int) s; + syscallarg(caddr_t) buf; + syscallarg(size_t) len; + syscallarg(int) flags; + syscallarg(caddr_t) from; + syscallarg(int *) fromlenaddr; +}; + +struct compat_43_setreuid_args { + syscallarg(int) ruid; + syscallarg(int) euid; +}; + +struct compat_43_setregid_args { + syscallarg(int) rgid; + syscallarg(int) egid; +}; + +struct rename_args { + syscallarg(char *) from; + syscallarg(char *) to; +}; + +struct compat_43_truncate_args { + syscallarg(char *) path; + syscallarg(long) length; +}; + +struct compat_43_ftruncate_args { + syscallarg(int) fd; + syscallarg(long) length; +}; + +struct flock_args { + syscallarg(int) fd; + syscallarg(int) how; +}; + +struct mkfifo_args { + syscallarg(char *) path; + syscallarg(int) mode; +}; + +struct sendto_args { + syscallarg(int) s; + syscallarg(caddr_t) buf; + syscallarg(size_t) len; + syscallarg(int) flags; + syscallarg(caddr_t) to; + syscallarg(int) tolen; +}; + +struct shutdown_args { + syscallarg(int) s; + syscallarg(int) how; +}; + +struct socketpair_args { + syscallarg(int) domain; + syscallarg(int) type; + syscallarg(int) protocol; + syscallarg(int *) rsv; +}; + +struct mkdir_args { + syscallarg(char *) path; + syscallarg(int) mode; +}; + +struct rmdir_args { + syscallarg(char *) path; +}; + +struct utimes_args { + syscallarg(char *) path; + syscallarg(struct timeval *) tptr; +}; + +struct adjtime_args { + syscallarg(struct timeval *) delta; + syscallarg(struct timeval *) olddelta; +}; + +struct compat_43_getpeername_args { + syscallarg(int) fdes; + syscallarg(caddr_t) asa; + syscallarg(int *) alen; +}; + +struct compat_43_sethostid_args { + syscallarg(int32_t) hostid; +}; + +struct compat_43_getrlimit_args { + syscallarg(u_int) which; + syscallarg(struct ogetrlimit *) rlp; +}; + +struct compat_43_setrlimit_args { + syscallarg(u_int) which; + syscallarg(struct ogetrlimit *) rlp; +}; + +struct compat_43_killpg_args { + syscallarg(int) pgid; + syscallarg(int) signum; +}; + +struct quotactl_args { + syscallarg(char *) path; + syscallarg(int) cmd; + syscallarg(int) uid; + syscallarg(caddr_t) arg; +}; + +struct compat_43_getsockname_args { + syscallarg(int) fdec; + syscallarg(caddr_t) asa; + syscallarg(int *) alen; +}; + +struct nfssvc_args { + syscallarg(int) flag; + syscallarg(caddr_t) argp; +}; + +struct compat_43_getdirentries_args { + syscallarg(int) fd; + syscallarg(char *) buf; + syscallarg(u_int) count; + syscallarg(long *) basep; +}; + +struct statfs_args { + syscallarg(char *) path; + syscallarg(struct statfs *) buf; +}; + +struct fstatfs_args { + syscallarg(int) fd; + syscallarg(struct statfs *) buf; +}; + +struct getfh_args { + syscallarg(char *) fname; + syscallarg(fhandle_t *) fhp; +}; + +struct compat_43_shmsys_args { + syscallarg(int) which; + syscallarg(int) a2; + syscallarg(int) a3; + syscallarg(int) a4; +}; + +struct setgid_args { + syscallarg(gid_t) gid; +}; + +struct setegid_args { + syscallarg(gid_t) egid; +}; + +struct seteuid_args { + syscallarg(uid_t) euid; +}; + +struct lfs_bmapv_args { + syscallarg(fsid_t *) fsidp; + syscallarg(struct block_info *) blkiov; + syscallarg(int) blkcnt; +}; + +struct lfs_markv_args { + syscallarg(fsid_t *) fsidp; + syscallarg(struct block_info *) blkiov; + syscallarg(int) blkcnt; +}; + +struct lfs_segclean_args { + syscallarg(fsid_t *) fsidp; + syscallarg(u_long) segment; +}; + +struct lfs_segwait_args { + syscallarg(fsid_t *) fsidp; + syscallarg(struct timeval *) tv; +}; + +struct stat_args { + syscallarg(char *) path; + syscallarg(struct stat *) ub; +}; + +struct fstat_args { + syscallarg(int) fd; + syscallarg(struct stat *) sb; +}; + +struct lstat_args { + syscallarg(char *) path; + syscallarg(struct stat *) ub; +}; + +struct pathconf_args { + syscallarg(char *) path; + syscallarg(int) name; +}; + +struct fpathconf_args { + syscallarg(int) fd; + syscallarg(int) name; +}; + +struct getrlimit_args { + syscallarg(u_int) which; + syscallarg(struct rlimit *) rlp; +}; + +struct setrlimit_args { + syscallarg(u_int) which; + syscallarg(struct rlimit *) rlp; +}; + +struct getdirentries_args { + syscallarg(int) fd; + syscallarg(char *) buf; + syscallarg(u_int) count; + syscallarg(long *) basep; +}; + +struct mmap_args { + syscallarg(caddr_t) addr; + syscallarg(size_t) len; + syscallarg(int) prot; + syscallarg(int) flags; + syscallarg(int) fd; + syscallarg(long) pad; + syscallarg(off_t) pos; +}; + +struct lseek_args { + syscallarg(int) fd; + syscallarg(int) pad; + syscallarg(off_t) offset; + syscallarg(int) whence; +}; + +struct truncate_args { + syscallarg(char *) path; + syscallarg(int) pad; + syscallarg(off_t) length; +}; + +struct ftruncate_args { + syscallarg(int) fd; + syscallarg(int) pad; + syscallarg(off_t) length; +}; + +struct __sysctl_args { + syscallarg(int *) name; + syscallarg(u_int) namelen; + syscallarg(void *) old; + syscallarg(size_t *) oldlenp; + syscallarg(void *) new; + syscallarg(size_t) newlen; +}; + +struct mlock_args { + syscallarg(caddr_t) addr; + syscallarg(size_t) len; +}; + +struct munlock_args { + syscallarg(caddr_t) addr; + syscallarg(size_t) len; +}; + +struct undelete_args { + syscallarg(char *) path; +}; + +struct shmat_args { + syscallarg(int) shmid; + syscallarg(void *) shmaddr; + syscallarg(int) shmflg; +}; + +struct shmctl_args { + syscallarg(int) shmid; + syscallarg(int) cmd; + syscallarg(struct shmid_ds *) buf; +}; + +struct shmdt_args { + syscallarg(void *) shmaddr; +}; + +struct shmget_args { + syscallarg(key_t) key; + syscallarg(int) size; + syscallarg(int) shmflg; +}; + +#undef syscallarg diff --git a/sys/sys/sysctl.h b/sys/sys/sysctl.h index 4ad83a7..f196de2 100644 --- a/sys/sys/sysctl.h +++ b/sys/sys/sysctl.h @@ -33,7 +33,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)sysctl.h 8.1 (Berkeley) 6/2/93 + * @(#)sysctl.h 8.2 (Berkeley) 3/30/95 */ #ifndef _SYS_SYSCTL_H_ @@ -83,7 +83,7 @@ struct ctlname { #define CTL_UNSPEC 0 /* unused */ #define CTL_KERN 1 /* "high kernel": proc, limits */ #define CTL_VM 2 /* virtual memory */ -#define CTL_FS 3 /* file system, mount type is next */ +#define CTL_VFS 3 /* file system, mount type is next */ #define CTL_NET 4 /* network, see socket.h */ #define CTL_DEBUG 5 /* debugging parameters */ #define CTL_HW 6 /* generic cpu/io */ @@ -95,7 +95,7 @@ struct ctlname { { 0, 0 }, \ { "kern", CTLTYPE_NODE }, \ { "vm", CTLTYPE_NODE }, \ - { "fs", CTLTYPE_NODE }, \ + { "vfs", CTLTYPE_NODE }, \ { "net", CTLTYPE_NODE }, \ { "debug", CTLTYPE_NODE }, \ { "hw", CTLTYPE_NODE }, \ diff --git a/sys/sys/systm.h b/sys/sys/systm.h index 91cb64b..8760355 100644 --- a/sys/sys/systm.h +++ b/sys/sys/systm.h @@ -35,7 +35,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)systm.h 8.4 (Berkeley) 2/23/94 + * @(#)systm.h 8.7 (Berkeley) 3/29/95 */ /* @@ -92,9 +92,12 @@ extern dev_t swapdev; /* swapping device */ extern struct vnode *swapdev_vp;/* vnode equivalent to above */ extern struct sysent { /* system call table */ - int sy_narg; /* number of arguments */ + short sy_narg; /* number of args */ + short sy_argsize; /* total size of arguments */ int (*sy_call)(); /* implementing function */ } sysent[]; +extern int nsysent; +#define SCARG(p,k) ((p)->k.datum) /* get arg from args pointer */ extern int boothowto; /* reboot flags, from console subsystem */ @@ -110,8 +113,10 @@ int enodev __P((void)); int enoioctl __P((void)); int enxio __P((void)); int eopnotsupp __P((void)); +int einval __P((void)); int seltrue __P((dev_t dev, int which, struct proc *p)); void *hashinit __P((int count, int type, u_long *hashmask)); +int nosys __P((struct proc *, void *, register_t *)); #ifdef __GNUC__ volatile void panic __P((const char *, ...)); diff --git a/sys/sys/tablet.h b/sys/sys/tablet.h index cbb3f23..44cd43e 100644 --- a/sys/sys/tablet.h +++ b/sys/sys/tablet.h @@ -30,13 +30,12 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)tablet.h 8.3 (Berkeley) 1/4/94 + * @(#)tablet.h 8.4 (Berkeley) 7/10/94 */ #ifndef _SYS_TABLET_H_ #define _SYS_TABLET_H_ -/* * Tablet line discipline. */ #include @@ -49,25 +48,25 @@ * the information. */ struct tbpos { - int xpos, ypos; /* raw x-y coordinates */ - short status; /* buttons/pen down */ + int32_t xpos, ypos; /* raw x-y coordinates */ + int16_t status; /* buttons/pen down */ #define TBINPROX 0100000 /* pen in proximity of tablet */ - short scount; /* sample count */ + int16_t scount; /* sample count */ }; struct gtcopos { - int xpos, ypos; /* raw x-y coordinates */ - short status; /* as above */ - short scount; /* sample count */ - short xtilt, ytilt; /* raw tilt */ - short pressure; - short pad; /* pad to longword boundary */ + int32_t xpos, ypos; /* raw x-y coordinates */ + int16_t status; /* as above */ + int16_t scount; /* sample count */ + int16_t xtilt, ytilt; /* raw tilt */ + int16_t pressure; + int16_t pad; /* pad to longword boundary */ }; struct polpos { - short p_x, p_y, p_z; /* raw 3-space coordinates */ - short p_azi, p_pit, p_rol; /* azimuth, pitch, and roll */ - short p_stat; /* status, as above */ + int16_t p_x, p_y, p_z; /* raw 3-space coordinates */ + int16_t p_azi, p_pit, p_rol; /* azimuth, pitch, and roll */ + int16_t p_stat; /* status, as above */ char p_key; /* calculator input keyboard */ }; diff --git a/sys/sys/time.h b/sys/sys/time.h index 5322771..e069e6e 100644 --- a/sys/sys/time.h +++ b/sys/sys/time.h @@ -30,12 +30,14 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)time.h 8.1 (Berkeley) 6/2/93 + * @(#)time.h 8.5 (Berkeley) 5/4/95 */ #ifndef _SYS_TIME_H_ #define _SYS_TIME_H_ +#include + /* * Structure returned by gettimeofday(2) system call, * and used in other calls. @@ -49,7 +51,7 @@ struct timeval { * Structure defined by POSIX.4 to be like a timeval. */ struct timespec { - long ts_sec; /* seconds */ + time_t ts_sec; /* seconds */ long ts_nsec; /* and nanoseconds */ }; @@ -105,7 +107,11 @@ struct clockinfo { int profhz; /* profiling clock frequency */ }; -#ifndef KERNEL +#ifdef KERNEL +int itimerfix __P((struct timeval *tv)); +int itimerdecr __P((struct itimerval *itp, int usec)); +void microtime __P((struct timeval *tv)); +#else /* !KERNEL */ #include #ifndef _POSIX_SOURCE diff --git a/sys/sys/tty.h b/sys/sys/tty.h index 4a89b03..48383c2 100644 --- a/sys/sys/tty.h +++ b/sys/sys/tty.h @@ -35,7 +35,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)tty.h 8.6 (Berkeley) 1/21/94 + * @(#)tty.h 8.7 (Berkeley) 1/9/95 */ #include @@ -65,7 +65,7 @@ struct tty { long t_cancc; /* Canonical queue statistics. */ struct clist t_outq; /* Device output queue. */ long t_outcc; /* Output queue statistics. */ - char t_line; /* Interface to device drivers. */ + u_char t_line; /* Interface to device drivers. */ dev_t t_dev; /* Device. */ int t_state; /* Device and driver (TS*) state. */ int t_flags; /* Tty flags. */ @@ -188,7 +188,7 @@ int unputc __P((struct clist *q)); int nullmodem __P((struct tty *tp, int flag)); int tputchar __P((int c, struct tty *tp)); -int ttioctl __P((struct tty *tp, int com, void *data, int flag)); +int ttioctl __P((struct tty *tp, u_long com, void *data, int flag)); int ttread __P((struct tty *tp, struct uio *uio, int flag)); void ttrstrt __P((void *tp)); int ttselect __P((dev_t device, int rw, struct proc *p)); diff --git a/sys/sys/types.h b/sys/sys/types.h index 76d2975..576cac9 100644 --- a/sys/sys/types.h +++ b/sys/sys/types.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1982, 1986, 1991, 1993 + * Copyright (c) 1982, 1986, 1991, 1993, 1994 * The Regents of the University of California. All rights reserved. * (c) UNIX System Laboratories, Inc. * All or some portions of this file are derived from material licensed @@ -35,14 +35,15 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)types.h 8.4 (Berkeley) 1/21/94 + * @(#)types.h 8.6 (Berkeley) 2/19/95 */ #ifndef _SYS_TYPES_H_ #define _SYS_TYPES_H_ /* Machine type dependent parameters. */ -#include +#include +#include #ifndef _POSIX_SOURCE typedef unsigned char u_char; @@ -53,23 +54,24 @@ typedef unsigned short ushort; /* Sys V compatibility */ typedef unsigned int uint; /* Sys V compatibility */ #endif -typedef unsigned long long u_quad_t; /* quads */ -typedef long long quad_t; +typedef u_int64_t u_quad_t; /* quads */ +typedef int64_t quad_t; typedef quad_t * qaddr_t; typedef char * caddr_t; /* core address */ -typedef long daddr_t; /* disk address */ -typedef unsigned long dev_t; /* device number */ -typedef unsigned long fixpt_t; /* fixed point number */ -typedef unsigned long gid_t; /* group id */ -typedef unsigned long ino_t; /* inode number */ -typedef unsigned short mode_t; /* permissions */ -typedef unsigned short nlink_t; /* link count */ +typedef int32_t daddr_t; /* disk address */ +typedef u_int32_t dev_t; /* device number */ +typedef u_int32_t fixpt_t; /* fixed point number */ +typedef u_int32_t gid_t; /* group id */ +typedef u_int32_t ino_t; /* inode number */ +typedef long key_t; /* IPC key (for Sys V IPC) */ +typedef u_int16_t mode_t; /* permissions */ +typedef u_int16_t nlink_t; /* link count */ typedef quad_t off_t; /* file offset */ -typedef long pid_t; /* process id */ -typedef long segsz_t; /* segment size */ -typedef long swblk_t; /* swap offset */ -typedef unsigned long uid_t; /* user id */ +typedef int32_t pid_t; /* process id */ +typedef int32_t segsz_t; /* segment size */ +typedef int32_t swblk_t; /* swap offset */ +typedef u_int32_t uid_t; /* user id */ /* * This belongs in unistd.h, but is placed here to ensure that programs @@ -84,13 +86,13 @@ __END_DECLS #endif #ifndef _POSIX_SOURCE -#define major(x) ((int)(((u_int)(x) >> 8)&0xff)) /* major number */ -#define minor(x) ((int)((x)&0xff)) /* minor number */ -#define makedev(x,y) ((dev_t)(((x)<<8) | (y))) /* create dev_t */ + /* major number */ +#define major(x) ((int32_t)(((u_int32_t)(x) >> 8) & 0xff)) +#define minor(x) ((int32_t)((x) & 0xff)) /* minor number */ +#define makedev(x,y) ((dev_t)(((x) << 8) | (y))) /* create dev_t */ #endif -#include -#include +#include #ifdef _BSD_CLOCK_T_ typedef _BSD_CLOCK_T_ clock_t; @@ -125,11 +127,11 @@ typedef _BSD_TIME_T_ time_t; #define FD_SETSIZE 256 #endif -typedef long fd_mask; +typedef int32_t fd_mask; #define NFDBITS (sizeof(fd_mask) * NBBY) /* bits per mask */ #ifndef howmany -#define howmany(x, y) (((x)+((y)-1))/(y)) +#define howmany(x, y) (((x) + ((y) - 1)) / (y)) #endif typedef struct fd_set { diff --git a/sys/sys/ucred.h b/sys/sys/ucred.h index d3ee02d..8998517 100644 --- a/sys/sys/ucred.h +++ b/sys/sys/ucred.h @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)ucred.h 8.2 (Berkeley) 1/4/94 + * @(#)ucred.h 8.4 (Berkeley) 1/9/95 */ #ifndef _SYS_UCRED_H_ @@ -46,14 +46,17 @@ struct ucred { gid_t cr_groups[NGROUPS]; /* groups */ }; #define cr_gid cr_groups[0] -#define NOCRED ((struct ucred *)-1) /* no credential available */ -#define FSCRED ((struct ucred *)-2) /* filesystem credential */ +#define NOCRED ((struct ucred *)0) /* no credential available */ +#define FSCRED ((struct ucred *)-1) /* filesystem credential */ #ifdef KERNEL #define crhold(cr) (cr)->cr_ref++ -struct ucred *crget(); -struct ucred *crcopy(); -struct ucred *crdup(); + +struct ucred *crcopy __P((struct ucred *cr)); +struct ucred *crdup __P((struct ucred *cr)); +void crfree __P((struct ucred *cr)); +struct ucred *crget __P((void)); +int suser __P((struct ucred *cred, u_short *acflag)); #endif /* KERNEL */ #endif /* !_SYS_UCRED_H_ */ diff --git a/sys/sys/un.h b/sys/sys/un.h index 3e214a2..b872b99 100644 --- a/sys/sys/un.h +++ b/sys/sys/un.h @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)un.h 8.1 (Berkeley) 6/2/93 + * @(#)un.h 8.3 (Berkeley) 2/19/95 */ /* @@ -43,10 +43,25 @@ struct sockaddr_un { }; #ifdef KERNEL -int unp_discard(); -#else +struct unpcb; + +int uipc_usrreq __P((struct socket *so, int req, struct mbuf *m, + struct mbuf *nam, struct mbuf *control)); +int unp_attach __P((struct socket *so)); +int unp_bind __P((struct unpcb *unp, struct mbuf *nam, struct proc *p)); +int unp_connect __P((struct socket *so, struct mbuf *nam, struct proc *p)); +int unp_connect2 __P((struct socket *so, struct socket *so2)); +void unp_detach __P((struct unpcb *unp)); +void unp_discard __P((struct file *fp)); +void unp_disconnect __P((struct unpcb *unp)); +void unp_drop __P((struct unpcb *unp, int errno)); +void unp_gc __P((void)); +void unp_mark __P((struct file *fp)); +void unp_scan __P((struct mbuf *m0, void (*op) __P((struct file *)))); +void unp_shutdown __P((struct unpcb *unp)); +#else /* !KERNEL */ /* actual length of an initialized sockaddr_un */ #define SUN_LEN(su) \ (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path)) -#endif +#endif /* KERNEL */ diff --git a/sys/sys/vmmeter.h b/sys/sys/vmmeter.h index f0b3d57..bcf95ff 100644 --- a/sys/sys/vmmeter.h +++ b/sys/sys/vmmeter.h @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)vmmeter.h 8.1 (Berkeley) 6/2/93 + * @(#)vmmeter.h 8.2 (Berkeley) 7/10/94 */ /* @@ -40,47 +40,47 @@ struct vmmeter { /* * General system activity. */ - unsigned v_swtch; /* context switches */ - unsigned v_trap; /* calls to trap */ - unsigned v_syscall; /* calls to syscall() */ - unsigned v_intr; /* device interrupts */ - unsigned v_soft; /* software interrupts */ - unsigned v_faults; /* total faults taken */ + u_int v_swtch; /* context switches */ + u_int v_trap; /* calls to trap */ + u_int v_syscall; /* calls to syscall() */ + u_int v_intr; /* device interrupts */ + u_int v_soft; /* software interrupts */ + u_int v_faults; /* total faults taken */ /* * Virtual memory activity. */ - unsigned v_lookups; /* object cache lookups */ - unsigned v_hits; /* object cache hits */ - unsigned v_vm_faults; /* number of address memory faults */ - unsigned v_cow_faults; /* number of copy-on-writes */ - unsigned v_swpin; /* swapins */ - unsigned v_swpout; /* swapouts */ - unsigned v_pswpin; /* pages swapped in */ - unsigned v_pswpout; /* pages swapped out */ - unsigned v_pageins; /* number of pageins */ - unsigned v_pageouts; /* number of pageouts */ - unsigned v_pgpgin; /* pages paged in */ - unsigned v_pgpgout; /* pages paged out */ - unsigned v_intrans; /* intransit blocking page faults */ - unsigned v_reactivated; /* number of pages reactivated from free list */ - unsigned v_rev; /* revolutions of the hand */ - unsigned v_scan; /* scans in page out daemon */ - unsigned v_dfree; /* pages freed by daemon */ - unsigned v_pfree; /* pages freed by exiting processes */ - unsigned v_zfod; /* pages zero filled on demand */ - unsigned v_nzfod; /* number of zfod's created */ + u_int v_lookups; /* object cache lookups */ + u_int v_hits; /* object cache hits */ + u_int v_vm_faults; /* number of address memory faults */ + u_int v_cow_faults; /* number of copy-on-writes */ + u_int v_swpin; /* swapins */ + u_int v_swpout; /* swapouts */ + u_int v_pswpin; /* pages swapped in */ + u_int v_pswpout; /* pages swapped out */ + u_int v_pageins; /* number of pageins */ + u_int v_pageouts; /* number of pageouts */ + u_int v_pgpgin; /* pages paged in */ + u_int v_pgpgout; /* pages paged out */ + u_int v_intrans; /* intransit blocking page faults */ + u_int v_reactivated; /* number of pages reactivated from free list */ + u_int v_rev; /* revolutions of the hand */ + u_int v_scan; /* scans in page out daemon */ + u_int v_dfree; /* pages freed by daemon */ + u_int v_pfree; /* pages freed by exiting processes */ + u_int v_zfod; /* pages zero filled on demand */ + u_int v_nzfod; /* number of zfod's created */ /* * Distribution of page usages. */ - unsigned v_page_size; /* page size in bytes */ - unsigned v_kernel_pages;/* number of pages in use by kernel */ - unsigned v_free_target; /* number of pages desired free */ - unsigned v_free_min; /* minimum number of pages desired free */ - unsigned v_free_count; /* number of pages free */ - unsigned v_wire_count; /* number of pages wired down */ - unsigned v_active_count;/* number of pages active */ - unsigned v_inactive_target; /* number of pages desired inactive */ - unsigned v_inactive_count; /* number of pages inactive */ + u_int v_page_size; /* page size in bytes */ + u_int v_kernel_pages; /* number of pages in use by kernel */ + u_int v_free_target; /* number of pages desired free */ + u_int v_free_min; /* minimum number of pages desired free */ + u_int v_free_count; /* number of pages free */ + u_int v_wire_count; /* number of pages wired down */ + u_int v_active_count; /* number of pages active */ + u_int v_inactive_target; /* number of pages desired inactive */ + u_int v_inactive_count; /* number of pages inactive */ }; #ifdef KERNEL struct vmmeter cnt; @@ -89,20 +89,20 @@ struct vmmeter cnt; /* systemwide totals computed every five seconds */ struct vmtotal { - short t_rq; /* length of the run queue */ - short t_dw; /* jobs in ``disk wait'' (neg priority) */ - short t_pw; /* jobs in page wait */ - short t_sl; /* jobs sleeping in core */ - short t_sw; /* swapped out runnable/short block jobs */ - long t_vm; /* total virtual memory */ - long t_avm; /* active virtual memory */ - long t_rm; /* total real memory in use */ - long t_arm; /* active real memory */ - long t_vmshr; /* shared virtual memory */ - long t_avmshr; /* active shared virtual memory */ - long t_rmshr; /* shared real memory */ - long t_armshr; /* active shared real memory */ - long t_free; /* free memory pages */ + int16_t t_rq; /* length of the run queue */ + int16_t t_dw; /* jobs in ``disk wait'' (neg priority) */ + int16_t t_pw; /* jobs in page wait */ + int16_t t_sl; /* jobs sleeping in core */ + int16_t t_sw; /* swapped out runnable/short block jobs */ + int32_t t_vm; /* total virtual memory */ + int32_t t_avm; /* active virtual memory */ + int32_t t_rm; /* total real memory in use */ + int32_t t_arm; /* active real memory */ + int32_t t_vmshr; /* shared virtual memory */ + int32_t t_avmshr; /* active shared virtual memory */ + int32_t t_rmshr; /* shared real memory */ + int32_t t_armshr; /* active shared real memory */ + int32_t t_free; /* free memory pages */ }; #ifdef KERNEL struct vmtotal total; @@ -128,20 +128,20 @@ struct vmtotal total; #define NRMON 64 /* data and stack size distribution counters */ -unsigned int dmon[NDMON+1]; -unsigned int smon[NSMON+1]; +u_int dmon[NDMON+1]; +u_int smon[NSMON+1]; /* page in time distribution counters */ -unsigned int pmon[NPMON+2]; +u_int pmon[NPMON+2]; /* reclaim time distribution counters */ -unsigned int rmon[NRMON+2]; +u_int rmon[NRMON+2]; int pmonmin; int pres; int rmonmin; int rres; -unsigned rectime; /* accumulator for reclaim times */ -unsigned pgintime; /* accumulator for page in times */ +u_int rectime; /* accumulator for reclaim times */ +u_int pgintime; /* accumulator for page in times */ #endif diff --git a/sys/sys/vnioctl.h b/sys/sys/vnioctl.h index ace82ee..2bd82a1 100644 --- a/sys/sys/vnioctl.h +++ b/sys/sys/vnioctl.h @@ -44,7 +44,7 @@ * Ioctl definitions for file (vnode) disk pseudo-device. */ -#define _PATH_VNTAB "/etc/vntab" /* default config file */ +#define FDISKFILE "/etc/fdisks" /* default config file */ struct vn_ioctl { char *vn_file; /* pathname of file to mount */ diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h index fa51d99..a5cd4ce 100644 --- a/sys/sys/vnode.h +++ b/sys/sys/vnode.h @@ -30,9 +30,10 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)vnode.h 8.7 (Berkeley) 2/4/94 + * @(#)vnode.h 8.17 (Berkeley) 5/20/95 */ +#include #include /* @@ -63,6 +64,13 @@ enum vtagtype { */ LIST_HEAD(buflists, buf); +/* + * Reading or writing any of these items requires holding the appropriate lock. + * v_freelist is locked by the global vnode_free_list simple lock. + * v_mntvnodes is locked by the global mntvnodes simple lock. + * v_flag, v_usecount, v_holdcount and v_writecount are + * locked by the v_interlock simple lock. + */ struct vnode { u_long v_flag; /* vnode flags (see below) */ short v_usecount; /* reference count of users */ @@ -92,7 +100,9 @@ struct vnode { int v_clen; /* length of current cluster */ int v_ralen; /* Read-ahead length */ daddr_t v_maxra; /* last readahead block */ - long v_spare[7]; /* round to 128 bytes */ + struct simplelock v_interlock; /* lock on usecount and flag */ + struct lock *v_vnlock; /* used for non-locking fs's */ + long v_spare[5]; /* round to 128 bytes */ enum vtagtype v_tag; /* type of underlying data */ void *v_data; /* private data for fs */ }; @@ -108,6 +118,7 @@ struct vnode { #define VROOT 0x0001 /* root of its file system */ #define VTEXT 0x0002 /* vnode is a pure text prototype */ #define VSYSTEM 0x0004 /* vnode being used by kernel */ +#define VISTTY 0x0008 /* vnode represents a tty */ #define VXLOCK 0x0100 /* vnode is locked to change underlying type */ #define VXWANT 0x0200 /* process is waiting for vnode */ #define VBWAIT 0x0400 /* waiting for output to complete */ @@ -141,9 +152,10 @@ struct vattr { }; /* - * Flags for va_cflags. + * Flags for va_vaflags. */ #define VA_UTIMES_NULL 0x01 /* utimes argument was NULL */ +#define VA_EXCLUSIVE 0x02 /* exclusive create request */ /* * Flags for ioflag. @@ -189,6 +201,7 @@ extern int vttoif_tab[]; #define DOCLOSE 0x0008 /* vclean: close active files */ #define V_SAVE 0x0001 /* vinvalbuf: sync file first */ #define V_SAVEMETA 0x0002 /* vinvalbuf: leave indirect blocks */ +#define REVOKEALL 0x0001 /* vop_revoke: revoke all aliases */ #ifdef DIAGNOSTIC #define HOLDRELE(vp) holdrele(vp) @@ -201,11 +214,32 @@ void vattr_null __P((struct vattr *)); void vhold __P((struct vnode *)); void vref __P((struct vnode *)); #else -#define HOLDRELE(vp) (vp)->v_holdcnt-- /* decrease buf or page ref */ #define VATTR_NULL(vap) (*(vap) = va_null) /* initialize a vattr */ -#define VHOLD(vp) (vp)->v_holdcnt++ /* increase buf or page ref */ -#define VREF(vp) (vp)->v_usecount++ /* increase reference */ -#endif +#define HOLDRELE(vp) holdrele(vp) /* decrease buf or page ref */ +static __inline holdrele(vp) + struct vnode *vp; +{ + simple_lock(&vp->v_interlock); + vp->v_holdcnt--; + simple_unlock(&vp->v_interlock); +} +#define VHOLD(vp) vhold(vp) /* increase buf or page ref */ +static __inline vhold(vp) + struct vnode *vp; +{ + simple_lock(&vp->v_interlock); + vp->v_holdcnt++; + simple_unlock(&vp->v_interlock); +} +#define VREF(vp) vref(vp) /* increase reference */ +static __inline vref(vp) + struct vnode *vp; +{ + simple_lock(&vp->v_interlock); + vp->v_usecount++; + simple_unlock(&vp->v_interlock); +} +#endif /* DIAGNOSTIC */ #define NULLVP ((struct vnode *)NULL) @@ -222,16 +256,6 @@ extern struct vattr va_null; /* predefined null vattr structure */ #define LEASE_READ 0x1 /* Check lease for readers */ #define LEASE_WRITE 0x2 /* Check lease for modifiers */ -#ifdef NFS -void lease_check __P((struct vnode *vp, struct proc *p, - struct ucred *ucred, int flag)); -void lease_updatetime __P((int deltat)); -#define LEASE_CHECK(vp, p, cred, flag) lease_check((vp), (p), (cred), (flag)) -#define LEASE_UPDATETIME(dt) lease_updatetime(dt) -#else -#define LEASE_CHECK(vp, p, cred, flag) -#define LEASE_UPDATETIME(dt) -#endif /* NFS */ #endif /* KERNEL */ @@ -290,6 +314,10 @@ struct vnodeop_desc { */ extern struct vnodeop_desc *vnodeop_descs[]; +/* + * Interlock for scanning list of vnodes attached to a mountpoint + */ +struct simplelock mntvnode_slock; /* * This macro is very helpful in defining those offsets in the vdesc struct. @@ -358,6 +386,7 @@ struct vop_generic_args { struct file; struct mount; struct nameidata; +struct ostat; struct proc; struct stat; struct ucred; @@ -367,20 +396,27 @@ struct vnode; struct vop_bwrite_args; int bdevvp __P((dev_t dev, struct vnode **vpp)); +void cvtstat __P((struct stat *st, struct ostat *ost)); int getnewvnode __P((enum vtagtype tag, struct mount *mp, int (**vops)(), struct vnode **vpp)); -int vinvalbuf __P((struct vnode *vp, int save, struct ucred *cred, - struct proc *p, int slpflag, int slptimeo)); +void insmntque __P((struct vnode *vp, struct mount *mp)); void vattr_null __P((struct vattr *vap)); int vcount __P((struct vnode *vp)); -int vget __P((struct vnode *vp, int lockflag)); +int vflush __P((struct mount *mp, struct vnode *skipvp, int flags)); +int vget __P((struct vnode *vp, int lockflag, struct proc *p)); void vgone __P((struct vnode *vp)); -void vgoneall __P((struct vnode *vp)); +int vinvalbuf __P((struct vnode *vp, int save, struct ucred *cred, + struct proc *p, int slpflag, int slptimeo)); +void vprint __P((char *label, struct vnode *vp)); +int vrecycle __P((struct vnode *vp, struct simplelock *inter_lkp, + struct proc *p)); int vn_bwrite __P((struct vop_bwrite_args *ap)); int vn_close __P((struct vnode *vp, int flags, struct ucred *cred, struct proc *p)); int vn_closefile __P((struct file *fp, struct proc *p)); -int vn_ioctl __P((struct file *fp, int com, caddr_t data, struct proc *p)); +int vn_ioctl __P((struct file *fp, u_long com, caddr_t data, + struct proc *p)); +int vn_lock __P((struct vnode *vp, int flags, struct proc *p)); int vn_open __P((struct nameidata *ndp, int fmode, int cmode)); int vn_rdwr __P((enum uio_rw rw, struct vnode *vp, caddr_t base, int len, off_t offset, enum uio_seg segflg, int ioflg, @@ -389,6 +425,10 @@ int vn_read __P((struct file *fp, struct uio *uio, struct ucred *cred)); int vn_select __P((struct file *fp, int which, struct proc *p)); int vn_stat __P((struct vnode *vp, struct stat *sb, struct proc *p)); int vn_write __P((struct file *fp, struct uio *uio, struct ucred *cred)); +int vop_noislocked __P((struct vop_islocked_args *)); +int vop_nolock __P((struct vop_lock_args *)); +int vop_nounlock __P((struct vop_unlock_args *)); +int vop_revoke __P((struct vop_revoke_args *)); struct vnode * checkalias __P((struct vnode *vp, dev_t nvp_rdev, struct mount *mp)); void vput __P((struct vnode *vp)); diff --git a/sys/sys/wait.h b/sys/sys/wait.h index 33a68d9..172c0a9 100644 --- a/sys/sys/wait.h +++ b/sys/sys/wait.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1982, 1986, 1989, 1993 + * Copyright (c) 1982, 1986, 1989, 1993, 1994 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)wait.h 8.1 (Berkeley) 6/2/93 + * @(#)wait.h 8.2 (Berkeley) 7/10/94 */ /* @@ -73,7 +73,7 @@ * this option is done, it is as though they were still running... nothing * about them is returned. */ -#define WNOHANG 1 /* dont hang in wait */ +#define WNOHANG 1 /* don't hang in wait */ #define WUNTRACED 2 /* tell about stopped, untraced children */ #ifndef _POSIX_SOURCE -- cgit v1.1