From b761211fff76eb7b7a4c61fef0ab22c7f1837821 Mon Sep 17 00:00:00 2001 From: patacongo Date: Sat, 17 Mar 2012 00:25:34 +0000 Subject: [PATCH] NFS update; fix STM32 enabling of CAN2 clock git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@4494 42af7a65-404d-4744-a932-0658087f49c3 --- fs/nfs/Make.defs | 2 +- fs/nfs/nfs.h | 360 ++++++++++ fs/nfs/nfs_proto.h | 454 +++++++++++++ fs/nfs/nfs_socket.c | 230 +++++++ fs/nfs/nfs_socket.h | 69 ++ fs/nfs/nfsmount.h | 106 +++ fs/nfs/rpc.h | 243 +++++-- fs/nfs/rpc_clnt.c | 1306 +++++++++++++++++++++++++++++++++++++ fs/nfs/rpc_clnt_private.h | 129 ++++ fs/nfs/rpc_idgen.h | 69 -- fs/nfs/rpc_mbuf.h | 449 ------------- fs/nfs/rpc_subr.c | 456 ------------- fs/nfs/rpc_types.h | 44 +- fs/nfs/xdr_subs.h | 8 +- 14 files changed, 2876 insertions(+), 1049 deletions(-) create mode 100644 fs/nfs/nfs.h create mode 100644 fs/nfs/nfs_proto.h create mode 100644 fs/nfs/nfs_socket.c create mode 100644 fs/nfs/nfs_socket.h create mode 100644 fs/nfs/nfsmount.h create mode 100644 fs/nfs/rpc_clnt.c create mode 100644 fs/nfs/rpc_clnt_private.h delete mode 100644 fs/nfs/rpc_idgen.h delete mode 100644 fs/nfs/rpc_mbuf.h delete mode 100644 fs/nfs/rpc_subr.c diff --git a/fs/nfs/Make.defs b/fs/nfs/Make.defs index c0a19e8b29..be633c1fa8 100644 --- a/fs/nfs/Make.defs +++ b/fs/nfs/Make.defs @@ -42,7 +42,7 @@ CSRCS += # Files required for NFS RPC ASRCS += -CSRCS += rpc_subr.c +CSRCS += rpc_clnt.c # Argument for dependency checking diff --git a/fs/nfs/nfs.h b/fs/nfs/nfs.h new file mode 100644 index 0000000000..a5092e07ae --- /dev/null +++ b/fs/nfs/nfs.h @@ -0,0 +1,360 @@ +/* + * Copyright (c) 1989, 1993, 1995 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Rick Macklem at The University of Guelph. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)nfs.h 8.4 (Berkeley) 5/1/95 + */ + +#ifndef _NFS_NFS_H_ +#define _NFS_NFS_H_ + +#define NFS_TICKINTVL 5 /* Desired time for a tick (msec) */ +#define NFS_HZ (CLOCKS_PER_SEC / 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_TIMEOUTMUL 2 /* Timeout/Delay multiplier */ +#define NFS_MAXREXMIT 100 /* Stop counting after this many */ +#define NFS_RETRANS 10 /* Num of retrans for soft mounts */ +#define NFS_MAXGRPS 16 /* Max. size of groups list */ +#define NFS_MINATTRTIMO 5 /* Attribute cache timeout in sec */ +#define NFS_MAXATTRTIMO 60 +#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_MAXASYNCDAEMON 20 /* Max. number async_daemons runable */ + +/* Ideally, NFS_DIRBLKSIZ should be bigger, but I've seen servers with + * broken NFS/ethernet drivers that won't work with anything bigger (Linux..) + */ + +#define NFS_DIRBLKSIZ 1024 /* Must be a multiple of DIRBLKSIZ */ +#define NFS_READDIRBLKSIZ 512 /* Size of read dir blocks. XXX */ + +/* + * Oddballs + */ + +#define NFS_CMPFH(n, f, s) \ + ((n)->n_fhsize == (s) && !bcmp((void *)(n)->n_fhp, (void *)(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) + +/* + * sys/malloc.h needs M_NFSDIROFF, M_NFSRVDESC and M_NFSBIGFH added. + */ + +#ifndef M_NFSRVDESC +# define M_NFSRVDESC M_TEMP +#endif +#ifndef M_NFSDIROFF +# define M_NFSDIROFF M_TEMP +#endif +#ifndef M_NFSBIGFH +# define M_NFSBIGFH M_TEMP +#endif + +/* + * 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 + +/* + * Structures for the nfssvc(2) syscall. + * Not that anyone besides nfsd(8) should ever use it. + */ + +struct nfsd_args +{ + int sock; /* Socket to serve */ + void *name; /* Client addr for connection based sockets */ + int namelen; /* Length of name */ +}; + +struct nfsd_srvargs +{ + struct nfsd *nsd_nfsd; /* Pointer to in kernel nfsd struct */ + uid_t nsd_uid; /* Effective uid mapped to cred */ + uint32_t nsd_haddr; /* IP address of client */ + int nsd_authlen; /* Length of auth string (ret) */ + unsigned char *nsd_authstr; /* Auth string (ret) */ + int nsd_verflen; /* and the verifier */ + unsigned char *nsd_verfstr; + struct timeval nsd_timestamp; /* timestamp from verifier */ + uint32_t nsd_ttl; /* credential ttl (sec) */ +}; + +/* + * Stats structure + */ + +struct nfsstats +{ + uint64_t attrcache_hits; + uint64_t attrcache_misses; + uint64_t lookupcache_hits; + uint64_t lookupcache_misses; + uint64_t direofcache_hits; + uint64_t direofcache_misses; + uint64_t biocache_reads; + uint64_t read_bios; + uint64_t read_physios; + uint64_t biocache_writes; + uint64_t write_bios; + uint64_t write_physios; + uint64_t biocache_readlinks; + uint64_t readlink_bios; + uint64_t biocache_readdirs; + uint64_t readdir_bios; + uint64_t rpccnt[NFS_NPROCS]; + uint64_t rpcretries; + uint64_t srvrpccnt[NFS_NPROCS]; + uint64_t srvrpc_errs; + uint64_t srv_errs; + uint64_t rpcrequests; + uint64_t rpctimeouts; + uint64_t rpcunexpected; + uint64_t rpcinvalid; + uint64_t srvcache_inproghits; + uint64_t srvcache_idemdonehits; + uint64_t srvcache_nonidemdonehits; + uint64_t srvcache_misses; + uint64_t forcedsync; + uint64_t srvnqnfs_leases; + uint64_t srvnqnfs_maxleases; + uint64_t srvnqnfs_getleases; + uint64_t srvvop_writes; +}; + +/* + * Flags for nfssvc() system call. + */ + +#define NFSSVC_BIOD 0x002 +#define NFSSVC_NFSD 0x004 +#define NFSSVC_ADDSOCK 0x008 +#define NFSSVC_AUTHIN 0x010 +#define NFSSVC_GOTAUTH 0x040 +#define NFSSVC_AUTHINFAIL 0x080 +#define NFSSVC_MNTD 0x100 + +/* + * fs.nfs sysctl(3) identifiers + */ + +#define NFS_NFSSTATS 1 /* struct: struct nfsstats */ +#define NFS_NIOTHREADS 2 /* number of i/o threads */ +#define NFS_MAXID 3 + +#define FS_NFS_NAMES { \ + { 0, 0 }, \ + { "nfsstats", CTLTYPE_STRUCT }, \ + { "iothreads", CTLTYPE_INT } \ +} + +/* + * 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 + * be minimal. My reasoning is that many current programs that use signals + * such as SIGALRM will not expect file I/O system calls to be interrupted + * by them and break. + */ + +#ifdef _KERNEL +extern int nfs_niothreads; + +struct uio; +struct buf; +struct vattr; +struct nameidata; /* XXX */ + +#define NFSINT_SIGMASK (sigmask(SIGINT)|sigmask(SIGTERM)|sigmask(SIGKILL)| \ + sigmask(SIGHUP)|sigmask(SIGQUIT)) + +/* + * Socket errors ignored for connectionless sockets?? + * For now, ignore them all + */ + +#define NFSIGNORE_SOERROR(s, e) \ + ((e) != EINTR && (e) != ERESTART && (e) != EWOULDBLOCK && \ + ((s) & PR_CONNREQUIRED) == 0) + +/* + * Nfs outstanding request list element + */ + +struct nfsreq +{ + dq_entry_t r_chain; + void *r_dpos; + struct nfsmount *r_nmp; + uint32_t r_xid; + int r_flags; /* flags on request, see below */ + int r_rexmit; /* current retrans count */ + int r_timer; /* tick counter on reply */ + int r_procnum; /* NFS procedure number */ + int r_rtt; /* RTT for rpc */ +}; + +/* Flag values for r_flags */ + +#define R_TIMING 0x01/* timing request (in mntp) */ +#define R_SENT 0x02/* request has been sent */ +#define R_SOFTTERM 0x04/* soft mnt, too many retries */ +#define R_INTR 0x08/* intr mnt, signal pending */ +#define R_SOCKERR 0x10/* Fatal error on socket */ +#define R_TPRINTFMSG 0x20/* Did a tprintf msg. */ +#define R_MUSTRESEND 0x40/* Must resend request */ + +/* + * On fast networks, the estimator will try to reduce the + * timeout lower than the latency of the server's disks, + * which results in too many timeouts, so cap the lower + * bound. + */ + +#define NFS_MINRTO (NFS_HZ >> 2) + +/* + * Keep the RTO from increasing to unreasonably large values + * when a server is not responding. + */ +#define NFS_MAXRTO (20 * NFS_HZ) + +enum nfs_rto_timers +{ + NFS_DEFAULT_TIMER, + NFS_GETATTR_TIMER, + NFS_LOOKUP_TIMER, + NFS_READ_TIMER, + NFS_WRITE_TIMER, +}; + +#define NFS_MAX_TIMER (NFS_WRITE_TIMER) +#define NFS_INITRTT (NFS_HZ << 3) + +/* + * Network address hash list element + */ + +union nethostaddr +{ + u_int32_t had_inetaddr; + struct mbuf *had_nam; +}; + +struct nfssvc_sock +{ + TAILQ_ENTRY(nfssvc_sock) ns_chain; /* List of all nfssvc_sock's */ + struct file *ns_fp; /* fp from the... */ + struct socket *ns_so; /* ...socket this struct wraps */ + struct mbuf *ns_nam; /* MT_SONAME of client */ + struct mbuf *ns_raw; /* head of unpeeked mbufs */ + struct mbuf *ns_rawend; /* tail of unpeeked mbufs */ + struct mbuf *ns_rec; /* queued RPC records */ + struct mbuf *ns_recend; /* last queued RPC record */ + struct mbuf *ns_frag; /* end of record fragment */ + int ns_flag; /* socket status flags */ + int ns_solock; /* lock for connected socket */ + int ns_cc; /* actual chars queued */ + int ns_reclen; /* length of first queued record */ + u_int32_t ns_sref; /* # of refs to this struct */ +}; + +/* Bits for "ns_flag" */ + +#define SLP_VALID 0x01/* connection is usable */ +#define SLP_DOREC 0x02/* receive operation required */ +#define SLP_NEEDQ 0x04/* connection has data to queue from socket */ +#define SLP_DISCONN 0x08/* connection is closed */ +#define SLP_GETSTREAM 0x10/* extracting RPC from TCP connection */ +#define SLP_LASTFRAG 0x20/* last fragment received on TCP connection */ +#define SLP_ALLFLAGS 0xff/* convenience */ + +extern TAILQ_HEAD(nfssvc_sockhead, nfssvc_sock) nfssvc_sockhead; +extern int nfssvc_sockhead_flag; + +#define SLP_INIT 0x01/* NFS data undergoing initialization */ +#define SLP_WANTINIT 0x02/* thread waiting on NFS initialization */ + +/* + * One of these structures is allocated for each nfsd. + */ + +struct nfsd +{ + TAILQ_ENTRY(nfsd) nfsd_chain; /* List of all nfsd's */ + int nfsd_flag; /* NFSD_ flags */ + struct nfssvc_sock *nfsd_slp; /* Current socket */ + struct nfsrv_descript *nfsd_nd; /* Associated nfsrv_descript */ +}; + +/* Bits for "nfsd_flag" */ + +#define NFSD_WAITING 0x01 +#define NFSD_REQINPROG 0x02 +#define NFSD_NEEDAUTH 0x04 +#define NFSD_AUTHFAIL 0x08 + +/* + * This structure is used by the server for describing each request. + */ + +struct nfsrv_descript +{ + unsigned int nd_procnum; /* RPC # */ + int nd_flag; /* nd_flag */ + int nd_repstat; /* Reply status */ + u_int32_t nd_retxid; /* Reply xid */ +}; + +/* Bits for "nd_flag" */ + +#define ND_NFSV3 0x08 + +extern struct pool nfsreqpl; +extern struct pool nfs_node_pool; +extern TAILQ_HEAD(nfsdhead, nfsd) nfsd_head; +extern int nfsd_head_flag; + +#define NFSD_CHECKSLP 0x01 + +#endif /* _KERNEL */ +#endif /* _NFS_NFS_H */ diff --git a/fs/nfs/nfs_proto.h b/fs/nfs/nfs_proto.h new file mode 100644 index 0000000000..f53ace79e3 --- /dev/null +++ b/fs/nfs/nfs_proto.h @@ -0,0 +1,454 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Rick Macklem at The University of Guelph. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _NFS_NFSPROTO_H_ +#define _NFS_NFSPROTO_H_ + +/* + * Constants as defined in the Sun NFS Version 2 and 3 specs. + * "NFS: Network File System Protocol Specification" RFC1094 + * and in the "NFS: Network File System Version 3 Protocol + * Specification" + */ + +#define NFS_PORT 2049 +#define NFS_PROG 100003 +#define NFS_VER2 2 +#define NFS_VER3 3 +#define NFS_VER4 4 +#define NFS_V2MAXDATA 8192 +#define NFS_MAXDGRAMDATA 32768 +#define NFS_MAXDATA MAXBSIZE +#define NFS_MAXPATHLEN 1024 +#define NFS_MAXNAMLEN 255 +#define NFS_MAXPKTHDR 404 +#define NFS_MAXPACKET (NFS_MAXPKTHDR + NFS_MAXDATA) +#define NFS_MINPACKET 20 +#define NFS_FABLKSIZE 512 /* Size in bytes of a block wrt fa_blocks */ + +/* Stat numbers for rpc returns (version 2 and 3) */ + +#define NFS_OK 0 +#define NFSERR_PERM 1 +#define NFSERR_NOENT 2 +#define NFSERR_IO 5 +#define NFSERR_NXIO 6 +#define NFSERR_ACCES 13 +#define NFSERR_EXIST 17 +#define NFSERR_XDEV 18 /* Version 3 only */ +#define NFSERR_NODEV 19 +#define NFSERR_NOTDIR 20 +#define NFSERR_ISDIR 21 +#define NFSERR_INVAL 22 /* Version 3 only */ +#define NFSERR_FBIG 27 +#define NFSERR_NOSPC 28 +#define NFSERR_ROFS 30 +#define NFSERR_MLINK 31 /* Version 3 only */ +#define NFSERR_NAMETOL 63 +#define NFSERR_NOTEMPTY 66 +#define NFSERR_DQUOT 69 +#define NFSERR_STALE 70 +#define NFSERR_REMOTE 71 /* Version 3 only */ +#define NFSERR_WFLUSH 99 /* Version 2 only */ +#define NFSERR_BADHANDLE 10001 /* The rest Version 3 only */ +#define NFSERR_NOT_SYNC 10002 +#define NFSERR_BAD_COOKIE 10003 +#define NFSERR_NOTSUPP 10004 +#define NFSERR_TOOSMALL 10005 +#define NFSERR_SERVERFAULT 10006 +#define NFSERR_BADTYPE 10007 +#define NFSERR_JUKEBOX 10008 +#define NFSERR_TRYLATER NFSERR_JUKEBOX +#define NFSERR_STALEWRITEVERF 30001 /* Fake return for nfs_commit() */ + +#define NFSERR_RETVOID 0x20000000 /* Return void, not error */ +#define NFSERR_AUTHERR 0x40000000 /* Mark an authentication error + */ +#define NFSERR_RETERR 0x80000000 /* Mark an error return for V3 */ + +/* Sizes in bytes of various nfs rpc components */ + +#define NFSX_UNSIGNED 4 + +/* specific to NFS Version 2 */ + +#define NFSX_V2FH 32 +#define NFSX_V2FATTR 68 +#define NFSX_V2SATTR 32 +#define NFSX_V2COOKIE 4 +#define NFSX_V2STATFS 20 + +/* specific to NFS Version 3 */ + +#define NFSX_V3FH (sizeof (fhandle_t)) /* size this server uses */ +#define NFSX_V3FHMAX 64 /* max. allowed by protocol */ +#define NFSX_V3FATTR 84 +#define NFSX_V3SATTR 60 /* max. all fields filled in */ +#define NFSX_V3SRVSATTR (sizeof (struct nfsv3_sattr)) +#define NFSX_V3POSTOPATTR (NFSX_V3FATTR + NFSX_UNSIGNED) +#define NFSX_V3WCCDATA (NFSX_V3POSTOPATTR + 8 * NFSX_UNSIGNED) +#define NFSX_V3COOKIEVERF 8 +#define NFSX_V3WRITEVERF 8 +#define NFSX_V3CREATEVERF 8 +#define NFSX_V3STATFS 52 +#define NFSX_V3FSINFO 48 +#define NFSX_V3PATHCONF 24 + +/* variants for both versions */ +#define NFSX_FH(v3) ((v3) ? (NFSX_V3FHMAX + NFSX_UNSIGNED) : \ + NFSX_V2FH) +#define NFSX_SRVFH(v3) ((v3) ? NFSX_V3FH : NFSX_V2FH) +#define NFSX_FATTR(v3) ((v3) ? NFSX_V3FATTR : NFSX_V2FATTR) +#define NFSX_PREOPATTR(v3) ((v3) ? (7 * NFSX_UNSIGNED) : 0) +#define NFSX_POSTOPATTR(v3) ((v3) ? (NFSX_V3FATTR + NFSX_UNSIGNED) : 0) +#define NFSX_POSTOPORFATTR(v3) ((v3) ? (NFSX_V3FATTR + NFSX_UNSIGNED) : \ + NFSX_V2FATTR) +#define NFSX_WCCDATA(v3) ((v3) ? NFSX_V3WCCDATA : 0) +#define NFSX_WCCORFATTR(v3) ((v3) ? NFSX_V3WCCDATA : NFSX_V2FATTR) +#define NFSX_SATTR(v3) ((v3) ? NFSX_V3SATTR : NFSX_V2SATTR) +#define NFSX_COOKIEVERF(v3) ((v3) ? NFSX_V3COOKIEVERF : 0) +#define NFSX_WRITEVERF(v3) ((v3) ? NFSX_V3WRITEVERF : 0) +#define NFSX_READDIR(v3) ((v3) ? (5 * NFSX_UNSIGNED) : \ + (2 * NFSX_UNSIGNED)) +#define NFSX_STATFS(v3) ((v3) ? NFSX_V3STATFS : NFSX_V2STATFS) + +/* nfs rpc procedure numbers (before version mapping) */ + +#define NFSPROC_NULL 0 +#define NFSPROC_GETATTR 1 +#define NFSPROC_SETATTR 2 +#define NFSPROC_LOOKUP 3 +#define NFSPROC_ACCESS 4 +#define NFSPROC_READLINK 5 +#define NFSPROC_READ 6 +#define NFSPROC_WRITE 7 +#define NFSPROC_CREATE 8 +#define NFSPROC_MKDIR 9 +#define NFSPROC_SYMLINK 10 +#define NFSPROC_MKNOD 11 +#define NFSPROC_REMOVE 12 +#define NFSPROC_RMDIR 13 +#define NFSPROC_RENAME 14 +#define NFSPROC_LINK 15 +#define NFSPROC_READDIR 16 +#define NFSPROC_READDIRPLUS 17 +#define NFSPROC_FSSTAT 18 +#define NFSPROC_FSINFO 19 +#define NFSPROC_PATHCONF 20 +#define NFSPROC_COMMIT 21 +#define NFSPROC_NOOP 22 +#define NFS_NPROCS 23 + +/* Actual Version 2 procedure numbers */ + +#define NFSV2PROC_NULL 0 +#define NFSV2PROC_GETATTR 1 +#define NFSV2PROC_SETATTR 2 +#define NFSV2PROC_NOOP 3 +#define NFSV2PROC_ROOT NFSV2PROC_NOOP/* Obsolete */ +#define NFSV2PROC_LOOKUP 4 +#define NFSV2PROC_READLINK 5 +#define NFSV2PROC_READ 6 +#define NFSV2PROC_WRITECACHE NFSV2PROC_NOOP/* Obsolete */ +#define NFSV2PROC_WRITE 8 +#define NFSV2PROC_CREATE 9 +#define NFSV2PROC_REMOVE 10 +#define NFSV2PROC_RENAME 11 +#define NFSV2PROC_LINK 12 +#define NFSV2PROC_SYMLINK 13 +#define NFSV2PROC_MKDIR 14 +#define NFSV2PROC_RMDIR 15 +#define NFSV2PROC_READDIR 16 +#define NFSV2PROC_STATFS 17 + +/* + * Constants used by the Version 3 protocol for various RPCs + */ + +#define NFSV3SATTRTIME_DONTCHANGE 0 +#define NFSV3SATTRTIME_TOSERVER 1 +#define NFSV3SATTRTIME_TOCLIENT 2 + +#define NFSV3ACCESS_READ 0x01 +#define NFSV3ACCESS_LOOKUP 0x02 +#define NFSV3ACCESS_MODIFY 0x04 +#define NFSV3ACCESS_EXTEND 0x08 +#define NFSV3ACCESS_DELETE 0x10 +#define NFSV3ACCESS_EXECUTE 0x20 + +#define NFSV3WRITE_UNSTABLE 0 +#define NFSV3WRITE_DATASYNC 1 +#define NFSV3WRITE_FILESYNC 2 + +#define NFSV3CREATE_UNCHECKED 0 +#define NFSV3CREATE_GUARDED 1 +#define NFSV3CREATE_EXCLUSIVE 2 + +#define NFSV3FSINFO_LINK 0x01 +#define NFSV3FSINFO_SYMLINK 0x02 +#define NFSV3FSINFO_HOMOGENEOUS 0x08 +#define NFSV3FSINFO_CANSETTIME 0x10 + +/* Conversion macros */ +#define vtonfsv2_mode(t,m) \ + txdr_unsigned(((t) == VFIFO) ? MAKEIMODE(VCHR, (m)) : \ + MAKEIMODE((t), (m))) +#define vtonfsv3_mode(m) txdr_unsigned((m) & 07777) +#define nfstov_mode(a) (fxdr_unsigned(u_int16_t, (a))&07777) +#define vtonfsv2_type(a) txdr_unsigned(nfsv2_type[((int32_t)(a))]) +#define vtonfsv3_type(a) txdr_unsigned(nfsv3_type[((int32_t)(a))]) +#define nfsv2tov_type(a) nv2tov_type[fxdr_unsigned(uint32_t,(a))&0x7] +#define nfsv3tov_type(a) nv3tov_type[fxdr_unsigned(uint32_t,(a))&0x7] + +/* File types */ + +typedef enum +{ + NFNON = 0, + NFREG = 1, + NFDIR = 2, + NFBLK = 3, + NFCHR = 4, + NFLNK = 5, + NFSOCK = 6, + NFFIFO = 7 +} nfstype; + +/* Structs for common parts of the rpc's */ + +/* + * File Handle (32 bytes for version 2), variable up to 64 for version 3. + */ + +#ifndef NFS_MAXFHSIZE +# define NFS_MAXFHSIZE 64 +#endif + +union nfsfh +{ + fhandle_t fh_generic; + unsigned char fh_bytes[NFS_MAXFHSIZE]; +}; +typedef union nfsfh nfsfh_t; + +struct nfsv2_time +{ + uint32_t nfsv2_sec; + uint32_t nfsv2_usec; +}; +typedef struct nfsv2_time nfstime2; + +struct nfsv3_time +{ + uint32_t nfsv3_sec; + uint32_t nfsv3_nsec; +}; +typedef struct nfsv3_time nfstime3; + +/* + * Quads are defined as arrays of 2 longs to ensure dense packing for the + * protocol and to facilitate xdr conversion. + */ + +struct nfs_uquad +{ + uint32_t nfsuquad[2]; +}; +typedef struct nfs_uquad nfsuint64; + +/* + * NFS Version 3 special file number. + */ + +struct nfsv3_spec +{ + uint32_t specdata1; + uint32_t specdata2; +}; +typedef struct nfsv3_spec nfsv3spec; + +/* + * File attributes and setable attributes. These structures cover both + * NFS version 2 and the version 3 protocol. Note that the union is only + * used so that one pointer can refer to both variants. These structures + * go out on the wire and must be densely packed, so no quad data types + * are used. (all fields are longs or u_longs or structures of same) + * NB: You can't do sizeof(struct nfs_fattr), you must use the + * NFSX_FATTR(v3) macro. + */ + +struct nfs_fattr +{ + uint32_t fa_type; + uint32_t fa_mode; + uint32_t fa_nlink; + uint32_t fa_uid; + uint32_t fa_gid; + union + { + struct + { + uint32_t nfsv2fa_size; + uint32_t nfsv2fa_blocksize; + uint32_t nfsv2fa_rdev; + uint32_t nfsv2fa_blocks; + uint32_t nfsv2fa_fsid; + uint32_t nfsv2fa_fileid; + nfstime2 nfsv2fa_atime; + nfstime2 nfsv2fa_mtime; + nfstime2 nfsv2fa_ctime; + } fa_nfsv2; + struct + { + nfsuint64 nfsv3fa_size; + nfsuint64 nfsv3fa_used; + nfsv3spec nfsv3fa_rdev; + nfsuint64 nfsv3fa_fsid; + nfsuint64 nfsv3fa_fileid; + nfstime3 nfsv3fa_atime; + nfstime3 nfsv3fa_mtime; + nfstime3 nfsv3fa_ctime; + } fa_nfsv3; + } fa_un; +}; + +/* and some ugly defines for accessing union components */ + +#define fa2_size fa_un.fa_nfsv2.nfsv2fa_size +#define fa2_blocksize fa_un.fa_nfsv2.nfsv2fa_blocksize +#define fa2_rdev fa_un.fa_nfsv2.nfsv2fa_rdev +#define fa2_blocks fa_un.fa_nfsv2.nfsv2fa_blocks +#define fa2_fsid fa_un.fa_nfsv2.nfsv2fa_fsid +#define fa2_fileid fa_un.fa_nfsv2.nfsv2fa_fileid +#define fa2_atime fa_un.fa_nfsv2.nfsv2fa_atime +#define fa2_mtime fa_un.fa_nfsv2.nfsv2fa_mtime +#define fa2_ctime fa_un.fa_nfsv2.nfsv2fa_ctime +#define fa3_size fa_un.fa_nfsv3.nfsv3fa_size +#define fa3_used fa_un.fa_nfsv3.nfsv3fa_used +#define fa3_rdev fa_un.fa_nfsv3.nfsv3fa_rdev +#define fa3_fsid fa_un.fa_nfsv3.nfsv3fa_fsid +#define fa3_fileid fa_un.fa_nfsv3.nfsv3fa_fileid +#define fa3_atime fa_un.fa_nfsv3.nfsv3fa_atime +#define fa3_mtime fa_un.fa_nfsv3.nfsv3fa_mtime +#define fa3_ctime fa_un.fa_nfsv3.nfsv3fa_ctime + +struct nfsv2_sattr +{ + uint32_t sa_mode; + uint32_t sa_uid; + uint32_t sa_gid; + uint32_t sa_size; + nfstime2 sa_atime; + nfstime2 sa_mtime; +}; + +/* + * NFS Version 3 sattr structure for the new node creation case. + */ + +struct nfsv3_sattr +{ + uint32_t sa_modetrue; + uint32_t sa_mode; + uint32_t sa_uidfalse; + uint32_t sa_gidfalse; + uint32_t sa_sizefalse; + uint32_t sa_atimetype; + nfstime3 sa_atime; + uint32_t sa_mtimetype; + nfstime3 sa_mtime; +}; + +struct nfs_statfs +{ + union + { + struct + { + uint32_t nfsv2sf_tsize; + uint32_t nfsv2sf_bsize; + uint32_t nfsv2sf_blocks; + uint32_t nfsv2sf_bfree; + uint32_t nfsv2sf_bavail; + } sf_nfsv2; + struct + { + nfsuint64 nfsv3sf_tbytes; + nfsuint64 nfsv3sf_fbytes; + nfsuint64 nfsv3sf_abytes; + nfsuint64 nfsv3sf_tfiles; + nfsuint64 nfsv3sf_ffiles; + nfsuint64 nfsv3sf_afiles; + uint32_t nfsv3sf_invarsec; + } sf_nfsv3; + } sf_un; +}; + +#define sf_tsize sf_un.sf_nfsv2.nfsv2sf_tsize +#define sf_bsize sf_un.sf_nfsv2.nfsv2sf_bsize +#define sf_blocks sf_un.sf_nfsv2.nfsv2sf_blocks +#define sf_bfree sf_un.sf_nfsv2.nfsv2sf_bfree +#define sf_bavail sf_un.sf_nfsv2.nfsv2sf_bavail +#define sf_tbytes sf_un.sf_nfsv3.nfsv3sf_tbytes +#define sf_fbytes sf_un.sf_nfsv3.nfsv3sf_fbytes +#define sf_abytes sf_un.sf_nfsv3.nfsv3sf_abytes +#define sf_tfiles sf_un.sf_nfsv3.nfsv3sf_tfiles +#define sf_ffiles sf_un.sf_nfsv3.nfsv3sf_ffiles +#define sf_afiles sf_un.sf_nfsv3.nfsv3sf_afiles +#define sf_invarsec sf_un.sf_nfsv3.nfsv3sf_invarsec + +struct nfsv3_fsinfo +{ + uint32_t fs_rtmax; + uint32_t fs_rtpref; + uint32_t fs_rtmult; + uint32_t fs_wtmax; + uint32_t fs_wtpref; + uint32_t fs_wtmult; + uint32_t fs_dtpref; + nfsuint64 fs_maxfilesize; + nfstime3 fs_timedelta; + uint32_t fs_properties; +}; + +struct nfsv3_pathconf +{ + uint32_t pc_linkmax; + uint32_t pc_namemax; + uint32_t pc_notrunc; + uint32_t pc_chownrestricted; + uint32_t pc_caseinsensitive; + uint32_t pc_casepreserving; +}; + +#endif diff --git a/fs/nfs/nfs_socket.c b/fs/nfs/nfs_socket.c new file mode 100644 index 0000000000..b6810fdede --- /dev/null +++ b/fs/nfs/nfs_socket.c @@ -0,0 +1,230 @@ +/* + * copyright (c) 2004 + * the regents of the university of michigan + * all rights reserved + * + * permission is granted to use, copy, create derivative works and redistribute + * this software and such derivative works for any purpose, so long as the name + * of the university of michigan is not used in any advertising or publicity + * pertaining to the use or distribution of this software without specific, + * written prior authorization. if the above copyright notice or any other + * identification of the university of michigan is included in any copy of any + * portion of this software, then the disclaimer below must also be included. + * + * this software is provided as is, without representation from the university + * of michigan as to its fitness for any purpose, and without warranty by the + * university of michigan of any kind, either express or implied, including + * without limitation the implied warranties of merchantability and fitness for + * a particular purpose. the regents of the university of michigan shall not be + * liable for any damages, including special, indirect, incidental, or + * consequential damages, with respect to any claim arising out of or in + * connection with the use of the software, even if it has been or is hereafter + * advised of the possibility of such damages. + */ + +/* wrappers around rpcclnt */ + +/* XXX add tryagain code in nfs_request_xx */ + +/* + * Socket operations for use by nfs + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "rpc_clnt.h" +#include "rpc_v2.h" +#include "nfs_proto.h +#include "nfs.h" +#include "xdr_subs.h" +#include "nfsmount.h" +//#include +#include "nfs_socket.h" + +/* Flag translations */ +#define nfsmnt_to_rpcclnt(nf, rf, name) do { \ + if (nf & NFSMNT_##name)) { \ + rf |= RPCCLNT_##name \ + } \ +} while(0) + +static struct rpc_program nfs2_program = +{ + NFS_PROG, NFS_VER2, "NFSv2" +}; + +static struct rpc_program nfs3_program = +{ + NFS_PROG, NFS_VER3, "NFSv3" +}; + +static struct rpc_program nfs4_program = +{ + NFS_PROG, NFS_VER4, "NFSv4" +}; + +/* XXXMARIUS: name collision */ +int nfsx_connect(struct nfsmount *nmp) +{ + struct rpcclnt *rpc; + int error = 0; + + if (nmp == NULL) + return EFAULT; + + rpc = &nmp->nm_rpcclnt; + + rpc->rc_prog = &nfs3_program; + + printf("nfsxconnect!\n"); + + /* translate nfsmnt flags -> rpcclnt flags */ + rpc->rc_flag = 0; + nfsmnt_to_rpcclnt(nmp->nm_flag, rpc->rc_flag, SOFT); + nfsmnt_to_rpcclnt(nmp->nm_flag, rpc->rc_flag, INT); + nfsmnt_to_rpcclnt(nmp->nm_flag, rpc->rc_flag, NOCONN); + nfsmnt_to_rpcclnt(nmp->nm_flag, rpc->rc_flag, DUMBTIMR); + + rpc->rc_flag |= RPCCLNT_REDIRECT; /* Make this a mount option. */ + + rpc->rc_authtype = RPCAUTH_NULL; /* for now */ + rpc->rc_servername = nmp->nm_mountp->mnt_stat.f_mntfromname; + rpc->rc_name = (struct sockaddr *)nmp->nm_nam; + + rpc->rc_sotype = nmp->nm_sotype; + rpc->rc_soproto = nmp->nm_soproto; + rpc->rc_rsize = (nmp->nm_rsize > nmp->nm_readdirsize) ? + nmp->nm_rsize : nmp->nm_readdirsize; + rpc->rc_wsize = nmp->nm_wsize; + rpc->rc_deadthresh = nmp->nm_deadthresh; + rpc->rc_timeo = nmp->nm_timeo; + rpc->rc_retry = nmp->nm_retry; + + /* XXX v2,3 need to use this */ + rpc->rc_proctlen = 0; + rpc->rc_proct = NULL; + + if (error) + return error; + + return rpcclnt_connect(rpc); +} + +/* NFS disconnect. Clean up and unlink. */ + +/* XXXMARIUS: name collision */ + +void nfsx_disconnect(struct nfsmount *nmp) +{ + rpcclnt_disconnect(&nmp->nm_rpcclnt); +} + +#ifdef CONFIG_NFS_TCPIP +void nfsx_safedisconnect(struct nfsmount *nmp) +{ + rpcclnt_safedisconnect(&nmp->nm_rpcclnt); +} +#endif + +int +nfsx_request_xx(struct nfsmount *nm, struct vnode *vp, struct mbuf *mrest, + int procnum, cthread_t * td, struct ucred *cred, + struct mbuf **mrp, struct mbuf **mdp, caddr_t * dposp) +{ + int error; + u_int32_t *tl; + struct nfsmount *nmp; + struct rpcclnt *clnt; + struct mbuf *md, *mrep; + caddr_t dpos; + struct rpc_reply reply; +#if 0 + int t1; +#endif /* 0 */ + + if (vp != NULL) + nmp = VFSTONFS(vp->v_mount); + else + nmp = nm; + + clnt = &nmp->nm_rpcclnt; + +#if 0 +tryagain: +#endif + + memset(&reply, 0, sizeof(reply)); + + if ((error = rpcclnt_request(clnt, mrest, procnum, td, cred, &reply)) != 0) + goto out; + + mrep = reply.mrep; + md = reply.result_md; + dpos = reply.result_dpos; + + tl = nfsm_dissect(u_int32_t *, NFSX_UNSIGNED); + if (*tl != 0) + { + error = fxdr_unsigned(int, *tl); +#if 0 + if ((nmp->nm_flag & NFSMNT_NFSV3) && error == NFSERR_TRYLATER) + { + m_freem(mrep); + error = 0; + waituntil = time_second + trylater_delay; + while (time_second < waituntil) + (void)tsleep(&lbolt, PSOCK, "nqnfstry", 0); + trylater_delay *= nfs_backoff[trylater_cnt]; + if (trylater_cnt < NFS_NBACKOFF - 1) + trylater_cnt++; + goto tryagain; + } +#endif + + /* + ** If the File Handle was stale, invalidate the + ** lookup cache, just in case. + **/ + if (error == ESTALE) + if (vp != NULL) + cache_purge(vp); + else + printf("%s: ESTALE on mount from server %s\n", + nmp->nm_rpcclnt.rc_prog->prog_name, + nmp->nm_rpcclnt.rc_servername); + else + printf("%s: unknown error %d from server %s\n", + nmp->nm_rpcclnt.rc_prog->prog_name, error, + nmp->nm_rpcclnt.rc_servername); + goto out; + } + + m_freem(mrest); + + *mrp = mrep; + *mdp = md; + *dposp = dpos; + return (0); +nfsmout: +out: + /* XXX: don't free mrest if an error occured, to allow caller to retry */ + m_freem(mrest); + m_freem(reply.mrep); + *mrp = NULL; + *mdp = NULL; + + return (error); +} + +/* terminate any outstanding RPCs. */ + +int nfsx_nmcancelreqs(struct nfsmount *nmp) +{ + return rpcclnt_cancelreqs(&nmp->nm_rpcclnt); +} diff --git a/fs/nfs/nfs_socket.h b/fs/nfs/nfs_socket.h new file mode 100644 index 0000000000..89ef4fe89b --- /dev/null +++ b/fs/nfs/nfs_socket.h @@ -0,0 +1,69 @@ +/* + * copyright (c) 2004 + * the regents of the university of michigan + * all rights reserved + * + * permission is granted to use, copy, create derivative works and redistribute + * this software and such derivative works for any purpose, so long as the name + * of the university of michigan is not used in any advertising or publicity + * pertaining to the use or distribution of this software without specific, + * written prior authorization. if the above copyright notice or any other + * identification of the university of michigan is included in any copy of any + * portion of this software, then the disclaimer below must also be included. + * + * this software is provided as is, without representation from the university + * of michigan as to its fitness for any purpose, and without warranty by the + * university of michigan of any kind, either express or implied, including + * without limitation the implied warranties of merchantability and fitness for + * a particular purpose. the regents of the university of michigan shall not be + * liable for any damages, including special, indirect, incidental, or + * consequential damages, with respect to any claim arising out of or in + * connection with the use of the software, even if it has been or is hereafter + * advised of the possibility of such damages. + */ + +#ifndef __NFSX_H_ +#define __NFSX_H_ + +/* nfs_socket interface */ + +/* XXXMARIUS: name collision */ + +int nfsx_connect(struct nfsmount *); +void nfsx_disconnect(struct nfsmount *); +int nfsx_sigintr(struct nfsmount *, struct nfsreq *, cthread_t *); +void nfsx_safedisconnect(struct nfsmount *); +int nfsx_request_xx(struct nfsmount *, struct vnode *, struct mbuf *, int, + cthread_t *, struct ucred *, struct mbuf **, struct mbuf **, + caddr_t *); +int nfsx_nmcancelreqs(struct nfsmount *); + +#define nfs_connect nfs_connect_nfsx +#define nfs_disconnect nfs_disconnect_nfsx +#define nfs_sigintr nfs_sigintr_nfsx + +/* XXX dros: defined in nfs.h */ + +#if 0 +void nfs_safedisconnect(struct nfsmount *); +#endif + +#define nfsx_request(vp, m, p, td, cr, m2, m3, c) \ + nfsx_request_xx(NULL, vp, m, p, td, cr, m2, m3, c) + +#define nfsx_request_mnt(nmp, m, p, td, cr, m2, m3, c) \ + nfsx_request_xx(nmp, NULL, m, p, td, cr, m2, m3, c) + +/* don't use this.. use nfsx_request() of nfsx_request_mnt() */ + +int nfs_request_xx(struct nfsmount *, struct vnode *, struct mbuf *, int, + cthread_t *, struct ucred *, struct mbuf **, struct mbuf **, + caddr_t *); + +/* XXX dros: defined in nfs.h */ + +#if 0 +int nfs_nmcancelreqs(struct nfsmount *); +#endif + +#endif /* __NFSX_H_ */ diff --git a/fs/nfs/nfsmount.h b/fs/nfs/nfsmount.h new file mode 100644 index 0000000000..baa70aa184 --- /dev/null +++ b/fs/nfs/nfsmount.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Rick Macklem at The University of Guelph. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _NFSCLIENT_NFSMOUNT_H_ +#define _NFSCLIENT_NFSMOUNT_H_ + +/* + * Mount structure. + * One allocated on every NFS mount. + * Holds NFS specific information for mount. + */ + +struct nfsmount +{ + int nm_flag; /* Flags for soft/hard... */ + int nm_state; /* Internal state flags */ + struct mount *nm_mountp; /* Vfs structure for this filesystem */ + int nm_numgrps; /* Max. size of groupslist */ + nfsfh_t nm_fh; /* File handle of root dir */ + int nm_fhsize; /* Size of root file handle */ + struct rpcclnt nm_rpcclnt; /* rpc state */ + struct socket *nm_so; /* Rpc socket */ + int nm_sotype; /* Type of socket */ + int nm_soproto; /* and protocol */ + int nm_soflags; /* pr_flags for socket protocol */ + struct sockaddr *nm_nam; /* Addr of server */ + int nm_timeo; /* Init timer for NFSMNT_DUMBTIMR */ + int nm_retry; /* Max retries */ + int nm_srtt[4]; /* Timers for rpcs */ + int nm_sdrtt[4]; + int nm_sent; /* Request send count */ + int nm_cwnd; /* Request send window */ + int nm_timeouts; /* Request timeouts */ + 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_acdirmin; /* Directory attr cache min lifetime */ + int nm_acdirmax; /* Directory attr cache max lifetime */ + int nm_acregmin; /* Reg file attr cache min lifetime */ + int nm_acregmax; /* Reg file attr cache max lifetime */ + u_char nm_verf[NFSX_V3WRITEVERF]; /* V3 write verifier */ + TAILQ_HEAD(, buf) nm_bufq; /* async io buffer queue */ + short nm_bufqlen; /* number of buffers in queue */ + short nm_bufqwant; /* process wants to add to the queue */ + int nm_bufqiods; /* number of iods processing queue */ + u_int64_t nm_maxfilesize; /* maximum file size */ + + struct nfsx_nfsops *nm_nfsops; /* Version specific ops. */ + + /* NFSv4 */ + + uint64_t nm_clientid; + fsid_t nm_fsid; + u_int nm_lease_time; + time_t nm_last_renewal; + + struct vnode *nm_dvp; +}; + +#define NFSOP(nmp, op) (*nmp->nm_nfsops->nn_##op) +#define NFSHASOP(nmp, op) (nmp->nm_nfsops->nn_##op != NULL) +#define NFSDAT(nmp, nam) (nmp->nm_nfsops->nn_##nam) + +#if defined(_KERNEL) + +/* + * Convert mount ptr to nfsmount ptr. + */ + +# define VFSTONFS(mp) ((struct nfsmount *)((mp)->mnt_data)) + +#endif + +#endif diff --git a/fs/nfs/rpc.h b/fs/nfs/rpc.h index db29007fd3..0a907c126d 100644 --- a/fs/nfs/rpc.h +++ b/fs/nfs/rpc.h @@ -1,24 +1,48 @@ -/**************************************************************************** - * fs/nfs/rpc.h - * - * Copyright (C) 2012 Gregory Nutt. All rights reserved. - * Copyright (C) 2012 Jose Pablo Rojas Vargas. All rights reserved. - * Author: Jose Pablo Rojas Vargas - * - * Leveraged from OpenBSD: - * - * Copyright (c) 1982, 1986, 1988, 1993 +/* + * copyright (c) 2003 + * the regents of the university of michigan + * all rights reserved + * + * permission is granted to use, copy, create derivative works and redistribute + * this software and such derivative works for any purpose, so long as the name + * of the university of michigan is not used in any advertising or publicity + * pertaining to the use or distribution of this software without specific, + * written prior authorization. if the above copyright notice or any other + * identification of the university of michigan is included in any copy of any + * portion of this software, then the disclaimer below must also be included. + * + * this software is provided as is, without representation from the university + * of michigan as to its fitness for any purpose, and without warranty by the + * university of michigan of any kind, either express or implied, including + * without limitation the implied warranties of merchantability and fitness for + * a particular purpose. the regents of the university of michigan shall not be + * liable for any damages, including special, indirect, incidental, or + * consequential damages, with respect to any claim arising out of or in + * connection with the use of the software, even if it has been or is hereafter + * advised of the possibility of such damages. + */ + +/* + * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * + * This code is derived from software contributed to Berkeley by + * Rick Macklem at The University of Guelph. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: + * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -33,50 +57,175 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - ****************************************************************************/ + */ -#ifndef __FS_NFS_RPC_H -#define __FS_NFS_RPC_H +#ifndef _RPCCLNT_H_ +#define _RPCCLNT_H_ -/**************************************************************************** - * Included Files - ****************************************************************************/ +#include -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ +/* for rpcclnt's rc_flags */ -/* RPC definitions for the portmapper. */ +#define RPCCLNT_SOFT 0x001 /* soft mount (hard is details) */ +#define RPCCLNT_INT 0x002 /* allow interrupts on hard mounts */ +#define RPCCLNT_NOCONN 0x004 /* dont connect the socket (udp) */ +#define RPCCLNT_DUMBTIMR 0x010 -#define PMAPPORT 111 -#define PMAPPROG 100000 -#define PMAPVERS 2 -#define PMAPPROC_NULL 0 -#define PMAPPROC_SET 1 -#define PMAPPROC_UNSET 2 -#define PMAPPROC_GETPORT 3 -#define PMAPPROC_DUMP 4 -#define PMAPPROC_CALLIT 5 +/* XXX should be replaced with real locks */ -/* RPC definitions for bootparamd. */ +#define RPCCLNT_SNDLOCK 0x100 +#define RPCCLNT_WANTSND 0x200 +#define RPCCLNT_RCVLOCK 0x400 +#define RPCCLNT_WANTRCV 0x800 -#define BOOTPARAM_PROG 100026 -#define BOOTPARAM_VERS 1 -#define BOOTPARAM_WHOAMI 1 -#define BOOTPARAM_GETFILE 2 +struct rpc_program +{ + uint32_t prog_id; + uint32_t prog_version; + char * prog_name; +}; -/**************************************************************************** - * Public Function Prototypes - ****************************************************************************/ +struct rpctask +{ + dq_entry_t r_chain; + + struct rpcclnt *r_rpcclnt; -int krpc_call(struct sockaddr_in *, unsigned int, unsigned int, unsigned int, - struct sockaddr **, int); -int krpc_portmap(struct sockaddr_in *, unsigned int, unsigned int, uint16_t *); + uint32_t r_xid; + int r_flags; /* flags on request, see below */ + int r_retry; /* max retransmission count */ + int r_rexmit; /* current retrans count */ + int r_timer; /* tick counter on reply */ + int r_procnum; /* NFS procedure number */ + int r_rtt; /* RTT for rpc */ +}; -void xdr_string_encode(char *, int); -void xdr_string_decode(char *, int *); -void xdr_inaddr_encode(struct in_addr *); -void xdr_inaddr_decode(struct in_addr *); +/* Generic RPC headers */ -#endif /* __FS_NFS_RPC_H */ +struct rpc_auth_info +{ + uint32_t authtype; /* auth type */ + uint32_t authlen; /* auth length */ +}; + +struct auth_unix +{ + int32_t ua_time; + int32_t ua_hostname; /* null */ + int32_t ua_uid; + int32_t ua_gid; + int32_t ua_gidlist; /* null */ +}; + +struct rpc_call +{ + uint32_t rp_xid; /* request transaction id */ + int32_t rp_direction; /* call direction (0) */ + uint32_t rp_rpcvers; /* rpc version (2) */ + uint32_t rp_prog; /* program */ + uint32_t rp_vers; /* version */ + uint32_t rp_proc; /* procedure */ + struct rpc_auth_info rpc_auth; + struct auth_unix rpc_unix; + struct rpc_auth_info rpc_verf; +}; + +struct rpc_reply +{ + uint32_t rp_xid; /* request transaction id */ + int32_t rp_direction; /* call direction (1) */ + struct + { + uint32_t type; + uint32_t status; + + /* used only when reply == RPC_MSGDENIED and status == RPC_AUTHERR */ + + uint32_t autherr; + + /* rpc mismatch info if reply == RPC_MSGDENIED and status == RPC_MISMATCH */ + + struct + { + uint32_t low; + uint32_t high; + } mismatch_info; + } stat; + + struct rpc_auth_info rpc_verfi; +}; + +/* + * RPC Client connection context. + * One allocated on every NFS mount. + * Holds RPC specific information for mount. + */ + +/* XXX: please note that all pointer type variables are just set (not copied), + * so it is up to the user to free these values */ + +struct rpcclnt +{ + int rc_flag; /* For RPCCLNT_* flags */ + + int rc_wsize; /* Max size of the request data */ + int rc_rsize; /* Max size of the response data */ + + struct sockaddr *rc_name; + struct socket *rc_so; /* Rpc socket */ + + int rc_sotype; /* Type of socket */ + int rc_soproto; /* and protocol */ + int rc_soflags; /* pr_flags for socket protocol */ + + int rc_timeo; /* Init timer for NFSMNT_DUMBTIMR */ + int rc_retry; /* Max retries */ + int rc_srtt[4]; /* Timers for rpcs */ + int rc_sdrtt[4]; + int rc_sent; /* Request send count */ + int rc_cwnd; /* Request send window */ + int rc_timeouts; /* Request timeouts */ + + int rc_deadthresh; /* Threshold of timeouts-->dead server*/ + + /* authentication: */ + /* currently can be RPCAUTH_NULL, RPCAUTH_KERBV4, RPCAUTH_UNIX */ + /* should be kept in XDR form */ + + int rc_authtype; /* Authenticator type */ +#ifdef CONFIG_NFS_UNIX_AUTH + /* RPCAUTH_UNIX*/ + + struct rpc_auth_info rc_oldauth; /* authentication */ +#endif + void *rc_auth; + + struct rpc_program * rc_prog; + + char *rc_servername; + + int rc_proctlen; /* if == 0 then rc_proct == NULL */ + int * rc_proct; +}; + +/* +void rpcclnt_create(struct rpcclnt ** rpc); +void rpcclnt_destroy(struct rpcclnt * rpc); + +#define rpcclnt_get(X) rpcclnt_create(&(X)) +#define rpcclnt_put(X) rpcclnt_destroy(X) + +*/ + +void rpcclnt_init(void); +//void rpcclnt_uninit(void); + +int rpcclnt_setup(struct rpcclnt *, struct rpc_program *, struct sockaddr *, int, int, struct rpc_auth_info *, int, int, int); +int rpcclnt_connect(struct rpcclnt *); +int rpcclnt_reconnect(struct rpctask *); +void rpcclnt_disconnect(struct rpcclnt *); +void rpcclnt_safedisconnect(struct rpcclnt *); +int rpcclnt_request(struct rpcclnt *, int, struct rpc_reply *); +int rpcclnt_cancelreqs(struct rpcclnt *); + +#endif /* _RPCCLNT_H_ */ diff --git a/fs/nfs/rpc_clnt.c b/fs/nfs/rpc_clnt.c new file mode 100644 index 0000000000..a852c80363 --- /dev/null +++ b/fs/nfs/rpc_clnt.c @@ -0,0 +1,1306 @@ +/* + * rpcclnt.c + * + * Copyright (c) 2004 The Regents of the University of Michigan. + * All rights reserved. + * + * Copyright (c) 2004 Weston Andros Adamson . + * Copyright (c) 2004 Marius Aamodt Eriksen . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * 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 Rick Macklem at + * The University of Guelph. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. 3. All advertising + * materials mentioning features or use of this software must display the + * following acknowledgement: This product includes software developed by the + * University of California, Berkeley and its contributors. 4. Neither the + * name of the University nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "xdr_subs.h" +#include "rpc_types.h" +#include "nfs_proto.h" +#include "nfs.h" +#include "rpc.h" +#include "rpc_clnt_private.h" +#include "rpc_v2.h" + +#define RPC_RETURN(X) do { dbg("returning %d", X); return X; }while(0) + +/* + * Estimate rto for an nfs rpc sent via. an unreliable datagram. Use the mean + * and mean deviation of rtt for the appropriate type of rpc for the frequent + * rpcs and a default for the others. The justification for doing "other" + * this way is that these rpcs happen so infrequently that timer est. would + * probably be stale. Also, since many of these rpcs are non-idempotent, a + * conservative timeout is desired. getattr, lookup - A+2D read, write - + * A+4D other - nm_timeo + */ +#define RPC_RTO(n, t) \ + ((t) == 0 ? (n)->rc_timeo : \ + ((t) < 3 ? \ + (((((n)->rc_srtt[t-1] + 3) >> 2) + (n)->rc_sdrtt[t-1] + 1) >> 1) : \ + ((((n)->rc_srtt[t-1] + 7) >> 3) + (n)->rc_sdrtt[t-1] + 1))) + +#define RPC_SRTT(s,r) (r)->r_rpcclnt->rc_srtt[rpcclnt_proct((s),\ + (r)->r_procnum) - 1] + +#define RPC_SDRTT(s,r) (r)->r_rpcclnt->rc_sdrtt[rpcclnt_proct((s),\ + (r)->r_procnum) - 1] + +/* + * There is a congestion window for outstanding rpcs maintained per mount + * point. The cwnd size is adjusted in roughly the way that: Van Jacobson, + * Congestion avoidance and Control, In "Proceedings of SIGCOMM '88". ACM, + * August 1988. describes for TCP. The cwnd size is chopped in half on a + * retransmit timeout and incremented by 1/cwnd when each rpc reply is + * received and a full cwnd of rpcs is in progress. (The sent count and cwnd + * are scaled for integer arith.) Variants of "slow start" were tried and + * were found to be too much of a performance hit (ave. rtt 3 times larger), + * I suspect due to the large rtt that nfs rpcs have. + */ +#define RPC_CWNDSCALE 256 +#define RPC_MAXCWND (RPC_CWNDSCALE * 32) +static int rpcclnt_backoff[8] = { 2, 4, 8, 16, 32, 64, 128, 256, }; + +#define RPC_ERRSTR_ACCEPTED_SIZE 6 +char *rpc_errstr_accepted[RPC_ERRSTR_ACCEPTED_SIZE] = { + "", /* no good message... */ + "remote server hasn't exported program.", + "remote server can't support version number.", + "program can't support procedure.", + "procedure can't decode params.", + "remote error. remote side memory allocation failure?" +}; + +char *rpc_errstr_denied[2] = { + "remote server doesnt support rpc version 2!", + "remote server authentication error." +}; + +#define RPC_ERRSTR_AUTH_SIZE 6 +char *rpc_errstr_auth[RPC_ERRSTR_AUTH_SIZE] = { + "", + "auth error: bad credential (seal broken).", + "auth error: client must begin new session.", + "auth error: bad verifier (seal broken).", + "auth error: verifier expired or replayed.", + "auth error: rejected for security reasons.", +}; + +/* + * Static data, mostly RPC constants in XDR form + */ +static uint32_t rpc_reply, rpc_call, rpc_vers, rpc_msgdenied, + rpc_mismatch, rpc_auth_unix, rpc_msgaccepted, rpc_autherr, rpc_auth_null; + +static uint32_t rpcclnt_xid = 0; +static uint32_t rpcclnt_xid_touched = 0; +struct rpcstats rpcstats; +int rpcclnt_ticks; +struct rpc_call *callmgs; +struct rpc_reply *replymsg; + +/* + * Queue head for rpctask's + */ +static dq_queue_t *rpctask_q; +//struct callout_handle rpcclnt_timer_handle; + +static int rpcclnt_send(struct socket *, struct sockaddr *, struct rpc_call *, + struct rpctask *); +static int rpcclnt_receive(struct rpctask *, struct sockaddr *, + struct rpc_reply *, struct rpc_call *); +static int rpcclnt_reply(struct rpctask *, struct rpc_call *, + struct rpc_reply *); +static void rpcclnt_timer(void *, struct rpc_call *); +#ifdef CONFIG_NFS_TCPIP +static int rpcclnt_sndlock(int *, struct rpctask *); +static void rpcclnt_sndunlock(int *); +static int rpcclnt_rcvlock(struct rpctask *); +static void rpcclnt_rcvunlock(int *); +#endif +static void rpcclnt_softterm(struct rpctask *task); + +static uint32_t rpcclnt_proct(struct rpcclnt *, uint32_t); +static int rpcclnt_buildheader(struct rpcclnt *, int, int, struct rpc_call *); + +void rpcclnt_init(void) +{ + rpcclnt_ticks = (CLOCKS_PER_SEC * RPC_TICKINTVL + 500) / 1000; + if (rpcclnt_ticks < 1) + rpcclnt_ticks = 1; + rpcstats.rpcretries = 0; + rpcstats.rpcrequests = 0; + rpcstats.rpctimeouts = 0; + rpcstats.rpcunexpected = 0; + rpcstats.rpcinvalid = 0; + + /* + * rpc constants how about actually using more than one of these! + */ + + rpc_reply = txdr_unsigned(RPC_REPLY); + rpc_vers = txdr_unsigned(RPC_VER2); + rpc_call = txdr_unsigned(RPC_CALL); + rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); + rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); + rpc_mismatch = txdr_unsigned(RPC_MISMATCH); + rpc_autherr = txdr_unsigned(RPC_AUTHERR); + rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); + rpc_auth_null = txdr_unsigned(RPCAUTH_NULL); + + /* initialize rpctask queue */ + dq_init(rpctask_q); + + rpcclnt_timer(NULL, callmgs); + + printf("rpc initialed"); + return; +} + +/* +void +rpcclnt_uninit(void) +{ + printf("uninit"); + untimeout(rpcclnt_timer, (void *)NULL, rpcclnt_timer_handle); + +} +*/ + +/* + * Initialize sockets and congestion for a new RPC connection. We do not free + * the sockaddr if error. + */ +int rpcclnt_connect(struct rpcclnt *rpc) +{ + struct socket *so; + int error; + struct sockaddr *saddr; + struct sockaddr_in *sin; + struct timeval *tv; + uint16_t tport; + + /* create the socket */ + rpc->rc_so = NULL; + saddr = rpc->rc_name; + rpc->rc_sotype = SOCK_DGRAM; + + error = + psock_socket(saddr->sa_family, rpc->rc_sotype, rpc->rc_soproto, rpc->rc_so); + + if (error != 0) + { + printf("error %d in psock_socket()", error); + RPC_RETURN(error); + } + + so = rpc->rc_so; + rpc->rc_soflags = so->s_flags; + + /* + * Some servers require that the client port be a reserved port + * number. We always allocate a reserved port, as this prevents + * filehandle disclosure through UDP port capture. + */ + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = INADDR_ANY; + tport = 1024; + + do + { + tport--; + sin->sin_port = htons(tport); + error = psock_bind(so, (struct sockaddr *)sin, sizeof(*sin)); + } + while (error == EADDRINUSE && tport > 1024 / 2); + + if (error) + { + printf("bind failed\n"); + goto bad; + } + + /* + * Protocols that do not require connections may be optionally left + * unconnected for servers that reply from a port other than + * NFS_PORT. + */ + +#ifdef CONFIG_NFS_TCPIP + if (rpc->rc_soflags == PR_CONNREQUIRED) + { + error = ENOTCONN; + goto bad; + + } + else + { +#endif + error = psock_connect(so, saddr, sizeof(*saddr)); + + if (error) + { + dbg("psock_connect returns %d", error); + goto bad; + + } + +#ifdef CONFIG_NFS_TCPIP + } +#endif + + /* + * Always set receive timeout to detect server crash and reconnect. + * Otherwise, we can get stuck in psock_receive forever. + */ + + tv->tv_sec = 1; + tv->tv_usec = 0; + + if ((error = + psock_setsockopt(so, SOL_SOCKET, SO_RCVTIMEO, (const void *)tv, + sizeof(*tv)))) + { + goto bad; + } + + /* Initialize other non-zero congestion variables */ + rpc->rc_srtt[0] = rpc->rc_srtt[1] = rpc->rc_srtt[2] = rpc->rc_srtt[3] = + rpc->rc_srtt[4] = (RPC_TIMEO << 3); + rpc->rc_sdrtt[0] = rpc->rc_sdrtt[1] = rpc->rc_sdrtt[2] = rpc->rc_sdrtt[3] = + rpc->rc_sdrtt[4] = 0; + rpc->rc_cwnd = RPC_MAXCWND / 2; /* Initial send window */ + rpc->rc_sent = 0; + rpc->rc_timeouts = 0; + + RPC_RETURN(0); + +bad: + rpcclnt_disconnect(rpc); + RPC_RETURN(error); +} + +/* + * Reconnect routine: Called when a connection is broken on a reliable + * protocol. - clean up the old socket - nfs_connect() again - set + * TASK_MUSTRESEND for all outstanding requests on mount point If this + * fails the mount point is DEAD! nb: Must be called with the + * nfs_sndlock() set on the mount point. + */ +int rpcclnt_reconnect(struct rpctask *rep) +{ + struct rpctask *rp; + struct rpcclnt *rpc = rep->r_rpcclnt; + int error; + + rpcclnt_disconnect(rpc); + while ((error = rpcclnt_connect(rpc)) != 0) + { + if (error == EINTR || error == ERESTART) + return (EINTR); + } + + /* + * Loop through outstanding request list and fix up all + * requests on old socket. + */ + for (rp = (struct rpctask *)rpctask_q->head; rp != NULL; + rp = (struct rpctask *)rp->r_chain.blink) + { + if (rp->r_rpcclnt == rpc) + rp->r_flags |= TASK_MUSTRESEND; + } + return (0); +} + +void rpcclnt_disconnect(struct rpcclnt *rpc) +{ + struct socket *so; + + if (rpc->rc_so != NULL) + { + so = rpc->rc_so; + rpc->rc_so = NULL; + (void)psock_close(so); + } +} + +#ifdef CONFIG_NFS_TCPIP +void rpcclnt_safedisconnect(struct rpcclnt *rpc) +{ + struct rpctask dummytask; + + memset((void *)dummytask, 0, sizeof(*call)); + dummytask.r_rpcclnt = rpc; + rpcclnt_rcvlock(&dummytask); + rpcclnt_disconnect(rpc); + rpcclnt_rcvunlock(&rpc->rc_flag); +} + +#endif + +/* + * This is the nfs send routine. For connection based socket types, it must + * be called with an nfs_sndlock() on the socket. "rep == NULL" indicates + * that it has been called from a server. For the client side: - return EINTR + * if the RPC is terminated, 0 otherwise - set TASK_MUSTRESEND if the send fails + * for any reason - do any cleanup required by recoverable socket errors + * (???) For the server side: - return EINTR or ERESTART if interrupted by a + * signal - return EPIPE if a connection is lost for connection based sockets + * (TCP...) - do any cleanup required by recoverable socket errors (???) + */ +static int +rpcclnt_send(struct socket *so, struct sockaddr *nam, struct rpc_call *call, + struct rpctask *rep) +{ + struct sockaddr *sendnam; + int error, soflags, flags; + + if (rep != NULL) + { + if (rep->r_flags & TASK_SOFTTERM) + { + RPC_RETURN(EINTR); + } + if ((so = rep->r_rpcclnt->rc_so) == NULL) + { + rep->r_flags |= TASK_MUSTRESEND; + RPC_RETURN(0); + } + rep->r_flags &= ~TASK_MUSTRESEND; + soflags = rep->r_rpcclnt->rc_soflags; + } + else + soflags = so->s_flags; +#ifdef CONFIG_NFS_TCPIP + if ((soflags & PR_CONNREQUIRED)) + sendnam = NULL; + else +#endif + sendnam = nam; + + if (so->s_type == SOCK_SEQPACKET) + flags = MSG_EOR; + else + flags = 0; + + error = + psock_sendto(so, call, sizeof(*call), flags, sendnam, sizeof(*sendnam)); + + if (error != 0) + { + if (rep != NULL) + { + printf("rpc send error %d for service %s\n", error, + rep->r_rpcclnt->rc_prog->prog_name); + /* + * Deal with errors for the client side. + */ + if (rep->r_flags & TASK_SOFTTERM) + error = EINTR; + else + rep->r_flags |= TASK_MUSTRESEND; + } + else + printf("rpc service send error %d\n", error); + + /* + * Handle any recoverable (soft) socket errors here. + */ + if (error != EINTR && error != ERESTART && + error != EWOULDBLOCK && error != EPIPE) + error = 0; + } + + RPC_RETURN(error); +} + +/* + * Receive a Sun RPC Request/Reply. For SOCK_DGRAM, the work is all + * done by soreceive().For SOCK_STREAM, first get the + * Record Mark to find out how much more there is to get. We must + * lock the socket against other receivers until we have an entire + * rpc request/reply. + */ +static int rpcclnt_receive(struct rpctask *rep, struct sockaddr *aname, + struct rpc_reply *reply, struct rpc_call *call) +{ + struct socket *so; +#ifdef CONFIG_NFS_TCPIP + uint32_t len; +#endif + int error, sotype, rcvflg; + + /* + * Set up arguments for soreceive() + */ + + sotype = rep->r_rpcclnt->rc_sotype; + + /* + * For reliable protocols, lock against other senders/receivers in + * case a reconnect is necessary. For SOCK_STREAM, first get the + * Record Mark to find out how much more there is to get. We must + * lock the socket against other receivers until we have an entire + * rpc request/reply. + */ +#ifdef CONFIG_NFS_TCPIP + if (sotype != SOCK_DGRAM) + { + error = rpcclnt_sndlock(&rep->r_rpcclnt->rc_flag, rep); + if (error != 0) + return (error); + tryagain: + /* + * Check for fatal errors and resending request. + */ + /* + * Ugh: If a reconnect attempt just happened, rc_so would + * have changed. NULL indicates a failed attempt that has + * essentially shut down this mount point. + */ + if (rep->r_flags & TASK_SOFTTERM) + { + rpcclnt_sndunlock(&rep->r_rpcclnt->rc_flag); + return (EINTR); + } + so = rep->r_rpcclnt->rc_so; + if (so == NULL) + { + error = rpcclnt_reconnect(rep); + if (error) + { + rpcclnt_sndunlock(&rep->r_rpcclnt->rc_flag); + return (error); + } + goto tryagain; + } + while (rep->r_flags & TASK_MUSTRESEND) + { + rpcstats.rpcretries++; + error = rpcclnt_send(so, rep->r_rpcclnt->rc_name, call, rep); + if (error) + { + if (error == EINTR || error == ERESTART || + (error = rpcclnt_reconnect(rep)) != 0) + { + rpcclnt_sndunlock(&rep->r_rpcclnt->rc_flag); + return (error); + } + goto tryagain; + } + } + + rpcclnt_sndunlock(&rep->r_rpcclnt->rc_flag); + if (sotype == SOCK_STREAM) + { + do + { + rcvflg = MSG_WAITALL; + error = psock_recvfrom(so, reply, sizeof(*reply), + &rcvflg, rep->r_rpcclnt->rc_name, + sizeof(*rep->r_rpcclnt->rc_name)); + if (error == EWOULDBLOCK && rep && (rep->r_flags & TASK_SOFTTERM)) + RPC_RETURN(EINTR); + } + while (error == EWOULDBLOCK); + + if (error == 0) + { + printf("short receive from rpc server %s\n", + rep->r_rpcclnt->rc_prog->prog_name); + error = EPIPE; + } + + len = ntohl(len) & ~0x80000000; + /* + * This is SERIOUS! We are out of sync with the + * sender and forcing a disconnect/reconnect is all I + * can do. + */ + if (len > RPC_MAXPACKET) + { + printf("%s (%d) from rpc server %s\n", + "impossible packet length", + len, rep->r_rpcclnt->rc_prog->prog_name); + error = EFBIG; + goto errout; + } + do + { + rcvflg = MSG_WAITALL; + error = psock_recvfrom(so, reply, sizeof(*reply), + &rcvflg, rep->r_rpcclnt->rc_name, + sizeof(*rep->r_rpcclnt->rc_name)); + } + while (error == EWOULDBLOCK || error == EINTR || error == ERESTART); + + if (error == 0) + { + printf("short receive from rpc server %s\n", + rep->r_rpcclnt->rc_prog->prog_name); + error = EPIPE; + } + + if (error != 0) + goto errout; + + } + else + { + /* + * NB: Since uio_resid is big, MSG_WAITALL is ignored + * and soreceive() will return when it has either a + * control msg or a data msg. We have no use for + * control msg., but must grab them and then throw + * them away so we know what is going on. + */ + do + { + rcvflg = 0; + error = psock_recvfrom(so, reply, sizeof(*reply), + &rcvflg, rep->r_rpcclnt->rc_name, + sizeof(*rep->r_rpcclnt->rc_name)); + if (error == EWOULDBLOCK && rep) + { + if (rep->r_flags & TASK_SOFTTERM) + { + return (EINTR); + } + } + } + while (error == EWOULDBLOCK || (!error)); + + if ((rcvflg & MSG_EOR) == 0) + printf("Egad!!\n"); + if (error == 0) + error = EPIPE; + } + + errout: + if (error != 0 && error != EINTR && error != ERESTART) + { + if (error != EPIPE) + printf("receive error %d from rpc server %s\n", + error, rep->r_rpcclnt->rc_prog->prog_name); + error = rpcclnt_sndlock(&rep->r_rpcclnt->rc_flag, rep); + if (error == 0) + error = rpcclnt_reconnect(rep); + if (error == 0) + goto tryagain; + } + } + else + { +#endif + if ((so = rep->r_rpcclnt->rc_so) == NULL) + RPC_RETURN(EACCES); + + do + { + rcvflg = 0; + error = + psock_recvfrom(so, reply, sizeof(*reply), rcvflg, aname, + (socklen_t *) sizeof(*aname)); + dbg("psock_recvfrom returns %d", error); + if (error == EWOULDBLOCK && (rep->r_flags & TASK_SOFTTERM)) + { + dbg("wouldblock && softerm -> EINTR"); + RPC_RETURN(EINTR); + } + } + while (error == EWOULDBLOCK); + +#ifdef CONFIG_NFS_TCPIP + } +#endif + RPC_RETURN(error); +} + +/* + * Implement receipt of reply on a socket. We must search through the list of + * received datagrams matching them with outstanding requests using the xid, + * until ours is found. + */ + +/* ARGSUSED */ +static int +rpcclnt_reply(struct rpctask *myrep, struct rpc_call *call, + struct rpc_reply *reply) +{ + struct rpctask *rep; + struct rpcclnt *rpc = myrep->r_rpcclnt; + int32_t t1; + struct sockaddr *nam; + uint32_t rxid; + int error; + + /* + * Loop around until we get our own reply + */ + for (;;) + { + /* + * Lock against other receivers so that I don't get stuck in + * sbwait() after someone else has received my reply for me. + * Also necessary for connection based protocols to avoid + * race conditions during a reconnect. + */ +#ifdef CONFIG_NFS_TCPIP + error = rpcclnt_rcvlock(myrep); + if (error) + return (error); +#endif + /* + * Get the next Rpc reply off the socket + */ + error = rpcclnt_receive(myrep, nam, reply, call); + +#ifdef CONFIG_NFS_TCPIP + rpcclnt_rcvunlock(&rpc->rc_flag); +#endif + + if (error != 0) + { + /* + * Ignore routing errors on connectionless + * protocols?? + */ + if (RPCIGNORE_SOERROR(rpc->rc_soflags, error)) + { + if (myrep->r_flags & TASK_GETONEREP) + RPC_RETURN(0); + dbg("ingoring routing error on connectionless protocol."); + continue; + } + RPC_RETURN(error); + } + + /* + * Get the xid and check that it is an rpc reply + */ + rxid = reply->rp_xid; + if (reply->rp_direction != rpc_reply) + { + rpcstats.rpcinvalid++; + if (myrep->r_flags & TASK_GETONEREP) + RPC_RETURN(0); + continue; + } + /* + * Loop through the request list to match up the reply Iff no + * match, just drop the datagram + */ + for (rep = (struct rpctask *)rpctask_q->head; rep; + rep = (struct rpctask *)rep->r_chain.flink) + { + if (rxid == rep->r_xid) + { + /* + * Update congestion window. Do the additive + * increase of one rpc/rtt. + */ + if (rpc->rc_cwnd <= rpc->rc_sent) + { + rpc->rc_cwnd += + (RPC_CWNDSCALE * RPC_CWNDSCALE + + (rpc->rc_cwnd >> 1)) / rpc->rc_cwnd; + if (rpc->rc_cwnd > RPC_MAXCWND) + rpc->rc_cwnd = RPC_MAXCWND; + } + + rep->r_flags &= ~TASK_SENT; + rpc->rc_sent -= RPC_CWNDSCALE; + + /* + * Update rtt using a gain of 0.125 on the + * mean and a gain of 0.25 on the deviation. + */ + if (rep->r_flags & TASK_TIMING) + { + /* + * Since the timer resolution of + * NFS_HZ is so course, it can often + * result in r_rtt == 0. Since r_rtt + * == N means that the actual rtt is + * between N+dt and N+2-dt ticks, add + * 1. + */ + t1 = rep->r_rtt + 1; + t1 -= (RPC_SRTT(rpc, rep) >> 3); + RPC_SRTT(rpc, rep) += t1; + if (t1 < 0) + t1 = -t1; + t1 -= (RPC_SDRTT(rpc, rep) >> 2); + RPC_SDRTT(rpc, rep) += t1; + } + rpc->rc_timeouts = 0; + break; + } + } + /* + * If not matched to a request, drop it. If it's mine, get + * out. + */ + if (rep == 0) + { + rpcstats.rpcunexpected++; + dbg("rpc reply not matched\n"); + } + else if (rep == myrep) + { + RPC_RETURN(0); + } + if (myrep->r_flags & TASK_GETONEREP) + RPC_RETURN(0); + } +} + +/* XXX: ignores tryagain! */ + +/* + * code from nfs_request - goes something like this - fill in task struct - + * links task into list - calls nfs_send() for first transmit - calls + * nfs_receive() to get reply - fills in reply (which should be initialized + * prior to calling), which is valid when 0 is returned and is NEVER freed in + * this function + * + * always frees the request header, but NEVER frees 'mrest' + * + */ + +/* + * note that reply->result_* are invalid unless reply->type == + * RPC_MSGACCEPTED and reply->status == RPC_SUCCESS and that reply->verf_* + * are invalid unless reply->type == RPC_MSGACCEPTED + */ +int rpcclnt_request(struct rpcclnt *rpc, int procnum, struct rpc_reply *reply) +{ + struct rpc_call *call; + struct rpc_reply *replysvr; + struct rpctask *task, _task; + int error = 0; + int xid; + + task = &_task; + memset(task, 0, sizeof(*task)); + + task->r_rpcclnt = rpc; + task->r_procnum = procnum; + + error = rpcclnt_buildheader(rpc, procnum, xid, call); + if (error) + { + printf("building call header error"); + goto rpcmout; + } + + task->r_xid = fxdr_unsigned(uint32_t, xid); + + if (rpc->rc_flag & RPCCLNT_SOFT) + task->r_retry = rpc->rc_retry; + else + task->r_retry = RPC_MAXREXMIT + 1; /* past clip limit */ + task->r_rtt = task->r_rexmit = 0; + + if (rpcclnt_proct(rpc, procnum) > 0) + task->r_flags = TASK_TIMING; + else + task->r_flags = 0; + + /* + * Do the client side RPC. + */ + rpcstats.rpcrequests++; + + /* + * Chain request into list of outstanding requests. Be sure to put it + * LAST so timer finds oldest requests first. + */ + dq_addlast(&task->r_chain, rpctask_q); + + /* + * If backing off another request or avoiding congestion, don't send + * this one now but let timer do it. If not timing a request, do it + * now. + */ + if (rpc->rc_so && (rpc->rc_sotype != SOCK_DGRAM || + (rpc->rc_flag & RPCCLNT_DUMBTIMR) || + rpc->rc_sent < rpc->rc_cwnd)) + { + +#ifdef CONFIG_NFS_TCPIP + if (rpc->rc_soflags & PR_CONNREQUIRED) + error = rpcclnt_sndlock(&rpc->rc_flag, task); +#endif + + if (error == 0) + { + error = rpcclnt_send(rpc->rc_so, rpc->rc_name, call, task); + +#ifdef CONFIG_NFS_TCPIP + if (rpc->rc_soflags & PR_CONNREQUIRED) + rpcclnt_sndunlock(&rpc->rc_flag); +#endif + } + if (error == 0 && (task->r_flags & TASK_MUSTRESEND) == 0) + { + rpc->rc_sent += RPC_CWNDSCALE; + task->r_flags |= TASK_SENT; + } + } + else + { + task->r_rtt = -1; + } + + /* + * Wait for the reply from our send. + */ + if (error == 0 || error == EPIPE) + error = rpcclnt_reply(task, call, replysvr); + + /* + * RPC done, unlink the request. + */ + dq_rem(&task->r_chain, rpctask_q); + + /* + * Decrement the outstanding request count. + */ + if (task->r_flags & TASK_SENT) + { + task->r_flags &= ~TASK_SENT; /* paranoia */ + rpc->rc_sent -= RPC_CWNDSCALE; + } + + if (error != 0) + goto rpcmout; + + /* + * break down the rpc header and check if ok + */ + reply->stat.type = fxdr_unsigned(uint32_t, replysvr->stat.type); + if (reply->stat.type == RPC_MSGDENIED) + { + reply->stat.status = fxdr_unsigned(uint32_t, replysvr->stat.status); + switch (reply->stat.status) + { + case RPC_MISMATCH: + reply->stat.mismatch_info.low = + fxdr_unsigned(uint32_t, replysvr->stat.mismatch_info.low); + reply->stat.mismatch_info.high = + fxdr_unsigned(uint32_t, replysvr->stat.mismatch_info.high); + printf("RPC_MSGDENIED: RPC_MISMATCH error"); + error = EOPNOTSUPP; + break; + case RPC_AUTHERR: + reply->stat.autherr = fxdr_unsigned(uint32_t, replysvr->stat.autherr); + printf("RPC_MSGDENIED: RPC_AUTHERR error"); + error = EACCES; + break; + default: + error = EOPNOTSUPP; + break; + } + goto rpcmout; + } + else if (reply->stat.type != RPC_MSGACCEPTED) + { + error = EOPNOTSUPP; + goto rpcmout; + } + + /* Verifier */ + + reply->rpc_verfi.authtype = + fxdr_unsigned(uint32_t, replysvr->rpc_verfi.authtype); + reply->rpc_verfi.authlen = + fxdr_unsigned(uint32_t, replysvr->rpc_verfi.authlen); + + if (reply->stat.status == RPC_SUCCESS) + { + printf("RPC_SUCCESS"); + } + else if (reply->stat.status == RPC_PROGMISMATCH) + { + reply->stat.mismatch_info.low = + fxdr_unsigned(uint32_t, replysvr->stat.mismatch_info.low); + reply->stat.mismatch_info.high = + fxdr_unsigned(uint32_t, replysvr->stat.mismatch_info.high); + printf("RPC_MSGACCEPTED: RPC_PROGMISMATCH error"); + error = EOPNOTSUPP; /* XXXMARIUS */ + } + else if (reply->stat.status > 5) + { + error = EOPNOTSUPP; + goto rpcmout; + } + +rpcmout: + RPC_RETURN(error); +} + +/* + * Nfs timer routine Scan the nfsreq list and retranmit any requests that + * have timed out To avoid retransmission attempts on STREAM sockets (in the + * future) make sure to set the r_retry field to 0 (implies nm_retry == 0). + */ +void rpcclnt_timer(void *arg, struct rpc_call *call) +{ + struct rpctask *rep; + struct socket *so; + struct rpcclnt *rpc; + int timeo, error; + + for (rep = (struct rpctask *)rpctask_q->head; rep; + rep = (struct rpctask *)rep->r_chain.flink) + { + rpc = rep->r_rpcclnt; + if (rep->r_flags & TASK_SOFTTERM) + continue; + if (rep->r_rtt >= 0) + { + rep->r_rtt++; + if (rpc->rc_flag & RPCCLNT_DUMBTIMR) + timeo = rpc->rc_timeo; + else + timeo = RPC_RTO(rpc, rpcclnt_proct(rep->r_rpcclnt, rep->r_procnum)); + if (rpc->rc_timeouts > 0) + timeo *= rpcclnt_backoff[rpc->rc_timeouts - 1]; + if (rep->r_rtt <= timeo) + continue; + if (rpc->rc_timeouts < 8) + rpc->rc_timeouts++; + } + /* + * Check for server not responding + */ + if ((rep->r_flags & TASK_TPRINTFMSG) == 0 && + rep->r_rexmit > rpc->rc_deadthresh) + { + printf("Server is not responding"); + rep->r_flags |= TASK_TPRINTFMSG; + } + if (rep->r_rexmit >= rep->r_retry) + { /* too many */ + rpcstats.rpctimeouts++; + rep->r_flags |= TASK_SOFTTERM; + continue; + } + if (rpc->rc_sotype != SOCK_DGRAM) + { + if (++rep->r_rexmit > RPC_MAXREXMIT) + rep->r_rexmit = RPC_MAXREXMIT; + continue; + } + if ((so = rpc->rc_so) == NULL) + continue; + + /* + * If there is enough space and the window allows.. Resend it + * Set r_rtt to -1 in case we fail to send it now. + */ + rep->r_rtt = -1; + if ((rpc->rc_flag & RPCCLNT_DUMBTIMR) || (rep->r_flags & TASK_SENT) || + rpc->rc_sent < rpc->rc_cwnd) + { + + if ((rpc->rc_flag & RPCCLNT_NOCONN) == 0) + error = psock_sendto(so, call, sizeof(*call), 0, NULL, 0); + else + error = + psock_sendto(so, call, sizeof(*call), 0, rpc->rc_name, + sizeof(*rpc->rc_name)); + + if (!error) + { + /* + * Iff first send, start timing else turn + * timing off, backoff timer and divide + * congestion window by 2. + */ + if (rep->r_flags & TASK_SENT) + { + rep->r_flags &= ~TASK_TIMING; + if (++rep->r_rexmit > RPC_MAXREXMIT) + rep->r_rexmit = RPC_MAXREXMIT; + rpc->rc_cwnd >>= 1; + if (rpc->rc_cwnd < RPC_CWNDSCALE) + rpc->rc_cwnd = RPC_CWNDSCALE; + rpcstats.rpcretries++; + } + else + { + rep->r_flags |= TASK_SENT; + rpc->rc_sent += RPC_CWNDSCALE; + } + rep->r_rtt = 0; + } + } + } + + // rpcclnt_timer_handle = timeout(rpcclnt_timer, NULL, rpcclnt_ticks); +} + +#ifdef CONFIG_NFS_TCPIP + +/* + * Lock a socket against others. Necessary for STREAM sockets to ensure you + * get an entire rpc request/reply and also to avoid race conditions between + * the processes with nfs requests in progress when a reconnect is necessary. + */ +static int rpcclnt_sndlock(flagp, task) + int *flagp; + struct rpctask *task; +{ + int slpflag = 0, slptimeo = 0; + + if (task) + { + if (task->r_rpcclnt->rc_flag & RPCCLNT_INT) + slpflag = PCATCH; + } + while (*flagp & RPCCLNT_SNDLOCK) + { + if (rpcclnt_sigintr(task->r_rpcclnt, task, p)) + return (EINTR); + *flagp |= RPCCLNT_WANTSND; + if (slpflag == PCATCH) + { + slpflag = 0; + slptimeo = 2 * CLOCKS_PER_SEC; + } + } + + *flagp |= RPCCLNT_SNDLOCK; + return (0); +} + +/* + * Unlock the stream socket for others. + */ +static void rpcclnt_sndunlock(flagp) + int *flagp; +{ + if ((*flagp & RPCCLNT_SNDLOCK) == 0) + panic("rpc sndunlock"); + *flagp &= ~RPCCLNT_SNDLOCK; + if (*flagp & RPCCLNT_WANTSND) + { + *flagp &= ~RPCCLNT_WANTSND; + } +} + +static int rpcclnt_rcvlock(task) + struct rpctask *task; +{ + int *flagp = &task->r_rpcclnt->rc_flag; + int slpflag, slptimeo = 0; + + if (*flagp & RPCCLNT_INT) + slpflag = PCATCH; + else + slpflag = 0; + + while (*flagp & RPCCLNT_RCVLOCK) + { + if (rpcclnt_sigintr(task->r_rpcclnt, task, task->r_td)) + return (EINTR); + *flagp |= RPCCLNT_WANTRCV; + tsleep((caddr_t) flagp, slpflag | (PZERO - 1), "rpcrcvlk", slptimeo); + if (slpflag == PCATCH) + { + slpflag = 0; + slptimeo = 2 * CLOCKS_PER_SEC; + } + } + *flagp |= RPCCLNT_RCVLOCK; + return (0); +} + +/* + * Unlock the stream socket for others. + */ +static void rpcclnt_rcvunlock(flagp) + int *flagp; +{ + + if ((*flagp & RPCCLNT_RCVLOCK) == 0) + panic("nfs rcvunlock"); + *flagp &= ~RPCCLNT_RCVLOCK; + if (*flagp & RPCCLNT_WANTRCV) + { + *flagp &= ~RPCCLNT_WANTRCV; + wakeup((caddr_t) flagp); + } +} +#endif + +/* + * Build the RPC header and fill in the authorization info. + */ +int rpcclnt_buildheader(struct rpcclnt *rc, int procid, + int xidp, struct rpc_call *call) +{ + struct timeval *tv; + srand(time(NULL)); + + /* + * The RPC header. + */ + + /* Get a new (non-zero) xid */ + if ((rpcclnt_xid == 0) && (rpcclnt_xid_touched == 0)) + { + rpcclnt_xid = rand(); + rpcclnt_xid_touched = 1; + } + else + { + do + { + xidp = rand(); + } + while ((xidp % 256) == 0); + rpcclnt_xid += xidp; + } + + call->rp_xid = xidp = txdr_unsigned(rpcclnt_xid); + call->rp_direction = rpc_call; + call->rp_rpcvers = rpc_vers; + call->rp_prog = txdr_unsigned(rc->rc_prog->prog_id); + call->rp_vers = txdr_unsigned(rc->rc_prog->prog_version); + call->rp_proc = txdr_unsigned(procid); + + /* rpc_auth part (auth_unix as root) */ + + call->rpc_auth.authtype = rpc_auth_null; + call->rpc_auth.authlen = txdr_unsigned(sizeof(NULL)); + + tv->tv_sec = 1; +#ifdef CONFIG_NFS_UNIX_AUTH + call->rpc_unix.ua_time = txdr_unsigned(tv->tv_sec); + call->rpc_unix.ua_hostname = 0; + call->rpc_unix.ua_uid = geteuid(); + call->rpc_unix.ua_gid = getegid(); + call->rpc_unix.ua_gidlist = 0; +#endif + /* rpc_verf part (auth_null) */ + + call->rpc_verf.authtype = 0; + call->rpc_verf.authlen = 0; + + return (0); +} + +static uint32_t rpcclnt_proct(struct rpcclnt *rpc, uint32_t procid) +{ + if (rpc->rc_proctlen != 0 && rpc->rc_proct != NULL && + procid < rpc->rc_proctlen) + return (rpc->rc_proct[procid]); + + return (0); +} + +int rpcclnt_cancelreqs(struct rpcclnt *rpc) +{ + struct rpctask *task; + int i; + + for (task = (struct rpctask *)rpctask_q->head; task; + task = (struct rpctask *)task->r_chain.flink) + { + if (rpc != task->r_rpcclnt || (task->r_flags & TASK_SOFTTERM)) + continue; + rpcclnt_softterm(task); + } + + for (i = 0; i < 30; i++) + { + for (task = (struct rpctask *)rpctask_q->head; task; + task = (struct rpctask *)task->r_chain.flink) + { + if (rpc == task->r_rpcclnt) + break; + } + if (task == NULL) + return (0); + } + + return (EBUSY); +} + +static void rpcclnt_softterm(struct rpctask *task) +{ + task->r_flags |= TASK_SOFTTERM; + if (task->r_flags & TASK_SENT) + { + task->r_rpcclnt->rc_sent -= RPC_CWNDSCALE; + task->r_flags &= ~TASK_SENT; + } +} diff --git a/fs/nfs/rpc_clnt_private.h b/fs/nfs/rpc_clnt_private.h new file mode 100644 index 0000000000..990f125581 --- /dev/null +++ b/fs/nfs/rpc_clnt_private.h @@ -0,0 +1,129 @@ +/* + * copyright (c) 2003 + * the regents of the university of michigan + * all rights reserved + * + * permission is granted to use, copy, create derivative works and redistribute + * this software and such derivative works for any purpose, so long as the name + * of the university of michigan is not used in any advertising or publicity + * pertaining to the use or distribution of this software without specific, + * written prior authorization. if the above copyright notice or any other + * identification of the university of michigan is included in any copy of any + * portion of this software, then the disclaimer below must also be included. + * + * this software is provided as is, without representation from the university + * of michigan as to its fitness for any purpose, and without warranty by the + * university of michigan of any kind, either express or implied, including + * without limitation the implied warranties of merchantability and fitness for + * a particular purpose. the regents of the university of michigan shall not be + * liable for any damages, including special, indirect, incidental, or + * consequential damages, with respect to any claim arising out of or in + * connection with the use of the software, even if it has been or is hereafter + * advised of the possibility of such damages. + */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Rick Macklem at The University of Guelph. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _RPCCLNT_PRIVATE_H_ +#define _RPCCLNT_PRIVATE_H_ + +#define RPCCLNT_DEBUG 1 + +#define RPC_TICKINTVL 5 + +/* from nfs/nfsproto.h */ + +#define RPC_MAXDATA 32768 +#define RPC_MAXPKTHDR 404 +#define RPC_MAXPACKET (RPC_MAXPKTHDR + RPC_MAXDATA) + +#define RPCX_UNSIGNED 4 + +#define RPC_SUCCESS 0 + +/* Flag values for r_flags */ + +#define TASK_TIMING 0x01 /* timing request (in mntp) */ +#define TASK_SENT 0x02 /* request has been sent */ +#define TASK_SOFTTERM 0x04 /* soft mnt, too many retries */ + + +#define TASK_INTR 0x08 /* intr mnt, signal pending */ +#define TASK_SOCKERR 0x10 /* Fatal error on socket */ + + +#define TASK_TPRINTFMSG 0x20 /* Did a tprintf msg. */ + +#define TASK_MUSTRESEND 0x40 /* Must resend request */ +#define TASK_GETONEREP 0x80 /* Probe for one reply only */ + + +#define RPC_HZ (CLOCKS_PER_SEC / rpcclnt_ticks) /* Ticks/sec */ +#define RPC_TIMEO (1 * RPC_HZ) /* Default timeout = 1 second */ + +#define RPC_MAXREXMIT 100 /* Stop counting after this many */ + + +#define RPCIGNORE_SOERROR(s, e) \ + ((e) != EINTR && (e) != ERESTART && (e) != EWOULDBLOCK) + +#define RPCINT_SIGMASK (sigmask(SIGINT)|sigmask(SIGTERM)|sigmask(SIGKILL)| \ + sigmask(SIGHUP)|sigmask(SIGQUIT)) + +#define RPCMADV(m, s) (m)->m_data += (s) + +#define RPCAUTH_ROOTCREDS NULL + +#define RPCCLNTINT_SIGMASK(set) \ + (SIGISMEMBER(set, SIGINT) || SIGISMEMBER(set, SIGTERM) || \ + SIGISMEMBER(set, SIGHUP) || SIGISMEMBER(set, SIGKILL) || \ + SIGISMEMBER(set, SIGQUIT)) + +/* global rpcstats + * XXX should be per rpcclnt */ + +struct rpcstats +{ + int rpcretries; + int rpcrequests; + int rpctimeouts; + int rpcunexpected; + int rpcinvalid; +}; + +#endif /* _RPCCLNT_PRIVATE_H_ */ diff --git a/fs/nfs/rpc_idgen.h b/fs/nfs/rpc_idgen.h deleted file mode 100644 index 42babc4d7d..0000000000 --- a/fs/nfs/rpc_idgen.h +++ /dev/null @@ -1,69 +0,0 @@ - -/* $OpenBSD: idgen.h,v 1.2 2008/06/25 00:55:53 djm Exp $ */ - -/* - */ - -/**************************************************************************** - * fs/nfs/rpc_idgen.h - * - * Copyright (C) 2012 Gregory Nutt. All rights reserved. - * Copyright (C) 2012 Jose Pablo Rojas Vargas. All rights reserved. - * Author: Jose Pablo Rojas Vargas - * - * Leveraged from OpenBSD: - * - * Copyright (c) 2008 Damien Miller - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - ****************************************************************************/ - -#ifndef __FS_NFS_RPC_IDGEN_H -#define __FS_NFS_RPC_IDGEN_H - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -#define IDGEN32_ROUNDS 31 -#define IDGEN32_KEYLEN 32 -#define IDGEN32_REKEY_LIMIT 0x60000000 -#define IDGEN32_REKEY_TIME 600 - -/**************************************************************************** - * Public Types - ****************************************************************************/ - -struct idgen32_ctx -{ - uint32_t id_counter; - uint32_t id_offset; - uint32_t id_hibit; - uint8_t id_key[IDGEN32_KEYLEN]; - time_t id_rekey_time; -}; - -/**************************************************************************** - * Public Function Prototypes - ****************************************************************************/ - -void idgen32_init(struct idgen32_ctx *); -uint32_t idgen32(struct idgen32_ctx *); - -#endif /* __FS_NFS_RPC_IDGEN_H */ - diff --git a/fs/nfs/rpc_mbuf.h b/fs/nfs/rpc_mbuf.h deleted file mode 100644 index f820f80457..0000000000 --- a/fs/nfs/rpc_mbuf.h +++ /dev/null @@ -1,449 +0,0 @@ -/**************************************************************************** - * fs/nfs/rpc_mbuf.h - * - * Copyright (C) 2012 Gregory Nutt. All rights reserved. - * Copyright (C) 2012 Jose Pablo Rojas Vargas. All rights reserved. - * Author: Jose Pablo Rojas Vargas - * - * Leveraged from OpenBSD: - * - * Copyright (c) 1982, 1986, 1988, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - ****************************************************************************/ - -#ifndef __FS_NFS_RPC_MBUF_H -#define __FS_NFS_RPC_MBUF_H - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ -/* Mbufs are of a single size, MSIZE (sys/param.h), which - * includes overhead. An mbuf may add a single "mbuf cluster" of size - * MCLBYTES (also in sys/param.h), which has no additional overhead - * and is used instead of the internal data area; this is done when - * at least MINCLSIZE of data must be stored. - */ - -#define MSIZE 128 -#define MCLSHIFT 11 /* Convert bytes to m_buf clusters */ - /* 2K cluster can hold Ether frame */ -#define MCLBYTES (1 << MCLSHIFT) /* Size of a m_buf cluster */ -#define MLEN (MSIZE - sizeof(struct m_hdr)) /* Normal data len */ -#define MHLEN (MLEN - sizeof(struct pkthdr)) /* Data len w/pkthdr */ - -/* smallest amount to put in cluster */ - -#define MINCLSIZE (MHLEN + MLEN + 1) -#define M_MAXCOMPRESS (MHLEN / 2) /* Max amount to copy for compression */ - -/* Macros for type conversion - * mtod(m,t) - convert mbuf pointer to data pointer of correct type - */ - -#define mtod(m,t) ((t)((m)->m_data)) - -/* mbuf flags */ - -#define M_EXT 0x0001 /* has associated external storage */ -#define M_PKTHDR 0x0002 /* start of record */ -#define M_EOR 0x0004 /* end of record */ -#define M_CLUSTER 0x0008 /* external storage is a cluster */ -#define M_PROTO1 0x0010 /* protocol-specific */ - -/* mbuf pkthdr flags, also in m_flags */ - -#define M_VLANTAG 0x0020 /* ether_vtag is valid */ -#define M_LOOP 0x0040 /* for Mbuf statistics */ -#define M_FILDROP 0x0080 /* dropped by bpf filter */ -#define M_BCAST 0x0100 /* send/received as link-level broadcast */ -#define M_MCAST 0x0200 /* send/received as link-level multicast */ -#define M_CONF 0x0400 /* payload was encrypted (ESP-transport) */ -#define M_AUTH 0x0800 /* payload was authenticated (AH or ESP auth) */ -#define M_TUNNEL 0x1000 /* IP-in-IP added by tunnel mode IPsec */ -#define M_AUTH_AH 0x2000 /* header was authenticated (AH) */ -#define M_COMP 0x4000 /* header was decompressed */ -#define M_LINK0 0x8000 /* link layer specific flag */ - -/* Flags copied when copying m_pkthdr */ - -#define M_COPYFLAGS (M_PKTHDR|M_EOR|M_PROTO1|M_BCAST|M_MCAST|M_CONF|M_COMP|\ - M_AUTH|M_LOOP|M_TUNNEL|M_LINK0|M_VLANTAG|M_FILDROP) - -/* Checksumming flags */ - -#define M_IPV4_CSUM_OUT 0x0001 /* IPv4 checksum needed */ -#define M_TCP_CSUM_OUT 0x0002 /* TCP checksum needed */ -#define M_UDP_CSUM_OUT 0x0004 /* UDP checksum needed */ -#define M_IPV4_CSUM_IN_OK 0x0008 /* IPv4 checksum verified */ -#define M_IPV4_CSUM_IN_BAD 0x0010 /* IPv4 checksum bad */ -#define M_TCP_CSUM_IN_OK 0x0020 /* TCP/IPv4 checksum verified */ -#define M_TCP_CSUM_IN_BAD 0x0040 /* TCP/IPv4 checksum bad */ -#define M_UDP_CSUM_IN_OK 0x0080 /* UDP/IPv4 checksum verified */ -#define M_UDP_CSUM_IN_BAD 0x0100 /* UDP/IPv4 checksum bad */ -#define M_ICMP_CSUM_OUT 0x0200 /* ICMP checksum needed */ -#define M_ICMP_CSUM_IN_OK 0x0400 /* ICMP checksum verified */ -#define M_ICMP_CSUM_IN_BAD 0x0800 /* ICMP checksum bad */ - -/* mbuf types */ - -#define MT_FREE 0 /* should be on free list */ -#define MT_DATA 1 /* dynamic (data) allocation */ -#define MT_HEADER 2 /* packet header */ -#define MT_SONAME 3 /* socket name */ -#define MT_SOOPTS 4 /* socket options */ -#define MT_FTABLE 5 /* fragment reassembly header */ -#define MT_CONTROL 6 /* extra-data protocol message */ -#define MT_OOBDATA 7 /* expedited data */ - -/* Flags to m_get/MGET */ - -#define M_DONTWAIT 0x0000 -#define M_WAIT 0x0001 - -/* mbuf allocation/deallocation macros: - * - * MGET(struct mbuf *m, int how, int type) - * allocates an mbuf and initializes it to contain internal data. - * - * MGETHDR(struct mbuf *m, int how, int type) - * allocates an mbuf and initializes it to contain a packet header - * and internal data. - */ - -#define MGET(m, how, type) m = m_get((how), (type)) -#define MGETHDR(m, how, type) m = m_gethdr((how), (type)) - -/* Macros for tracking external storage associated with an mbuf. - * - * Note: add and delete reference must be called at splnet(). - */ - -#ifdef CONFIG_DEBUG -# define MCLREFDEBUGN(m, file, line) do { \ - (m)->m_ext.ext_nfile = (file); \ - (m)->m_ext.ext_nline = (line); \ - } while (/* CONSTCOND */ 0) -# define MCLREFDEBUGO(m, file, line) do { \ - (m)->m_ext.ext_ofile = (file); \ - (m)->m_ext.ext_oline = (line); \ - } while (/* CONSTCOND */ 0) -#else -# define MCLREFDEBUGN(m, file, line) -# define MCLREFDEBUGO(m, file, line) -#endif - -#define MCLISREFERENCED(m) ((m)->m_ext.ext_nextref != (m)) - -#define MCLADDREFERENCE(o, n) do { \ - int ms = splnet(); \ - (n)->m_flags |= ((o)->m_flags & (M_EXT|M_CLUSTER)); \ - (n)->m_ext.ext_nextref = (o)->m_ext.ext_nextref; \ - (n)->m_ext.ext_prevref = (o); \ - (o)->m_ext.ext_nextref = (n); \ - (n)->m_ext.ext_nextref->m_ext.ext_prevref = (n); \ - splx(ms); \ - MCLREFDEBUGN((n), __FILE__, __LINE__); \ - } while (/* CONSTCOND */ 0) - -#define MCLINITREFERENCE(m) do { \ - (m)->m_ext.ext_prevref = (m); \ - (m)->m_ext.ext_nextref = (m); \ - MCLREFDEBUGO((m), __FILE__, __LINE__); \ - MCLREFDEBUGN((m), NULL, 0); \ - } while (/* CONSTCOND */ 0) - -/* Macros for mbuf external storage. - * - * MEXTADD adds pre-allocated external storage to - * a normal mbuf; the flag M_EXT is set. - * - * MCLGET allocates and adds an mbuf cluster to a normal mbuf; - * the flag M_EXT is set upon success. - */ - -#define MEXTADD(m, buf, size, type, free, arg) do { \ - (m)->m_data = (m)->m_ext.ext_buf = (char*)(buf); \ - (m)->m_flags |= M_EXT; \ - (m)->m_flags &= ~M_CLUSTER; \ - (m)->m_ext.ext_size = (size); \ - (m)->m_ext.ext_free = (free); \ - (m)->m_ext.ext_arg = (arg); \ - (m)->m_ext.ext_type = (type); \ - MCLINITREFERENCE(m); \ -} while (/* CONSTCOND */ 0) - -#define MCLGET(m, how) (void) m_clget((m), (how), NULL, MCLBYTES) -#define MCLGETI(m, how, ifp, l) m_clget((m), (how), (ifp), (l)) - -/* MFREE(struct mbuf *m, struct mbuf *n) - * Free a single mbuf and associated external storage. - * Place the successor, if any, in n. - */ - -#define MFREE(m, n) n = m_free((m)) - -/* Move just m_pkthdr from from to to, - * remove M_PKTHDR and clean flags/tags for from. - */ - -#define M_MOVE_HDR(to, from) do { \ - (to)->m_pkthdr = (from)->m_pkthdr; \ - (from)->m_flags &= ~M_PKTHDR; \ - SLIST_INIT(&(from)->m_pkthdr.tags); \ -} while (/* CONSTCOND */ 0) - -/* MOVE mbuf pkthdr from from to to. - * from must have M_PKTHDR set, and to must be empty. - */ - -#define M_MOVE_PKTHDR(to, from) do { \ - (to)->m_flags = ((to)->m_flags & (M_EXT | M_CLUSTER)); \ - (to)->m_flags |= (from)->m_flags & M_COPYFLAGS; \ - M_MOVE_HDR((to), (from)); \ - if (((to)->m_flags & M_EXT) == 0) \ - (to)->m_data = (to)->m_pktdat; \ -} while (/* CONSTCOND */ 0) - -/* Set the m_data pointer of a newly-allocated mbuf (m_get/MGET) to place - * an object of the specified size at the end of the mbuf, longword aligned. - */ - -#define M_ALIGN(m, len) \ - (m)->m_data += (MLEN - (len)) &~ (sizeof(long) - 1) - -/* As above, for mbufs allocated with m_gethdr/MGETHDR - * or initialized by M_MOVE_PKTHDR. - */ - -#define MH_ALIGN(m, len) \ - (m)->m_data += (MHLEN - (len)) &~ (sizeof(long) - 1) - -/* Determine if an mbuf's data area is read-only. This is true for - * non-cluster external storage and for clusters that are being - * referenced by more than one mbuf. - */ - -#define M_READONLY(m) \ - (((m)->m_flags & M_EXT) != 0 && \ - (((m)->m_flags & M_CLUSTER) == 0 || MCLISREFERENCED(m))) - -/* Compute the amount of space available - * before the current start of data in an mbuf. - */ - -#define M_LEADINGSPACE(m) m_leadingspace(m) - -/* Compute the amount of space available - * after the end of data in an mbuf. - */ - -#define M_TRAILINGSPACE(m) m_trailingspace(m) - -/* Arrange to prepend space of size plen to mbuf m. - * If a new mbuf must be allocated, how specifies whether to wait. - * If how is M_DONTWAIT and allocation fails, the original mbuf chain - * is freed and m is set to NULL. - */ - -#define M_PREPEND(m, plen, how) \ - (m) = m_prepend((m), (plen), (how)) - -/* Length to m_copy to copy all */ - -#define M_COPYALL 1000000000 - -/* Compatibility with 4.3 */ - -#define m_copy(m, o, l) m_copym((m), (o), (l), M_DONTWAIT) - - - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/* 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 */ - char *mh_data; /* Location of data */ - unsigned int mh_len; /* Amount of data in this mbuf */ - short mh_type; /* Type of data in this mbuf */ - unsigned short mh_flags; /* Flags; see below */ -}; - -/* Record/packet header in first mbuf of chain; valid if M_PKTHDR set */ - -struct pkthdr -{ - struct ifnet *rcvif; /* rcv interface */ - int len; /* Total packet length */ -}; - -/* Description of external storage mapped into mbuf, valid if M_EXT set */ - -struct mbuf_ext -{ - char* ext_buf; /* start of buffer */ - /* free routine if not the usual */ - // void (*ext_free)(); - // void *ext_arg; /* argument for ext_free */ - // unsigned int ext_size; /* size of buffer, for ext_free */ - unsigned int ext_size; /* size of buffer, for ext_free */ - }; - -struct mbuf - { - struct m_hdr m_hdr; - union - { - struct - { - struct pkthdr MH_pkthdr; /* M_PKTHDR set */ - union - { - struct mbuf_ext MH_ext; /* M_EXT set */ - char MH_databuf[MHLEN]; - } MH_dat; - } MH; - char M_databuf[MLEN]; /* !M_PKTHDR, !M_EXT */ - } M_dat; - }; - -#define m_next m_hdr.mh_next -#define m_len m_hdr.mh_len -#define m_data m_hdr.mh_data -#define m_type m_hdr.mh_type -#define m_flags m_hdr.mh_flags -#define m_nextpkt m_hdr.mh_nextpkt -#define m_act m_nextpkt -#define m_pkthdr M_dat.MH.MH_pkthdr -#define m_ext M_dat.MH.MH_dat.MH_ext -#define m_pktdat M_dat.MH.MH_dat.MH_databuf -#define m_dat M_dat.M_databuf - -/* Mbuf statistics. - * For statistics related to mbuf and cluster allocations, see also the - * pool headers (mbpool and mclpool). - */ - -struct mbstat -{ - unsigned long _m_spare; /* formerly m_mbufs */ - unsigned long _m_spare1; /* formerly m_clusters */ - unsigned long _m_spare2; /* spare field */ - unsigned long _m_spare3; /* formely m_clfree - free clusters */ - unsigned long m_drops; /* times failed to find space */ - unsigned long m_wait; /* times waited for space */ - unsigned long m_drain; /* times drained protocols for space */ - unsigned short m_mtypes[256]; /* type specific mbuf allocations */ -}; - -struct mclsizes -{ - unsigned int size; - unsigned int hwm; -}; - -/**************************************************************************** - * Public Data - ****************************************************************************/ - -extern struct mbstat mbstat; -extern int nmbclust; /* limit on the # of clusters */ -extern int mblowat; /* mbuf low water mark */ -extern int mcllowat; /* mbuf cluster low water mark */ -extern int max_linkhdr; /* largest link-level header */ -extern int max_protohdr; /* largest protocol header */ -extern int max_hdr; /* largest link+protocol header */ -extern int max_datalen; /* MHLEN - max_hdr */ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -void mbinit(void); -struct mbuf *m_copym2(struct mbuf *, int, int, int); -struct mbuf *m_copym(struct mbuf *, int, int, int); -struct mbuf *m_free(struct mbuf *); -struct mbuf *m_free_unlocked(struct mbuf *); -struct mbuf *m_get(int, int); -struct mbuf *m_getclr(int, int); -struct mbuf *m_gethdr(int, int); -struct mbuf *m_inithdr(struct mbuf *); -int m_defrag(struct mbuf *, int); -struct mbuf *m_prepend(struct mbuf *, int, int); -struct mbuf *m_pulldown(struct mbuf *, int, int, int *); -struct mbuf *m_pullup(struct mbuf *, int); -struct mbuf *m_split(struct mbuf *, int, int); -struct mbuf *m_inject(struct mbuf *, int, int, int); -struct mbuf *m_getptr(struct mbuf *, int, int *); -int m_leadingspace(struct mbuf *); -int m_trailingspace(struct mbuf *); -struct mbuf *m_clget(struct mbuf *, int, struct ifnet *, unsigned int); -void m_clsetwms(struct ifnet *, unsigned int, unsigned int, unsigned int); -int m_cldrop(struct ifnet *, int); -void m_clcount(struct ifnet *, int); -void m_cluncount(struct mbuf *, int); -void m_clinitifp(struct ifnet *); -void m_adj(struct mbuf *, int); -int m_copyback(struct mbuf *, int, int, const void *, int); -void m_freem(struct mbuf *); -void m_reclaim(void *, int); -void m_copydata(struct mbuf *, int, int, char*); -void m_cat(struct mbuf *, struct mbuf *); -struct mbuf *m_devget(char *, int, int, struct ifnet *, - void (*)(const void *, void *, size_t)); -void m_zero(struct mbuf *); -int m_apply(struct mbuf *, int, int, - int (*)(char*, char*, unsigned int), char*); -int m_dup_pkthdr(struct mbuf *, struct mbuf *, int); - -/* Packet tag routines */ - -struct m_tag *m_tag_get(int, int, int); -void m_tag_prepend(struct mbuf *, struct m_tag *); -void m_tag_delete(struct mbuf *, struct m_tag *); -void m_tag_delete_chain(struct mbuf *); -struct m_tag *m_tag_find(struct mbuf *, int, struct m_tag *); -struct m_tag *m_tag_copy(struct m_tag *, int); -int m_tag_copy_chain(struct mbuf *, struct mbuf *, int); -void m_tag_init(struct mbuf *); -struct m_tag *m_tag_first(struct mbuf *); -struct m_tag *m_tag_next(struct mbuf *, struct m_tag *); - -#endif /* __FS_NFS_RPC_MBUF_H */ - diff --git a/fs/nfs/rpc_subr.c b/fs/nfs/rpc_subr.c deleted file mode 100644 index 46543eddb0..0000000000 --- a/fs/nfs/rpc_subr.c +++ /dev/null @@ -1,456 +0,0 @@ -/**************************************************************************** - * fs/nfs/rpc_subr.c - * - * Copyright (C) 2012 Gregory Nutt. All rights reserved. - * Copyright (C) 2012 Jose Pablo Rojas Vargas. All rights reserved. - * Author: Jose Pablo Rojas Vargas - * - * Leveraged from OpenBSD: - * - * Copyright (c) 1995 Gordon Ross, Adam Glass - * Copyright (c) 1992 Regents of the University of California. - * All rights reserved. - * - * This software was developed by the Computer Systems Engineering group - * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and - * contributed to Berkeley. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Lawrence Berkeley Laboratory and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include -#include -#include -#include -#include -#include - -#include "rpc_v2.h" -#include "rpc.h" -#include "xdr_subs.h" - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -#define MIN_REPLY_HDR 16 /* xid, dir, astat, errno */ - -/* What is the longest we will wait before re-sending a request? - * Note this is also the frequency of "RPC timeout" messages. - * The re-send loop count sup linearly to this maximum, so the - * first complaint will happen after (1+2+3+4+5)=15 seconds. - */ - -#define MAX_RESEND_DELAY 5 /* seconds */ - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/* Generic RPC headers */ - -struct auth_info -{ - uint32_t authtype; /* auth type */ - uint32_t authlen; /* auth length */ -}; - -struct auth_unix -{ - int32_t ua_time; - int32_t ua_hostname; /* null */ - int32_t ua_uid; - int32_t ua_gid; - int32_t ua_gidlist; /* null */ -}; - -struct rpc_call -{ - uint32_t rp_xid; /* request transaction id */ - int32_t rp_direction; /* call direction (0) */ - uint32_t rp_rpcvers; /* rpc version (2) */ - uint32_t rp_prog; /* program */ - uint32_t rp_vers; /* version */ - uint32_t rp_proc; /* procedure */ - struct auth_info rpc_auth; - struct auth_unix rpc_unix; - struct auth_info rpc_verf; -}; - -struct rpc_reply -{ - uint32_t rp_xid; /* request transaction id */ - int32_t rp_direction; /* call direction (1) */ - int32_t rp_astatus; /* accept status (0: accepted) */ - union - { - uint32_t rpu_errno; - struct - { - struct auth_info rok_auth; - uint32_t rok_status; - } rpu_rok; - } rp_u; -}; - -#define rp_errno rp_u.rpu_errno -#define rp_auth rp_u.rpu_rok.rok_auth -#define rp_status rp_u.rpu_rok.rok_status - -/* String representation for RPC. */ - -struct xdr_string -{ - uint32_t len; /* length without null or padding */ - char data[4]; /* data (longer, of course) */ - /* data is padded to a long-word boundary */ -}; - -/* Inet address in RPC messages (Note, really four ints, NOT chars. Blech.) */ - -struct xdr_inaddr -{ - uint32_t atype; - uint32_t addr[4]; -}; - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/* Call portmap to lookup a port number for a particular rpc program - * Returns non-zero error on failure. - */ - -int krpc_portmap(struct sockaddr_in *sin, unsigned int prog, unsigned int vers, - uint16_t * portp) -{ - struct sdata - { - uint32_t prog; /* call program */ - uint32_t vers; /* call version */ - uint32_t proto; /* call protocol */ - uint32_t port; /* call port (unused) */ - } *sdata; - struct rdata - { - uint16_t pad; - uint16_t port; - } *rdata; - int error; - - /* The portmapper port is fixed. */ - - if (prog == PMAPPROG) - { - *portp = htons(PMAPPORT); - return 0; - } - - /* Do the RPC to get it. */ - - sdata->prog = txdr_unsigned(prog); - sdata->vers = txdr_unsigned(vers); - sdata->proto = txdr_unsigned(IPPROTO_UDP); - sdata->port = txdr_unsigned(0); - - sin->sin_port = htons(PMAPPORT); - error = krpc_call(sin, PMAPPROG, PMAPVERS, PMAPPROC_GETPORT, NULL, -1); - if (error) - { - return error; - } - - *portp = rdata->port; - - return 0; -} - -/* Do a remote procedure call (RPC) and wait for its reply. - * data: input/output - */ - -int krpc_call(struct sockaddr_in *sa, unsigned int prog, unsigned int vers, - unsigned int func, struct sockaddr **from_p, int retries) -{ - struct socket *so; - struct sockaddr_in *sin; - struct rpc_call *call; - struct rpc_reply *reply; - int error, rcvflg, timo, secs; - static uint32_t xid = 0; - struct timeval *tv; - uint16_t tport; - srand(time(NULL)); - - /* Validate address family. - * Sorry, this is INET specific... - */ - - if (sa->sin_family != AF_INET) - { - return (EAFNOSUPPORT); - } - - /* Create socket and set its receive timeout. */ - - if ((error = psock_socket(AF_INET, SOCK_DGRAM, 0, so))) - { - goto out; - } - - tv->tv_sec = 1; - tv->tv_usec = 0; - - if ((error = psock_setsockopt(so, SOL_SOCKET, SO_RCVTIMEO,(const void *) tv, sizeof (*tv)))) - { - goto out; - } - - /* Enable broadcast if necessary. */ - - if (from_p) - { - int on = 1; - if ((error = psock_setsockopt(so, SOL_SOCKET, SO_BROADCAST, (const void *) on, sizeof (on)))) - { - goto out; - } - } - - /* Bind the local endpoint to a reserved port, - * because some NFS servers refuse requests from - * non-reserved (non-privileged) ports. - */ - - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = INADDR_ANY; - tport = 1024; - - do - { - tport--; - sin->sin_port = htons(tport); - error = psock_bind(so, (struct sockaddr*) sin, sizeof(*sin)); - } - while (error == EADDRINUSE && tport > 1024 / 2); - - if (error) - { - printf("bind failed\n"); - goto out; - } - - /* Setup socket address for the server. */ - - memmove((void*)sin,(void*)sa, sizeof(*sa)); - - /* Prepend RPC message header. */ - - memset((void*) call, 0, sizeof(*call)); - - /* rpc_call part */ - - xid = rand(); - call->rp_xid = txdr_unsigned(xid); - call->rp_direction = txdr_unsigned(0); - call->rp_rpcvers = txdr_unsigned(2); - call->rp_prog = txdr_unsigned(prog); - call->rp_vers = txdr_unsigned(vers); - call->rp_proc = txdr_unsigned(func); - - /* rpc_auth part (auth_unix as root) */ - - call->rpc_auth.authtype = txdr_unsigned(RPCAUTH_UNIX); - call->rpc_auth.authlen = txdr_unsigned(sizeof(struct auth_unix)); - - /* rpc_verf part (auth_null) */ - - call->rpc_verf.authtype = 0; - call->rpc_verf.authlen = 0; - - /* Send it, repeatedly, until a reply is received, - * but delay each re-send by an increasing amount. - * If the delay hits the maximum, start complaining. - */ - - for (timo = 0; retries; retries--) - { - /* Send RPC request (or re-send). */ - - error = psock_send(so, call, sizeof(*call), 0); - if (error) - { - printf("krpc_call: psock_send: %d\n", error); - goto out; - } - - /* Determine new timeout. */ - - if (timo < MAX_RESEND_DELAY) - { - timo++; - } - else - { - printf("RPC timeout for server %s (0x%x) prog %u\n", - inet_ntoa(sin->sin_addr), ntohl(sin->sin_addr.s_addr), prog); - } - - /* Wait for up to timo seconds for a reply. - * The socket receive timeout was set to 1 second. - */ - - secs = timo; - while (secs > 0) - { - rcvflg = 0; - error = psock_recvfrom(so, reply, sizeof(*reply), rcvflg, NULL, 0); - if (error == EWOULDBLOCK) - { - secs--; - continue; - } - - if (error) - { - goto out; - } - - /* Is it the right reply? */ - - if (reply->rp_direction != txdr_unsigned(RPC_REPLY)) - { - continue; - } - - if (reply->rp_xid != txdr_unsigned(xid)) - { - continue; - } - - /* Was RPC accepted? (authorization OK) */ - - if (reply->rp_astatus != 0) - { - error = fxdr_unsigned(uint32_t, reply->rp_errno); - printf("rpc denied, error=%d\n", error); - error = ECONNREFUSED; - goto out; - } - - /* Did the call succeed? */ - - if (reply->rp_status != 0) - { - error = fxdr_unsigned(uint32_t, reply->rp_status); - printf("rpc denied, status=%d\n", error); - error = ECONNREFUSED; - goto out; - } - - goto gotsucreply; /* break two levels */ - } - } - - error = ETIMEDOUT; - goto out; - -gotsucreply: - return 0; - -out: - (void)psock_close(so); - return error; -} - -/* eXternal Data Representation routines. (but with non-standard args...) */ - -void xdr_string_encode(char *str, int len) -{ - struct xdr_string *xs; - - xs->len = txdr_unsigned(len); - strncpy(xs->data, str, len); -} - -void xdr_string_decode(char *str, int *len_p) -{ - struct xdr_string *xs; - int slen; /* string length */ - - slen = fxdr_unsigned(uint32_t, xs->len); - - if (slen > *len_p) - { - slen = *len_p; - } - - str[slen] = '\0'; - *len_p = slen; -} - -void xdr_inaddr_encode(struct in_addr *ia) -{ - struct xdr_inaddr *xi; - uint8_t *cp; - uint32_t *ip; - - xi->atype = txdr_unsigned(1); - ip = xi->addr; - cp = (uint8_t *) & ia->s_addr; - *ip++ = txdr_unsigned(*cp++); - *ip++ = txdr_unsigned(*cp++); - *ip++ = txdr_unsigned(*cp++); - *ip++ = txdr_unsigned(*cp++); -} - -void xdr_inaddr_decode(struct in_addr *ia) -{ - struct xdr_inaddr *xi; - uint8_t *cp; - uint32_t *ip; - - ip = xi->addr; - cp = (uint8_t *) & ia->s_addr; - *cp++ = fxdr_unsigned(uint8_t, *ip++); - *cp++ = fxdr_unsigned(uint8_t, *ip++); - *cp++ = fxdr_unsigned(uint8_t, *ip++); - *cp++ = fxdr_unsigned(uint8_t, *ip++); - - if (xi->atype != txdr_unsigned(1)) - { - ia->s_addr = INADDR_ANY; - } -} diff --git a/fs/nfs/rpc_types.h b/fs/nfs/rpc_types.h index df4b3dfe21..06924f86b3 100644 --- a/fs/nfs/rpc_types.h +++ b/fs/nfs/rpc_types.h @@ -59,35 +59,33 @@ struct lock int dummy; }; -struct iovec +typedef struct { int32_t val[2]; } fsid_t; /* file system id type */ + +/* + * File identifier. + * These are unique per filesystem on a single machine. + */ + +#define MAXFIDSZ 16 + +struct fid { - void *iov_base; /* Base address. */ - size_t iov_len; /* Length. */ + unsigned short fid_len; /* length of data in bytes */ + unsigned short fid_reserved; /* force longword alignment */ + char fid_data[MAXFIDSZ]; /* data (variable length) */ }; -enum uio_rw +/* + * Generic file handle + */ + +struct fhandle { - UIO_READ, - UIO_WRITE + fsid_t fh_fsid; /* File system id of mount point */ + struct fid fh_fid; /* File sys specific id */ }; -/* Segment flag values. */ - -enum uio_seg -{ - UIO_USERSPACE, /* from user data space */ - UIO_SYSSPACE /* from system space */ -}; - -struct uio -{ - struct iovec *uio_iov; /* scatter/gather list */ - int uio_iovcnt; /* length of scatter/gather list */ - off_t uio_offset; /* offset in target object */ - ssize_t uio_resid; /* remaining bytes to process */ - enum uio_seg uio_segflg; /* address space */ - enum uio_rw uio_rw; /* operation */ -}; +typedef struct fhandle fhandle_t; struct componentname { diff --git a/fs/nfs/xdr_subs.h b/fs/nfs/xdr_subs.h index 336fbc587f..6752d1f41f 100644 --- a/fs/nfs/xdr_subs.h +++ b/fs/nfs/xdr_subs.h @@ -92,12 +92,12 @@ } #define fxdr_hyper(f) \ - ((((uint64_t)ntohl(((u_int32_t *)(f))[0])) << 32) | \ - (uint64_t)(ntohl(((u_int32_t *)(f))[1]))) + ((((uint64_t)ntohl(((uint32_t *)(f))[0])) << 32) | \ + (uint64_t)(ntohl(((uint32_t *)(f))[1]))) #define txdr_hyper(f, t) { \ - ((u_int32_t *)(t))[0] = htonl((u_int32_t)((f) >> 32)); \ - ((u_int32_t *)(t))[1] = htonl((u_int32_t)((f) & 0xffffffff)); \ + ((uint32_t *)(t))[0] = htonl((uint32_t)((f) >> 32)); \ + ((uint32_t *)(t))[1] = htonl((uint32_t)((f) & 0xffffffff)); \ } #endif /* __FS_NFS_XDR_SUBS_H */