diff options
author | rmacklem <rmacklem@FreeBSD.org> | 2009-05-04 15:23:58 +0000 |
---|---|---|
committer | rmacklem <rmacklem@FreeBSD.org> | 2009-05-04 15:23:58 +0000 |
commit | e3d34903b6fb9cb09f7e616bde59d97341958fa2 (patch) | |
tree | 0246ff14527b554e60f1c9212be00ee8c1128197 /sys/fs/nfs | |
parent | fb2908c8ff440e0985013b83071bd8dfecb11371 (diff) | |
download | FreeBSD-src-e3d34903b6fb9cb09f7e616bde59d97341958fa2.zip FreeBSD-src-e3d34903b6fb9cb09f7e616bde59d97341958fa2.tar.gz |
Add the experimental nfs subtree to the kernel, that includes
support for NFSv4 as well as NFSv2 and 3.
It lives in 3 subdirs under sys/fs:
nfs - functions that are common to the client and server
nfsclient - a mutation of sys/nfsclient that call generic functions
to do RPCs and handle state. As such, it retains the
buffer cache handling characteristics and vnode semantics that
are found in sys/nfsclient, for the most part.
nfsserver - the server. It includes a DRC designed specifically for
NFSv4, that is used instead of the generic DRC in sys/rpc.
The build glue will be checked in later, so at this point, it
consists of 3 new subdirs that should not affect kernel building.
Approved by: kib (mentor)
Diffstat (limited to 'sys/fs/nfs')
-rw-r--r-- | sys/fs/nfs/nfs.h | 704 | ||||
-rw-r--r-- | sys/fs/nfs/nfs_commonacl.c | 750 | ||||
-rw-r--r-- | sys/fs/nfs/nfs_commonkrpc.c | 901 | ||||
-rw-r--r-- | sys/fs/nfs/nfs_commonport.c | 486 | ||||
-rw-r--r-- | sys/fs/nfs/nfs_commonsubs.c | 3404 | ||||
-rw-r--r-- | sys/fs/nfs/nfs_var.h | 604 | ||||
-rw-r--r-- | sys/fs/nfs/nfscl.h | 71 | ||||
-rw-r--r-- | sys/fs/nfs/nfsclstate.h | 175 | ||||
-rw-r--r-- | sys/fs/nfs/nfsdport.h | 105 | ||||
-rw-r--r-- | sys/fs/nfs/nfskpiport.h | 73 | ||||
-rw-r--r-- | sys/fs/nfs/nfsm_subs.h | 129 | ||||
-rw-r--r-- | sys/fs/nfs/nfsport.h | 751 | ||||
-rw-r--r-- | sys/fs/nfs/nfsproto.h | 1129 | ||||
-rw-r--r-- | sys/fs/nfs/nfsrvcache.h | 107 | ||||
-rw-r--r-- | sys/fs/nfs/nfsrvstate.h | 235 | ||||
-rw-r--r-- | sys/fs/nfs/nfsv4_errstr.h | 101 | ||||
-rw-r--r-- | sys/fs/nfs/rpcv2.h | 207 | ||||
-rw-r--r-- | sys/fs/nfs/xdr_subs.h | 99 |
18 files changed, 10031 insertions, 0 deletions
diff --git a/sys/fs/nfs/nfs.h b/sys/fs/nfs/nfs.h new file mode 100644 index 0000000..8a341ac --- /dev/null +++ b/sys/fs/nfs/nfs.h @@ -0,0 +1,704 @@ +/*- + * 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. + * + * $FreeBSD$ + */ + +#ifndef _NFS_NFS_H_ +#define _NFS_NFS_H_ +/* + * Tunable constants for nfs + */ + +#define NFS_MAXIOVEC 34 +#define NFS_TICKINTVL 10 /* Desired time for a tick (msec) */ +#define NFS_HZ (hz / nfscl_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_TCPTIMEO 300 /* TCP timeout */ +#define NFS_MAXRCVTIMEO 60 /* 1 minute in seconds */ +#define NFS_MINIDEMTIMEO (5 * NFS_HZ) /* Min timeout for non-idempotent ops*/ +#define NFS_MAXREXMIT 100 /* Stop counting after this many */ +#define NFSV4_CALLBACKTIMEO (2 * NFS_HZ) /* Timeout in ticks */ +#define NFSV4_CALLBACKRETRY 5 /* Number of retries before failure */ +#define NFSV4_CBRETRYCNT 4 /* # of CBRecall retries upon err */ +#define NFSV4_UPCALLTIMEO (15 * NFS_HZ) /* Timeout in ticks for upcalls */ + /* to gssd or nfsuserd */ +#define NFSV4_UPCALLRETRY 4 /* Number of retries before failure */ +#define NFS_MAXWINDOW 1024 /* Max number of outstanding requests */ +#define NFS_RETRANS 10 /* Num of retrans for soft mounts */ +#define NFS_MAXGRPS 16 /* Max. size of groups list */ +#define NFS_TRYLATERDEL 15 /* Maximum delay timeout (sec) */ +#ifndef NFS_REMOVETIMEO +#define NFS_REMOVETIMEO 15 /* # sec to wait for delegret in local syscall */ +#endif +#ifndef NFS_MINATTRTIMO +#define NFS_MINATTRTIMO 5 /* Attribute cache timeout in sec */ +#endif +#ifndef NFS_MAXATTRTIMO +#define NFS_MAXATTRTIMO 60 +#endif +#define NFS_WSIZE 8192 /* Def. write data size <= 8192 */ +#define NFS_RSIZE 8192 /* Def. read data size <= 8192 */ +#define NFS_READDIRSIZE 8192 /* Def. readdir size */ +#define NFS_DEFRAHEAD 0 /* Def. read ahead # blocks */ +#define NFS_MAXRAHEAD 32 /* Max. read ahead # blocks */ +#define NFS_MAXUIDHASH 64 /* Max. # of hashed uid entries/mp */ +#ifndef NFSRV_LEASE +#define NFSRV_LEASE 120 /* Lease time in seconds for V4 */ +#endif /* assigned to nfsrv_lease */ +#ifndef NFSRV_STALELEASE +#define NFSRV_STALELEASE (5 * nfsrv_lease) +#endif +#ifndef NFSRV_MOULDYLEASE +#define NFSRV_MOULDYLEASE 604800 /* One week (in sec) */ +#endif +#ifndef NFSCLIENTHASHSIZE +#define NFSCLIENTHASHSIZE 20 /* Size of server client hash table */ +#endif +#ifndef NFSLOCKHASHSIZE +#define NFSLOCKHASHSIZE 20 /* Size of server nfslock hash table */ +#endif +#define NFSSTATEHASHSIZE 10 /* Size of server stateid hash table */ +#ifndef NFSUSERHASHSIZE +#define NFSUSERHASHSIZE 30 /* Size of user id hash table */ +#endif +#ifndef NFSGROUPHASHSIZE +#define NFSGROUPHASHSIZE 5 /* Size of group id hash table */ +#endif +#ifndef NFSCLDELEGHIGHWATER +#define NFSCLDELEGHIGHWATER 10000 /* limit for client delegations */ +#endif +#ifndef NFSNOOPEN /* Inactive open owner (sec) */ +#define NFSNOOPEN 120 +#endif +#define NFSRV_LEASEDELTA 15 /* # of seconds to delay beyond lease */ +#define NFS_IDMAXSIZE 4 /* max sizeof (in_addr_t) */ +#ifndef NFSRVCACHE_UDPTIMEOUT +#define NFSRVCACHE_UDPTIMEOUT 30 /* # of sec to hold cached rpcs(udp) */ +#endif +#ifndef NFSRVCACHE_UDPHIGHWATER +#define NFSRVCACHE_UDPHIGHWATER 500 /* Max # of udp cache entries */ +#endif +#ifndef NFSRVCACHE_TCPTIMEOUT +#define NFSRVCACHE_TCPTIMEOUT (3600*12) /*#of sec to hold cached rpcs(tcp) */ +#endif +#ifndef NFSRVCACHE_FLOODLEVEL +#define NFSRVCACHE_FLOODLEVEL 16384 /* Very high water mark for cache */ +#endif +#ifndef NFSRV_CLIENTHIGHWATER +#define NFSRV_CLIENTHIGHWATER 1000 +#endif +#ifndef NFSRV_MAXDUMPLIST +#define NFSRV_MAXDUMPLIST 10000 +#endif +#ifndef NFS_ACCESSCACHESIZE +#define NFS_ACCESSCACHESIZE 8 +#endif +#define NFSV4_CBPORT 7745 /* Callback port for testing */ + +/* + * This macro defines the high water mark for issuing V4 delegations. + * (It is currently set at a conservative 20% of NFSRV_V4STATELIMIT. This + * may want to increase when clients can make more effective use of + * delegations.) + */ +#define NFSRV_V4DELEGLIMIT(c) (((c) * 5) > NFSRV_V4STATELIMIT) + +#define NFS_READDIRBLKSIZ DIRBLKSIZ /* Minimal nm_readdirsize */ + +/* + * Oddballs + */ +#define NFS_CMPFH(n, f, s) \ + ((n)->n_fhp->nfh_len == (s) && !NFSBCMP((n)->n_fhp->nfh_fh, (caddr_t)(f), (s))) +#define NFSRV_CMPFH(nf, ns, f, s) \ + ((ns) == (s) && !NFSBCMP((caddr_t)(nf), (caddr_t)(f), (s))) +#define NFS_CMPTIME(t1, t2) \ + ((t1).tv_sec == (t2).tv_sec && (t1).tv_nsec == (t2).tv_nsec) +#define NFS_SETTIME(t) do { \ + (t).tv_sec = time.tv_sec; (t).tv_nsec = 1000 * time.tv_usec; } while (0) +#define NFS_SRVMAXDATA(n) \ + (((n)->nd_flag & (ND_NFSV3 | ND_NFSV4)) ? \ + NFS_MAXDATA : NFS_V2MAXDATA) +#define NFS64BITSSET 0xffffffffffffffffull +#define NFS64BITSMINUS1 0xfffffffffffffffeull + +/* + * Structures for the nfssvc(2) syscall. Not that anyone but nfsd, mount_nfs + * and nfsloaduser should ever try and use it. + */ +struct nfsd_args { + int sock; /* Socket to serve */ + caddr_t name; /* Client addr for connection based sockets */ + int namelen; /* Length of name */ +}; + +/* + * nfsd argument for new krpc. + */ +struct nfsd_nfsd_args { + const char *principal; /* GSS-API service principal name */ + int minthreads; /* minimum service thread count */ + int maxthreads; /* maximum service thread count */ +}; + +/* + * Arguments for use by the callback daemon. + */ +struct nfsd_nfscbd_args { + const char *principal; /* GSS-API service principal name */ +}; + +struct nfscbd_args { + int sock; /* Socket to serve */ + caddr_t name; /* Client addr for connection based sockets */ + int namelen; /* Length of name */ + u_short port; /* Port# for callbacks */ +}; + +struct nfsd_idargs { + int nid_flag; /* Flags (see below) */ + uid_t nid_uid; /* user/group id */ + gid_t nid_gid; + int nid_usermax; /* Upper bound on user name cache */ + int nid_usertimeout;/* User name timeout (minutes) */ + u_char *nid_name; /* Name */ + int nid_namelen; /* and its length */ +}; + +struct nfsd_clid { + int nclid_idlen; /* Length of client id */ + u_char nclid_id[NFSV4_OPAQUELIMIT]; /* and name */ +}; + +struct nfsd_dumplist { + int ndl_size; /* Number of elements */ + void *ndl_list; /* and the list of elements */ +}; + +struct nfsd_dumpclients { + u_int32_t ndcl_flags; /* LCL_xxx flags */ + u_int32_t ndcl_nopenowners; /* Number of openowners */ + u_int32_t ndcl_nopens; /* and opens */ + u_int32_t ndcl_nlockowners; /* and of lockowners */ + u_int32_t ndcl_nlocks; /* and of locks */ + u_int32_t ndcl_ndelegs; /* and of delegations */ + u_int32_t ndcl_nolddelegs; /* and old delegations */ + sa_family_t ndcl_addrfam; /* Callback address */ + union { + struct in_addr sin_addr; + struct in6_addr sin6_addr; + } ndcl_cbaddr; + struct nfsd_clid ndcl_clid; /* and client id */ +}; + +struct nfsd_dumplocklist { + char *ndllck_fname; /* File Name */ + int ndllck_size; /* Number of elements */ + void *ndllck_list; /* and the list of elements */ +}; + +struct nfsd_dumplocks { + u_int32_t ndlck_flags; /* state flags NFSLCK_xxx */ + nfsv4stateid_t ndlck_stateid; /* stateid */ + u_int64_t ndlck_first; /* lock byte range */ + u_int64_t ndlck_end; + struct nfsd_clid ndlck_owner; /* Owner of open/lock */ + sa_family_t ndlck_addrfam; /* Callback address */ + union { + struct in_addr sin_addr; + struct in6_addr sin6_addr; + } ndlck_cbaddr; + struct nfsd_clid ndlck_clid; /* and client id */ +}; + +/* + * Structure for referral information. + */ +struct nfsreferral { + u_char *nfr_srvlist; /* List of servers */ + int nfr_srvcnt; /* number of servers */ + vnode_t nfr_vp; /* vnode for referral */ + u_int32_t nfr_dfileno; /* assigned dir inode# */ +}; + +/* + * Flags for lc_flags and opsflags for nfsrv_getclient(). + */ +#define LCL_NEEDSCONFIRM 0x00000001 +#define LCL_DONTCLEAN 0x00000002 +#define LCL_WAKEUPWANTED 0x00000004 +#define LCL_TCPCALLBACK 0x00000008 +#define LCL_CALLBACKSON 0x00000010 +#define LCL_INDEXNOTOK 0x00000020 +#define LCL_STAMPEDSTABLE 0x00000040 +#define LCL_EXPIREIT 0x00000080 +#define LCL_CBDOWN 0x00000100 +#define LCL_KERBV 0x00000400 +#define LCL_NAME 0x00000800 +#define LCL_NEEDSCBNULL 0x00001000 +#define LCL_GSSINTEGRITY 0x00002000 +#define LCL_GSSPRIVACY 0x00004000 +#define LCL_ADMINREVOKED 0x00008000 + +#define LCL_GSS LCL_KERBV /* Or of all mechs */ + +/* + * Bits for flags in nfslock and nfsstate. + * The access, deny, NFSLCK_READ and NFSLCK_WRITE bits must be defined as + * below, in the correct order, so the shifts work for tests. + */ +#define NFSLCK_READACCESS 0x00000001 +#define NFSLCK_WRITEACCESS 0x00000002 +#define NFSLCK_ACCESSBITS (NFSLCK_READACCESS | NFSLCK_WRITEACCESS) +#define NFSLCK_SHIFT 2 +#define NFSLCK_READDENY 0x00000004 +#define NFSLCK_WRITEDENY 0x00000008 +#define NFSLCK_DENYBITS (NFSLCK_READDENY | NFSLCK_WRITEDENY) +#define NFSLCK_SHAREBITS \ + (NFSLCK_READACCESS|NFSLCK_WRITEACCESS|NFSLCK_READDENY|NFSLCK_WRITEDENY) +#define NFSLCK_LOCKSHIFT 4 +#define NFSLCK_READ 0x00000010 +#define NFSLCK_WRITE 0x00000020 +#define NFSLCK_BLOCKING 0x00000040 +#define NFSLCK_RECLAIM 0x00000080 +#define NFSLCK_OPENTOLOCK 0x00000100 +#define NFSLCK_TEST 0x00000200 +#define NFSLCK_LOCK 0x00000400 +#define NFSLCK_UNLOCK 0x00000800 +#define NFSLCK_OPEN 0x00001000 +#define NFSLCK_CLOSE 0x00002000 +#define NFSLCK_CHECK 0x00004000 +#define NFSLCK_RELEASE 0x00008000 +#define NFSLCK_NEEDSCONFIRM 0x00010000 +#define NFSLCK_CONFIRM 0x00020000 +#define NFSLCK_DOWNGRADE 0x00040000 +#define NFSLCK_DELEGREAD 0x00080000 +#define NFSLCK_DELEGWRITE 0x00100000 +#define NFSLCK_DELEGCUR 0x00200000 +#define NFSLCK_DELEGPREV 0x00400000 +#define NFSLCK_OLDDELEG 0x00800000 +#define NFSLCK_DELEGRECALL 0x01000000 +#define NFSLCK_SETATTR 0x02000000 +#define NFSLCK_DELEGPURGE 0x04000000 +#define NFSLCK_DELEGRETURN 0x08000000 + +/* And bits for nid_flag */ +#define NFSID_INITIALIZE 0x0001 +#define NFSID_ADDUID 0x0002 +#define NFSID_DELUID 0x0004 +#define NFSID_ADDUSERNAME 0x0008 +#define NFSID_DELUSERNAME 0x0010 +#define NFSID_ADDGID 0x0020 +#define NFSID_DELGID 0x0040 +#define NFSID_ADDGROUPNAME 0x0080 +#define NFSID_DELGROUPNAME 0x0100 + +/* + * Stats structure + */ +struct nfsstats { + int attrcache_hits; + int attrcache_misses; + int lookupcache_hits; + int lookupcache_misses; + int direofcache_hits; + int direofcache_misses; + int accesscache_hits; + int accesscache_misses; + int biocache_reads; + int read_bios; + int read_physios; + int biocache_writes; + int write_bios; + int write_physios; + int biocache_readlinks; + int readlink_bios; + int biocache_readdirs; + int readdir_bios; + int rpccnt[NFS_NPROCS]; + int rpcretries; + int srvrpccnt[NFSV4OP_NOPS + NFSV4OP_FAKENOPS]; + int srvrpc_errs; + int srv_errs; + int rpcrequests; + int rpctimeouts; + int rpcunexpected; + int rpcinvalid; + int srvcache_inproghits; + int srvcache_idemdonehits; + int srvcache_nonidemdonehits; + int srvcache_misses; + int srvcache_tcppeak; + int srvcache_size; + int srvclients; + int srvopenowners; + int srvopens; + int srvlockowners; + int srvlocks; + int srvdelegates; + int cbrpccnt[NFSV4OP_CBNOPS]; + int clopenowners; + int clopens; + int cllockowners; + int cllocks; + int cldelegates; + int cllocalopenowners; + int cllocalopens; + int cllocallockowners; + int cllocallocks; +}; + +/* + * fs.nfs sysctl(3) identifiers + */ +#define NFS_NFSSTATS 1 /* struct: struct nfsstats */ + +#define FS_NFS_NAMES { \ + { 0, 0 }, \ + { "nfsstats", CTLTYPE_STRUCT }, \ +} + +/* + * Here is the definition of the attribute bits array and macros that + * manipulate it. + * THE MACROS MUST BE MANUALLY MODIFIED IF NFSATTRBIT_MAXWORDS CHANGES!! + * It is (NFSATTRBIT_MAX + 31) / 32. + */ +#define NFSATTRBIT_MAXWORDS 2 + +typedef struct { + u_int32_t bits[NFSATTRBIT_MAXWORDS]; +} nfsattrbit_t; + +#define NFSZERO_ATTRBIT(b) do { (b)->bits[0] = 0; (b)->bits[1] = 0; } while (0) +#define NFSSET_ATTRBIT(t, f) do { (t)->bits[0] = (f)->bits[0]; \ + (t)->bits[1] = (f)->bits[1]; } while (0) +#define NFSSETSUPP_ATTRBIT(b) do { \ + (b)->bits[0] = NFSATTRBIT_SUPP0; \ + (b)->bits[1] = (NFSATTRBIT_SUPP1 | NFSATTRBIT_SUPPSETONLY); } while (0) +#define NFSISSET_ATTRBIT(b, p) ((b)->bits[(p) / 32] & (1 << ((p) % 32))) +#define NFSSETBIT_ATTRBIT(b, p) ((b)->bits[(p) / 32] |= (1 << ((p) % 32))) +#define NFSCLRBIT_ATTRBIT(b, p) ((b)->bits[(p) / 32] &= ~(1 << ((p) % 32))) +#define NFSCLRALL_ATTRBIT(b, a) do { \ + (b)->bits[0] &= ~((a)->bits[0]); \ + (b)->bits[1] &= ~((a)->bits[1]); \ + } while (0) +#define NFSCLRNOT_ATTRBIT(b, a) do { \ + (b)->bits[0] &= ((a)->bits[0]); \ + (b)->bits[1] &= ((a)->bits[1]); \ + } while (0) +#define NFSCLRNOTFILLABLE_ATTRBIT(b) do { \ + (b)->bits[0] &= NFSATTRBIT_SUPP0; \ + (b)->bits[1] &= NFSATTRBIT_SUPP1; } while (0) +#define NFSCLRNOTSETABLE_ATTRBIT(b) do { \ + (b)->bits[0] &= NFSATTRBIT_SETABLE0; \ + (b)->bits[1] &= NFSATTRBIT_SETABLE1; } while (0) +#define NFSNONZERO_ATTRBIT(b) ((b)->bits[0] || (b)->bits[1]) +#define NFSEQUAL_ATTRBIT(b, p) \ + ((b)->bits[0] == (p)->bits[0] && (b)->bits[1] == (p)->bits[1]) +#define NFSGETATTR_ATTRBIT(b) do { \ + (b)->bits[0] = NFSATTRBIT_GETATTR0; \ + (b)->bits[1] = NFSATTRBIT_GETATTR1; } while (0) +#define NFSWCCATTR_ATTRBIT(b) do { \ + (b)->bits[0] = NFSATTRBIT_WCCATTR0; \ + (b)->bits[1] = NFSATTRBIT_WCCATTR1; } while (0) +#define NFSWRITEGETATTR_ATTRBIT(b) do { \ + (b)->bits[0] = NFSATTRBIT_WRITEGETATTR0; \ + (b)->bits[1] = NFSATTRBIT_WRITEGETATTR1; } while (0) +#define NFSCBGETATTR_ATTRBIT(b, c) do { \ + (c)->bits[0] = ((b)->bits[0] & NFSATTRBIT_CBGETATTR0); \ + (c)->bits[1] = ((b)->bits[1] & NFSATTRBIT_CBGETATTR1); } while (0) +#define NFSPATHCONF_GETATTRBIT(b) do { \ + (b)->bits[0] = NFSGETATTRBIT_PATHCONF0; \ + (b)->bits[1] = NFSGETATTRBIT_PATHCONF1; } while (0) +#define NFSSTATFS_GETATTRBIT(b) do { \ + (b)->bits[0] = NFSGETATTRBIT_STATFS0; \ + (b)->bits[1] = NFSGETATTRBIT_STATFS1; } while (0) +#define NFSISSETSTATFS_ATTRBIT(b) \ + (((b)->bits[0] & NFSATTRBIT_STATFS0) || \ + ((b)->bits[1] & NFSATTRBIT_STATFS1)) +#define NFSCLRSTATFS_ATTRBIT(b) do { \ + (b)->bits[0] &= ~NFSATTRBIT_STATFS0; \ + (b)->bits[1] &= ~NFSATTRBIT_STATFS1; } while (0) +#define NFSREADDIRPLUS_ATTRBIT(b) do { \ + (b)->bits[0] = NFSATTRBIT_READDIRPLUS0; \ + (b)->bits[1] = NFSATTRBIT_READDIRPLUS1; } while (0) +#define NFSREFERRAL_ATTRBIT(b) do { \ + (b)->bits[0] = NFSATTRBIT_REFERRAL0; \ + (b)->bits[1] = NFSATTRBIT_REFERRAL1; } while (0) + +/* + * Store uid, gid creds that handle maps to. + * Since some BSDen define cr_gid as cr_groups[0], I'll just keep them + * all in nfsc_groups[NGROUPS + 1]. + */ +struct nfscred { + uid_t nfsc_uid; + gid_t nfsc_groups[NGROUPS + 1]; + int nfsc_ngroups; +}; + +/* + * Constants that define the file handle for the V4 root directory. + * (The FSID must never be used by other file systems that are exported.) + */ +#define NFSV4ROOT_FSID0 ((int32_t) -1) +#define NFSV4ROOT_FSID1 ((int32_t) -1) +#define NFSV4ROOT_REFERRAL ((int32_t) -2) +#define NFSV4ROOT_INO 2 /* It's traditional */ +#define NFSV4ROOT_GEN 1 + +/* + * 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. + */ +#if defined(_KERNEL) || defined(KERNEL) + +struct uio; struct buf; struct vattr; struct nameidata; /* XXX */ + +/* + * 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) + + +/* + * This structure holds socket information for a connection. Used by the + * client and the server for callbacks. + */ +struct nfssockreq { + NFSSOCKADDR_T nr_nam; + int nr_sotype; + int nr_soproto; + int nr_soflags; + struct ucred *nr_cred; + int nr_lock; + NFSMUTEX_T nr_mtx; + u_int32_t nr_prog; + u_int32_t nr_vers; + struct __rpc_client *nr_client; +}; + +/* + * And associated nr_lock bits. + */ +#define NFSR_SNDLOCK 0x01 +#define NFSR_WANTSND 0x02 +#define NFSR_RCVLOCK 0x04 +#define NFSR_WANTRCV 0x08 +#define NFSR_RESERVEDPORT 0x10 +#define NFSR_LOCALHOST 0x20 + +/* + * Queue head for nfsreq's + */ +TAILQ_HEAD(nfsreqhead, nfsreq); + +/* First 8 R_xxx flags defined in rpc/rpcclnt.h, the rest are here */ +#define R_DONTRECOVER 0x00000100 /* don't initiate recovery when this + rpc gets a stale state reply */ + +/* + * Network address hash list element + */ +union nethostaddr { + struct in_addr had_inet; + struct in6_addr had_inet6; +}; + +/* + * Structure of list of mechanisms. + */ +struct nfsgss_mechlist { + int len; + const u_char *str; + int totlen; +}; +#define KERBV_MECH 0 /* position in list */ + +/* + * This structure is used by the server for describing each request. + */ +struct nfsrv_descript { + mbuf_t nd_mrep; /* Request mbuf list */ + mbuf_t nd_md; /* Current dissect mbuf */ + mbuf_t nd_mreq; /* Reply mbuf list */ + mbuf_t nd_mb; /* Current build mbuf */ + NFSSOCKADDR_T nd_nam; /* and socket addr */ + NFSSOCKADDR_T nd_nam2; /* return socket addr */ + caddr_t nd_dpos; /* Current dissect pos */ + caddr_t nd_bpos; /* Current build pos */ + u_int16_t nd_procnum; /* RPC # */ + u_int32_t nd_flag; /* nd_flag */ + u_int32_t nd_repstat; /* Reply status */ + int *nd_errp; /* Pointer to ret status */ + u_int32_t nd_retxid; /* Reply xid */ + struct nfsrvcache *nd_rp; /* Assoc. cache entry */ + struct timeval nd_starttime; /* Time RPC initiated */ + fhandle_t nd_fh; /* File handle */ + struct ucred *nd_cred; /* Credentials */ + uid_t nd_saveduid; /* Saved uid */ + u_int64_t nd_sockref; /* Rcv socket ref# */ + u_int64_t nd_compref; /* Compound RPC ref# */ + time_t nd_tcpconntime; /* Time TCP connection est. */ + nfsquad_t nd_clientid; /* Implied clientid */ + int nd_credflavor; /* credential flavor */ + int nd_gssnamelen; /* principal name length */ + char *nd_gssname; /* principal name */ +}; + +#define nd_princlen nd_gssnamelen +#define nd_principal nd_gssname + +/* Bits for "nd_flag" */ +#define ND_DONTSAVEREPLY 0x00000001 +#define ND_SAVEREPLY 0x00000002 +#define ND_NFSV2 0x00000004 +#define ND_NFSV3 0x00000008 +#define ND_NFSV4 0x00000010 +#define ND_KERBV 0x00000020 +#define ND_GSSINTEGRITY 0x00000040 +#define ND_GSSPRIVACY 0x00000080 +#define ND_WINDOWVERF 0x00000100 +#define ND_GSSINITREPLY 0x00000200 +#define ND_STREAMSOCK 0x00000400 +#define ND_PUBLOOKUP 0x00000800 +#define ND_USEGSSNAME 0x00001000 +#define ND_SAMETCPCONN 0x00002000 +#define ND_IMPLIEDCLID 0x00004000 +#define ND_NOMOREDATA 0x00008000 +#define ND_V4WCCATTR 0x00010000 +#define ND_NFSCB 0x00020000 +#define ND_AUTHNONE 0x00040000 +#define ND_EXGSSONLY 0x00080000 +#define ND_INCRSEQID 0x00100000 + +/* + * ND_GSS should be the "or" of all GSS type authentications. + */ +#define ND_GSS (ND_KERBV) + +struct nfsv4_opflag { + int retfh; + int needscfh; + int savereply; + int modifyfs; +}; + +/* + * Flags used to indicate what to do w.r.t. seqid checking. + */ +#define NFSRVSEQID_FIRST 0x01 +#define NFSRVSEQID_LAST 0x02 +#define NFSRVSEQID_OPEN 0x04 + +/* + * MNT_EXGSSONLY is the Or of all the EXGSS bits. + */ +#define MNT_EXGSSONLY MNT_EXGSSKRB5 + +/* + * assign a doubly linked list to a new head + * and prepend one list into another. + */ +#define LIST_NEWHEAD(nhead, ohead, field) do { \ + if (((nhead)->lh_first = (ohead)->lh_first) != NULL) \ + (ohead)->lh_first->field.le_prev = &(nhead)->lh_first; \ + (ohead)->lh_first = NULL; \ + } while (0) + +#define LIST_PREPEND(head, phead, lelm, field) do { \ + if ((head)->lh_first != NULL) { \ + (lelm)->field.le_next = (head)->lh_first; \ + (lelm)->field.le_next->field.le_prev = \ + &(lelm)->field.le_next; \ + } \ + (head)->lh_first = (phead)->lh_first; \ + (head)->lh_first->field.le_prev = &(head)->lh_first; \ + } while (0) + +/* + * File handle structure for client. Malloc'd to the correct length with + * malloc type M_NFSFH. + */ +struct nfsfh { + u_int16_t nfh_len; /* Length of file handle */ + u_int8_t nfh_fh[1]; /* and the file handle */ +}; + +/* + * File handle structure for server. The NFSRV_MAXFH constant is + * set in nfsdport.h. I use a 32bit length, so that alignment is + * preserved. + */ +struct nfsrvfh { + u_int32_t nfsrvfh_len; + u_int8_t nfsrvfh_data[NFSRV_MAXFH]; +}; + +/* + * This structure is used for sleep locks on the NFSv4 nfsd threads and + * NFSv4 client data structures. + */ +struct nfsv4lock { + u_int32_t nfslock_usecnt; + u_int8_t nfslock_lock; +}; +#define NFSV4LOCK_LOCK 0x01 +#define NFSV4LOCK_LOCKWANTED 0x02 +#define NFSV4LOCK_WANTED 0x04 + +/* + * Values for the override argument for nfsvno_accchk(). + */ +#define NFSACCCHK_NOOVERRIDE 0 +#define NFSACCCHK_ALLOWROOT 1 +#define NFSACCCHK_ALLOWOWNER 2 + +/* + * and values for the vpislocked argument for nfsvno_accchk(). + */ +#define NFSACCCHK_VPNOTLOCKED 0 +#define NFSACCCHK_VPISLOCKED 1 + +#endif /* _KERNEL */ + +#endif /* _NFS_NFS_H */ diff --git a/sys/fs/nfs/nfs_commonacl.c b/sys/fs/nfs/nfs_commonacl.c new file mode 100644 index 0000000..9ebfd32 --- /dev/null +++ b/sys/fs/nfs/nfs_commonacl.c @@ -0,0 +1,750 @@ +/*- + * Copyright (c) 2009 Rick Macklem, University of Guelph + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#ifndef APPLEKEXT +#include <fs/nfs/nfsport.h> + +extern int nfsrv_useacl; +#endif + +static int nfsrv_acemasktoperm(u_int32_t acetype, u_int32_t mask, int owner, + enum vtype type, acl_perm_t *permp); + +#if defined(NFS4_ACL_EXTATTR_NAME) +/* + * Handle xdr for an ace. + */ +APPLESTATIC int +nfsrv_dissectace(struct nfsrv_descript *nd, struct acl_entry *acep, + int *aceerrp, int *acesizep, NFSPROC_T *p) +{ + u_int32_t *tl; + int len, gotid = 0, owner = 0, error = 0, aceerr = 0; + u_char *name, namestr[NFSV4_SMALLSTR + 1]; + u_int32_t flag, mask, acetype; + gid_t gid; + uid_t uid; + + *aceerrp = 0; + acep->ae_flags = 0; + NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); + acetype = fxdr_unsigned(u_int32_t, *tl++); + flag = fxdr_unsigned(u_int32_t, *tl++); + mask = fxdr_unsigned(u_int32_t, *tl++); + len = fxdr_unsigned(int, *tl); + if (len < 0) { + return (NFSERR_BADXDR); + } else if (len == 0) { + /* Netapp filers return a 0 length who for nil users */ + acep->ae_tag = ACL_UNDEFINED_TAG; + acep->ae_id = ACL_UNDEFINED_ID; + acep->ae_perm = (acl_perm_t)0; + acep->ae_extended = ACL_EXTENDED_DENY; + if (acesizep) + *acesizep = 4 * NFSX_UNSIGNED; + return (0); + } + if (len > NFSV4_SMALLSTR) + name = malloc(len + 1, M_NFSSTRING, M_WAITOK); + else + name = namestr; + error = nfsrv_mtostr(nd, name, len); + if (error) { + if (len > NFSV4_SMALLSTR) + free(name, M_NFSSTRING); + return (error); + } + if (len == 6) { + if (!NFSBCMP(name, "OWNER@", 6)) { + acep->ae_tag = ACL_USER_OBJ; + acep->ae_id = ACL_UNDEFINED_ID; + owner = 1; + gotid = 1; + } else if (!NFSBCMP(name, "GROUP@", 6)) { + acep->ae_tag = ACL_GROUP_OBJ; + acep->ae_id = ACL_UNDEFINED_ID; + gotid = 1; + } + } else if (len == 9 && !NFSBCMP(name, "EVERYONE@", 9)) { + acep->ae_tag = ACL_EVERYONE; + acep->ae_id = ACL_UNDEFINED_ID; + gotid = 1; + } + if (gotid == 0) { + if (flag & NFSV4ACE_IDENTIFIERGROUP) { + acep->ae_tag = ACL_GROUP; + aceerr = nfsv4_strtogid(name, len, &gid, p); + if (aceerr == 0) + acep->ae_id = (uid_t)gid; + } else { + acep->ae_tag = ACL_USER; + aceerr = nfsv4_strtouid(name, len, &uid, p); + if (aceerr == 0) + acep->ae_id = uid; + } + } + if (len > NFSV4_SMALLSTR) + free(name, M_NFSSTRING); + + if (aceerr == 0) { + /* + * Handle the flags. + */ + flag &= ~NFSV4ACE_IDENTIFIERGROUP; + if (flag & NFSV4ACE_FILEINHERIT) { + flag &= ~NFSV4ACE_FILEINHERIT; + acep->ae_flags |= ACL_ENTRY_FILE_INHERIT; + } + if (flag & NFSV4ACE_DIRECTORYINHERIT) { + flag &= ~NFSV4ACE_DIRECTORYINHERIT; + acep->ae_flags |= ACL_ENTRY_DIRECTORY_INHERIT; + } + if (flag & NFSV4ACE_NOPROPAGATEINHERIT) { + flag &= ~NFSV4ACE_NOPROPAGATEINHERIT; + acep->ae_flags |= ACL_ENTRY_LIMIT_INHERIT; + } + if (flag & NFSV4ACE_INHERITONLY) { + flag &= ~NFSV4ACE_INHERITONLY; + acep->ae_flags |= ACL_ENTRY_ONLY_INHERIT; + } + if (flag & NFSV4ACE_SUCCESSFULACCESS) { + flag &= ~NFSV4ACE_SUCCESSFULACCESS; + acep->ae_flags |= ACL_ENTRY_SUCCESSFUL_ACCESS; + } + if (flag & NFSV4ACE_FAILEDACCESS) { + flag &= ~NFSV4ACE_FAILEDACCESS; + acep->ae_flags |= ACL_ENTRY_FAILED_ACCESS; + } + /* + * Set ae_extended. + */ + if (acetype == NFSV4ACE_ALLOWEDTYPE) + acep->ae_extended = ACL_EXTENDED_ALLOW; + else if (acetype == NFSV4ACE_DENIEDTYPE) + acep->ae_extended = ACL_EXTENDED_DENY; + else if (acetype == NFSV4ACE_AUDITTYPE) + acep->ae_extended = ACL_EXTENDED_AUDIT; + else if (acetype == NFSV4ACE_ALARMTYPE) + acep->ae_extended = ACL_EXTENDED_ALARM; + else + aceerr = NFSERR_ATTRNOTSUPP; + } + + /* + * Now, check for unsupported flag bits. + */ + if (aceerr == 0 && flag != 0) + aceerr = NFSERR_ATTRNOTSUPP; + + /* + * And turn the mask into perm bits. + */ + if (aceerr == 0) + aceerr = nfsrv_acemasktoperm(acetype, mask, owner, VREG, + &acep->ae_perm); + *aceerrp = aceerr; + if (acesizep) + *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED); + return (0); +nfsmout: + return (error); +} + +/* + * Turn an NFSv4 ace mask into R/W/X flag bits. + */ +static int +nfsrv_acemasktoperm(u_int32_t acetype, u_int32_t mask, int owner, + enum vtype type, acl_perm_t *permp) +{ + acl_perm_t perm = 0x0; + + if (mask & NFSV4ACE_READDATA) { + mask &= ~NFSV4ACE_READDATA; + perm |= ACL_READ_DATA; + } + if (mask & NFSV4ACE_LISTDIRECTORY) { + mask &= ~NFSV4ACE_LISTDIRECTORY; + perm |= ACL_LIST_DIRECTORY; + } + if (mask & NFSV4ACE_WRITEDATA) { + mask &= ~NFSV4ACE_WRITEDATA; + perm |= ACL_WRITE_DATA; + } + if (mask & NFSV4ACE_ADDFILE) { + mask &= ~NFSV4ACE_ADDFILE; + perm |= ACL_ADD_FILE; + } + if (mask & NFSV4ACE_APPENDDATA) { + mask &= ~NFSV4ACE_APPENDDATA; + perm |= ACL_APPEND_DATA; + } + if (mask & NFSV4ACE_ADDSUBDIRECTORY) { + mask &= ~NFSV4ACE_ADDSUBDIRECTORY; + perm |= ACL_ADD_SUBDIRECTORY; + } + if (mask & NFSV4ACE_READNAMEDATTR) { + mask &= ~NFSV4ACE_READNAMEDATTR; + perm |= ACL_READ_NAMED_ATTRS; + } + if (mask & NFSV4ACE_WRITENAMEDATTR) { + mask &= ~NFSV4ACE_WRITENAMEDATTR; + perm |= ACL_WRITE_NAMED_ATTRS; + } + if (mask & NFSV4ACE_EXECUTE) { + mask &= ~NFSV4ACE_EXECUTE; + perm |= ACL_EXECUTE; + } + if (mask & NFSV4ACE_SEARCH) { + mask &= ~NFSV4ACE_SEARCH; + perm |= ACL_SEARCH; + } + if (mask & NFSV4ACE_DELETECHILD) { + mask &= ~NFSV4ACE_DELETECHILD; + perm |= ACL_DELETE_CHILD; + } + if (mask & NFSV4ACE_READATTRIBUTES) { + mask &= ~NFSV4ACE_READATTRIBUTES; + perm |= ACL_READ_ATTRIBUTES; + } + if (mask & NFSV4ACE_WRITEATTRIBUTES) { + mask &= ~NFSV4ACE_WRITEATTRIBUTES; + perm |= ACL_WRITE_ATTRIBUTES; + } + if (mask & NFSV4ACE_DELETE) { + mask &= ~NFSV4ACE_DELETE; + perm |= ACL_DELETE; + } + if (mask & NFSV4ACE_READACL) { + mask &= ~NFSV4ACE_READACL; + perm |= ACL_READ_ACL; + } + if (mask & NFSV4ACE_WRITEACL) { + mask &= ~NFSV4ACE_WRITEACL; + perm |= ACL_WRITE_ACL; + } + if (mask & NFSV4ACE_WRITEOWNER) { + mask &= ~NFSV4ACE_WRITEOWNER; + perm |= ACL_WRITE_OWNER; + } + if (mask & NFSV4ACE_SYNCHRONIZE) { + mask &= ~NFSV4ACE_SYNCHRONIZE; + perm |= ACL_SYNCHRONIZE; + } + if (mask != 0) + return (NFSERR_ATTRNOTSUPP); + *permp = perm; + return (0); +} +#else +/* + * Handle xdr for an ace. + */ +APPLESTATIC int +nfsrv_dissectace(struct nfsrv_descript *nd, struct acl_entry *acep, + int *aceerrp, int *acesizep, NFSPROC_T *p) +{ + u_int32_t *tl; + int len, gotid = 0, owner = 0, error = 0, aceerr = 0; + u_char *name, namestr[NFSV4_SMALLSTR + 1]; + u_int32_t flag, mask, acetype; + gid_t gid; + uid_t uid; + + *aceerrp = 0; + NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); + acetype = fxdr_unsigned(u_int32_t, *tl++); + flag = fxdr_unsigned(u_int32_t, *tl++); + mask = fxdr_unsigned(u_int32_t, *tl++); + len = fxdr_unsigned(int, *tl); + if (len < 0) { + return (NFSERR_BADXDR); + } else if (len == 0) { + /* Netapp filers return a 0 length who for nil users */ + acep->ae_tag = ACL_UNDEFINED_TAG; + acep->ae_id = ACL_UNDEFINED_ID; + acep->ae_perm = (acl_perm_t)0; + if (acesizep) + *acesizep = 4 * NFSX_UNSIGNED; + return (0); + } + if (len > NFSV4_SMALLSTR) + name = malloc(len + 1, M_NFSSTRING, M_WAITOK); + else + name = namestr; + error = nfsrv_mtostr(nd, name, len); + if (error) { + if (len > NFSV4_SMALLSTR) + free(name, M_NFSSTRING); + return (error); + } + if (len == 6) { + if (!NFSBCMP(name, "OWNER@", 6)) { + acep->ae_tag = ACL_USER_OBJ; + acep->ae_id = ACL_UNDEFINED_ID; + owner = 1; + gotid = 1; + } else if (!NFSBCMP(name, "GROUP@", 6)) { + acep->ae_tag = ACL_GROUP_OBJ; + acep->ae_id = ACL_UNDEFINED_ID; + gotid = 1; + flag &= ~NFSV4ACE_IDENTIFIERGROUP; + } + } else if (len == 9 && !NFSBCMP(name, "EVERYONE@", 9)) { + acep->ae_tag = ACL_OTHER; + acep->ae_id = ACL_UNDEFINED_ID; + gotid = 1; + } + if (!gotid) { + if (flag & NFSV4ACE_IDENTIFIERGROUP) { + flag &= ~NFSV4ACE_IDENTIFIERGROUP; + acep->ae_tag = ACL_GROUP; + aceerr = nfsv4_strtogid(name, len, &gid, p); + if (!aceerr) + acep->ae_id = (uid_t)gid; + } else { + acep->ae_tag = ACL_USER; + aceerr = nfsv4_strtouid(name, len, &uid, p); + if (!aceerr) + acep->ae_id = uid; + } + } + if (len > NFSV4_SMALLSTR) + free(name, M_NFSSTRING); + + /* + * Now, check for unsupported types or flag bits. + */ + if (!aceerr && ((acetype != NFSV4ACE_ALLOWEDTYPE && + acetype != NFSV4ACE_AUDITTYPE && acetype != NFSV4ACE_ALARMTYPE + && acetype != NFSV4ACE_DENIEDTYPE) || flag)) + aceerr = NFSERR_ATTRNOTSUPP; + + /* + * And turn the mask into perm bits. + */ + if (!aceerr) + aceerr = nfsrv_acemasktoperm(acetype, mask, owner, VREG, + &acep->ae_perm); + *aceerrp = aceerr; + if (acesizep) + *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED); + return (0); +nfsmout: + return (error); +} + +/* + * Turn an NFSv4 ace mask into R/W/X flag bits. + */ +static int +nfsrv_acemasktoperm(u_int32_t acetype, u_int32_t mask, int owner, + enum vtype type, acl_perm_t *permp) +{ + acl_perm_t perm = 0x0; + + if (acetype != NFSV4ACE_ALLOWEDTYPE && acetype != NFSV4ACE_DENIEDTYPE){ + if (mask & ~NFSV4ACE_AUDITMASK) + return (NFSERR_ATTRNOTSUPP); + } + if (mask & NFSV4ACE_DELETE) { + return (NFSERR_ATTRNOTSUPP); + } + if (acetype == NFSV4ACE_DENIEDTYPE) { + if (mask & NFSV4ACE_ALLFILESMASK) { + return (NFSERR_ATTRNOTSUPP); + } + if (owner) { + if (mask & NFSV4ACE_OWNERMASK) { + return (NFSERR_ATTRNOTSUPP); + } + } else { + if ((mask & NFSV4ACE_OWNERMASK) != NFSV4ACE_OWNERMASK) { + return (NFSERR_ATTRNOTSUPP); + } + mask &= ~NFSV4ACE_OWNERMASK; + } + } else if (acetype == NFSV4ACE_ALLOWEDTYPE) { + if ((mask & NFSV4ACE_ALLFILESMASK) != NFSV4ACE_ALLFILESMASK) { + return (NFSERR_ATTRNOTSUPP); + } + mask &= ~NFSV4ACE_ALLFILESMASK; + if (owner) { + if ((mask & NFSV4ACE_OWNERMASK) != NFSV4ACE_OWNERMASK) { + return (NFSERR_ATTRNOTSUPP); + } + mask &= ~NFSV4ACE_OWNERMASK; + } else if (mask & NFSV4ACE_OWNERMASK) { + return (NFSERR_ATTRNOTSUPP); + } + } + if (type == VDIR) { + if ((mask & NFSV4ACE_DIRREADMASK) == NFSV4ACE_DIRREADMASK) { + perm |= ACL_READ; + mask &= ~NFSV4ACE_DIRREADMASK; + } + if ((mask & NFSV4ACE_DIRWRITEMASK) == NFSV4ACE_DIRWRITEMASK) { + perm |= ACL_WRITE; + mask &= ~NFSV4ACE_DIRWRITEMASK; + } + if ((mask & NFSV4ACE_DIREXECUTEMASK)==NFSV4ACE_DIREXECUTEMASK){ + perm |= ACL_EXECUTE; + mask &= ~NFSV4ACE_DIREXECUTEMASK; + } + } else { + if (acetype == NFSV4ACE_DENIEDTYPE && + (mask & NFSV4ACE_SYNCHRONIZE)) { + return (NFSERR_ATTRNOTSUPP); + } + mask &= ~(NFSV4ACE_SYNCHRONIZE | NFSV4ACE_DELETECHILD); + if ((mask & NFSV4ACE_READMASK) == NFSV4ACE_READMASK) { + perm |= ACL_READ; + mask &= ~NFSV4ACE_READMASK; + } + if ((mask & NFSV4ACE_WRITEMASK) == NFSV4ACE_WRITEMASK) { + perm |= ACL_WRITE; + mask &= ~NFSV4ACE_WRITEMASK; + } + if ((mask & NFSV4ACE_EXECUTEMASK) == NFSV4ACE_EXECUTEMASK) { + perm |= ACL_EXECUTE; + mask &= ~NFSV4ACE_EXECUTEMASK; + } + } + if (mask) { + return (NFSERR_ATTRNOTSUPP); + } + *permp = perm; + return (0); +} +#endif /* !NFS4_ACL_EXTATTR_NAME */ + +#ifdef NFS4_ACL_EXTATTR_NAME +/* local functions */ +static int nfsrv_buildace(struct nfsrv_descript *, u_char *, int, + enum vtype, int, int, struct acl_entry *); + +/* + * This function builds an NFS ace. + */ +static int +nfsrv_buildace(struct nfsrv_descript *nd, u_char *name, int namelen, + enum vtype type, int group, int owner, struct acl_entry *ace) +{ + u_int32_t *tl, aceflag = 0x0, acemask = 0x0, acetype; + int full_len; + + full_len = NFSM_RNDUP(namelen); + NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED + full_len); + + /* + * Fill in the ace type. + */ + if (ace->ae_extended & ACL_EXTENDED_ALLOW) + acetype = NFSV4ACE_ALLOWEDTYPE; + else if (ace->ae_extended & ACL_EXTENDED_DENY) + acetype = NFSV4ACE_DENIEDTYPE; + else if (ace->ae_extended & ACL_EXTENDED_AUDIT) + acetype = NFSV4ACE_AUDITTYPE; + else + acetype = NFSV4ACE_ALARMTYPE; + *tl++ = txdr_unsigned(acetype); + + /* + * Set the flag bits from the ACL. + */ + if (ace->ae_flags & ACL_ENTRY_FILE_INHERIT) + aceflag |= NFSV4ACE_FILEINHERIT; + if (ace->ae_flags & ACL_ENTRY_DIRECTORY_INHERIT) + aceflag |= NFSV4ACE_DIRECTORYINHERIT; + if (ace->ae_flags & ACL_ENTRY_LIMIT_INHERIT) + aceflag |= NFSV4ACE_NOPROPAGATEINHERIT; + if (ace->ae_flags & ACL_ENTRY_ONLY_INHERIT) + aceflag |= NFSV4ACE_INHERITONLY; + if (ace->ae_flags & ACL_ENTRY_SUCCESSFUL_ACCESS) + aceflag |= NFSV4ACE_SUCCESSFULACCESS; + if (ace->ae_flags & ACL_ENTRY_FAILED_ACCESS) + aceflag |= NFSV4ACE_FAILEDACCESS; + if (group) + aceflag |= NFSV4ACE_IDENTIFIERGROUP; + *tl++ = txdr_unsigned(aceflag); + if (type == VDIR) { + if (ace->ae_perm & ACL_LIST_DIRECTORY) + acemask |= NFSV4ACE_LISTDIRECTORY; + if (ace->ae_perm & ACL_ADD_FILE) + acemask |= NFSV4ACE_ADDFILE; + if (ace->ae_perm & ACL_ADD_SUBDIRECTORY) + acemask |= NFSV4ACE_ADDSUBDIRECTORY; + if (ace->ae_perm & ACL_READ_NAMED_ATTRS) + acemask |= NFSV4ACE_READNAMEDATTR; + if (ace->ae_perm & ACL_WRITE_NAMED_ATTRS) + acemask |= NFSV4ACE_WRITENAMEDATTR; + if (ace->ae_perm & ACL_SEARCH) + acemask |= NFSV4ACE_SEARCH; + if (ace->ae_perm & ACL_DELETE_CHILD) + acemask |= NFSV4ACE_DELETECHILD; + if (ace->ae_perm & ACL_READ_ATTRIBUTES) + acemask |= NFSV4ACE_READATTRIBUTES; + if (ace->ae_perm & ACL_WRITE_ATTRIBUTES) + acemask |= NFSV4ACE_WRITEATTRIBUTES; + if (ace->ae_perm & ACL_DELETE) + acemask |= NFSV4ACE_DELETE; + if (ace->ae_perm & ACL_READ_ACL) + acemask |= NFSV4ACE_READACL; + if (ace->ae_perm & ACL_WRITE_ACL) + acemask |= NFSV4ACE_WRITEACL; + if (ace->ae_perm & ACL_WRITE_OWNER) + acemask |= NFSV4ACE_WRITEOWNER; + } else { + if (ace->ae_perm & ACL_READ_DATA) + acemask |= NFSV4ACE_READDATA; + if (ace->ae_perm & ACL_WRITE_DATA) + acemask |= NFSV4ACE_WRITEDATA; + if (ace->ae_perm & ACL_APPEND_DATA) + acemask |= NFSV4ACE_APPENDDATA; + if (ace->ae_perm & ACL_READ_NAMED_ATTRS) + acemask |= NFSV4ACE_READNAMEDATTR; + if (ace->ae_perm & ACL_WRITE_NAMED_ATTRS) + acemask |= NFSV4ACE_WRITENAMEDATTR; + if (ace->ae_perm & ACL_EXECUTE) + acemask |= NFSV4ACE_EXECUTE; + if (ace->ae_perm & ACL_READ_ATTRIBUTES) + acemask |= NFSV4ACE_READATTRIBUTES; + if (ace->ae_perm & ACL_WRITE_ATTRIBUTES) + acemask |= NFSV4ACE_WRITEATTRIBUTES; + if (ace->ae_perm & ACL_DELETE) + acemask |= NFSV4ACE_DELETE; + if (ace->ae_perm & ACL_READ_ACL) + acemask |= NFSV4ACE_READACL; + if (ace->ae_perm & ACL_WRITE_ACL) + acemask |= NFSV4ACE_WRITEACL; + if (ace->ae_perm & ACL_WRITE_OWNER) + acemask |= NFSV4ACE_WRITEOWNER; + if (ace->ae_perm & ACL_SYNCHRONIZE) + acemask |= NFSV4ACE_SYNCHRONIZE; + } + *tl++ = txdr_unsigned(acemask); + *tl++ = txdr_unsigned(namelen); + if (full_len - namelen) + *(tl + (namelen / NFSX_UNSIGNED)) = 0x0; + NFSBCOPY(name, (caddr_t)tl, namelen); + return (full_len + 4 * NFSX_UNSIGNED); +} + +/* + * Build an NFSv4 ACL. + */ +APPLESTATIC int +nfsrv_buildacl(struct nfsrv_descript *nd, NFSACL_T *aclp, enum vtype type, + NFSPROC_T *p) +{ + int i, entrycnt = 0, retlen; + u_int32_t *entrycntp; + int isowner, isgroup, namelen, malloced; + u_char *name, namestr[NFSV4_SMALLSTR]; + + NFSM_BUILD(entrycntp, u_int32_t *, NFSX_UNSIGNED); + retlen = NFSX_UNSIGNED; + /* + * Loop through the acl entries, building each one. + */ + for (i = 0; i < aclp->acl_cnt; i++) { + isowner = isgroup = malloced = 0; + switch (aclp->acl_entry[i].ae_tag) { + case ACL_USER_OBJ: + isowner = 1; + name = "OWNER@"; + namelen = 6; + break; + case ACL_GROUP_OBJ: + isgroup = 1; + name = "GROUP@"; + namelen = 6; + break; + case ACL_EVERYONE: + name = "EVERYONE@"; + namelen = 9; + break; + case ACL_USER: + name = namestr; + nfsv4_uidtostr(aclp->acl_entry[i].ae_id, &name, + &namelen, p); + if (name != namestr) + malloced = 1; + break; + case ACL_GROUP: + isgroup = 1; + name = namestr; + nfsv4_gidtostr((gid_t)aclp->acl_entry[i].ae_id, &name, + &namelen, p); + if (name != namestr) + malloced = 1; + break; + default: + continue; + }; + retlen += nfsrv_buildace(nd, name, namelen, type, isgroup, + isowner, &aclp->acl_entry[i]); + entrycnt++; + if (malloced) + free(name, M_NFSSTRING); + } + *entrycntp = txdr_unsigned(entrycnt); + return (retlen); +} + +/* + * Check access for an NFSv4 acl. + * The vflags are the basic VREAD, VWRITE, VEXEC. The mask is the NFSV4ACE + * mask bits for the more detailed check. + * If the more detailed check fails, due to no acl, do a basic one. + */ +APPLESTATIC int +nfsrv_aclaccess(vnode_t vp, accmode_t vflags, u_int32_t mask, + struct ucred *cred, NFSPROC_T *p) +{ + int error = 0; + accmode_t access; + + if (nfsrv_useacl == 0) { + error = VOP_ACCESS(vp, vflags, cred, p); + return (error); + } + + /* Convert NFSV4ACE mask to vaccess_t */ + access = 0; + if (mask & NFSV4ACE_READDATA) + access |= VREAD; + if (mask & NFSV4ACE_LISTDIRECTORY) + access |= VREAD; + if (mask & NFSV4ACE_WRITEDATA) + access |= VWRITE; + if (mask & NFSV4ACE_ADDFILE) + access |= VWRITE; + if (mask & NFSV4ACE_APPENDDATA) + access |= VAPPEND; + if (mask & NFSV4ACE_ADDSUBDIRECTORY) + access |= VAPPEND; + if (mask & NFSV4ACE_READNAMEDATTR) + access |= VREAD_NAMED_ATTRS; + if (mask & NFSV4ACE_WRITENAMEDATTR) + access |= VWRITE_NAMED_ATTRS; + if (mask & NFSV4ACE_EXECUTE) + access |= VEXEC; + if (mask & NFSV4ACE_SEARCH) + access |= VEXEC; + if (mask & NFSV4ACE_DELETECHILD) + access |= VDELETE_CHILD; + if (mask & NFSV4ACE_READATTRIBUTES) + access |= VREAD_ATTRIBUTES; + if (mask & NFSV4ACE_WRITEATTRIBUTES) + access |= VWRITE_ATTRIBUTES; + if (mask & NFSV4ACE_DELETE) + access |= VDELETE; + if (mask & NFSV4ACE_READACL) + access |= VREAD_ACL; + if (mask & NFSV4ACE_WRITEACL) + access |= VWRITE_ACL; + if (mask & NFSV4ACE_WRITEOWNER) + access |= VWRITE_OWNER; + if (mask & NFSV4ACE_SYNCHRONIZE) + access |= VSYNCHRONIZE; + + if (access != 0) + error = VOP_ACCESS(vp, access, cred, p); + else + error = VOP_ACCESS(vp, vflags, cred, p); + return (error); +} + +/* + * Set an NFSv4 acl. + */ +APPLESTATIC int +nfsrv_setacl(vnode_t vp, NFSACL_T *aclp, struct ucred *cred, + NFSPROC_T *p) +{ + int error; + + if (nfsrv_useacl == 0 || !NFSHASNFS4ACL(vnode_mount(vp))) + return (NFSERR_ATTRNOTSUPP); + /* + * With NFS4 ACLs, chmod(2) may need to add additional entries. + * Make sure it has enough room for that - splitting every entry + * into two and appending "canonical six" entries at the end. + * Cribbed out of kern/vfs_acl.c - Rick M. + */ + if (aclp->acl_cnt > (ACL_MAX_ENTRIES - 6) / 2) + return (NFSERR_ATTRNOTSUPP); + error = VOP_ACLCHECK(vp, ACL_TYPE_NFS4, aclp, cred, p); +#ifdef MAC + if (!error) + error = mac_check_vnode_setacl(cred, vp, ACL_TYPE_NFS4, aclp); +#endif + if (!error) + error = VOP_SETACL(vp, ACL_TYPE_NFS4, aclp, cred, p); + return (error); +} + +/* + * Compare two NFSv4 acls. + * Return 0 if they are the same, 1 if not the same. + */ +APPLESTATIC int +nfsrv_compareacl(NFSACL_T *aclp1, NFSACL_T *aclp2) +{ + int i; + struct acl_entry *acep1, *acep2; + + if (aclp1->acl_cnt != aclp2->acl_cnt) + return (1); + acep1 = aclp1->acl_entry; + acep2 = aclp2->acl_entry; + for (i = 0; i < aclp1->acl_cnt; i++) { + if (acep1->ae_tag != acep2->ae_tag) + return (1); + switch (acep1->ae_tag) { + case ACL_GROUP: + case ACL_USER: + if (acep1->ae_id != acep2->ae_id) + return (1); + /* fall through */ + case ACL_USER_OBJ: + case ACL_GROUP_OBJ: + case ACL_OTHER: + if (acep1->ae_perm != acep2->ae_perm) + return (1); + }; + acep1++; + acep2++; + } + return (0); +} + +#endif /* NFS4_ACL_EXTATTR_NAME */ diff --git a/sys/fs/nfs/nfs_commonkrpc.c b/sys/fs/nfs/nfs_commonkrpc.c new file mode 100644 index 0000000..429eed2 --- /dev/null +++ b/sys/fs/nfs/nfs_commonkrpc.c @@ -0,0 +1,901 @@ +/*- + * 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. + * 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Socket operations for use by nfs + */ + +#include "opt_inet6.h" +#include "opt_kgssapi.h" +#include "opt_nfs.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/limits.h> +#include <sys/lock.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/mount.h> +#include <sys/mutex.h> +#include <sys/proc.h> +#include <sys/signalvar.h> +#include <sys/syscallsubr.h> +#include <sys/sysctl.h> +#include <sys/syslog.h> +#include <sys/vnode.h> + +#include <rpc/rpc.h> +#include <rpc/rpcclnt.h> + +#include <kgssapi/krb5/kcrypto.h> + +#include <fs/nfs/nfsport.h> + +NFSSTATESPINLOCK; +NFSREQSPINLOCK; +extern struct nfsstats newnfsstats; +extern struct nfsreqhead nfsd_reqq; +extern int nfscl_ticks; +extern void (*ncl_call_invalcaches)(struct vnode *); + +static int nfsrv_gsscallbackson = 0; +static int nfs_bufpackets = 4; +static int nfs_reconnects; +static int nfs3_jukebox_delay = 10; +static int nfs_skip_wcc_data_onerr = 1; +static int nfs_keytab_enctype = ETYPE_DES_CBC_CRC; + +SYSCTL_DECL(_vfs_newnfs); + +SYSCTL_INT(_vfs_newnfs, OID_AUTO, bufpackets, CTLFLAG_RW, &nfs_bufpackets, 0, + "Buffer reservation size 2 < x < 64"); +SYSCTL_INT(_vfs_newnfs, OID_AUTO, reconnects, CTLFLAG_RD, &nfs_reconnects, 0, + "Number of times the nfs client has had to reconnect"); +SYSCTL_INT(_vfs_newnfs, OID_AUTO, nfs3_jukebox_delay, CTLFLAG_RW, &nfs3_jukebox_delay, 0, + "Number of seconds to delay a retry after receiving EJUKEBOX"); +SYSCTL_INT(_vfs_newnfs, OID_AUTO, skip_wcc_data_onerr, CTLFLAG_RW, &nfs_skip_wcc_data_onerr, 0, + "Disable weak cache consistency checking when server returns an error"); +SYSCTL_INT(_vfs_newnfs, OID_AUTO, keytab_enctype, CTLFLAG_RW, &nfs_keytab_enctype, 0, + "Encryption type for the keytab entry used by nfs"); + +static void nfs_down(struct nfsmount *, struct thread *, const char *, + int, int); +static void nfs_up(struct nfsmount *, struct thread *, const char *, + int, int); +static int nfs_msg(struct thread *, const char *, const char *, int); + +extern int nfsv2_procid[]; + +struct nfs_cached_auth { + int ca_refs; /* refcount, including 1 from the cache */ + uid_t ca_uid; /* uid that corresponds to this auth */ + AUTH *ca_auth; /* RPC auth handle */ +}; + +/* + * Initialize sockets and congestion for a new NFS connection. + * We do not free the sockaddr if error. + */ +int +newnfs_connect(struct nfsmount *nmp, struct nfssockreq *nrp, + struct ucred *cred, NFSPROC_T *p, int callback_retry_mult) +{ + int rcvreserve, sndreserve; + int pktscale; + struct sockaddr *saddr; + struct ucred *origcred; + CLIENT *client; + struct netconfig *nconf; + struct socket *so; + int one = 1, retries, error, printsbmax = 0; + struct thread *td = curthread; + + /* + * We need to establish the socket using the credentials of + * the mountpoint. Some parts of this process (such as + * sobind() and soconnect()) will use the curent thread's + * credential instead of the socket credential. To work + * around this, temporarily change the current thread's + * credential to that of the mountpoint. + * + * XXX: It would be better to explicitly pass the correct + * credential to sobind() and soconnect(). + */ + origcred = td->td_ucred; + + /* + * Use the credential in nr_cred, if not NULL. + */ + if (nrp->nr_cred != NULL) + td->td_ucred = nrp->nr_cred; + else + td->td_ucred = cred; + saddr = nrp->nr_nam; + + if (saddr->sa_family == AF_INET) + if (nrp->nr_sotype == SOCK_DGRAM) + nconf = getnetconfigent("udp"); + else + nconf = getnetconfigent("tcp"); + else + if (nrp->nr_sotype == SOCK_DGRAM) + nconf = getnetconfigent("udp6"); + else + nconf = getnetconfigent("tcp6"); + + pktscale = nfs_bufpackets; + if (pktscale < 2) + pktscale = 2; + if (pktscale > 64) + pktscale = 64; + /* + * soreserve() can fail if sb_max is too small, so shrink pktscale + * and try again if there is an error. + * Print a log message suggesting increasing sb_max. + * Creating a socket and doing this is necessary since, if the + * reservation sizes are too large and will make soreserve() fail, + * the connection will work until a large send is attempted and + * then it will loop in the krpc code. + */ + so = NULL; + saddr = NFSSOCKADDR(nrp->nr_nam, struct sockaddr *); + error = socreate(saddr->sa_family, &so, nrp->nr_sotype, + nrp->nr_soproto, td->td_ucred, td); + if (error) { + td->td_ucred = origcred; + return (error); + } + do { + if (error != 0 && pktscale > 2) { + pktscale--; + if (printsbmax == 0) { + printf("nfscl: consider increasing kern.ipc.maxsockbuf\n"); + printsbmax = 1; + } + } + if (nrp->nr_sotype == SOCK_DGRAM) { + if (nmp != NULL) { + sndreserve = (NFS_MAXDGRAMDATA + NFS_MAXPKTHDR) * + pktscale; + rcvreserve = (NFS_MAXDGRAMDATA + NFS_MAXPKTHDR) * + pktscale; + } else { + sndreserve = rcvreserve = 1024 * pktscale; + } + } else { + if (nrp->nr_sotype != SOCK_STREAM) + panic("nfscon sotype"); + if (nmp != NULL) { + sndreserve = (NFS_MAXBSIZE + NFS_MAXPKTHDR + + sizeof (u_int32_t)) * pktscale; + rcvreserve = (NFS_MAXBSIZE + NFS_MAXPKTHDR + + sizeof (u_int32_t)) * pktscale; + } else { + sndreserve = rcvreserve = 1024 * pktscale; + } + } + error = soreserve(so, sndreserve, rcvreserve); + } while (error != 0 && pktscale > 2); + soclose(so); + if (error) { + td->td_ucred = origcred; + return (error); + } + + client = clnt_reconnect_create(nconf, saddr, nrp->nr_prog, + nrp->nr_vers, sndreserve, rcvreserve); + CLNT_CONTROL(client, CLSET_WAITCHAN, "newnfsreq"); + if (nmp != NULL) { + if ((nmp->nm_flag & NFSMNT_INT)) + CLNT_CONTROL(client, CLSET_INTERRUPTIBLE, &one); + if ((nmp->nm_flag & NFSMNT_RESVPORT)) + CLNT_CONTROL(client, CLSET_PRIVPORT, &one); + if (NFSHASSOFT(nmp)) + retries = nmp->nm_retry; + else + retries = INT_MAX; + } else { + /* + * Three cases: + * - Null RPC callback to client + * - Non-Null RPC callback to client, wait a little longer + * - upcalls to nfsuserd and gssd (clp == NULL) + */ + if (callback_retry_mult == 0) { + retries = NFSV4_UPCALLRETRY; + CLNT_CONTROL(client, CLSET_PRIVPORT, &one); + } else { + retries = NFSV4_CALLBACKRETRY * callback_retry_mult; + } + } + CLNT_CONTROL(client, CLSET_RETRIES, &retries); + + mtx_lock(&nrp->nr_mtx); + if (nrp->nr_client != NULL) { + /* + * Someone else already connected. + */ + CLNT_RELEASE(client); + } else { + nrp->nr_client = client; + } + + /* + * Protocols that do not require connections may be optionally left + * unconnected for servers that reply from a port other than NFS_PORT. + */ + if (nmp == NULL || (nmp->nm_flag & NFSMNT_NOCONN) == 0) { + mtx_unlock(&nrp->nr_mtx); + CLNT_CONTROL(client, CLSET_CONNECT, &one); + } else { + mtx_unlock(&nrp->nr_mtx); + } + + /* Restore current thread's credentials. */ + td->td_ucred = origcred; + return (0); +} + +/* + * NFS disconnect. Clean up and unlink. + */ +void +newnfs_disconnect(struct nfssockreq *nrp) +{ + CLIENT *client; + + mtx_lock(&nrp->nr_mtx); + if (nrp->nr_client != NULL) { + client = nrp->nr_client; + nrp->nr_client = NULL; + mtx_unlock(&nrp->nr_mtx); +#ifdef KGSSAPI + rpc_gss_secpurge(client); +#endif + CLNT_CLOSE(client); + CLNT_RELEASE(client); + } else { + mtx_unlock(&nrp->nr_mtx); + } +} + +static AUTH * +nfs_getauth(struct nfssockreq *nrp, int secflavour, char *clnt_principal, + char *srv_principal, gss_OID mech_oid, struct ucred *cred) +{ +#ifdef KGSSAPI + rpc_gss_service_t svc; + AUTH *auth; + rpc_gss_options_req_t req_options; +#endif + + switch (secflavour) { +#ifdef KGSSAPI + case RPCSEC_GSS_KRB5: + case RPCSEC_GSS_KRB5I: + case RPCSEC_GSS_KRB5P: + if (!mech_oid) { + if (!rpc_gss_mech_to_oid("kerberosv5", &mech_oid)) + return (NULL); + } + if (secflavour == RPCSEC_GSS_KRB5) + svc = rpc_gss_svc_none; + else if (secflavour == RPCSEC_GSS_KRB5I) + svc = rpc_gss_svc_integrity; + else + svc = rpc_gss_svc_privacy; + req_options.req_flags = GSS_C_MUTUAL_FLAG; + req_options.time_req = 0; + req_options.my_cred = GSS_C_NO_CREDENTIAL; + req_options.input_channel_bindings = NULL; + req_options.enc_type = nfs_keytab_enctype; + + auth = rpc_gss_secfind(nrp->nr_client, cred, + clnt_principal, srv_principal, mech_oid, svc, + &req_options); + return (auth); +#endif + case AUTH_SYS: + default: + return (authunix_create(cred)); + + } +} + +/* + * Callback from the RPC code to generate up/down notifications. + */ + +struct nfs_feedback_arg { + struct nfsmount *nf_mount; + int nf_lastmsg; /* last tprintf */ + int nf_tprintfmsg; + struct thread *nf_td; +}; + +static void +nfs_feedback(int type, int proc, void *arg) +{ + struct nfs_feedback_arg *nf = (struct nfs_feedback_arg *) arg; + struct nfsmount *nmp = nf->nf_mount; + struct timeval now; + + getmicrouptime(&now); + + switch (type) { + case FEEDBACK_REXMIT2: + case FEEDBACK_RECONNECT: + if (nf->nf_lastmsg + nmp->nm_tprintf_delay < now.tv_sec) { + nfs_down(nmp, nf->nf_td, + "not responding", 0, NFSSTA_TIMEO); + nf->nf_tprintfmsg = TRUE; + nf->nf_lastmsg = now.tv_sec; + } + break; + + case FEEDBACK_OK: + nfs_up(nf->nf_mount, nf->nf_td, + "is alive again", NFSSTA_TIMEO, nf->nf_tprintfmsg); + break; + } +} + +/* + * newnfs_request - goes something like this + * - does the rpc by calling the krpc layer + * - break down rpc header and return with nfs reply + * nb: always frees up nd_mreq mbuf list + */ +int +newnfs_request(struct nfsrv_descript *nd, struct nfsmount *nmp, + struct nfsclient *clp, struct nfssockreq *nrp, vnode_t vp, + struct thread *td, struct ucred *cred, u_int32_t prog, u_int32_t vers, + u_char *retsum, int toplevel, u_int64_t *xidp) +{ + u_int32_t *tl; + time_t waituntil; + int i, j; + int trycnt, error = 0, usegssname = 0, secflavour = AUTH_SYS; + u_int16_t procnum; + u_int trylater_delay = 1; + struct nfs_feedback_arg nf; + struct timeval timo, now; + AUTH *auth; + struct rpc_callextra ext; + enum clnt_stat stat; + struct nfsreq *rep = NULL; + char *srv_principal = NULL; + + if (xidp != NULL) + *xidp = 0; + /* Reject requests while attempting a forced unmount. */ + if (nmp != NULL && (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF)) { + m_freem(nd->nd_mreq); + return (ESTALE); + } + + /* + * For a client side mount, nmp is != NULL and clp == NULL. For + * server calls (callbacks or upcalls), nmp == NULL. + */ + if (clp != NULL) { + NFSLOCKSTATE(); + if ((clp->lc_flags & LCL_GSS) && nfsrv_gsscallbackson) { + secflavour = RPCSEC_GSS_KRB5; + if (nd->nd_procnum != NFSPROC_NULL) { + if (clp->lc_flags & LCL_GSSINTEGRITY) + secflavour = RPCSEC_GSS_KRB5I; + else if (clp->lc_flags & LCL_GSSPRIVACY) + secflavour = RPCSEC_GSS_KRB5P; + } + } + NFSUNLOCKSTATE(); + } else if (nmp != NULL && NFSHASKERB(nmp) && + nd->nd_procnum != NFSPROC_NULL) { + if (NFSHASALLGSSNAME(nmp) && nmp->nm_krbnamelen > 0) + nd->nd_flag |= ND_USEGSSNAME; + if ((nd->nd_flag & ND_USEGSSNAME) && nmp->nm_krbnamelen > 0) + usegssname = 1; + if (NFSHASINTEGRITY(nmp)) + secflavour = RPCSEC_GSS_KRB5I; + else if (NFSHASPRIVACY(nmp)) + secflavour = RPCSEC_GSS_KRB5P; + else + secflavour = RPCSEC_GSS_KRB5; + srv_principal = NFSMNT_SRVKRBNAME(nmp); + } + + if (nmp != NULL) { + bzero(&nf, sizeof(struct nfs_feedback_arg)); + nf.nf_mount = nmp; + nf.nf_td = td; + getmicrouptime(&now); + nf.nf_lastmsg = now.tv_sec - + ((nmp->nm_tprintf_delay)-(nmp->nm_tprintf_initial_delay)); + } + + /* + * XXX if not already connected call nfs_connect now. Longer + * term, change nfs_mount to call nfs_connect unconditionally + * and let clnt_reconnect_create handle reconnects. + */ + if (nrp->nr_client == NULL) + newnfs_connect(nmp, nrp, cred, td, 0); + + if (usegssname) + auth = nfs_getauth(nrp, secflavour, nmp->nm_krbname, + srv_principal, NULL, cred); + else + auth = nfs_getauth(nrp, secflavour, NULL, + srv_principal, NULL, cred); + if (auth == NULL) { + m_freem(nd->nd_mreq); + return (EACCES); + } + bzero(&ext, sizeof(ext)); + ext.rc_auth = auth; + if (nmp != NULL) { + ext.rc_feedback = nfs_feedback; + ext.rc_feedback_arg = &nf; + } + + procnum = nd->nd_procnum; + if ((nd->nd_flag & ND_NFSV4) && + nd->nd_procnum != NFSV4PROC_CBNULL && + nd->nd_procnum != NFSV4PROC_CBCOMPOUND) + procnum = NFSV4PROC_COMPOUND; + + if (nmp != NULL) { + NFSINCRGLOBAL(newnfsstats.rpcrequests); + /* + * Now only used for the R_DONTRECOVER case, but until that is + * supported within the krpc code, I need to keep a queue of + * outstanding RPCs for nfsv4 client requests. + */ + if ((nd->nd_flag & ND_NFSV4) && procnum == NFSV4PROC_COMPOUND) + MALLOC(rep, struct nfsreq *, sizeof(struct nfsreq), + M_NFSDREQ, M_WAITOK); + } + trycnt = 0; +tryagain: + if (nmp == NULL) { + timo.tv_usec = 0; + if (clp == NULL) + timo.tv_sec = NFSV4_UPCALLTIMEO; + else + timo.tv_sec = NFSV4_CALLBACKTIMEO; + } else { + if (nrp->nr_sotype != SOCK_DGRAM) { + timo.tv_usec = 0; + if ((nmp->nm_flag & NFSMNT_NFSV4)) + timo.tv_sec = INT_MAX; + else + timo.tv_sec = NFS_TCPTIMEO; + } else { + timo.tv_sec = nmp->nm_timeo / NFS_HZ; + timo.tv_usec = (nmp->nm_timeo * 1000000) / NFS_HZ; + } + + if (rep != NULL) { + rep->r_flags = 0; + rep->r_nmp = nmp; + /* + * Chain request into list of outstanding requests. + */ + NFSLOCKREQ(); + TAILQ_INSERT_TAIL(&nfsd_reqq, rep, r_chain); + NFSUNLOCKREQ(); + } + } + + nd->nd_mrep = NULL; + stat = CLNT_CALL_MBUF(nrp->nr_client, &ext, procnum, nd->nd_mreq, + &nd->nd_mrep, timo); + + if (rep != NULL) { + /* + * RPC done, unlink the request. + */ + NFSLOCKREQ(); + TAILQ_REMOVE(&nfsd_reqq, rep, r_chain); + NFSUNLOCKREQ(); + } + + /* + * If there was a successful reply and a tprintf msg. + * tprintf a response. + */ + if (stat == RPC_SUCCESS) { + error = 0; + } else if (stat == RPC_TIMEDOUT) { + error = ETIMEDOUT; + } else if (stat == RPC_VERSMISMATCH) { + error = EOPNOTSUPP; + } else if (stat == RPC_PROGVERSMISMATCH) { + error = EPROTONOSUPPORT; + } else { + error = EACCES; + } + if (error) { + m_freem(nd->nd_mreq); + AUTH_DESTROY(auth); + if (rep != NULL) + FREE((caddr_t)rep, M_NFSDREQ); + return (error); + } + + KASSERT(nd->nd_mrep != NULL, ("mrep shouldn't be NULL if no error\n")); + + nd->nd_md = nd->nd_mrep; + nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t); + nd->nd_repstat = 0; + if (nd->nd_procnum != NFSPROC_NULL) { + /* + * and now the actual NFS xdr. + */ + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + nd->nd_repstat = fxdr_unsigned(u_int32_t, *tl); + if (nd->nd_repstat != 0) { + if ((nd->nd_repstat == NFSERR_DELAY && + (nd->nd_flag & ND_NFSV4) && + nd->nd_procnum != NFSPROC_SETATTR && + nd->nd_procnum != NFSPROC_READ && + nd->nd_procnum != NFSPROC_WRITE && + nd->nd_procnum != NFSPROC_OPEN && + nd->nd_procnum != NFSPROC_CREATE && + nd->nd_procnum != NFSPROC_OPENCONFIRM && + nd->nd_procnum != NFSPROC_OPENDOWNGRADE && + nd->nd_procnum != NFSPROC_CLOSE && + nd->nd_procnum != NFSPROC_LOCK && + nd->nd_procnum != NFSPROC_LOCKU) || + (nd->nd_repstat == NFSERR_DELAY && + (nd->nd_flag & ND_NFSV4) == 0) || + nd->nd_repstat == NFSERR_RESOURCE) { + if (trylater_delay > NFS_TRYLATERDEL) + trylater_delay = NFS_TRYLATERDEL; + waituntil = NFSD_MONOSEC + trylater_delay; + while (NFSD_MONOSEC < waituntil) + (void) nfs_catnap(PZERO, "nfstry"); + trylater_delay *= 2; + goto tryagain; + } + + /* + * If the File Handle was stale, invalidate the + * lookup cache, just in case. + * (vp != NULL implies a client side call) + */ + if (nd->nd_repstat == ESTALE && vp != NULL) { + cache_purge(vp); + if (ncl_call_invalcaches != NULL) + (*ncl_call_invalcaches)(vp); + } + } + + /* + * Get rid of the tag, return count, and PUTFH result for V4. + */ + if (nd->nd_flag & ND_NFSV4) { + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + i = fxdr_unsigned(int, *tl); + error = nfsm_advance(nd, NFSM_RNDUP(i), -1); + if (error) + goto nfsmout; + NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); + i = fxdr_unsigned(int, *++tl); + + /* + * If the first op's status is non-zero, mark that + * there is no more data to process. + */ + if (*++tl) + nd->nd_flag |= ND_NOMOREDATA; + + /* + * If the first op is Putfh, throw its results away + * and toss the op# and status for the first op. + */ + if (nmp != NULL && i == NFSV4OP_PUTFH && *tl == 0) { + NFSM_DISSECT(tl,u_int32_t *,2 * NFSX_UNSIGNED); + i = fxdr_unsigned(int, *tl++); + j = fxdr_unsigned(int, *tl); + /* + * All Compounds that do an Op that must + * be in sequence consist of NFSV4OP_PUTFH + * followed by one of these. As such, we + * can determine if the seqid# should be + * incremented, here. + */ + if ((i == NFSV4OP_OPEN || + i == NFSV4OP_OPENCONFIRM || + i == NFSV4OP_OPENDOWNGRADE || + i == NFSV4OP_CLOSE || + i == NFSV4OP_LOCK || + i == NFSV4OP_LOCKU) && + (j == 0 || + (j != NFSERR_STALECLIENTID && + j != NFSERR_STALESTATEID && + j != NFSERR_BADSTATEID && + j != NFSERR_BADSEQID && + j != NFSERR_BADXDR && + j != NFSERR_RESOURCE && + j != NFSERR_NOFILEHANDLE))) + nd->nd_flag |= ND_INCRSEQID; + /* + * If the first op's status is non-zero, mark + * that there is no more data to process. + */ + if (j) + nd->nd_flag |= ND_NOMOREDATA; + } + + /* + * If R_DONTRECOVER is set, replace the stale error + * reply, so that recovery isn't initiated. + */ + if ((nd->nd_repstat == NFSERR_STALECLIENTID || + nd->nd_repstat == NFSERR_STALESTATEID) && + rep != NULL && (rep->r_flags & R_DONTRECOVER)) + nd->nd_repstat = NFSERR_STALEDONTRECOVER; + } + + m_freem(nd->nd_mreq); + AUTH_DESTROY(auth); + if (rep != NULL) + FREE((caddr_t)rep, M_NFSDREQ); + return (0); + } + error = EPROTONOSUPPORT; +nfsmout: + mbuf_freem(nd->nd_mrep); + mbuf_freem(nd->nd_mreq); + AUTH_DESTROY(auth); + if (rep != NULL) + FREE((caddr_t)rep, M_NFSDREQ); + return (error); +} + +/* + * Mark all of an nfs mount's outstanding requests with R_SOFTTERM and + * wait for all requests to complete. This is used by forced unmounts + * to terminate any outstanding RPCs. + */ +int +newnfs_nmcancelreqs(struct nfsmount *nmp) +{ + + if (nmp->nm_sockreq.nr_client != NULL) + CLNT_CLOSE(nmp->nm_sockreq.nr_client); + return (0); +} + +/* + * Any signal that can interrupt an NFS operation in an intr mount + * should be added to this set. SIGSTOP and SIGKILL cannot be masked. + */ +int newnfs_sig_set[] = { + SIGINT, + SIGTERM, + SIGHUP, + SIGKILL, + SIGSTOP, + SIGQUIT +}; + +/* + * Check to see if one of the signals in our subset is pending on + * the process (in an intr mount). + */ +static int +nfs_sig_pending(sigset_t set) +{ + int i; + + for (i = 0 ; i < sizeof(newnfs_sig_set)/sizeof(int) ; i++) + if (SIGISMEMBER(set, newnfs_sig_set[i])) + return (1); + return (0); +} + +/* + * The set/restore sigmask functions are used to (temporarily) overwrite + * the process p_sigmask during an RPC call (for example). These are also + * used in other places in the NFS client that might tsleep(). + */ +void +newnfs_set_sigmask(struct thread *td, sigset_t *oldset) +{ + sigset_t newset; + int i; + struct proc *p; + + SIGFILLSET(newset); + if (td == NULL) + td = curthread; /* XXX */ + p = td->td_proc; + /* Remove the NFS set of signals from newset */ + PROC_LOCK(p); + mtx_lock(&p->p_sigacts->ps_mtx); + for (i = 0 ; i < sizeof(newnfs_sig_set)/sizeof(int) ; i++) { + /* + * But make sure we leave the ones already masked + * by the process, ie. remove the signal from the + * temporary signalmask only if it wasn't already + * in p_sigmask. + */ + if (!SIGISMEMBER(td->td_sigmask, newnfs_sig_set[i]) && + !SIGISMEMBER(p->p_sigacts->ps_sigignore, newnfs_sig_set[i])) + SIGDELSET(newset, newnfs_sig_set[i]); + } + mtx_unlock(&p->p_sigacts->ps_mtx); + PROC_UNLOCK(p); + kern_sigprocmask(td, SIG_SETMASK, &newset, oldset, 0); +} + +void +newnfs_restore_sigmask(struct thread *td, sigset_t *set) +{ + if (td == NULL) + td = curthread; /* XXX */ + kern_sigprocmask(td, SIG_SETMASK, set, NULL, 0); +} + +/* + * NFS wrapper to msleep(), that shoves a new p_sigmask and restores the + * old one after msleep() returns. + */ +int +newnfs_msleep(struct thread *td, void *ident, struct mtx *mtx, int priority, char *wmesg, int timo) +{ + sigset_t oldset; + int error; + struct proc *p; + + if ((priority & PCATCH) == 0) + return msleep(ident, mtx, priority, wmesg, timo); + if (td == NULL) + td = curthread; /* XXX */ + newnfs_set_sigmask(td, &oldset); + error = msleep(ident, mtx, priority, wmesg, timo); + newnfs_restore_sigmask(td, &oldset); + p = td->td_proc; + return (error); +} + +/* + * Test for a termination condition pending on the process. + * This is used for NFSMNT_INT mounts. + */ +int +newnfs_sigintr(struct nfsmount *nmp, struct thread *td) +{ + struct proc *p; + sigset_t tmpset; + + /* Terminate all requests while attempting a forced unmount. */ + if (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF) + return (EIO); + if (!(nmp->nm_flag & NFSMNT_INT)) + return (0); + if (td == NULL) + return (0); + p = td->td_proc; + PROC_LOCK(p); + tmpset = p->p_siglist; + SIGSETOR(tmpset, td->td_siglist); + SIGSETNAND(tmpset, td->td_sigmask); + mtx_lock(&p->p_sigacts->ps_mtx); + SIGSETNAND(tmpset, p->p_sigacts->ps_sigignore); + mtx_unlock(&p->p_sigacts->ps_mtx); + if ((SIGNOTEMPTY(p->p_siglist) || SIGNOTEMPTY(td->td_siglist)) + && nfs_sig_pending(tmpset)) { + PROC_UNLOCK(p); + return (EINTR); + } + PROC_UNLOCK(p); + return (0); +} + +static int +nfs_msg(struct thread *td, const char *server, const char *msg, int error) +{ + struct proc *p; + + p = td ? td->td_proc : NULL; + if (error) { + tprintf(p, LOG_INFO, "newnfs server %s: %s, error %d\n", + server, msg, error); + } else { + tprintf(p, LOG_INFO, "newnfs server %s: %s\n", server, msg); + } + return (0); +} + +static void +nfs_down(struct nfsmount *nmp, struct thread *td, const char *msg, + int error, int flags) +{ + if (nmp == NULL) + return; + mtx_lock(&nmp->nm_mtx); + if ((flags & NFSSTA_TIMEO) && !(nmp->nm_state & NFSSTA_TIMEO)) { + nmp->nm_state |= NFSSTA_TIMEO; + mtx_unlock(&nmp->nm_mtx); + vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid, + VQ_NOTRESP, 0); + } else + mtx_unlock(&nmp->nm_mtx); + mtx_lock(&nmp->nm_mtx); + if ((flags & NFSSTA_LOCKTIMEO) && !(nmp->nm_state & NFSSTA_LOCKTIMEO)) { + nmp->nm_state |= NFSSTA_LOCKTIMEO; + mtx_unlock(&nmp->nm_mtx); + vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid, + VQ_NOTRESPLOCK, 0); + } else + mtx_unlock(&nmp->nm_mtx); + nfs_msg(td, nmp->nm_mountp->mnt_stat.f_mntfromname, msg, error); +} + +static void +nfs_up(struct nfsmount *nmp, struct thread *td, const char *msg, + int flags, int tprintfmsg) +{ + if (nmp == NULL) + return; + if (tprintfmsg) { + nfs_msg(td, nmp->nm_mountp->mnt_stat.f_mntfromname, msg, 0); + } + + mtx_lock(&nmp->nm_mtx); + if ((flags & NFSSTA_TIMEO) && (nmp->nm_state & NFSSTA_TIMEO)) { + nmp->nm_state &= ~NFSSTA_TIMEO; + mtx_unlock(&nmp->nm_mtx); + vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid, + VQ_NOTRESP, 1); + } else + mtx_unlock(&nmp->nm_mtx); + + mtx_lock(&nmp->nm_mtx); + if ((flags & NFSSTA_LOCKTIMEO) && (nmp->nm_state & NFSSTA_LOCKTIMEO)) { + nmp->nm_state &= ~NFSSTA_LOCKTIMEO; + mtx_unlock(&nmp->nm_mtx); + vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid, + VQ_NOTRESPLOCK, 1); + } else + mtx_unlock(&nmp->nm_mtx); +} + diff --git a/sys/fs/nfs/nfs_commonport.c b/sys/fs/nfs/nfs_commonport.c new file mode 100644 index 0000000..1c22657 --- /dev/null +++ b/sys/fs/nfs/nfs_commonport.c @@ -0,0 +1,486 @@ +/*- + * 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. + * + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Functions that need to be different for different versions of BSD + * kernel should be kept here, along with any global storage specific + * to this BSD variant. + */ +#include <fs/nfs/nfsport.h> +#include <sys/sysctl.h> +#include <vm/vm.h> +#include <vm/vm_object.h> +#include <vm/vm_page.h> +#include <vm/vm_param.h> +#include <vm/vm_map.h> +#include <vm/vm_kern.h> +#include <vm/vm_extern.h> +#include <vm/uma.h> +#include <vm/uma_int.h> + +extern int nfscl_ticks; +extern int nfsrv_nfsuserd; +extern struct nfssockreq nfsrv_nfsuserdsock; +extern void (*nfsd_call_recall)(struct vnode *, int, struct ucred *, + struct thread *); +extern int nfsrv_useacl; +struct mount nfsv4root_mnt; +int newnfs_numnfsd = 0; +struct nfsstats newnfsstats; +int nfs_numnfscbd = 0; +char nfsv4_callbackaddr[INET6_ADDRSTRLEN]; +struct callout newnfsd_callout; +void (*nfsd_call_servertimer)(void) = NULL; +void (*ncl_call_invalcaches)(struct vnode *) = NULL; + +static int nfs_realign_test; +static int nfs_realign_count; + +SYSCTL_NODE(_vfs, OID_AUTO, newnfs, CTLFLAG_RW, 0, "New NFS filesystem"); +SYSCTL_INT(_vfs_newnfs, OID_AUTO, realign_test, CTLFLAG_RW, &nfs_realign_test, 0, ""); +SYSCTL_INT(_vfs_newnfs, OID_AUTO, realign_count, CTLFLAG_RW, &nfs_realign_count, 0, ""); +SYSCTL_INT(_vfs_newnfs, OID_AUTO, nfs4acl_enable, CTLFLAG_RW, &nfsrv_useacl, 0, ""); +SYSCTL_STRING(_vfs_newnfs, OID_AUTO, callback_addr, CTLFLAG_RW, + nfsv4_callbackaddr, sizeof(nfsv4_callbackaddr), ""); + +/* + * Defines for malloc + * (Here for FreeBSD, since they allocate storage.) + */ +MALLOC_DEFINE(M_NEWNFSRVCACHE, "NFSD srvcache", "NFSD Server Request Cache"); +MALLOC_DEFINE(M_NEWNFSDCLIENT, "NFSD V4client", "NFSD V4 Client Id"); +MALLOC_DEFINE(M_NEWNFSDSTATE, "NFSD V4state", "NFSD V4 State (Openowner, Open, Lockowner, Delegation"); +MALLOC_DEFINE(M_NEWNFSDLOCK, "NFSD V4lock", "NFSD V4 byte range lock"); +MALLOC_DEFINE(M_NEWNFSDLOCKFILE, "NFSD lckfile", "NFSD Open/Lock file"); +MALLOC_DEFINE(M_NEWNFSSTRING, "NFSD string", "NFSD V4 long string"); +MALLOC_DEFINE(M_NEWNFSUSERGROUP, "NFSD usrgroup", "NFSD V4 User/group map"); +MALLOC_DEFINE(M_NEWNFSDREQ, "NFS req", "NFS request header"); +MALLOC_DEFINE(M_NEWNFSFH, "NFS fh", "NFS file handle"); +MALLOC_DEFINE(M_NEWNFSCLOWNER, "NFSCL owner", "NFSCL Open Owner"); +MALLOC_DEFINE(M_NEWNFSCLOPEN, "NFSCL open", "NFSCL Open"); +MALLOC_DEFINE(M_NEWNFSCLDELEG, "NFSCL deleg", "NFSCL Delegation"); +MALLOC_DEFINE(M_NEWNFSCLCLIENT, "NFSCL client", "NFSCL Client"); +MALLOC_DEFINE(M_NEWNFSCLLOCKOWNER, "NFSCL lckown", "NFSCL Lock Owner"); +MALLOC_DEFINE(M_NEWNFSCLLOCK, "NFSCL lck", "NFSCL Lock"); +MALLOC_DEFINE(M_NEWNFSV4NODE, "NEWNFSnode", "New nfs vnode"); +MALLOC_DEFINE(M_NEWNFSDIRECTIO, "NEWdirectio", "New nfs Direct IO buffer"); +MALLOC_DEFINE(M_NEWNFSDIROFF, "Newnfscl_diroff", "New NFS directory offset data"); + +/* + * Definition of mutex locks. + * newnfsd_mtx is used in nfsrvd_nfsd() to protect the nfs socket list + * and assorted other nfsd structures. + * Giant is used to protect the nfsd list and count, which is just + * updated when nfsd's start/stop and is grabbed for nfsrvd_dorpc() + * for the VFS ops. + */ +struct mtx newnfsd_mtx; +struct mtx nfs_sockl_mutex; +struct mtx nfs_state_mutex; +struct mtx nfs_nameid_mutex; +struct mtx nfs_req_mutex; +struct mtx nfs_slock_mutex; + +/* local functions */ +static int nfssvc_call(struct thread *, struct nfssvc_args *, struct ucred *); + +#if defined(__i386__) +/* + * These architectures don't need re-alignment, so just return. + */ +void +newnfs_realign(struct mbuf **pm) +{ + + return; +} +#else +/* + * nfs_realign: + * + * Check for badly aligned mbuf data and realign by copying the unaligned + * portion of the data into a new mbuf chain and freeing the portions + * of the old chain that were replaced. + * + * We cannot simply realign the data within the existing mbuf chain + * because the underlying buffers may contain other rpc commands and + * we cannot afford to overwrite them. + * + * We would prefer to avoid this situation entirely. The situation does + * not occur with NFS/UDP and is supposed to only occassionally occur + * with TCP. Use vfs.nfs.realign_count and realign_test to check this. + */ +void +newnfs_realign(struct mbuf **pm) +{ + struct mbuf *m; + struct mbuf *n = NULL; + int off = 0; + + ++nfs_realign_test; + while ((m = *pm) != NULL) { + if ((m->m_len & 0x3) || (mtod(m, intptr_t) & 0x3)) { + MGET(n, M_WAIT, MT_DATA); + if (m->m_len >= MINCLSIZE) { + MCLGET(n, M_WAIT); + } + n->m_len = 0; + break; + } + pm = &m->m_next; + } + + /* + * If n is non-NULL, loop on m copying data, then replace the + * portion of the chain that had to be realigned. + */ + if (n != NULL) { + ++nfs_realign_count; + while (m) { + m_copyback(n, off, m->m_len, mtod(m, caddr_t)); + off += m->m_len; + m = m->m_next; + } + m_freem(*pm); + *pm = n; + } +} +#endif /* newnfs_realign */ + +#ifdef notdef +static void +nfsrv_object_create(struct vnode *vp, struct thread *td) +{ + + if (vp == NULL || vp->v_type != VREG) + return; + (void) vfs_object_create(vp, td, td->td_ucred); +} +#endif + +/* + * Look up a file name. Basically just initialize stuff and call namei(). + */ +int +nfsrv_lookupfilename(struct nameidata *ndp, char *fname, NFSPROC_T *p) +{ + int error; + + NDINIT(ndp, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, fname, p); + error = namei(ndp); + if (!error) { + NDFREE(ndp, NDF_ONLY_PNBUF); + } + return (error); +} + +/* + * Copy NFS uid, gids to the cred structure. + */ +void +newnfs_copycred(struct nfscred *nfscr, struct ucred *cr) +{ + int ngroups, i; + + cr->cr_uid = nfscr->nfsc_uid; + ngroups = (nfscr->nfsc_ngroups < NGROUPS) ? + nfscr->nfsc_ngroups : NGROUPS; + for (i = 0; i < ngroups; i++) + cr->cr_groups[i] = nfscr->nfsc_groups[i]; + cr->cr_ngroups = ngroups; +} + +/* + * Map args from nfsmsleep() to msleep(). + */ +int +nfsmsleep(void *chan, void *mutex, int prio, const char *wmesg, + struct timespec *ts) +{ + u_int64_t nsecval; + int error, timeo; + + if (ts) { + timeo = hz * ts->tv_sec; + nsecval = (u_int64_t)ts->tv_nsec; + nsecval = ((nsecval * ((u_int64_t)hz)) + 500000000) / + 1000000000; + timeo += (int)nsecval; + } else { + timeo = 0; + } + error = msleep(chan, (struct mtx *)mutex, prio, wmesg, timeo); + return (error); +} + +/* + * Get the file system info for the server. For now, just assume FFS. + */ +void +nfsvno_getfs(struct nfsfsinfo *sip, int isdgram) +{ + int pref; + + /* + * XXX + * There should be file system VFS OP(s) to get this information. + * For now, assume ufs. + */ + if (isdgram) + pref = NFS_MAXDGRAMDATA; + else + pref = NFS_MAXDATA; + sip->fs_rtmax = NFS_MAXDATA; + sip->fs_rtpref = pref; + sip->fs_rtmult = NFS_FABLKSIZE; + sip->fs_wtmax = NFS_MAXDATA; + sip->fs_wtpref = pref; + sip->fs_wtmult = NFS_FABLKSIZE; + sip->fs_dtpref = pref; + sip->fs_maxfilesize = 0xffffffffffffffffull; + sip->fs_timedelta.tv_sec = 0; + sip->fs_timedelta.tv_nsec = 1; + sip->fs_properties = (NFSV3FSINFO_LINK | + NFSV3FSINFO_SYMLINK | NFSV3FSINFO_HOMOGENEOUS | + NFSV3FSINFO_CANSETTIME); +} + +/* Fake nfsrv_atroot. Just return 0 */ +int +nfsrv_atroot(struct vnode *vp, long *retp) +{ + + return (0); +} + +/* + * Set the credentials to refer to root. + * If only the various BSDen could agree on whether cr_gid is a separate + * field or cr_groups[0]... + */ +void +newnfs_setroot(struct ucred *cred) +{ + + cred->cr_uid = 0; + cred->cr_groups[0] = 0; + cred->cr_ngroups = 1; +} + +/* + * Get the client credential. Used for Renew and recovery. + */ +struct ucred * +newnfs_getcred(void) +{ + struct ucred *cred; + struct thread *td = curthread; + + cred = crdup(td->td_ucred); + newnfs_setroot(cred); + return (cred); +} + +/* + * Nfs timer routine + * Call the nfsd's timer function once/sec. + */ +void +newnfs_timer(void *arg) +{ + static time_t lasttime = 0; + /* + * Call the server timer, if set up. + * The argument indicates if it is the next second and therefore + * leases should be checked. + */ + if (lasttime != NFSD_MONOSEC) { + lasttime = NFSD_MONOSEC; + if (nfsd_call_servertimer != NULL) + (*nfsd_call_servertimer)(); + } + callout_reset(&newnfsd_callout, nfscl_ticks, newnfs_timer, NULL); +} + + +/* + * sleep for a short period of time. + * Since lbolt doesn't exist in FreeBSD-CURRENT, just use a timeout on + * an event that never gets a wakeup. Only return EINTR or 0. + */ +int +nfs_catnap(int prio, const char *wmesg) +{ + static int non_event; + int ret; + + ret = tsleep(&non_event, prio, wmesg, 1); + if (ret != EINTR) + ret = 0; + return (ret); +} + +/* + * Get referral. For now, just fail. + */ +struct nfsreferral * +nfsv4root_getreferral(struct vnode *vp, struct vnode *dvp, u_int32_t fileno) +{ + + return (NULL); +} + +static int +nfssvc_nfscommon(struct thread *td, struct nfssvc_args *uap) +{ + int error; + + error = nfssvc_call(td, uap, td->td_ucred); + return (error); +} + +static int +nfssvc_call(struct thread *p, struct nfssvc_args *uap, struct ucred *cred) +{ + int error = EINVAL; + struct nfsd_idargs nid; + + if (uap->flag & NFSSVC_IDNAME) { + error = copyin(uap->argp, (caddr_t)&nid, sizeof (nid)); + if (error) + return (error); + error = nfssvc_idname(&nid); + return (error); + } else if (uap->flag & NFSSVC_GETSTATS) { + error = copyout(&newnfsstats, + CAST_USER_ADDR_T(uap->argp), sizeof (newnfsstats)); + return (error); + } else if (uap->flag & NFSSVC_NFSUSERDPORT) { + u_short sockport; + + error = copyin(uap->argp, (caddr_t)&sockport, + sizeof (u_short)); + if (!error) + error = nfsrv_nfsuserdport(sockport, p); + } else if (uap->flag & NFSSVC_NFSUSERDDELPORT) { + nfsrv_nfsuserddelport(); + error = 0; + } + return (error); +} + +/* + * called by all three modevent routines, so that it gets things + * initialized soon enough. + */ +void +newnfs_portinit(void) +{ + static int inited = 0; + + if (inited) + return; + inited = 1; + /* Initialize SMP locks used by both client and server. */ + mtx_init(&newnfsd_mtx, "newnfsd_mtx", NULL, MTX_DEF); + mtx_init(&nfs_state_mutex, "nfs_state_mutex", NULL, MTX_DEF); +} + +extern int (*nfsd_call_nfscommon)(struct thread *, struct nfssvc_args *); + +/* + * Called once to initialize data structures... + */ +static int +nfscommon_modevent(module_t mod, int type, void *data) +{ + int error = 0; + static int loaded = 0; + + switch (type) { + case MOD_LOAD: + if (loaded) + return (0); + newnfs_portinit(); + mtx_init(&nfs_nameid_mutex, "nfs_nameid_mutex", NULL, MTX_DEF); + mtx_init(&nfs_sockl_mutex, "nfs_sockl_mutex", NULL, MTX_DEF); + mtx_init(&nfs_slock_mutex, "nfs_slock_mutex", NULL, MTX_DEF); + mtx_init(&nfs_req_mutex, "nfs_req_mutex", NULL, MTX_DEF); + mtx_init(&nfsrv_nfsuserdsock.nr_mtx, "nfsuserd", NULL, + MTX_DEF); + callout_init(&newnfsd_callout, CALLOUT_MPSAFE); + newnfs_init(); + nfsd_call_nfscommon = nfssvc_nfscommon; + loaded = 1; + break; + + case MOD_UNLOAD: + if (newnfs_numnfsd != 0 || nfsrv_nfsuserd != 0 || + nfs_numnfscbd != 0) { + error = EBUSY; + break; + } + + nfsd_call_nfscommon = NULL; + callout_drain(&newnfsd_callout); + /* and get rid of the mutexes */ + mtx_destroy(&nfs_nameid_mutex); + mtx_destroy(&newnfsd_mtx); + mtx_destroy(&nfs_state_mutex); + mtx_destroy(&nfs_sockl_mutex); + mtx_destroy(&nfs_slock_mutex); + mtx_destroy(&nfs_req_mutex); + mtx_destroy(&nfsrv_nfsuserdsock.nr_mtx); + loaded = 0; + break; + default: + error = EOPNOTSUPP; + break; + } + return error; +} +static moduledata_t nfscommon_mod = { + "nfscommon", + nfscommon_modevent, + NULL, +}; +DECLARE_MODULE(nfscommon, nfscommon_mod, SI_SUB_VFS, SI_ORDER_ANY); + +/* So that loader and kldload(2) can find us, wherever we are.. */ +MODULE_VERSION(nfscommon, 1); +MODULE_DEPEND(nfscommon, nfssvc, 1, 1, 1); +MODULE_DEPEND(nfscommon, krpc, 1, 1, 1); + diff --git a/sys/fs/nfs/nfs_commonsubs.c b/sys/fs/nfs/nfs_commonsubs.c new file mode 100644 index 0000000..bb19902 --- /dev/null +++ b/sys/fs/nfs/nfs_commonsubs.c @@ -0,0 +1,3404 @@ +/*- + * 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. + * + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * These functions support the macros and help fiddle mbuf chains for + * the nfs op functions. They do things like create the rpc header and + * copy data between mbuf chains and uio lists. + */ +#ifndef APPLEKEXT +#include <fs/nfs/nfsport.h> + +/* + * Data items converted to xdr at startup, since they are constant + * This is kinda hokey, but may save a little time doing byte swaps + */ +u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1; + +/* And other global data */ +nfstype nfsv34_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK, + NFFIFO, NFNON }; +enum vtype newnv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON }; +enum vtype nv34tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO }; +struct timeval nfsboottime; /* Copy boottime once, so it never changes */ +int nfscl_ticks; +int nfsrv_useacl = 1; +struct nfssockreq nfsrv_nfsuserdsock; +int nfsrv_nfsuserd = 0; +struct nfsreqhead nfsd_reqq; +uid_t nfsrv_defaultuid; +gid_t nfsrv_defaultgid; +int nfsrv_lease = NFSRV_LEASE; +int ncl_mbuf_mlen = MLEN; +NFSNAMEIDMUTEX; +NFSSOCKMUTEX; + +/* + * This array of structures indicates, for V4: + * retfh - which of 3 types of calling args are used + * 0 - doesn't change cfh or use a sfh + * 1 - replaces cfh with a new one (unless it returns an error status) + * 2 - uses cfh and sfh + * needscfh - if the op wants a cfh and premtime + * 0 - doesn't use a cfh + * 1 - uses a cfh, but doesn't want pre-op attributes + * 2 - uses a cfh and wants pre-op attributes + * savereply - indicates a non-idempotent Op + * 0 - not non-idempotent + * 1 - non-idempotent + * Ops that are ordered via seqid# are handled separately from these + * non-idempotent Ops. + * Define it here, since it is used by both the client and server. + */ +struct nfsv4_opflag nfsv4_opflag[NFSV4OP_NOPS] = { + { 0, 0, 0, 0 }, /* undef */ + { 0, 0, 0, 0 }, /* undef */ + { 0, 0, 0, 0 }, /* undef */ + { 0, 1, 0, 0 }, /* Access */ + { 0, 1, 0, 0 }, /* Close */ + { 0, 2, 0, 1 }, /* Commit */ + { 1, 2, 1, 1 }, /* Create */ + { 0, 0, 0, 0 }, /* Delegpurge */ + { 0, 1, 0, 0 }, /* Delegreturn */ + { 0, 1, 0, 0 }, /* Getattr */ + { 0, 1, 0, 0 }, /* GetFH */ + { 2, 1, 1, 1 }, /* Link */ + { 0, 1, 0, 0 }, /* Lock */ + { 0, 1, 0, 0 }, /* LockT */ + { 0, 1, 0, 0 }, /* LockU */ + { 1, 1, 0, 0 }, /* Lookup */ + { 1, 1, 0, 0 }, /* Lookupp */ + { 0, 1, 0, 0 }, /* NVerify */ + { 1, 1, 0, 1 }, /* Open */ + { 1, 1, 0, 0 }, /* OpenAttr */ + { 0, 1, 0, 0 }, /* OpenConfirm */ + { 0, 1, 0, 0 }, /* OpenDowngrade */ + { 1, 0, 0, 0 }, /* PutFH */ + { 1, 0, 0, 0 }, /* PutPubFH */ + { 1, 0, 0, 0 }, /* PutRootFH */ + { 0, 1, 0, 0 }, /* Read */ + { 0, 1, 0, 0 }, /* Readdir */ + { 0, 1, 0, 0 }, /* ReadLink */ + { 0, 2, 1, 1 }, /* Remove */ + { 2, 1, 1, 1 }, /* Rename */ + { 0, 0, 0, 0 }, /* Renew */ + { 0, 0, 0, 0 }, /* RestoreFH */ + { 0, 1, 0, 0 }, /* SaveFH */ + { 0, 1, 0, 0 }, /* SecInfo */ + { 0, 2, 1, 1 }, /* Setattr */ + { 0, 0, 0, 0 }, /* SetClientID */ + { 0, 0, 0, 0 }, /* SetClientIDConfirm */ + { 0, 1, 0, 0 }, /* Verify */ + { 0, 2, 1, 1 }, /* Write */ + { 0, 0, 0, 0 }, /* ReleaseLockOwner */ +}; +#endif /* !APPLEKEXT */ + +static int ncl_mbuf_mhlen = MHLEN; +static int nfsrv_usercnt = 0; +static int nfsrv_dnsnamelen; +static u_char *nfsrv_dnsname = NULL; +static int nfsrv_usermax = 999999999; +static struct nfsuserhashhead nfsuserhash[NFSUSERHASHSIZE]; +static struct nfsuserhashhead nfsusernamehash[NFSUSERHASHSIZE]; +static struct nfsuserhashhead nfsgrouphash[NFSGROUPHASHSIZE]; +static struct nfsuserhashhead nfsgroupnamehash[NFSGROUPHASHSIZE]; +static struct nfsuserlruhead nfsuserlruhead; + +/* + * This static array indicates whether or not the RPC generates a large + * reply. This is used by nfs_reply() to decide whether or not an mbuf + * cluster should be allocated. (If a cluster is required by an RPC + * marked 0 in this array, the code will still work, just not quite as + * efficiently.) + */ +static int nfs_bigreply[NFS_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0 }; + +/* local functions */ +static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep); +static void nfsv4_wanted(struct nfsv4lock *lp); +static int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len); +static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, + NFSPROC_T *p); +static void nfsrv_removeuser(struct nfsusrgrp *usrp); +static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **, + int *, int *); +static void nfsrv_refstrbigenough(int, u_char **, u_char **, int *); + + +#ifndef APPLE +/* + * copies mbuf chain to the uio scatter/gather list + */ +int +nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz) +{ + char *mbufcp, *uiocp; + int xfer, left, len; + mbuf_t mp; + long uiosiz, rem; + int error = 0; + + mp = nd->nd_md; + mbufcp = nd->nd_dpos; + len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - mbufcp; + rem = NFSM_RNDUP(siz) - siz; + while (siz > 0) { + if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) + return (EBADRPC); + left = uiop->uio_iov->iov_len; + uiocp = uiop->uio_iov->iov_base; + if (left > siz) + left = siz; + uiosiz = left; + while (left > 0) { + while (len == 0) { + mp = mbuf_next(mp); + if (mp == NULL) + return (EBADRPC); + mbufcp = NFSMTOD(mp, caddr_t); + len = mbuf_len(mp); + } + xfer = (left > len) ? len : left; +#ifdef notdef + /* Not Yet.. */ + if (uiop->uio_iov->iov_op != NULL) + (*(uiop->uio_iov->iov_op)) + (mbufcp, uiocp, xfer); + else +#endif + if (uiop->uio_segflg == UIO_SYSSPACE) + NFSBCOPY(mbufcp, uiocp, xfer); + else + copyout(mbufcp, CAST_USER_ADDR_T(uiocp), xfer); + left -= xfer; + len -= xfer; + mbufcp += xfer; + uiocp += xfer; + uiop->uio_offset += xfer; + uiop->uio_resid -= xfer; + } + if (uiop->uio_iov->iov_len <= siz) { + uiop->uio_iovcnt--; + uiop->uio_iov++; + } else { + uiop->uio_iov->iov_base = (void *) + ((char *)uiop->uio_iov->iov_base + uiosiz); + uiop->uio_iov->iov_len -= uiosiz; + } + siz -= uiosiz; + } + nd->nd_dpos = mbufcp; + nd->nd_md = mp; + if (rem > 0) { + if (len < rem) + error = nfsm_advance(nd, rem, len); + else + nd->nd_dpos += rem; + } + return (error); +} +#endif /* !APPLE */ + +/* + * Help break down an mbuf chain by setting the first siz bytes contiguous + * pointed to by returned val. + * This is used by the macro NFSM_DISSECT for tough + * cases. + */ +APPLESTATIC void * +nfsm_dissct(struct nfsrv_descript *nd, int siz) +{ + mbuf_t mp2; + int siz2, xfer; + caddr_t p; + int left; + caddr_t retp; + + retp = NULL; + left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) - nd->nd_dpos; + while (left == 0) { + nd->nd_md = mbuf_next(nd->nd_md); + if (nd->nd_md == NULL) + return (retp); + left = mbuf_len(nd->nd_md); + nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t); + } + if (left >= siz) { + retp = nd->nd_dpos; + nd->nd_dpos += siz; + } else if (mbuf_next(nd->nd_md) == NULL) { + return (retp); + } else if (siz > ncl_mbuf_mhlen) { + panic("nfs S too big"); + } else { + NFSMGET(mp2); + mbuf_setnext(mp2, mbuf_next(nd->nd_md)); + mbuf_setnext(nd->nd_md, mp2); + mbuf_setlen(nd->nd_md, mbuf_len(nd->nd_md) - left); + nd->nd_md = mp2; + retp = p = NFSMTOD(mp2, caddr_t); + NFSBCOPY(nd->nd_dpos, p, left); /* Copy what was left */ + siz2 = siz - left; + p += left; + mp2 = mbuf_next(mp2); + /* Loop around copying up the siz2 bytes */ + while (siz2 > 0) { + if (mp2 == NULL) + return (NULL); + xfer = (siz2 > mbuf_len(mp2)) ? mbuf_len(mp2) : siz2; + if (xfer > 0) { + NFSBCOPY(NFSMTOD(mp2, caddr_t), p, xfer); + NFSM_DATAP(mp2, xfer); + mbuf_setlen(mp2, mbuf_len(mp2) - xfer); + p += xfer; + siz2 -= xfer; + } + if (siz2 > 0) + mp2 = mbuf_next(mp2); + } + mbuf_setlen(nd->nd_md, siz); + nd->nd_md = mp2; + nd->nd_dpos = NFSMTOD(mp2, caddr_t); + } + return (retp); +} + +/* + * Advance the position in the mbuf chain. + * If offs == 0, this is a no-op, but it is simpler to just return from + * here than check for offs > 0 for all calls to nfsm_advance. + * If left == -1, it should be calculated here. + */ +APPLESTATIC int +nfsm_advance(struct nfsrv_descript *nd, int offs, int left) +{ + + if (offs == 0) + return (0); + /* + * A negative offs should be considered a serious problem. + */ + if (offs < 0) + panic("nfsrv_advance"); + + /* + * If left == -1, calculate it here. + */ + if (left == -1) + left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) - + nd->nd_dpos; + + /* + * Loop around, advancing over the mbuf data. + */ + while (offs > left) { + offs -= left; + nd->nd_md = mbuf_next(nd->nd_md); + if (nd->nd_md == NULL) + return (EBADRPC); + left = mbuf_len(nd->nd_md); + nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t); + } + nd->nd_dpos += offs; + return (0); +} + +/* + * Copy a string into mbuf(s). + * Return the number of bytes output, including XDR overheads. + */ +APPLESTATIC int +nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz) +{ + mbuf_t m2; + int xfer, left; + mbuf_t m1; + int rem, bytesize; + u_int32_t *tl; + char *cp2; + + NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); + *tl = txdr_unsigned(siz); + rem = NFSM_RNDUP(siz) - siz; + bytesize = NFSX_UNSIGNED + siz + rem; + m2 = nd->nd_mb; + cp2 = nd->nd_bpos; + left = M_TRAILINGSPACE(m2); + + /* + * Loop around copying the string to mbuf(s). + */ + while (siz > 0) { + if (left == 0) { + if (siz > ncl_mbuf_mlen) + NFSMCLGET(m1, M_WAIT); + else + NFSMGET(m1); + mbuf_setlen(m1, 0); + mbuf_setnext(m2, m1); + m2 = m1; + cp2 = NFSMTOD(m2, caddr_t); + left = M_TRAILINGSPACE(m2); + } + if (left >= siz) + xfer = siz; + else + xfer = left; + NFSBCOPY(cp, cp2, xfer); + cp += xfer; + mbuf_setlen(m2, mbuf_len(m2) + xfer); + siz -= xfer; + left -= xfer; + if (siz == 0 && rem) { + if (left < rem) + panic("nfsm_strtom"); + NFSBZERO(cp2 + xfer, rem); + mbuf_setlen(m2, mbuf_len(m2) + rem); + } + } + nd->nd_mb = m2; + nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2); + return (bytesize); +} + +/* + * Called once to initialize data structures... + */ +APPLESTATIC void +newnfs_init(void) +{ + static int nfs_inited = 0; + + if (nfs_inited) + return; + nfs_inited = 1; + + newnfs_true = txdr_unsigned(TRUE); + newnfs_false = txdr_unsigned(FALSE); + newnfs_xdrneg1 = txdr_unsigned(-1); + nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000; + if (nfscl_ticks < 1) + nfscl_ticks = 1; + NFSSETBOOTTIME(nfsboottime); + + /* + * Initialize reply list and start timer + */ + TAILQ_INIT(&nfsd_reqq); + NFS_TIMERINIT; +} + +/* + * Put a file handle in an mbuf list. + * If the size argument == 0, just use the default size. + * set_true == 1 if there should be an newnfs_true prepended on the file handle. + * Return the number of bytes output, including XDR overhead. + */ +APPLESTATIC int +nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true) +{ + u_int32_t *tl; + u_int8_t *cp; + int fullsiz, rem, bytesize = 0; + + if (size == 0) + size = NFSX_MYFH; + switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) { + case ND_NFSV2: + if (size > NFSX_V2FH) + panic("fh size > NFSX_V2FH for NFSv2"); + NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH); + NFSBCOPY(fhp, cp, size); + if (size < NFSX_V2FH) + NFSBZERO(cp + size, NFSX_V2FH - size); + bytesize = NFSX_V2FH; + break; + case ND_NFSV3: + case ND_NFSV4: + fullsiz = NFSM_RNDUP(size); + rem = fullsiz - size; + if (set_true) { + bytesize = 2 * NFSX_UNSIGNED + fullsiz; + NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); + *tl = newnfs_true; + } else { + bytesize = NFSX_UNSIGNED + fullsiz; + } + (void) nfsm_strtom(nd, fhp, size); + break; + }; + return (bytesize); +} + +/* + * This function compares two net addresses by family and returns TRUE + * if they are the same host. + * If there is any doubt, return FALSE. + * The AF_INET family is handled as a special case so that address mbufs + * don't need to be saved to store "struct in_addr", which is only 4 bytes. + */ +APPLESTATIC int +nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam) +{ + struct sockaddr_in *inetaddr; + + switch (family) { + case AF_INET: + inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *); + if (inetaddr->sin_family == AF_INET && + inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr) + return (1); + break; +#ifdef INET6 + case AF_INET6: + { + struct sockaddr_in6 *inetaddr6; + + inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *); + /* XXX - should test sin6_scope_id ? */ + if (inetaddr6->sin6_family == AF_INET6 && + IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr, + &haddr->had_inet6)) + return (1); + } + break; +#endif + }; + return (0); +} + +/* + * Similar to the above, but takes to NFSSOCKADDR_T args. + */ +APPLESTATIC int +nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2) +{ + struct sockaddr_in *addr1, *addr2; + struct sockaddr *inaddr; + + inaddr = NFSSOCKADDR(nam1, struct sockaddr *); + switch (inaddr->sa_family) { + case AF_INET: + addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *); + addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *); + if (addr2->sin_family == AF_INET && + addr1->sin_addr.s_addr == addr2->sin_addr.s_addr) + return (1); + break; +#ifdef INET6 + case AF_INET6: + { + struct sockaddr_in6 *inet6addr1, *inet6addr2; + + inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *); + inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *); + /* XXX - should test sin6_scope_id ? */ + if (inet6addr2->sin6_family == AF_INET6 && + IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr, + &inet6addr2->sin6_addr)) + return (1); + } + break; +#endif + }; + return (0); +} + + +/* + * Trim the stuff already dissected off the mbuf list. + */ +APPLESTATIC void +newnfs_trimleading(nd) + struct nfsrv_descript *nd; +{ + mbuf_t m, n; + int offs; + + /* + * First, free up leading mbufs. + */ + if (nd->nd_mrep != nd->nd_md) { + m = nd->nd_mrep; + while (mbuf_next(m) != nd->nd_md) { + if (mbuf_next(m) == NULL) + panic("nfsm trim leading"); + m = mbuf_next(m); + } + mbuf_setnext(m, NULL); + mbuf_freem(nd->nd_mrep); + } + m = nd->nd_md; + + /* + * Now, adjust this mbuf, based on nd_dpos. + */ + offs = nd->nd_dpos - NFSMTOD(m, caddr_t); + if (offs == mbuf_len(m)) { + n = m; + m = mbuf_next(m); + if (m == NULL) + panic("nfsm trim leading2"); + mbuf_setnext(n, NULL); + mbuf_freem(n); + } else if (offs > 0) { + mbuf_setlen(m, mbuf_len(m) - offs); + NFSM_DATAP(m, offs); + } else if (offs < 0) + panic("nfsm trimleading offs"); + nd->nd_mrep = m; + nd->nd_md = m; + nd->nd_dpos = NFSMTOD(m, caddr_t); +} + +/* + * Trim trailing data off the mbuf list being built. + */ +APPLESTATIC void +newnfs_trimtrailing(nd, mb, bpos) + struct nfsrv_descript *nd; + mbuf_t mb; + caddr_t bpos; +{ + + if (mbuf_next(mb)) { + mbuf_freem(mbuf_next(mb)); + mbuf_setnext(mb, NULL); + } + mbuf_setlen(mb, bpos - NFSMTOD(mb, caddr_t)); + nd->nd_mb = mb; + nd->nd_bpos = bpos; +} + +/* + * Dissect a file handle on the client. + */ +APPLESTATIC int +nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp) +{ + u_int32_t *tl; + struct nfsfh *nfhp; + int error, len; + + *nfhpp = NULL; + if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + if ((len = fxdr_unsigned(int, *tl)) <= 0 || + len > NFSX_FHMAX) + return (EBADRPC); + } else + len = NFSX_V2FH; + MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + len, + M_NFSFH, M_WAITOK); + error = nfsrv_mtostr(nd, nfhp->nfh_fh, len); + if (error) { + FREE((caddr_t)nfhp, M_NFSFH); + return (error); + } + nfhp->nfh_len = len; + *nfhpp = nfhp; +nfsmout: + return (error); +} + +/* + * Break down the nfsv4 acl. + * If the aclp == NULL or won't fit in an acl, just discard the acl info. + */ +APPLESTATIC int +nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp, + int *aclsizep, __unused NFSPROC_T *p) +{ + u_int32_t *tl; + int i, aclsize; + int acecnt, error = 0, aceerr = 0, acesize; + + *aclerrp = 0; +#ifdef NFS4_ACL_EXTATTR_NAME + if (aclp) + aclp->acl_cnt = 0; +#endif + /* + * Parse out the ace entries and expect them to conform to + * what can be supported by R/W/X bits. + */ + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + aclsize = NFSX_UNSIGNED; + acecnt = fxdr_unsigned(int, *tl); +#ifdef NFS4_ACL_EXTATTR_NAME + if (acecnt > ACL_MAX_ENTRIES) + aceerr = 1; +#endif + if (nfsrv_useacl == 0) + aceerr = 1; + for (i = 0; i < acecnt; i++) { +#ifdef NFS4_ACL_EXTATTR_NAME + if (aclp && !aceerr) + error = nfsrv_dissectace(nd, &aclp->acl_entry[i], + &aceerr, &acesize, p); + else +#endif + error = nfsrv_skipace(nd, &acesize); + if (error) + return (error); + aclsize += acesize; + } +#ifdef NFS4_ACL_EXTATTR_NAME + if (aclp && !aceerr) + aclp->acl_cnt = acecnt; +#endif + if (aceerr) + *aclerrp = aceerr; + if (aclsizep) + *aclsizep = aclsize; +nfsmout: + return (error); +} + +/* + * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it. + */ +static int +nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep) +{ + u_int32_t *tl; + int error, len = 0; + + NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); + len = fxdr_unsigned(int, *(tl + 3)); + error = nfsm_advance(nd, NFSM_RNDUP(len), -1); +nfsmout: + *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED); + return (error); +} + +/* + * Get attribute bits from an mbuf list. + * Returns EBADRPC for a parsing error, 0 otherwise. + * If the clearinvalid flag is set, clear the bits not supported. + */ +APPLESTATIC int +nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp, + int *retnotsupp) +{ + u_int32_t *tl; + int cnt, i, outcnt; + int error = 0; + + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + cnt = fxdr_unsigned(int, *tl); + if (cnt < 0) + return (NFSERR_BADXDR); + if (cnt > NFSATTRBIT_MAXWORDS) { + outcnt = NFSATTRBIT_MAXWORDS; + if (retnotsupp) + *retnotsupp = NFSERR_ATTRNOTSUPP; + } else { + outcnt = cnt; + } + NFSZERO_ATTRBIT(attrbitp); + if (outcnt > 0) { + NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED); + for (i = 0; i < outcnt; i++) + attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++); + } + if (cnt > outcnt) + error = nfsm_advance(nd, (cnt - outcnt) * NFSX_UNSIGNED, -1); + if (cntp) + *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED); +nfsmout: + return (error); +} + +/* + * Get the attributes for V4. + * If the compare flag is true, test for any attribute changes, + * otherwise return the attribute values. + * These attributes cover fields in "struct vattr", "struct statfs", + * "struct nfsfsinfo", the file handle and the lease duration. + * The value of retcmpp is set to 1 if all attributes are the same, + * and 0 otherwise. + * Returns EBADRPC if it can't be parsed, 0 otherwise. + */ +APPLESTATIC int +nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp, + struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize, + struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp, + struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp, + u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred) +{ + u_int32_t *tl; + int i = 0, j, k, l, m, bitpos, attrsum = 0; + int error, tfhsize, aceerr, attrsize, cnt, retnotsup; + u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1]; + nfsattrbit_t attrbits, retattrbits, checkattrbits; + struct nfsfh *tnfhp; + struct nfsreferral *refp; + u_quad_t tquad; + nfsquad_t tnfsquad; + struct timespec temptime; + uid_t uid; + gid_t gid; + long fid; + u_int32_t freenum = 0, tuint; + u_int64_t uquad = 0, thyp, thyp2; +#ifdef QUOTA + struct dqblk dqb; + uid_t savuid; +#endif + + if (compare) { + retnotsup = 0; + error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup); + } else { + error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); + } + if (error) + return (error); + + if (compare) { + *retcmpp = retnotsup; + } else { + /* + * Just set default values to some of the important ones. + */ + if (nap != NULL) { + nap->na_type = VREG; + nap->na_mode = 0; + nap->na_rdev = (NFSDEV_T)0; + nap->na_mtime.tv_sec = 0; + nap->na_mtime.tv_nsec = 0; + nap->na_gen = 0; + nap->na_flags = 0; + nap->na_blocksize = NFS_FABLKSIZE; + } + if (sbp != NULL) { + sbp->f_bsize = NFS_FABLKSIZE; + sbp->f_blocks = 0; + sbp->f_bfree = 0; + sbp->f_bavail = 0; + sbp->f_files = 0; + sbp->f_ffree = 0; + } + if (fsp != NULL) { + fsp->fs_rtmax = 8192; + fsp->fs_rtpref = 8192; + fsp->fs_maxname = NFS_MAXNAMLEN; + fsp->fs_wtmax = 8192; + fsp->fs_wtpref = 8192; + fsp->fs_wtmult = NFS_FABLKSIZE; + fsp->fs_dtpref = 8192; + fsp->fs_maxfilesize = 0xffffffffffffffffull; + fsp->fs_timedelta.tv_sec = 0; + fsp->fs_timedelta.tv_nsec = 1; + fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK | + NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME); + } + if (pc != NULL) { + pc->pc_linkmax = LINK_MAX; + pc->pc_namemax = NAME_MAX; + pc->pc_notrunc = 0; + pc->pc_chownrestricted = 0; + pc->pc_caseinsensitive = 0; + pc->pc_casepreserving = 1; + } + } + + /* + * Loop around getting the attributes. + */ + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + attrsize = fxdr_unsigned(int, *tl); + for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) { + if (attrsum > attrsize) { + error = NFSERR_BADXDR; + goto nfsmout; + } + if (NFSISSET_ATTRBIT(&attrbits, bitpos)) + switch (bitpos) { + case NFSATTRBIT_SUPPORTEDATTRS: + retnotsup = 0; + if (compare || nap == NULL) + error = nfsrv_getattrbits(nd, &retattrbits, + &cnt, &retnotsup); + else + error = nfsrv_getattrbits(nd, &nap->na_suppattr, + &cnt, &retnotsup); + if (error) + return (error); + if (compare && !(*retcmpp)) { + NFSSETSUPP_ATTRBIT(&checkattrbits); + if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits) + || retnotsup) + *retcmpp = NFSERR_NOTSAME; + } + attrsum += cnt; + break; + case NFSATTRBIT_TYPE: + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + if (compare) { + if (!(*retcmpp)) { + if (nap->na_type != nfsv34tov_type(*tl)) + *retcmpp = NFSERR_NOTSAME; + } + } else if (nap != NULL) { + nap->na_type = nfsv34tov_type(*tl); + } + attrsum += NFSX_UNSIGNED; + break; + case NFSATTRBIT_FHEXPIRETYPE: + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + if (compare && !(*retcmpp)) { + if (fxdr_unsigned(int, *tl) != + NFSV4FHTYPE_PERSISTENT) + *retcmpp = NFSERR_NOTSAME; + } + attrsum += NFSX_UNSIGNED; + break; + case NFSATTRBIT_CHANGE: + NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); + if (compare) { + if (!(*retcmpp)) { + if (nap->na_filerev != fxdr_hyper(tl)) + *retcmpp = NFSERR_NOTSAME; + } + } else if (nap != NULL) { + nap->na_filerev = fxdr_hyper(tl); + } + attrsum += NFSX_HYPER; + break; + case NFSATTRBIT_SIZE: + NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); + if (compare) { + if (!(*retcmpp)) { + if (nap->na_size != fxdr_hyper(tl)) + *retcmpp = NFSERR_NOTSAME; + } + } else if (nap != NULL) { + nap->na_size = fxdr_hyper(tl); + } + attrsum += NFSX_HYPER; + break; + case NFSATTRBIT_LINKSUPPORT: + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + if (compare) { + if (!(*retcmpp)) { + if (fsp->fs_properties & NFSV3_FSFLINK) { + if (*tl == newnfs_false) + *retcmpp = NFSERR_NOTSAME; + } else { + if (*tl == newnfs_true) + *retcmpp = NFSERR_NOTSAME; + } + } + } else if (fsp != NULL) { + if (*tl == newnfs_true) + fsp->fs_properties |= NFSV3_FSFLINK; + else + fsp->fs_properties &= ~NFSV3_FSFLINK; + } + attrsum += NFSX_UNSIGNED; + break; + case NFSATTRBIT_SYMLINKSUPPORT: + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + if (compare) { + if (!(*retcmpp)) { + if (fsp->fs_properties & NFSV3_FSFSYMLINK) { + if (*tl == newnfs_false) + *retcmpp = NFSERR_NOTSAME; + } else { + if (*tl == newnfs_true) + *retcmpp = NFSERR_NOTSAME; + } + } + } else if (fsp != NULL) { + if (*tl == newnfs_true) + fsp->fs_properties |= NFSV3_FSFSYMLINK; + else + fsp->fs_properties &= ~NFSV3_FSFSYMLINK; + } + attrsum += NFSX_UNSIGNED; + break; + case NFSATTRBIT_NAMEDATTR: + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + if (compare && !(*retcmpp)) { + if (*tl != newnfs_false) + *retcmpp = NFSERR_NOTSAME; + } + attrsum += NFSX_UNSIGNED; + break; + case NFSATTRBIT_FSID: + NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); + thyp = fxdr_hyper(tl); + tl += 2; + thyp2 = fxdr_hyper(tl); + if (compare) { + if (*retcmpp == 0) { + if (thyp != (u_int64_t) + vfs_statfs(vnode_mount(vp))->f_fsid.val[0] || + thyp2 != (u_int64_t) + vfs_statfs(vnode_mount(vp))->f_fsid.val[1]) + *retcmpp = NFSERR_NOTSAME; + } + } else if (nap != NULL) { + nap->na_filesid[0] = thyp; + nap->na_filesid[1] = thyp2; + } + attrsum += (4 * NFSX_UNSIGNED); + break; + case NFSATTRBIT_UNIQUEHANDLES: + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + if (compare && !(*retcmpp)) { + if (*tl != newnfs_true) + *retcmpp = NFSERR_NOTSAME; + } + attrsum += NFSX_UNSIGNED; + break; + case NFSATTRBIT_LEASETIME: + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + if (compare) { + if (fxdr_unsigned(int, *tl) != nfsrv_lease && + !(*retcmpp)) + *retcmpp = NFSERR_NOTSAME; + } else if (leasep != NULL) { + *leasep = fxdr_unsigned(u_int32_t, *tl); + } + attrsum += NFSX_UNSIGNED; + break; + case NFSATTRBIT_RDATTRERROR: + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + if (compare) { + if (!(*retcmpp)) + *retcmpp = NFSERR_INVAL; + } else if (rderrp != NULL) { + *rderrp = fxdr_unsigned(u_int32_t, *tl); + } + attrsum += NFSX_UNSIGNED; + break; + case NFSATTRBIT_ACL: + if (compare) { + if (!(*retcmpp)) { +#ifdef NFS4_ACL_EXTATTR_NAME + if (nfsrv_useacl) { + NFSACL_T *naclp; + + naclp = acl_alloc(); + error = nfsrv_dissectacl(nd, naclp, &aceerr, + &cnt, p); + if (error) { + acl_free(naclp); + return (error); + } + if (aceerr || nfsrv_compareacl(aclp, naclp)) + *retcmpp = NFSERR_NOTSAME; + acl_free(naclp); + } else +#endif + { + error = nfsrv_dissectacl(nd, NULL, &aceerr, + &cnt, p); + *retcmpp = NFSERR_ATTRNOTSUPP; + } + } + } else { + if (vp != NULL && aclp != NULL) + error = nfsrv_dissectacl(nd, aclp, &aceerr, + &cnt, p); + else + error = nfsrv_dissectacl(nd, NULL, &aceerr, + &cnt, p); + if (error) + return (error); + } + attrsum += cnt; + break; + case NFSATTRBIT_ACLSUPPORT: + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + if (compare && !(*retcmpp)) { + if (nfsrv_useacl) { + if (fxdr_unsigned(u_int32_t, *tl) != + NFSV4ACE_SUPTYPES) + *retcmpp = NFSERR_NOTSAME; + } else { + *retcmpp = NFSERR_ATTRNOTSUPP; + } + } + attrsum += NFSX_UNSIGNED; + break; + case NFSATTRBIT_ARCHIVE: + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + if (compare && !(*retcmpp)) + *retcmpp = NFSERR_ATTRNOTSUPP; + attrsum += NFSX_UNSIGNED; + break; + case NFSATTRBIT_CANSETTIME: + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + if (compare) { + if (!(*retcmpp)) { + if (fsp->fs_properties & NFSV3_FSFCANSETTIME) { + if (*tl == newnfs_false) + *retcmpp = NFSERR_NOTSAME; + } else { + if (*tl == newnfs_true) + *retcmpp = NFSERR_NOTSAME; + } + } + } else if (fsp != NULL) { + if (*tl == newnfs_true) + fsp->fs_properties |= NFSV3_FSFCANSETTIME; + else + fsp->fs_properties &= ~NFSV3_FSFCANSETTIME; + } + attrsum += NFSX_UNSIGNED; + break; + case NFSATTRBIT_CASEINSENSITIVE: + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + if (compare) { + if (!(*retcmpp)) { + if (*tl != newnfs_false) + *retcmpp = NFSERR_NOTSAME; + } + } else if (pc != NULL) { + pc->pc_caseinsensitive = + fxdr_unsigned(u_int32_t, *tl); + } + attrsum += NFSX_UNSIGNED; + break; + case NFSATTRBIT_CASEPRESERVING: + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + if (compare) { + if (!(*retcmpp)) { + if (*tl != newnfs_true) + *retcmpp = NFSERR_NOTSAME; + } + } else if (pc != NULL) { + pc->pc_casepreserving = + fxdr_unsigned(u_int32_t, *tl); + } + attrsum += NFSX_UNSIGNED; + break; + case NFSATTRBIT_CHOWNRESTRICTED: + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + if (compare) { + if (!(*retcmpp)) { + if (*tl != newnfs_true) + *retcmpp = NFSERR_NOTSAME; + } + } else if (pc != NULL) { + pc->pc_chownrestricted = + fxdr_unsigned(u_int32_t, *tl); + } + attrsum += NFSX_UNSIGNED; + break; + case NFSATTRBIT_FILEHANDLE: + error = nfsm_getfh(nd, &tnfhp); + if (error) + return (error); + tfhsize = tnfhp->nfh_len; + if (compare) { + if (!(*retcmpp) && + !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize, + fhp, fhsize)) + *retcmpp = NFSERR_NOTSAME; + FREE((caddr_t)tnfhp, M_NFSFH); + } else if (nfhpp != NULL) { + *nfhpp = tnfhp; + } else { + FREE((caddr_t)tnfhp, M_NFSFH); + } + attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize)); + break; + case NFSATTRBIT_FILEID: + NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); + thyp = fxdr_hyper(tl); + if (compare) { + if (!(*retcmpp)) { + if ((u_int64_t)nap->na_fileid != thyp) + *retcmpp = NFSERR_NOTSAME; + } + } else if (nap != NULL) { + if (*tl++) + printf("NFSv4 fileid > 32bits\n"); + nap->na_fileid = thyp; + } + attrsum += NFSX_HYPER; + break; + case NFSATTRBIT_FILESAVAIL: + NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); + if (compare) { + if (!(*retcmpp) && + sfp->sf_afiles != fxdr_hyper(tl)) + *retcmpp = NFSERR_NOTSAME; + } else if (sfp != NULL) { + sfp->sf_afiles = fxdr_hyper(tl); + } + attrsum += NFSX_HYPER; + break; + case NFSATTRBIT_FILESFREE: + NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); + if (compare) { + if (!(*retcmpp) && + sfp->sf_ffiles != fxdr_hyper(tl)) + *retcmpp = NFSERR_NOTSAME; + } else if (sfp != NULL) { + sfp->sf_ffiles = fxdr_hyper(tl); + } + attrsum += NFSX_HYPER; + break; + case NFSATTRBIT_FILESTOTAL: + NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); + if (compare) { + if (!(*retcmpp) && + sfp->sf_tfiles != fxdr_hyper(tl)) + *retcmpp = NFSERR_NOTSAME; + } else if (sfp != NULL) { + sfp->sf_tfiles = fxdr_hyper(tl); + } + attrsum += NFSX_HYPER; + break; + case NFSATTRBIT_FSLOCATIONS: + error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m); + if (error) + return (error); + attrsum += l; + if (compare && !(*retcmpp)) { + refp = nfsv4root_getreferral(vp, NULL, 0); + if (refp != NULL) { + if (cp == NULL || cp2 == NULL || + strcmp(cp, "/") || + strcmp(cp2, refp->nfr_srvlist)) + *retcmpp = NFSERR_NOTSAME; + } else if (m == 0) { + *retcmpp = NFSERR_NOTSAME; + } + } + if (cp != NULL) + free(cp, M_NFSSTRING); + if (cp2 != NULL) + free(cp2, M_NFSSTRING); + break; + case NFSATTRBIT_HIDDEN: + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + if (compare && !(*retcmpp)) + *retcmpp = NFSERR_ATTRNOTSUPP; + attrsum += NFSX_UNSIGNED; + break; + case NFSATTRBIT_HOMOGENEOUS: + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + if (compare) { + if (!(*retcmpp)) { + if (fsp->fs_properties & + NFSV3_FSFHOMOGENEOUS) { + if (*tl == newnfs_false) + *retcmpp = NFSERR_NOTSAME; + } else { + if (*tl == newnfs_true) + *retcmpp = NFSERR_NOTSAME; + } + } + } else if (fsp != NULL) { + if (*tl == newnfs_true) + fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS; + else + fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS; + } + attrsum += NFSX_UNSIGNED; + break; + case NFSATTRBIT_MAXFILESIZE: + NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); + tnfsquad.qval = fxdr_hyper(tl); + if (compare) { + if (!(*retcmpp)) { + tquad = NFSRV_MAXFILESIZE; + if (tquad != tnfsquad.qval) + *retcmpp = NFSERR_NOTSAME; + } + } else if (fsp != NULL) { + fsp->fs_maxfilesize = tnfsquad.qval; + } + attrsum += NFSX_HYPER; + break; + case NFSATTRBIT_MAXLINK: + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + if (compare) { + if (!(*retcmpp)) { + if (fxdr_unsigned(int, *tl) != LINK_MAX) + *retcmpp = NFSERR_NOTSAME; + } + } else if (pc != NULL) { + pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl); + } + attrsum += NFSX_UNSIGNED; + break; + case NFSATTRBIT_MAXNAME: + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + if (compare) { + if (!(*retcmpp)) { + if (fsp->fs_maxname != + fxdr_unsigned(u_int32_t, *tl)) + *retcmpp = NFSERR_NOTSAME; + } + } else { + tuint = fxdr_unsigned(u_int32_t, *tl); + /* + * Some Linux NFSv4 servers report this + * as 0 or 4billion, so I'll set it to + * NFS_MAXNAMLEN. If a server actually creates + * a name longer than NFS_MAXNAMLEN, it will + * get an error back. + */ + if (tuint == 0 || tuint > NFS_MAXNAMLEN) + tuint = NFS_MAXNAMLEN; + if (fsp != NULL) + fsp->fs_maxname = tuint; + if (pc != NULL) + pc->pc_namemax = tuint; + } + attrsum += NFSX_UNSIGNED; + break; + case NFSATTRBIT_MAXREAD: + NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); + if (compare) { + if (!(*retcmpp)) { + if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t, + *(tl + 1)) || *tl != 0) + *retcmpp = NFSERR_NOTSAME; + } + } else if (fsp != NULL) { + fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl); + fsp->fs_rtpref = fsp->fs_rtmax; + fsp->fs_dtpref = fsp->fs_rtpref; + } + attrsum += NFSX_HYPER; + break; + case NFSATTRBIT_MAXWRITE: + NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); + if (compare) { + if (!(*retcmpp)) { + if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t, + *(tl + 1)) || *tl != 0) + *retcmpp = NFSERR_NOTSAME; + } + } else if (fsp != NULL) { + fsp->fs_wtmax = fxdr_unsigned(int, *++tl); + fsp->fs_wtpref = fsp->fs_wtmax; + } + attrsum += NFSX_HYPER; + break; + case NFSATTRBIT_MIMETYPE: + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + i = fxdr_unsigned(int, *tl); + attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i)); + error = nfsm_advance(nd, NFSM_RNDUP(i), -1); + if (error) + goto nfsmout; + if (compare && !(*retcmpp)) + *retcmpp = NFSERR_ATTRNOTSUPP; + break; + case NFSATTRBIT_MODE: + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + if (compare) { + if (!(*retcmpp)) { + if (nap->na_mode != nfstov_mode(*tl)) + *retcmpp = NFSERR_NOTSAME; + } + } else if (nap != NULL) { + nap->na_mode = nfstov_mode(*tl); + } + attrsum += NFSX_UNSIGNED; + break; + case NFSATTRBIT_NOTRUNC: + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + if (compare) { + if (!(*retcmpp)) { + if (*tl != newnfs_true) + *retcmpp = NFSERR_NOTSAME; + } + } else if (pc != NULL) { + pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl); + } + attrsum += NFSX_UNSIGNED; + break; + case NFSATTRBIT_NUMLINKS: + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + tuint = fxdr_unsigned(u_int32_t, *tl); + if (compare) { + if (!(*retcmpp)) { + if ((u_int32_t)nap->na_nlink != tuint) + *retcmpp = NFSERR_NOTSAME; + } + } else if (nap != NULL) { + nap->na_nlink = tuint; + } + attrsum += NFSX_UNSIGNED; + break; + case NFSATTRBIT_OWNER: + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + j = fxdr_unsigned(int, *tl); + if (j < 0) + return (NFSERR_BADXDR); + attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j)); + if (j > NFSV4_SMALLSTR) + cp = malloc(j + 1, M_NFSSTRING, M_WAITOK); + else + cp = namestr; + error = nfsrv_mtostr(nd, cp, j); + if (error) { + if (j > NFSV4_SMALLSTR) + free(cp, M_NFSSTRING); + return (error); + } + if (compare) { + if (!(*retcmpp)) { + if (nfsv4_strtouid(cp, j, &uid, p) || + nap->na_uid != uid) + *retcmpp = NFSERR_NOTSAME; + } + } else if (nap != NULL) { + if (nfsv4_strtouid(cp, j, &uid, p)) + nap->na_uid = nfsrv_defaultuid; + else + nap->na_uid = uid; + } + if (j > NFSV4_SMALLSTR) + free(cp, M_NFSSTRING); + break; + case NFSATTRBIT_OWNERGROUP: + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + j = fxdr_unsigned(int, *tl); + if (j < 0) + return (NFSERR_BADXDR); + attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j)); + if (j > NFSV4_SMALLSTR) + cp = malloc(j + 1, M_NFSSTRING, M_WAITOK); + else + cp = namestr; + error = nfsrv_mtostr(nd, cp, j); + if (error) { + if (j > NFSV4_SMALLSTR) + free(cp, M_NFSSTRING); + return (error); + } + if (compare) { + if (!(*retcmpp)) { + if (nfsv4_strtogid(cp, j, &gid, p) || + nap->na_gid != gid) + *retcmpp = NFSERR_NOTSAME; + } + } else if (nap != NULL) { + if (nfsv4_strtogid(cp, j, &gid, p)) + nap->na_gid = nfsrv_defaultgid; + else + nap->na_gid = gid; + } + if (j > NFSV4_SMALLSTR) + free(cp, M_NFSSTRING); + break; + case NFSATTRBIT_QUOTAHARD: + NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); + if (sbp != NULL) { + if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) + freenum = sbp->f_bfree; + else + freenum = sbp->f_bavail; +#ifdef QUOTA + /* + * ufs_quotactl() insists that the uid argument + * equal p_ruid for non-root quota access, so + * we'll just make sure that's the case. + */ + savuid = p->p_cred->p_ruid; + p->p_cred->p_ruid = cred->cr_uid; + if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA, + USRQUOTA), cred->cr_uid, (caddr_t)&dqb, p)) + freenum = min(dqb.dqb_bhardlimit, freenum); + p->p_cred->p_ruid = savuid; +#endif /* QUOTA */ + uquad = (u_int64_t)freenum; + NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize); + } + if (compare && !(*retcmpp)) { + if (uquad != fxdr_hyper(tl)) + *retcmpp = NFSERR_NOTSAME; + } + attrsum += NFSX_HYPER; + break; + case NFSATTRBIT_QUOTASOFT: + NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); + if (sbp != NULL) { + if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) + freenum = sbp->f_bfree; + else + freenum = sbp->f_bavail; +#ifdef QUOTA + /* + * ufs_quotactl() insists that the uid argument + * equal p_ruid for non-root quota access, so + * we'll just make sure that's the case. + */ + savuid = p->p_cred->p_ruid; + p->p_cred->p_ruid = cred->cr_uid; + if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA, + USRQUOTA), cred->cr_uid, (caddr_t)&dqb, p)) + freenum = min(dqb.dqb_bsoftlimit, freenum); + p->p_cred->p_ruid = savuid; +#endif /* QUOTA */ + uquad = (u_int64_t)freenum; + NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize); + } + if (compare && !(*retcmpp)) { + if (uquad != fxdr_hyper(tl)) + *retcmpp = NFSERR_NOTSAME; + } + attrsum += NFSX_HYPER; + break; + case NFSATTRBIT_QUOTAUSED: + NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); + if (sbp != NULL) { + freenum = 0; +#ifdef QUOTA + /* + * ufs_quotactl() insists that the uid argument + * equal p_ruid for non-root quota access, so + * we'll just make sure that's the case. + */ + savuid = p->p_cred->p_ruid; + p->p_cred->p_ruid = cred->cr_uid; + if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA, + USRQUOTA), cred->cr_uid, (caddr_t)&dqb, p)) + freenum = dqb.dqb_curblocks; + p->p_cred->p_ruid = savuid; +#endif /* QUOTA */ + uquad = (u_int64_t)freenum; + NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize); + } + if (compare && !(*retcmpp)) { + if (uquad != fxdr_hyper(tl)) + *retcmpp = NFSERR_NOTSAME; + } + attrsum += NFSX_HYPER; + break; + case NFSATTRBIT_RAWDEV: + NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA); + j = fxdr_unsigned(int, *tl++); + k = fxdr_unsigned(int, *tl); + if (compare) { + if (!(*retcmpp)) { + if (nap->na_rdev != NFSMAKEDEV(j, k)) + *retcmpp = NFSERR_NOTSAME; + } + } else if (nap != NULL) { + nap->na_rdev = NFSMAKEDEV(j, k); + } + attrsum += NFSX_V4SPECDATA; + break; + case NFSATTRBIT_SPACEAVAIL: + NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); + if (compare) { + if (!(*retcmpp) && + sfp->sf_abytes != fxdr_hyper(tl)) + *retcmpp = NFSERR_NOTSAME; + } else if (sfp != NULL) { + sfp->sf_abytes = fxdr_hyper(tl); + } + attrsum += NFSX_HYPER; + break; + case NFSATTRBIT_SPACEFREE: + NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); + if (compare) { + if (!(*retcmpp) && + sfp->sf_fbytes != fxdr_hyper(tl)) + *retcmpp = NFSERR_NOTSAME; + } else if (sfp != NULL) { + sfp->sf_fbytes = fxdr_hyper(tl); + } + attrsum += NFSX_HYPER; + break; + case NFSATTRBIT_SPACETOTAL: + NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); + if (compare) { + if (!(*retcmpp) && + sfp->sf_tbytes != fxdr_hyper(tl)) + *retcmpp = NFSERR_NOTSAME; + } else if (sfp != NULL) { + sfp->sf_tbytes = fxdr_hyper(tl); + } + attrsum += NFSX_HYPER; + break; + case NFSATTRBIT_SPACEUSED: + NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); + thyp = fxdr_hyper(tl); + if (compare) { + if (!(*retcmpp)) { + if ((u_int64_t)nap->na_bytes != thyp) + *retcmpp = NFSERR_NOTSAME; + } + } else if (nap != NULL) { + nap->na_bytes = thyp; + } + attrsum += NFSX_HYPER; + break; + case NFSATTRBIT_SYSTEM: + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + if (compare && !(*retcmpp)) + *retcmpp = NFSERR_ATTRNOTSUPP; + attrsum += NFSX_UNSIGNED; + break; + case NFSATTRBIT_TIMEACCESS: + NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); + fxdr_nfsv4time(tl, &temptime); + if (compare) { + if (!(*retcmpp)) { + if (!NFS_CMPTIME(temptime, nap->na_atime)) + *retcmpp = NFSERR_NOTSAME; + } + } else if (nap != NULL) { + nap->na_atime = temptime; + } + attrsum += NFSX_V4TIME; + break; + case NFSATTRBIT_TIMEACCESSSET: + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + attrsum += NFSX_UNSIGNED; + i = fxdr_unsigned(int, *tl); + if (i == NFSV4SATTRTIME_TOCLIENT) { + NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); + attrsum += NFSX_V4TIME; + } + if (compare && !(*retcmpp)) + *retcmpp = NFSERR_INVAL; + break; + case NFSATTRBIT_TIMEBACKUP: + NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); + if (compare && !(*retcmpp)) + *retcmpp = NFSERR_ATTRNOTSUPP; + attrsum += NFSX_V4TIME; + break; + case NFSATTRBIT_TIMECREATE: + NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); + if (compare && !(*retcmpp)) + *retcmpp = NFSERR_ATTRNOTSUPP; + attrsum += NFSX_V4TIME; + break; + case NFSATTRBIT_TIMEDELTA: + NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); + if (fsp != NULL) { + if (compare) { + if (!(*retcmpp)) { + if ((u_int32_t)fsp->fs_timedelta.tv_sec != + fxdr_unsigned(u_int32_t, *(tl + 1)) || + (u_int32_t)fsp->fs_timedelta.tv_nsec != + (fxdr_unsigned(u_int32_t, *(tl + 2)) % + 1000000000) || + *tl != 0) + *retcmpp = NFSERR_NOTSAME; + } + } else { + fxdr_nfsv4time(tl, &fsp->fs_timedelta); + } + } + attrsum += NFSX_V4TIME; + break; + case NFSATTRBIT_TIMEMETADATA: + NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); + fxdr_nfsv4time(tl, &temptime); + if (compare) { + if (!(*retcmpp)) { + if (!NFS_CMPTIME(temptime, nap->na_ctime)) + *retcmpp = NFSERR_NOTSAME; + } + } else if (nap != NULL) { + nap->na_ctime = temptime; + } + attrsum += NFSX_V4TIME; + break; + case NFSATTRBIT_TIMEMODIFY: + NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); + fxdr_nfsv4time(tl, &temptime); + if (compare) { + if (!(*retcmpp)) { + if (!NFS_CMPTIME(temptime, nap->na_mtime)) + *retcmpp = NFSERR_NOTSAME; + } + } else if (nap != NULL) { + nap->na_mtime = temptime; + } + attrsum += NFSX_V4TIME; + break; + case NFSATTRBIT_TIMEMODIFYSET: + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + attrsum += NFSX_UNSIGNED; + i = fxdr_unsigned(int, *tl); + if (i == NFSV4SATTRTIME_TOCLIENT) { + NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); + attrsum += NFSX_V4TIME; + } + if (compare && !(*retcmpp)) + *retcmpp = NFSERR_INVAL; + break; + case NFSATTRBIT_MOUNTEDONFILEID: + NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); + thyp = fxdr_hyper(tl); + if (compare) { + if (!(*retcmpp)) { + if (*tl++) { + *retcmpp = NFSERR_NOTSAME; + } else { + if (!vp || !nfsrv_atroot(vp, &fid)) + fid = nap->na_fileid; + if ((u_int64_t)fid != thyp) + *retcmpp = NFSERR_NOTSAME; + } + } + } else if (nap != NULL) { + if (*tl++) + printf("NFSv4 mounted on fileid > 32bits\n"); + nap->na_mntonfileno = thyp; + } + attrsum += NFSX_HYPER; + break; + default: + printf("EEK! nfsv4_loadattr unknown attr=%d\n", + bitpos); + if (compare && !(*retcmpp)) + *retcmpp = NFSERR_ATTRNOTSUPP; + /* + * and get out of the loop, since we can't parse + * the unknown attrbute data. + */ + bitpos = NFSATTRBIT_MAX; + break; + }; + } + + /* + * some clients pad the attrlist, so we need to skip over the + * padding. + */ + if (attrsum > attrsize) { + error = NFSERR_BADXDR; + } else { + attrsize = NFSM_RNDUP(attrsize); + if (attrsum < attrsize) + error = nfsm_advance(nd, attrsize - attrsum, -1); + } +nfsmout: + return (error); +} + +/* + * Implement sleep locks for newnfs. The nfslock_usecnt allows for a + * shared lock and the NFSXXX_LOCK flag permits an exclusive lock. + * The first argument is a pointer to an nfsv4lock structure. + * The second argument is 1 iff a blocking lock is wanted. + * If this argument is 0, the call waits until no thread either wants nor + * holds an exclusive lock. + * It returns 1 if the lock was acquired, 0 otherwise. + * If several processes call this function concurrently wanting the exclusive + * lock, one will get the lock and the rest will return without getting the + * lock. (If the caller must have the lock, it simply calls this function in a + * loop until the function returns 1 to indicate the lock was acquired.) + * Any usecnt must be decremented by calling nfsv4_relref() before + * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could + * be called in a loop. + * The last argument is set to indicate if the call slept, iff not NULL. + */ +APPLESTATIC int +nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp, + void *mutex) +{ + + if (isleptp) + *isleptp = 0; + /* + * If a lock is wanted, loop around until the lock is acquired by + * someone and then released. If I want the lock, try to acquire it. + * For a lock to be issued, no lock must be in force and the usecnt + * must be zero. + */ + if (iwantlock) { + if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) && + lp->nfslock_usecnt == 0) { + lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED; + lp->nfslock_lock |= NFSV4LOCK_LOCK; + return (1); + } + lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED; + } + while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) { + lp->nfslock_lock |= NFSV4LOCK_WANTED; + if (isleptp) + *isleptp = 1; + (void) nfsmsleep(&lp->nfslock_lock, mutex, + PZERO - 1, "nfsv4lck", NULL); + if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) && + lp->nfslock_usecnt == 0) { + lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED; + lp->nfslock_lock |= NFSV4LOCK_LOCK; + return (1); + } + } + return (0); +} + +/* + * Release the lock acquired by nfsv4_lock(). + * The second argument is set to 1 to indicate the nfslock_usecnt should be + * incremented, as well. + */ +APPLESTATIC void +nfsv4_unlock(struct nfsv4lock *lp, int incref) +{ + + lp->nfslock_lock &= ~NFSV4LOCK_LOCK; + if (incref) + lp->nfslock_usecnt++; + nfsv4_wanted(lp); +} + +/* + * Release a reference cnt. + */ +APPLESTATIC void +nfsv4_relref(struct nfsv4lock *lp) +{ + + if (lp->nfslock_usecnt <= 0) + panic("nfsv4root ref cnt"); + lp->nfslock_usecnt--; + if (lp->nfslock_usecnt == 0) + nfsv4_wanted(lp); +} + +/* + * Get a reference cnt. + * This function will wait for any exclusive lock to be released, but will + * not wait for threads that want the exclusive lock. If priority needs + * to be given to threads that need the exclusive lock, a call to nfsv4_lock() + * with the 2nd argument == 0 should be done before calling nfsv4_getref(). + */ +APPLESTATIC void +nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex) +{ + + if (isleptp) + *isleptp = 0; + + /* + * Wait for a lock held. + */ + while (lp->nfslock_lock & NFSV4LOCK_LOCK) { + lp->nfslock_lock |= NFSV4LOCK_WANTED; + if (isleptp) + *isleptp = 1; + (void) nfsmsleep(&lp->nfslock_lock, mutex, + PZERO - 1, "nfsv4lck", NULL); + } + + lp->nfslock_usecnt++; +} + +/* + * Wake up anyone sleeping, waiting for this lock. + */ +static void +nfsv4_wanted(struct nfsv4lock *lp) +{ + + if (lp->nfslock_lock & NFSV4LOCK_WANTED) { + lp->nfslock_lock &= ~NFSV4LOCK_WANTED; + wakeup((caddr_t)&lp->nfslock_lock); + } +} + +/* + * Copy a string from an mbuf list into a character array. + * Return EBADRPC if there is an mbuf error, + * 0 otherwise. + */ +APPLESTATIC int +nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz) +{ + char *cp; + int xfer, len; + mbuf_t mp; + int rem, error = 0; + + mp = nd->nd_md; + cp = nd->nd_dpos; + len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp; + rem = NFSM_RNDUP(siz) - siz; + while (siz > 0) { + if (len > siz) + xfer = siz; + else + xfer = len; + NFSBCOPY(cp, str, xfer); + str += xfer; + siz -= xfer; + if (siz > 0) { + mp = mbuf_next(mp); + if (mp == NULL) + return (EBADRPC); + cp = NFSMTOD(mp, caddr_t); + len = mbuf_len(mp); + } else { + cp += xfer; + len -= xfer; + } + } + *str = '\0'; + nd->nd_dpos = cp; + nd->nd_md = mp; + if (rem > 0) { + if (len < rem) + error = nfsm_advance(nd, rem, len); + else + nd->nd_dpos += rem; + } + return (error); +} + +/* + * Fill in the attributes as marked by the bitmap (V4). + */ +APPLESTATIC int +nfsv4_fillattr(struct nfsrv_descript *nd, vnode_t vp, NFSACL_T *saclp, + struct vattr *vap, fhandle_t *fhp, int rderror, nfsattrbit_t *attrbitp, + struct ucred *cred, NFSPROC_T *p, int isdgram, int reterr) +{ + int bitpos, retnum = 0; + u_int32_t *tl; + int siz, prefixnum, error; + u_char *cp, namestr[NFSV4_SMALLSTR]; + nfsattrbit_t attrbits, retbits; + nfsattrbit_t *retbitp = &retbits; + u_int32_t freenum, *retnump; + u_int64_t uquad; + long fid; + struct statfs fs; + struct nfsfsinfo fsinf; + struct timespec temptime; + struct timeval curtime; + NFSACL_T *aclp, *naclp = NULL; +#ifdef QUOTA + struct dqblk dqb; + uid_t savuid; +#endif + + /* + * First, set the bits that can be filled and get fsinfo. + */ + NFSSET_ATTRBIT(retbitp, attrbitp); + /* If p and cred are NULL, it is a client side call */ + if (p == NULL && cred == NULL) { + NFSCLRNOTSETABLE_ATTRBIT(retbitp); + aclp = saclp; + } else { + NFSCLRNOTFILLABLE_ATTRBIT(retbitp); +#ifdef NFS4_ACL_EXTATTR_NAME + naclp = acl_alloc(); +#endif + aclp = naclp; + } + nfsvno_getfs(&fsinf, isdgram); +#ifndef APPLE + /* + * Get the VFS_STATFS(), since some attributes need them. + */ + if (NFSISSETSTATFS_ATTRBIT(retbitp)) { + error = VFS_STATFS(vnode_mount(vp), &fs, p); + if (error != 0) { + if (reterr) { + nd->nd_repstat = NFSERR_ACCES; + return (0); + } + NFSCLRSTATFS_ATTRBIT(retbitp); + } + } +#endif + + /* + * And the NFSv4 ACL... + */ + if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) +#ifdef NFS4_ACL_EXTATTR_NAME + && (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) && + !NFSHASNFS4ACL(vnode_mount(vp)))) +#endif + ) { + NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT); + } + if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) { +#ifdef NFS4_ACL_EXTATTR_NAME + if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) && + !NFSHASNFS4ACL(vnode_mount(vp)))) { +#endif + NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL); +#ifdef NFS4_ACL_EXTATTR_NAME + } else if (naclp != NULL) { + NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY, p); + error = VOP_ACCESS(vp, VREAD_ACL, cred, p); + if (error == 0) + error = VOP_GETACL(vp, ACL_TYPE_NFS4, naclp, + cred, p); + NFSVOPUNLOCK(vp, 0, p); + if (error != 0) { + if (reterr) { + nd->nd_repstat = NFSERR_ACCES; + return (0); + } + NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL); + } + } +#endif + } + /* + * Put out the attribute bitmap for the ones being filled in + * and get the field for the number of attributes returned. + */ + prefixnum = nfsrv_putattrbit(nd, retbitp); + NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED); + prefixnum += NFSX_UNSIGNED; + + /* + * Now, loop around filling in the attributes for each bit set. + */ + for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) { + if (NFSISSET_ATTRBIT(retbitp, bitpos)) { + switch (bitpos) { + case NFSATTRBIT_SUPPORTEDATTRS: + NFSSETSUPP_ATTRBIT(&attrbits); +#ifdef NFS4_ACL_EXTATTR_NAME + if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) + && !NFSHASNFS4ACL(vnode_mount(vp)))) +#endif + { + NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT); + NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL); + } + retnum += nfsrv_putattrbit(nd, &attrbits); + break; + case NFSATTRBIT_TYPE: + NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); + *tl = vtonfsv34_type(vap->va_type); + retnum += NFSX_UNSIGNED; + break; + case NFSATTRBIT_FHEXPIRETYPE: + NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); + *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT); + retnum += NFSX_UNSIGNED; + break; + case NFSATTRBIT_CHANGE: + NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); + txdr_hyper(vap->va_filerev, tl); + retnum += NFSX_HYPER; + break; + case NFSATTRBIT_SIZE: + NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); + txdr_hyper(vap->va_size, tl); + retnum += NFSX_HYPER; + break; + case NFSATTRBIT_LINKSUPPORT: + NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); + if (fsinf.fs_properties & NFSV3FSINFO_LINK) + *tl = newnfs_true; + else + *tl = newnfs_false; + retnum += NFSX_UNSIGNED; + break; + case NFSATTRBIT_SYMLINKSUPPORT: + NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); + if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK) + *tl = newnfs_true; + else + *tl = newnfs_false; + retnum += NFSX_UNSIGNED; + break; + case NFSATTRBIT_NAMEDATTR: + NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); + *tl = newnfs_false; + retnum += NFSX_UNSIGNED; + break; + case NFSATTRBIT_FSID: + NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID); + *tl++ = 0; + *tl++=txdr_unsigned(vfs_statfs(vnode_mount(vp))->f_fsid.val[0]); + *tl++ = 0; + *tl=txdr_unsigned(vfs_statfs(vnode_mount(vp))->f_fsid.val[1]); + retnum += NFSX_V4FSID; + break; + case NFSATTRBIT_UNIQUEHANDLES: + NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); + *tl = newnfs_true; + retnum += NFSX_UNSIGNED; + break; + case NFSATTRBIT_LEASETIME: + NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); + *tl = txdr_unsigned(nfsrv_lease); + retnum += NFSX_UNSIGNED; + break; + case NFSATTRBIT_RDATTRERROR: + NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); + *tl = txdr_unsigned(rderror); + retnum += NFSX_UNSIGNED; + break; + /* + * Recommended Attributes. (Only the supported ones.) + */ +#ifdef NFS4_ACL_EXTATTR_NAME + case NFSATTRBIT_ACL: + retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p); + break; + case NFSATTRBIT_ACLSUPPORT: + NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); + *tl = txdr_unsigned(NFSV4ACE_SUPTYPES); + retnum += NFSX_UNSIGNED; + break; +#endif + case NFSATTRBIT_CANSETTIME: + NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); + if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME) + *tl = newnfs_true; + else + *tl = newnfs_false; + retnum += NFSX_UNSIGNED; + break; + case NFSATTRBIT_CASEINSENSITIVE: + NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); + *tl = newnfs_false; + retnum += NFSX_UNSIGNED; + break; + case NFSATTRBIT_CASEPRESERVING: + NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); + *tl = newnfs_true; + retnum += NFSX_UNSIGNED; + break; + case NFSATTRBIT_CHOWNRESTRICTED: + NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); + *tl = newnfs_true; + retnum += NFSX_UNSIGNED; + break; + case NFSATTRBIT_FILEHANDLE: + retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); + break; + case NFSATTRBIT_FILEID: + NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); + *tl++ = 0; + *tl = txdr_unsigned(vap->va_fileid); + retnum += NFSX_HYPER; + break; + case NFSATTRBIT_FILESAVAIL: + /* + * Check quota and use min(quota, f_ffree). + */ + freenum = fs.f_ffree; +#ifdef QUOTA + /* + * ufs_quotactl() insists that the uid argument + * equal p_ruid for non-root quota access, so + * we'll just make sure that's the case. + */ + savuid = p->p_cred->p_ruid; + p->p_cred->p_ruid = cred->cr_uid; + if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,USRQUOTA), + cred->cr_uid, (caddr_t)&dqb, p)) + freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes, + freenum); + p->p_cred->p_ruid = savuid; +#endif /* QUOTA */ + NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); + *tl++ = 0; + *tl = txdr_unsigned(freenum); + retnum += NFSX_HYPER; + break; + case NFSATTRBIT_FILESFREE: + NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); + *tl++ = 0; + *tl = txdr_unsigned(fs.f_ffree); + retnum += NFSX_HYPER; + break; + case NFSATTRBIT_FILESTOTAL: + NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); + *tl++ = 0; + *tl = txdr_unsigned(fs.f_files); + retnum += NFSX_HYPER; + break; + case NFSATTRBIT_FSLOCATIONS: + NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); + *tl++ = 0; + *tl = 0; + retnum += 2 * NFSX_UNSIGNED; + break; + case NFSATTRBIT_HOMOGENEOUS: + NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); + if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS) + *tl = newnfs_true; + else + *tl = newnfs_false; + retnum += NFSX_UNSIGNED; + break; + case NFSATTRBIT_MAXFILESIZE: + NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); + uquad = NFSRV_MAXFILESIZE; + txdr_hyper(uquad, tl); + retnum += NFSX_HYPER; + break; + case NFSATTRBIT_MAXLINK: + NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); + *tl = txdr_unsigned(LINK_MAX); + retnum += NFSX_UNSIGNED; + break; + case NFSATTRBIT_MAXNAME: + NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); + *tl = txdr_unsigned(NFS_MAXNAMLEN); + retnum += NFSX_UNSIGNED; + break; + case NFSATTRBIT_MAXREAD: + NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); + *tl++ = 0; + *tl = txdr_unsigned(fsinf.fs_rtmax); + retnum += NFSX_HYPER; + break; + case NFSATTRBIT_MAXWRITE: + NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); + *tl++ = 0; + *tl = txdr_unsigned(fsinf.fs_wtmax); + retnum += NFSX_HYPER; + break; + case NFSATTRBIT_MODE: + NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); + *tl = vtonfsv34_mode(vap->va_mode); + retnum += NFSX_UNSIGNED; + break; + case NFSATTRBIT_NOTRUNC: + NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); + *tl = newnfs_true; + retnum += NFSX_UNSIGNED; + break; + case NFSATTRBIT_NUMLINKS: + NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); + *tl = txdr_unsigned(vap->va_nlink); + retnum += NFSX_UNSIGNED; + break; + case NFSATTRBIT_OWNER: + cp = namestr; + nfsv4_uidtostr(vap->va_uid, &cp, &siz, p); + retnum += nfsm_strtom(nd, cp, siz); + if (cp != namestr) + free(cp, M_NFSSTRING); + break; + case NFSATTRBIT_OWNERGROUP: + cp = namestr; + nfsv4_gidtostr(vap->va_gid, &cp, &siz, p); + retnum += nfsm_strtom(nd, cp, siz); + if (cp != namestr) + free(cp, M_NFSSTRING); + break; + case NFSATTRBIT_QUOTAHARD: + if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) + freenum = fs.f_bfree; + else + freenum = fs.f_bavail; +#ifdef QUOTA + /* + * ufs_quotactl() insists that the uid argument + * equal p_ruid for non-root quota access, so + * we'll just make sure that's the case. + */ + savuid = p->p_cred->p_ruid; + p->p_cred->p_ruid = cred->cr_uid; + if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,USRQUOTA), + cred->cr_uid, (caddr_t)&dqb, p)) + freenum = min(dqb.dqb_bhardlimit, freenum); + p->p_cred->p_ruid = savuid; +#endif /* QUOTA */ + NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); + uquad = (u_int64_t)freenum; + NFSQUOTABLKTOBYTE(uquad, fs.f_bsize); + txdr_hyper(uquad, tl); + retnum += NFSX_HYPER; + break; + case NFSATTRBIT_QUOTASOFT: + if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) + freenum = fs.f_bfree; + else + freenum = fs.f_bavail; +#ifdef QUOTA + /* + * ufs_quotactl() insists that the uid argument + * equal p_ruid for non-root quota access, so + * we'll just make sure that's the case. + */ + savuid = p->p_cred->p_ruid; + p->p_cred->p_ruid = cred->cr_uid; + if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,USRQUOTA), + cred->cr_uid, (caddr_t)&dqb, p)) + freenum = min(dqb.dqb_bsoftlimit, freenum); + p->p_cred->p_ruid = savuid; +#endif /* QUOTA */ + NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); + uquad = (u_int64_t)freenum; + NFSQUOTABLKTOBYTE(uquad, fs.f_bsize); + txdr_hyper(uquad, tl); + retnum += NFSX_HYPER; + break; + case NFSATTRBIT_QUOTAUSED: + freenum = 0; +#ifdef QUOTA + /* + * ufs_quotactl() insists that the uid argument + * equal p_ruid for non-root quota access, so + * we'll just make sure that's the case. + */ + savuid = p->p_cred->p_ruid; + p->p_cred->p_ruid = cred->cr_uid; + if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,USRQUOTA), + cred->cr_uid, (caddr_t)&dqb, p)) + freenum = dqb.dqb_curblocks; + p->p_cred->p_ruid = savuid; +#endif /* QUOTA */ + NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); + uquad = (u_int64_t)freenum; + NFSQUOTABLKTOBYTE(uquad, fs.f_bsize); + txdr_hyper(uquad, tl); + retnum += NFSX_HYPER; + break; + case NFSATTRBIT_RAWDEV: + NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA); + *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev)); + *tl = txdr_unsigned(NFSMINOR(vap->va_rdev)); + retnum += NFSX_V4SPECDATA; + break; + case NFSATTRBIT_SPACEAVAIL: + NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); + if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0)) + uquad = (u_int64_t)fs.f_bfree; + else + uquad = (u_int64_t)fs.f_bavail; + uquad *= fs.f_bsize; + txdr_hyper(uquad, tl); + retnum += NFSX_HYPER; + break; + case NFSATTRBIT_SPACEFREE: + NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); + uquad = (u_int64_t)fs.f_bfree; + uquad *= fs.f_bsize; + txdr_hyper(uquad, tl); + retnum += NFSX_HYPER; + break; + case NFSATTRBIT_SPACETOTAL: + NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); + uquad = (u_int64_t)fs.f_blocks; + uquad *= fs.f_bsize; + txdr_hyper(uquad, tl); + retnum += NFSX_HYPER; + break; + case NFSATTRBIT_SPACEUSED: + NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); + txdr_hyper(vap->va_bytes, tl); + retnum += NFSX_HYPER; + break; + case NFSATTRBIT_TIMEACCESS: + NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); + txdr_nfsv4time(&vap->va_atime, tl); + retnum += NFSX_V4TIME; + break; + case NFSATTRBIT_TIMEACCESSSET: + NFSGETTIME(&curtime); + if (vap->va_atime.tv_sec != curtime.tv_sec) { + NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME); + *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT); + txdr_nfsv4time(&vap->va_atime, tl); + retnum += NFSX_V4SETTIME; + } else { + NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); + *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER); + retnum += NFSX_UNSIGNED; + } + break; + case NFSATTRBIT_TIMEDELTA: + NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); + temptime.tv_sec = 0; + temptime.tv_nsec = 1000000000 / hz; + txdr_nfsv4time(&temptime, tl); + retnum += NFSX_V4TIME; + break; + case NFSATTRBIT_TIMEMETADATA: + NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); + txdr_nfsv4time(&vap->va_ctime, tl); + retnum += NFSX_V4TIME; + break; + case NFSATTRBIT_TIMEMODIFY: + NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); + txdr_nfsv4time(&vap->va_mtime, tl); + retnum += NFSX_V4TIME; + break; + case NFSATTRBIT_TIMEMODIFYSET: + NFSGETTIME(&curtime); + if (vap->va_mtime.tv_sec != curtime.tv_sec) { + NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME); + *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT); + txdr_nfsv4time(&vap->va_mtime, tl); + retnum += NFSX_V4SETTIME; + } else { + NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); + *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER); + retnum += NFSX_UNSIGNED; + } + break; + case NFSATTRBIT_MOUNTEDONFILEID: + NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); + *tl++ = 0; + if (nfsrv_atroot(vp, &fid)) + *tl = txdr_unsigned(fid); + else + *tl = txdr_unsigned(vap->va_fileid); + retnum += NFSX_HYPER; + break; + default: + printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos); + }; + } + } +#ifdef NFS4_ACL_EXTATTR_NAME + if (naclp != NULL) + acl_free(naclp); +#endif + *retnump = txdr_unsigned(retnum); + return (retnum + prefixnum); +} + +/* + * Put the attribute bits onto an mbuf list. + * Return the number of bytes of output generated. + */ +APPLESTATIC int +nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp) +{ + u_int32_t *tl; + int cnt, i, bytesize; + + for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--) + if (attrbitp->bits[cnt - 1]) + break; + bytesize = (cnt + 1) * NFSX_UNSIGNED; + NFSM_BUILD(tl, u_int32_t *, bytesize); + *tl++ = txdr_unsigned(cnt); + for (i = 0; i < cnt; i++) + *tl++ = txdr_unsigned(attrbitp->bits[i]); + return (bytesize); +} + +/* + * Convert a uid to a string. + * If the lookup fails, just output the digits. + * uid - the user id + * cpp - points to a buffer of size NFSV4_SMALLSTR + * (malloc a larger one, as required) + * retlenp - pointer to length to be returned + */ +APPLESTATIC void +nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p) +{ + int i; + struct nfsusrgrp *usrp; + u_char *cp = *cpp; + uid_t tmp; + int cnt, hasampersand, len = NFSV4_SMALLSTR, ret; + + cnt = 0; +tryagain: + NFSLOCKNAMEID(); + if (nfsrv_dnsname) { + /* + * Always map nfsrv_defaultuid to "nobody". + */ + if (uid == nfsrv_defaultuid) { + i = nfsrv_dnsnamelen + 7; + if (i > len) { + NFSUNLOCKNAMEID(); + if (len > NFSV4_SMALLSTR) + free(cp, M_NFSSTRING); + cp = malloc(i, M_NFSSTRING, M_WAITOK); + *cpp = cp; + len = i; + goto tryagain; + } + *retlenp = i; + NFSBCOPY("nobody@", cp, 7); + cp += 7; + NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); + NFSUNLOCKNAMEID(); + return; + } + hasampersand = 0; + LIST_FOREACH(usrp, NFSUSERHASH(uid), lug_numhash) { + if (usrp->lug_uid == uid) { + if (usrp->lug_expiry < NFSD_MONOSEC) + break; + /* + * If the name doesn't already have an '@' + * in it, append @domainname to it. + */ + for (i = 0; i < usrp->lug_namelen; i++) { + if (usrp->lug_name[i] == '@') { + hasampersand = 1; + break; + } + } + if (hasampersand) + i = usrp->lug_namelen; + else + i = usrp->lug_namelen + + nfsrv_dnsnamelen + 1; + if (i > len) { + NFSUNLOCKNAMEID(); + if (len > NFSV4_SMALLSTR) + free(cp, M_NFSSTRING); + cp = malloc(i, M_NFSSTRING, M_WAITOK); + *cpp = cp; + len = i; + goto tryagain; + } + *retlenp = i; + NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen); + if (!hasampersand) { + cp += usrp->lug_namelen; + *cp++ = '@'; + NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); + } + TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru); + TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru); + NFSUNLOCKNAMEID(); + return; + } + } + NFSUNLOCKNAMEID(); + cnt++; + ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, + NULL, p); + if (ret == 0 && cnt < 2) + goto tryagain; + } else { + NFSUNLOCKNAMEID(); + } + + /* + * No match, just return a string of digits. + */ + tmp = uid; + i = 0; + while (tmp || i == 0) { + tmp /= 10; + i++; + } + len = (i > len) ? len : i; + *retlenp = len; + cp += (len - 1); + tmp = uid; + for (i = 0; i < len; i++) { + *cp-- = '0' + (tmp % 10); + tmp /= 10; + } + return; +} + +/* + * Convert a string to a uid. + * If no conversion is possible return NFSERR_BADOWNER, otherwise + * return 0. + */ +APPLESTATIC int +nfsv4_strtouid(u_char *str, int len, uid_t *uidp, NFSPROC_T *p) +{ + int i; + u_char *cp; + struct nfsusrgrp *usrp; + int cnt, ret; + + if (len == 0) + return (NFSERR_BADOWNER); + /* + * Look for an '@'. + */ + cp = str; + for (i = 0; i < len; i++) + if (*cp++ == '@') + break; + + cnt = 0; +tryagain: + NFSLOCKNAMEID(); + /* + * If an '@' is found and the domain name matches, search for the name + * with dns stripped off. + * Mixed case alpahbetics will match for the domain name, but all + * upper case will not. + */ + if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname && + (len - 1 - i) == nfsrv_dnsnamelen && + !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) { + len -= (nfsrv_dnsnamelen + 1); + *(cp - 1) = '\0'; + } + + /* + * Check for the special case of "nobody". + */ + if (len == 6 && !NFSBCMP(str, "nobody", 6)) { + *uidp = nfsrv_defaultuid; + NFSUNLOCKNAMEID(); + return (0); + } + + LIST_FOREACH(usrp, NFSUSERNAMEHASH(str, len), lug_namehash) { + if (usrp->lug_namelen == len && + !NFSBCMP(usrp->lug_name, str, len)) { + if (usrp->lug_expiry < NFSD_MONOSEC) + break; + *uidp = usrp->lug_uid; + TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru); + TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru); + NFSUNLOCKNAMEID(); + return (0); + } + } + NFSUNLOCKNAMEID(); + cnt++; + ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0, + str, p); + if (ret == 0 && cnt < 2) + goto tryagain; + return (NFSERR_BADOWNER); +} + +/* + * Convert a gid to a string. + * gid - the group id + * cpp - points to a buffer of size NFSV4_SMALLSTR + * (malloc a larger one, as required) + * retlenp - pointer to length to be returned + */ +APPLESTATIC void +nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p) +{ + int i; + struct nfsusrgrp *usrp; + u_char *cp = *cpp; + gid_t tmp; + int cnt, hasampersand, len = NFSV4_SMALLSTR, ret; + + cnt = 0; +tryagain: + NFSLOCKNAMEID(); + if (nfsrv_dnsname) { + /* + * Always map nfsrv_defaultgid to "nogroup". + */ + if (gid == nfsrv_defaultgid) { + i = nfsrv_dnsnamelen + 8; + if (i > len) { + NFSUNLOCKNAMEID(); + if (len > NFSV4_SMALLSTR) + free(cp, M_NFSSTRING); + cp = malloc(i, M_NFSSTRING, M_WAITOK); + *cpp = cp; + len = i; + goto tryagain; + } + *retlenp = i; + NFSBCOPY("nogroup@", cp, 8); + cp += 8; + NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); + NFSUNLOCKNAMEID(); + return; + } + hasampersand = 0; + LIST_FOREACH(usrp, NFSGROUPHASH(gid), lug_numhash) { + if (usrp->lug_gid == gid) { + if (usrp->lug_expiry < NFSD_MONOSEC) + break; + /* + * If the name doesn't already have an '@' + * in it, append @domainname to it. + */ + for (i = 0; i < usrp->lug_namelen; i++) { + if (usrp->lug_name[i] == '@') { + hasampersand = 1; + break; + } + } + if (hasampersand) + i = usrp->lug_namelen; + else + i = usrp->lug_namelen + + nfsrv_dnsnamelen + 1; + if (i > len) { + NFSUNLOCKNAMEID(); + if (len > NFSV4_SMALLSTR) + free(cp, M_NFSSTRING); + cp = malloc(i, M_NFSSTRING, M_WAITOK); + *cpp = cp; + len = i; + goto tryagain; + } + *retlenp = i; + NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen); + if (!hasampersand) { + cp += usrp->lug_namelen; + *cp++ = '@'; + NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); + } + TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru); + TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru); + NFSUNLOCKNAMEID(); + return; + } + } + NFSUNLOCKNAMEID(); + cnt++; + ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid, + NULL, p); + if (ret == 0 && cnt < 2) + goto tryagain; + } else { + NFSUNLOCKNAMEID(); + } + + /* + * No match, just return a string of digits. + */ + tmp = gid; + i = 0; + while (tmp || i == 0) { + tmp /= 10; + i++; + } + len = (i > len) ? len : i; + *retlenp = len; + cp += (len - 1); + tmp = gid; + for (i = 0; i < len; i++) { + *cp-- = '0' + (tmp % 10); + tmp /= 10; + } + return; +} + +/* + * Convert a string to a gid. + */ +APPLESTATIC int +nfsv4_strtogid(u_char *str, int len, gid_t *gidp, NFSPROC_T *p) +{ + int i; + u_char *cp; + struct nfsusrgrp *usrp; + int cnt, ret; + + if (len == 0) + return (NFSERR_BADOWNER); + /* + * Look for an '@'. + */ + cp = str; + for (i = 0; i < len; i++) + if (*cp++ == '@') + break; + + cnt = 0; +tryagain: + NFSLOCKNAMEID(); + /* + * If an '@' is found and the dns name matches, search for the name + * with the dns stripped off. + */ + if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname && + (len - 1 - i) == nfsrv_dnsnamelen && + !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) { + len -= (nfsrv_dnsnamelen + 1); + *(cp - 1) = '\0'; + } + + /* + * Check for the special case of "nogroup". + */ + if (len == 7 && !NFSBCMP(str, "nogroup", 7)) { + *gidp = nfsrv_defaultgid; + NFSUNLOCKNAMEID(); + return (0); + } + + LIST_FOREACH(usrp, NFSGROUPNAMEHASH(str, len), lug_namehash) { + if (usrp->lug_namelen == len && + !NFSBCMP(usrp->lug_name, str, len)) { + if (usrp->lug_expiry < NFSD_MONOSEC) + break; + *gidp = usrp->lug_gid; + TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru); + TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru); + NFSUNLOCKNAMEID(); + return (0); + } + } + NFSUNLOCKNAMEID(); + cnt++; + ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0, + str, p); + if (ret == 0 && cnt < 2) + goto tryagain; + return (NFSERR_BADOWNER); +} + +/* + * Cmp len chars, allowing mixed case in the first argument to match lower + * case in the second, but not if the first argument is all upper case. + * Return 0 for a match, 1 otherwise. + */ +static int +nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len) +{ + int i; + u_char tmp; + int fndlower = 0; + + for (i = 0; i < len; i++) { + if (*cp >= 'A' && *cp <= 'Z') { + tmp = *cp++ + ('a' - 'A'); + } else { + tmp = *cp++; + if (tmp >= 'a' && tmp <= 'z') + fndlower = 1; + } + if (tmp != *cp2++) + return (1); + } + if (fndlower) + return (0); + else + return (1); +} + +/* + * Set the port for the nfsuserd. + */ +APPLESTATIC int +nfsrv_nfsuserdport(u_short port, NFSPROC_T *p) +{ + struct nfssockreq *rp; + struct sockaddr_in *ad; + int error; + + NFSLOCKNAMEID(); + if (nfsrv_nfsuserd) { + NFSUNLOCKNAMEID(); + return (EPERM); + } + nfsrv_nfsuserd = 1; + NFSUNLOCKNAMEID(); + /* + * Set up the socket record and connect. + */ + rp = &nfsrv_nfsuserdsock; + rp->nr_client = NULL; + rp->nr_sotype = SOCK_DGRAM; + rp->nr_soproto = IPPROTO_UDP; + rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST); + rp->nr_cred = NULL; + NFSSOCKADDRALLOC(rp->nr_nam); + NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in)); + ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *); + ad->sin_family = AF_INET; + ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001); /* 127.0.0.1 */ + ad->sin_port = port; + rp->nr_prog = RPCPROG_NFSUSERD; + rp->nr_vers = RPCNFSUSERD_VERS; + error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0); + if (error) { + NFSSOCKADDRFREE(rp->nr_nam); + nfsrv_nfsuserd = 0; + } + return (error); +} + +/* + * Delete the nfsuserd port. + */ +APPLESTATIC void +nfsrv_nfsuserddelport(void) +{ + + NFSLOCKNAMEID(); + if (nfsrv_nfsuserd == 0) { + NFSUNLOCKNAMEID(); + return; + } + nfsrv_nfsuserd = 0; + NFSUNLOCKNAMEID(); + newnfs_disconnect(&nfsrv_nfsuserdsock); + NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam); +} + +/* + * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup + * name<-->id cache. + * Returns 0 upon success, non-zero otherwise. + */ +static int +nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p) +{ + u_int32_t *tl; + struct nfsrv_descript *nd; + int len; + struct nfsrv_descript nfsd; + struct ucred *cred; + int error; + + NFSLOCKNAMEID(); + if (nfsrv_nfsuserd == 0) { + NFSUNLOCKNAMEID(); + return (EPERM); + } + NFSUNLOCKNAMEID(); + nd = &nfsd; + cred = newnfs_getcred(); + nd->nd_flag = ND_GSSINITREPLY; + nfsrvd_rephead(nd); + + nd->nd_procnum = procnum; + if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) { + NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); + if (procnum == RPCNFSUSERD_GETUID) + *tl = txdr_unsigned(uid); + else + *tl = txdr_unsigned(gid); + } else { + len = strlen(name); + (void) nfsm_strtom(nd, name, len); + } + error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL, + cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL); + NFSFREECRED(cred); + if (!error) { + mbuf_freem(nd->nd_mrep); + error = nd->nd_repstat; + } + return (error); +} + +/* + * This function is called from the nfssvc(2) system call, to update the + * kernel user/group name list(s) for the V4 owner and ownergroup attributes. + */ +APPLESTATIC int +nfssvc_idname(struct nfsd_idargs *nidp) +{ + struct nfsusrgrp *nusrp, *usrp, *newusrp; + struct nfsuserhashhead *hp; + int i; + int error = 0; + u_char *cp; + + if (nidp->nid_flag & NFSID_INITIALIZE) { + cp = (u_char *)malloc(nidp->nid_namelen + 1, + M_NFSSTRING, M_WAITOK); + error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp, + nidp->nid_namelen); + NFSLOCKNAMEID(); + if (nfsrv_dnsname) { + /* + * Free up all the old stuff and reinitialize hash lists. + */ + TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) { + nfsrv_removeuser(usrp); + } + free(nfsrv_dnsname, M_NFSSTRING); + nfsrv_dnsname = NULL; + } + TAILQ_INIT(&nfsuserlruhead); + for (i = 0; i < NFSUSERHASHSIZE; i++) + LIST_INIT(&nfsuserhash[i]); + for (i = 0; i < NFSGROUPHASHSIZE; i++) + LIST_INIT(&nfsgrouphash[i]); + for (i = 0; i < NFSUSERHASHSIZE; i++) + LIST_INIT(&nfsusernamehash[i]); + for (i = 0; i < NFSGROUPHASHSIZE; i++) + LIST_INIT(&nfsgroupnamehash[i]); + + /* + * Put name in "DNS" string. + */ + if (!error) { + nfsrv_dnsname = cp; + nfsrv_dnsnamelen = nidp->nid_namelen; + nfsrv_defaultuid = nidp->nid_uid; + nfsrv_defaultgid = nidp->nid_gid; + nfsrv_usercnt = 0; + nfsrv_usermax = nidp->nid_usermax; + } + NFSUNLOCKNAMEID(); + if (error) + free(cp, M_NFSSTRING); + return (error); + } + + /* + * malloc the new one now, so any potential sleep occurs before + * manipulation of the lists. + */ + MALLOC(newusrp, struct nfsusrgrp *, sizeof (struct nfsusrgrp) + + nidp->nid_namelen, M_NFSUSERGROUP, M_WAITOK); + error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name, + nidp->nid_namelen); + if (error) { + free((caddr_t)newusrp, M_NFSUSERGROUP); + return (error); + } + newusrp->lug_namelen = nidp->nid_namelen; + + NFSLOCKNAMEID(); + /* + * Delete old entries, as required. + */ + if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) { + hp = NFSUSERHASH(nidp->nid_uid); + LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) { + if (usrp->lug_uid == nidp->nid_uid) + nfsrv_removeuser(usrp); + } + } + if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) { + hp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen); + LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) { + if (usrp->lug_namelen == newusrp->lug_namelen && + !NFSBCMP(usrp->lug_name, newusrp->lug_name, + usrp->lug_namelen)) + nfsrv_removeuser(usrp); + } + } + if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) { + hp = NFSGROUPHASH(nidp->nid_gid); + LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) { + if (usrp->lug_gid == nidp->nid_gid) + nfsrv_removeuser(usrp); + } + } + if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) { + hp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen); + LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) { + if (usrp->lug_namelen == newusrp->lug_namelen && + !NFSBCMP(usrp->lug_name, newusrp->lug_name, + usrp->lug_namelen)) + nfsrv_removeuser(usrp); + } + } + TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) { + if (usrp->lug_expiry < NFSD_MONOSEC) + nfsrv_removeuser(usrp); + } + while (nfsrv_usercnt >= nfsrv_usermax) { + usrp = TAILQ_FIRST(&nfsuserlruhead); + nfsrv_removeuser(usrp); + } + + /* + * Now, we can add the new one. + */ + if (nidp->nid_usertimeout) + newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout; + else + newusrp->lug_expiry = NFSD_MONOSEC + 5; + if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) { + newusrp->lug_uid = nidp->nid_uid; + LIST_INSERT_HEAD(NFSUSERHASH(newusrp->lug_uid), newusrp, + lug_numhash); + LIST_INSERT_HEAD(NFSUSERNAMEHASH(newusrp->lug_name, + newusrp->lug_namelen), newusrp, lug_namehash); + TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru); + nfsrv_usercnt++; + } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) { + newusrp->lug_gid = nidp->nid_gid; + LIST_INSERT_HEAD(NFSGROUPHASH(newusrp->lug_gid), newusrp, + lug_numhash); + LIST_INSERT_HEAD(NFSGROUPNAMEHASH(newusrp->lug_name, + newusrp->lug_namelen), newusrp, lug_namehash); + TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru); + nfsrv_usercnt++; + } else + FREE((caddr_t)newusrp, M_NFSUSERGROUP); + NFSUNLOCKNAMEID(); + return (error); +} + +/* + * Remove a user/group name element. + */ +static void +nfsrv_removeuser(struct nfsusrgrp *usrp) +{ + + NFSNAMEIDREQUIRED(); + LIST_REMOVE(usrp, lug_numhash); + LIST_REMOVE(usrp, lug_namehash); + TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru); + nfsrv_usercnt--; + FREE((caddr_t)usrp, M_NFSUSERGROUP); +} + +/* + * This function scans a byte string and checks for UTF-8 compliance. + * It returns 0 if it conforms and NFSERR_INVAL if not. + */ +APPLESTATIC int +nfsrv_checkutf8(u_int8_t *cp, int len) +{ + u_int32_t val = 0x0; + int cnt = 0, gotd = 0, shift = 0; + u_int8_t byte; + static int utf8_shift[5] = { 7, 11, 16, 21, 26 }; + + /* + * Here are what the variables are used for: + * val - the calculated value of a multibyte char, used to check + * that it was coded with the correct range + * cnt - the number of 10xxxxxx bytes to follow + * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for + * shift - lower order bits of range (ie. "val >> shift" should + * not be 0, in other words, dividing by the lower bound + * of the range should get a non-zero value) + * byte - used to calculate cnt + */ + while (len > 0) { + if (cnt > 0) { + /* This handles the 10xxxxxx bytes */ + if ((*cp & 0xc0) != 0x80 || + (gotd && (*cp & 0x20))) + return (NFSERR_INVAL); + gotd = 0; + val <<= 6; + val |= (*cp & 0x3f); + cnt--; + if (cnt == 0 && (val >> shift) == 0x0) + return (NFSERR_INVAL); + } else if (*cp & 0x80) { + /* first byte of multi byte char */ + byte = *cp; + while ((byte & 0x40) && cnt < 6) { + cnt++; + byte <<= 1; + } + if (cnt == 0 || cnt == 6) + return (NFSERR_INVAL); + val = (*cp & (0x3f >> cnt)); + shift = utf8_shift[cnt - 1]; + if (cnt == 2 && val == 0xd) + /* Check for the 0xd800-0xdfff case */ + gotd = 1; + } + cp++; + len--; + } + if (cnt > 0) + return (NFSERR_INVAL); + return (0); +} + +/* + * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd + * strings, one with the root path in it and the other with the list of + * locations. The list is in the same format as is found in nfr_refs. + * It is a "," separated list of entries, where each of them is of the + * form <server>:<rootpath>. For example + * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2" + * The nilp argument is set to 1 for the special case of a null fs_root + * and an empty server list. + * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the + * number of xdr bytes parsed in sump. + */ +static int +nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp, + int *sump, int *nilp) +{ + u_int32_t *tl; + u_char *cp = NULL, *cp2 = NULL, *cp3, *str; + int i, j, len, stringlen, cnt, slen, siz, xdrsum, error, nsrv; + struct list { + SLIST_ENTRY(list) next; + int len; + u_char host[1]; + } *lsp, *nlsp; + SLIST_HEAD(, list) head; + + *fsrootp = NULL; + *srvp = NULL; + *nilp = 0; + + /* + * Get the fs_root path and check for the special case of null path + * and 0 length server list. + */ + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + len = fxdr_unsigned(int, *tl); + if (len < 0 || len > 10240) + return (NFSERR_BADXDR); + if (len == 0) { + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + if (*tl != 0) + return (NFSERR_BADXDR); + *nilp = 1; + *sump = 2 * NFSX_UNSIGNED; + return (0); + } + cp = malloc(len + 1, M_NFSSTRING, M_WAITOK); + error = nfsrv_mtostr(nd, cp, len); + if (!error) { + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + cnt = fxdr_unsigned(int, *tl); + if (cnt <= 0) + error = NFSERR_BADXDR; + } + if (error) { + free(cp, M_NFSSTRING); + return (error); + } + + /* + * Now, loop through the location list and make up the srvlist. + */ + xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len); + cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK); + slen = 1024; + siz = 0; + for (i = 0; i < cnt; i++) { + SLIST_INIT(&head); + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + nsrv = fxdr_unsigned(int, *tl); + if (nsrv <= 0) { + free(cp, M_NFSSTRING); + free(cp2, M_NFSSTRING); + return (NFSERR_BADXDR); + } + + /* + * Handle the first server by putting it in the srvstr. + */ + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + len = fxdr_unsigned(int, *tl); + if (len <= 0 || len > 1024) { + free(cp, M_NFSSTRING); + free(cp2, M_NFSSTRING); + return (NFSERR_BADXDR); + } + nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen); + if (cp3 != cp2) { + *cp3++ = ','; + siz++; + } + error = nfsrv_mtostr(nd, cp3, len); + if (error) { + free(cp, M_NFSSTRING); + free(cp2, M_NFSSTRING); + return (error); + } + cp3 += len; + *cp3++ = ':'; + siz += (len + 1); + xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len); + for (j = 1; j < nsrv; j++) { + /* + * Yuck, put them in an slist and process them later. + */ + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + len = fxdr_unsigned(int, *tl); + if (len <= 0 || len > 1024) { + free(cp, M_NFSSTRING); + free(cp2, M_NFSSTRING); + return (NFSERR_BADXDR); + } + lsp = (struct list *)malloc(sizeof (struct list) + + len, M_TEMP, M_WAITOK); + error = nfsrv_mtostr(nd, lsp->host, len); + if (error) { + free(cp, M_NFSSTRING); + free(cp2, M_NFSSTRING); + return (error); + } + xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len); + lsp->len = len; + SLIST_INSERT_HEAD(&head, lsp, next); + } + + /* + * Finally, we can get the path. + */ + NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + len = fxdr_unsigned(int, *tl); + if (len <= 0 || len > 1024) { + free(cp, M_NFSSTRING); + free(cp2, M_NFSSTRING); + return (NFSERR_BADXDR); + } + nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen); + error = nfsrv_mtostr(nd, cp3, len); + if (error) { + free(cp, M_NFSSTRING); + free(cp2, M_NFSSTRING); + return (error); + } + xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len); + str = cp3; + stringlen = len; + cp3 += len; + siz += len; + SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) { + nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3, + &cp2, &cp3, &slen); + *cp3++ = ','; + NFSBCOPY(lsp->host, cp3, lsp->len); + cp3 += lsp->len; + *cp3++ = ':'; + NFSBCOPY(str, cp3, stringlen); + cp3 += stringlen; + *cp3 = '\0'; + siz += (lsp->len + stringlen + 2); + free((caddr_t)lsp, M_TEMP); + } + } + *fsrootp = cp; + *srvp = cp2; + *sump = xdrsum; + return (0); +nfsmout: + if (cp != NULL) + free(cp, M_NFSSTRING); + if (cp2 != NULL) + free(cp2, M_NFSSTRING); + return (error); +} + +/* + * Make the malloc'd space large enough. This is a pain, but the xdr + * doesn't set an upper bound on the side, so... + */ +static void +nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp) +{ + u_char *cp; + int i; + + if (siz <= *slenp) + return; + cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK); + NFSBCOPY(*cpp, cp, *slenp); + free(*cpp, M_NFSSTRING); + i = *cpp2 - *cpp; + *cpp = cp; + *cpp2 = cp + i; + *slenp = siz + 1024; +} + +/* + * Initialize the reply header data structures. + */ +APPLESTATIC void +nfsrvd_rephead(struct nfsrv_descript *nd) +{ + mbuf_t mreq; + + /* + * If this is a big reply, use a cluster. + */ + if ((nd->nd_flag & ND_GSSINITREPLY) == 0 && + nfs_bigreply[nd->nd_procnum]) { + NFSMCLGET(mreq, M_WAIT); + nd->nd_mreq = mreq; + nd->nd_mb = mreq; + } else { + NFSMGET(mreq); + nd->nd_mreq = mreq; + nd->nd_mb = mreq; + } + nd->nd_bpos = NFSMTOD(mreq, caddr_t); + mbuf_setlen(mreq, 0); + + if ((nd->nd_flag & ND_GSSINITREPLY) == 0) + NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED); +} + +/* + * Lock a socket against others. + * Currently used to serialize connect/disconnect attempts. + */ +int +newnfs_sndlock(int *flagp) +{ + struct timespec ts; + + NFSLOCKSOCK(); + while (*flagp & NFSR_SNDLOCK) { + *flagp |= NFSR_WANTSND; + ts.tv_sec = 0; + ts.tv_nsec = 0; + (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR, + PZERO - 1, "nfsndlck", &ts); + } + *flagp |= NFSR_SNDLOCK; + NFSUNLOCKSOCK(); + return (0); +} + +/* + * Unlock the stream socket for others. + */ +void +newnfs_sndunlock(int *flagp) +{ + + NFSLOCKSOCK(); + if ((*flagp & NFSR_SNDLOCK) == 0) + panic("nfs sndunlock"); + *flagp &= ~NFSR_SNDLOCK; + if (*flagp & NFSR_WANTSND) { + *flagp &= ~NFSR_WANTSND; + wakeup((caddr_t)flagp); + } + NFSUNLOCKSOCK(); +} + diff --git a/sys/fs/nfs/nfs_var.h b/sys/fs/nfs/nfs_var.h new file mode 100644 index 0000000..64b1e90 --- /dev/null +++ b/sys/fs/nfs/nfs_var.h @@ -0,0 +1,604 @@ +/*- + * 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. + * + * $FreeBSD$ + */ + +/* + * XXX needs <nfs/rpcv2.h> and <nfs/nfs.h> because of typedefs + */ + +struct uio; +struct ucred; +struct nfscred; +NFSPROC_T; +struct buf; +struct nfs_diskless; +struct sockaddr_in; +struct nfs_dlmount; +struct file; +struct nfsmount; +struct socket; +struct nfsreq; +struct nfssockreq; +struct vattr; +struct nameidata; +struct nfsnode; +struct nfsfh; +struct sillyrename; +struct componentname; +struct nfsd_srvargs; +struct nfsrv_descript; +struct nfs_fattr; +union nethostaddr; +struct nfsstate; +struct nfslock; +struct nfsclient; +struct nfslockconflict; +struct nfsd_idargs; +struct nfsd_clid; +struct nfsusrgrp; +struct nfsclowner; +struct nfsclopen; +struct nfsclopenhead; +struct nfsclclient; +struct nfscllockowner; +struct nfscllock; +struct nfscldeleg; +struct nfsv4lock; +struct nfsvattr; +struct nfs_vattr; +struct NFSSVCARGS; +#ifdef __FreeBSD__ +NFS_ACCESS_ARGS; +NFS_OPEN_ARGS; +NFS_GETATTR_ARGS; +NFS_LOOKUP_ARGS; +NFS_READDIR_ARGS; +#endif + +/* nfsd_srvstate.c */ +int nfsrv_setclient(struct nfsrv_descript *, struct nfsclient **, + nfsquad_t *, nfsquad_t *, NFSPROC_T *); +int nfsrv_getclient(nfsquad_t, int, struct nfsclient **, nfsquad_t, + struct nfsrv_descript *, NFSPROC_T *); +int nfsrv_adminrevoke(struct nfsd_clid *, NFSPROC_T *); +void nfsrv_dumpclients(struct nfsd_dumpclients *, int); +void nfsrv_dumplocks(vnode_t, struct nfsd_dumplocks *, int, NFSPROC_T *); +int nfsrv_lockctrl(vnode_t, struct nfsstate **, + struct nfslock **, struct nfslockconflict *, nfsquad_t, nfsv4stateid_t *, + struct nfsexstuff *, struct nfsrv_descript *, NFSPROC_T *); +int nfsrv_openctrl(struct nfsrv_descript *, vnode_t, + struct nfsstate **, nfsquad_t, nfsv4stateid_t *, nfsv4stateid_t *, + u_int32_t *, struct nfsexstuff *, NFSPROC_T *, u_quad_t); +int nfsrv_opencheck(nfsquad_t, nfsv4stateid_t *, struct nfsstate *, + vnode_t, struct nfsrv_descript *, NFSPROC_T *, int); +int nfsrv_openupdate(vnode_t, struct nfsstate *, nfsquad_t, + nfsv4stateid_t *, struct nfsrv_descript *, NFSPROC_T *); +int nfsrv_delegupdate(nfsquad_t, nfsv4stateid_t *, vnode_t, int, + struct ucred *, NFSPROC_T *); +int nfsrv_releaselckown(struct nfsstate *, nfsquad_t, NFSPROC_T *); +void nfsrv_zapclient(struct nfsclient *, NFSPROC_T *); +int nfssvc_idname(struct nfsd_idargs *); +void nfsrv_servertimer(void); +int nfsrv_getclientipaddr(struct nfsrv_descript *, struct nfsclient *); +void nfsrv_setupstable(NFSPROC_T *); +void nfsrv_updatestable(NFSPROC_T *); +void nfsrv_writestable(u_char *, int, int, NFSPROC_T *); +void nfsrv_throwawayopens(NFSPROC_T *); +int nfsrv_checkremove(vnode_t, int, NFSPROC_T *); +void nfsd_recalldelegation(vnode_t, NFSPROC_T *); +void nfsd_disabledelegation(vnode_t, NFSPROC_T *); +int nfsrv_checksetattr(vnode_t, struct nfsrv_descript *, + nfsv4stateid_t *, struct nfsvattr *, nfsattrbit_t *, struct nfsexstuff *, + NFSPROC_T *); +int nfsrv_checkgetattr(struct nfsrv_descript *, vnode_t, + struct nfsvattr *, nfsattrbit_t *, struct ucred *, NFSPROC_T *); +int nfsrv_nfsuserdport(u_short, NFSPROC_T *); +void nfsrv_nfsuserddelport(void); + +/* nfsd_serv.c */ +int nfsrvd_access(struct nfsrv_descript *, int, + vnode_t, NFSPROC_T *, struct nfsexstuff *); +int nfsrvd_getattr(struct nfsrv_descript *, int, + vnode_t, NFSPROC_T *, struct nfsexstuff *); +int nfsrvd_setattr(struct nfsrv_descript *, int, + vnode_t, NFSPROC_T *, struct nfsexstuff *); +int nfsrvd_lookup(struct nfsrv_descript *, int, + vnode_t, vnode_t *, fhandle_t *, NFSPROC_T *, + struct nfsexstuff *); +int nfsrvd_readlink(struct nfsrv_descript *, int, + vnode_t, NFSPROC_T *, struct nfsexstuff *); +int nfsrvd_read(struct nfsrv_descript *, int, + vnode_t, NFSPROC_T *, struct nfsexstuff *); +int nfsrvd_write(struct nfsrv_descript *, int, + vnode_t, NFSPROC_T *, struct nfsexstuff *); +int nfsrvd_create(struct nfsrv_descript *, int, + vnode_t, NFSPROC_T *, struct nfsexstuff *); +int nfsrvd_mknod(struct nfsrv_descript *, int, + vnode_t, vnode_t *, fhandle_t *, NFSPROC_T *, + struct nfsexstuff *); +int nfsrvd_remove(struct nfsrv_descript *, int, + vnode_t, NFSPROC_T *, struct nfsexstuff *); +int nfsrvd_rename(struct nfsrv_descript *, int, + vnode_t, vnode_t, NFSPROC_T *, struct nfsexstuff *, + struct nfsexstuff *); +int nfsrvd_link(struct nfsrv_descript *, int, + vnode_t, vnode_t, NFSPROC_T *, struct nfsexstuff *, + struct nfsexstuff *); +int nfsrvd_symlink(struct nfsrv_descript *, int, + vnode_t, vnode_t *, fhandle_t *, NFSPROC_T *, + struct nfsexstuff *); +int nfsrvd_mkdir(struct nfsrv_descript *, int, + vnode_t, vnode_t *, fhandle_t *, NFSPROC_T *, + struct nfsexstuff *); +int nfsrvd_readdir(struct nfsrv_descript *, int, + vnode_t, NFSPROC_T *, struct nfsexstuff *); +int nfsrvd_readdirplus(struct nfsrv_descript *, int, + vnode_t, NFSPROC_T *, struct nfsexstuff *); +int nfsrvd_commit(struct nfsrv_descript *, int, + vnode_t, NFSPROC_T *, struct nfsexstuff *); +int nfsrvd_statfs(struct nfsrv_descript *, int, + vnode_t, NFSPROC_T *, struct nfsexstuff *); +int nfsrvd_fsinfo(struct nfsrv_descript *, int, + vnode_t, NFSPROC_T *, struct nfsexstuff *); +int nfsrvd_close(struct nfsrv_descript *, int, + vnode_t, NFSPROC_T *, struct nfsexstuff *); +int nfsrvd_delegpurge(struct nfsrv_descript *, int, + vnode_t, NFSPROC_T *, struct nfsexstuff *); +int nfsrvd_delegreturn(struct nfsrv_descript *, int, + vnode_t, NFSPROC_T *, struct nfsexstuff *); +int nfsrvd_getfh(struct nfsrv_descript *, int, + vnode_t, NFSPROC_T *, struct nfsexstuff *); +int nfsrvd_lock(struct nfsrv_descript *, int, + vnode_t, NFSPROC_T *, struct nfsexstuff *); +int nfsrvd_lockt(struct nfsrv_descript *, int, + vnode_t, NFSPROC_T *, struct nfsexstuff *); +int nfsrvd_locku(struct nfsrv_descript *, int, + vnode_t, NFSPROC_T *, struct nfsexstuff *); +int nfsrvd_openconfirm(struct nfsrv_descript *, int, + vnode_t, NFSPROC_T *, struct nfsexstuff *); +int nfsrvd_opendowngrade(struct nfsrv_descript *, int, + vnode_t, NFSPROC_T *, struct nfsexstuff *); +int nfsrvd_renew(struct nfsrv_descript *, int, + vnode_t, NFSPROC_T *, struct nfsexstuff *); +int nfsrvd_secinfo(struct nfsrv_descript *, int, + vnode_t, NFSPROC_T *, struct nfsexstuff *); +int nfsrvd_setclientid(struct nfsrv_descript *, int, + vnode_t, NFSPROC_T *, struct nfsexstuff *); +int nfsrvd_setclientidcfrm(struct nfsrv_descript *, int, + vnode_t, NFSPROC_T *, struct nfsexstuff *); +int nfsrvd_verify(struct nfsrv_descript *, int, + vnode_t, NFSPROC_T *, struct nfsexstuff *); +int nfsrvd_open(struct nfsrv_descript *, int, + vnode_t, vnode_t *, fhandle_t *, NFSPROC_T *, + struct nfsexstuff *); +int nfsrvd_openattr(struct nfsrv_descript *, int, + vnode_t, vnode_t *, fhandle_t *, NFSPROC_T *, + struct nfsexstuff *); +int nfsrvd_releaselckown(struct nfsrv_descript *, int, + vnode_t, NFSPROC_T *, struct nfsexstuff *); +int nfsrvd_pathconf(struct nfsrv_descript *, int, + vnode_t, NFSPROC_T *, struct nfsexstuff *); + +/* newnfs_socket.c */ +int newnfs_request(struct nfsrv_descript *, struct nfsmount *, + struct nfsclient *, struct nfssockreq *, vnode_t, NFSPROC_T *, + struct ucred *, u_int32_t, u_int32_t, u_char *, int, u_int64_t *); +int newnfs_connect(struct nfsmount *, struct nfssockreq *, + struct ucred *, NFSPROC_T *, int); +void newnfs_disconnect(struct nfssockreq *); +void newnfs_timer(void *); +int newnfs_sigintr(struct nfsmount *, NFSPROC_T *); +int newnfs_sndlock(int *); +void newnfs_sndunlock(int *); + +/* nfsd_srvsocket.c */ +void nfsrvd_rephead(struct nfsrv_descript *); +void nfsrvd_dorpc(struct nfsrv_descript *, int, NFSPROC_T *); + +/* nfs_srvcache.c */ +void nfsrvd_initcache(void); +int nfsrvd_getcache(struct nfsrv_descript *, struct socket *); +struct nfsrvcache *nfsrvd_updatecache(struct nfsrv_descript *, + struct socket *); +void nfsrvd_sentcache(struct nfsrvcache *, struct socket *, int); +void nfsrvd_cleancache(void); +void nfsrvd_refcache(struct nfsrvcache *); +void nfsrvd_derefcache(struct nfsrvcache *); +void nfsrvd_delcache(struct nfsrvcache *); + +/* newnfs_subs.c */ +void newnfs_init(void); +int nfsaddr_match(int, union nethostaddr *, NFSSOCKADDR_T); +int nfsaddr2_match(NFSSOCKADDR_T, NFSSOCKADDR_T); +int nfsm_strtom(struct nfsrv_descript *, const char *, int); +int nfsm_mbufuio(struct nfsrv_descript *, struct uio *, int); +int nfsm_fhtom(struct nfsrv_descript *, u_int8_t *, int, int); +int nfsm_advance(struct nfsrv_descript *, int, int); +void *nfsm_dissct(struct nfsrv_descript *, int); +void newnfs_trimleading(struct nfsrv_descript *); +void newnfs_trimtrailing(struct nfsrv_descript *, mbuf_t, + caddr_t); +void newnfs_copycred(struct nfscred *, struct ucred *); +void newnfs_copyincred(struct ucred *, struct nfscred *); +int nfsrv_dissectacl(struct nfsrv_descript *, NFSACL_T *, int *, + int *, NFSPROC_T *); +int nfsrv_getattrbits(struct nfsrv_descript *, nfsattrbit_t *, int *, + int *); +int nfsv4_loadattr(struct nfsrv_descript *, vnode_t, + struct nfsvattr *, struct nfsfh **, fhandle_t *, int, + struct nfsv3_pathconf *, struct statfs *, struct nfsstatfs *, + struct nfsfsinfo *, NFSACL_T *, + int, int *, u_int32_t *, u_int32_t *, NFSPROC_T *, struct ucred *); +int nfsv4_lock(struct nfsv4lock *, int, int *, void *); +void nfsv4_unlock(struct nfsv4lock *, int); +void nfsv4_relref(struct nfsv4lock *); +void nfsv4_getref(struct nfsv4lock *, int *, void *); +int nfsrv_mtostr(struct nfsrv_descript *, char *, int); +int nfsrv_checkutf8(u_int8_t *, int); + +/* nfscl_subs.c */ +void nfsm_uiombuf(struct nfsrv_descript *, struct uio *, int); +void nfscl_reqstart(struct nfsrv_descript *, int, struct nfsmount *, + u_int8_t *, int, u_int32_t **); +nfsuint64 *nfscl_getcookie(struct nfsnode *, off_t off, int); +void nfscl_fillsattr(struct nfsrv_descript *, struct vattr *, + vnode_t, int, u_int32_t); +u_int8_t *nfscl_getmyip(struct nfsmount *, int *); +int nfsm_getfh(struct nfsrv_descript *, struct nfsfh **); +int nfscl_mtofh(struct nfsrv_descript *, struct nfsfh **, + struct nfsvattr *, int *); +int nfscl_postop_attr(struct nfsrv_descript *, struct nfsvattr *, int *, + void *); +int nfscl_wcc_data(struct nfsrv_descript *, vnode_t, + struct nfsvattr *, int *, int *, void *); +int nfsm_loadattr(struct nfsrv_descript *, struct nfsvattr *); +int nfscl_request(struct nfsrv_descript *, vnode_t, + NFSPROC_T *, struct ucred *, void *); +void nfsm_stateidtom(struct nfsrv_descript *, nfsv4stateid_t *, int); + +/* nfsd_srvsubs.c */ +void nfsd_fhtovp(struct nfsrv_descript *, struct nfsrvfh *, + vnode_t *, struct nfsexstuff *, + mount_t *, int, NFSPROC_T *); +int nfsd_excred(struct nfsrv_descript *, struct nfsexstuff *, struct ucred *); +int nfsrv_mtofh(struct nfsrv_descript *, struct nfsrvfh *); +int nfsrv_putattrbit(struct nfsrv_descript *, nfsattrbit_t *); +void nfsrv_wcc(struct nfsrv_descript *, int, struct nfsvattr *, int, + struct nfsvattr *); +int nfsv4_fillattr(struct nfsrv_descript *, vnode_t, NFSACL_T *, + struct vattr *, fhandle_t *, int, nfsattrbit_t *, + struct ucred *, NFSPROC_T *, int, int); +void nfsrv_fillattr(struct nfsrv_descript *, struct nfsvattr *); +void nfsrv_adj(mbuf_t, int, int); +void nfsrv_postopattr(struct nfsrv_descript *, int, struct nfsvattr *); +int nfsd_errmap(struct nfsrv_descript *); +void nfsv4_uidtostr(uid_t, u_char **, int *, NFSPROC_T *); +int nfsv4_strtouid(u_char *, int, uid_t *, NFSPROC_T *); +void nfsv4_gidtostr(gid_t, u_char **, int *, NFSPROC_T *); +int nfsv4_strtogid(u_char *, int, gid_t *, NFSPROC_T *); +int nfsrv_checkuidgid(struct nfsrv_descript *, struct nfsvattr *); +void nfsrv_fixattr(struct nfsrv_descript *, vnode_t, + struct nfsvattr *, NFSACL_T *, NFSPROC_T *, nfsattrbit_t *, + struct nfsexstuff *); +int nfsrv_errmoved(int); +int nfsrv_putreferralattr(struct nfsrv_descript *, nfsattrbit_t *, + struct nfsreferral *, int, int *); +int nfsrv_parsename(struct nfsrv_descript *, char *, u_long *, + NFSPATHLEN_T *); + +/* nfs_srvsyscalls.c */ +void nfsd_init(void); + +/* nfs_vfsops.c */ + +/* newnfs_port.c */ +int nfsrv_checksockseqnum(struct socket *, tcp_seq); +int nfsrv_getsockseqnum(struct socket *, tcp_seq *); +int nfsrv_getsocksndseq(struct socket *, tcp_seq *, tcp_seq *); +int nfsrv_lookupfilename(struct nameidata *, char *, NFSPROC_T *); +void nfsrv_object_create(vnode_t, NFSPROC_T *); +int nfsrv_mallocmget_limit(void); +int nfsvno_v4rootexport(struct nfsrv_descript *); +void newnfs_portinit(void); +struct ucred *newnfs_getcred(void); +void newnfs_setroot(struct ucred *); +int nfs_catnap(int, const char *); +struct nfsreferral *nfsv4root_getreferral(vnode_t, vnode_t, u_int32_t); +int nfsrv_atroot(vnode_t, long *); + +/* newnfs_acl.c */ +int nfsrv_dissectace(struct nfsrv_descript *, struct acl_entry *, + int *, int *, NFSPROC_T *); +#ifdef NFS4_ACL_EXTATTR_NAME +int nfsrv_buildacl(struct nfsrv_descript *, NFSACL_T *, enum vtype, + NFSPROC_T *); +int nfsrv_aclaccess(vnode_t, accmode_t, u_int32_t, struct ucred *, + NFSPROC_T *); +int nfsrv_setacl(vnode_t, NFSACL_T *, struct ucred *, + NFSPROC_T *); +int nfsrv_compareacl(NFSACL_T *, NFSACL_T *); +#endif + +/* nfscl_rpcops.c */ +int nfsrpc_null(vnode_t, struct ucred *, NFSPROC_T *); +int nfsrpc_access(vnode_t, int, struct ucred *, NFSPROC_T *, + struct nfsvattr *, int *); +int nfsrpc_accessrpc(vnode_t, u_int32_t, struct ucred *, + NFSPROC_T *, struct nfsvattr *, int *, u_int32_t *, void *); +int nfsrpc_open(vnode_t, int, struct ucred *, NFSPROC_T *); +int nfsrpc_openrpc(struct nfsmount *, vnode_t, u_int8_t *, int, u_int8_t *, int, + u_int32_t, struct nfsclopen *, u_int8_t *, int, struct nfscldeleg **, int, + u_int32_t, struct ucred *, NFSPROC_T *, int, int); +int nfsrpc_opendowngrade(vnode_t, u_int32_t, struct nfsclopen *, + struct ucred *, NFSPROC_T *); +int nfsrpc_close(vnode_t, struct ucred *, NFSPROC_T *); +int nfsrpc_closerpc(struct nfsrv_descript *, struct nfsmount *, + struct nfsclopen *, struct ucred *, NFSPROC_T *, int); +int nfsrpc_openconfirm(vnode_t, u_int8_t *, int, struct nfsclopen *, + struct ucred *, NFSPROC_T *); +int nfsrpc_setclient(struct nfsmount *, struct nfsclclient *, + struct ucred *, NFSPROC_T *); +int nfsrpc_getattr(vnode_t, struct ucred *, NFSPROC_T *, + struct nfsvattr *, void *); +int nfsrpc_getattrnovp(struct nfsmount *, u_int8_t *, int, int, + struct ucred *, NFSPROC_T *, struct nfsvattr *, u_int64_t *); +int nfsrpc_setattr(vnode_t, struct vattr *, NFSACL_T *, struct ucred *, + NFSPROC_T *, struct nfsvattr *, int *, void *); +int nfsrpc_lookup(vnode_t, char *, int, struct ucred *, NFSPROC_T *, + struct nfsvattr *, struct nfsvattr *, struct nfsfh **, int *, int *, + void *); +int nfsrpc_readlink(vnode_t, struct uio *, struct ucred *, + NFSPROC_T *, struct nfsvattr *, int *, void *); +int nfsrpc_read(vnode_t, struct uio *, struct ucred *, NFSPROC_T *, + struct nfsvattr *, int *, void *); +int nfsrpc_write(vnode_t, struct uio *, int *, u_char *, + struct ucred *, NFSPROC_T *, struct nfsvattr *, int *, void *); +int nfsrpc_mknod(vnode_t, char *, int, struct vattr *, u_int32_t, + enum vtype, struct ucred *, NFSPROC_T *, struct nfsvattr *, + struct nfsvattr *, struct nfsfh **, int *, int *, void *); +int nfsrpc_create(vnode_t, char *, int, struct vattr *, nfsquad_t, + int, struct ucred *, NFSPROC_T *, struct nfsvattr *, struct nfsvattr *, + struct nfsfh **, int *, int *, void *); +int nfsrpc_remove(vnode_t, char *, int, vnode_t, struct ucred *, NFSPROC_T *, + struct nfsvattr *, int *, void *); +int nfsrpc_rename(vnode_t, vnode_t, char *, int, vnode_t, vnode_t, char *, int, + struct ucred *, NFSPROC_T *, struct nfsvattr *, struct nfsvattr *, + int *, int *, void *, void *); +int nfsrpc_link(vnode_t, vnode_t, char *, int, + struct ucred *, NFSPROC_T *, struct nfsvattr *, struct nfsvattr *, + int *, int *, void *); +int nfsrpc_symlink(vnode_t, char *, int, char *, struct vattr *, + struct ucred *, NFSPROC_T *, struct nfsvattr *, struct nfsvattr *, + struct nfsfh **, int *, int *, void *); +int nfsrpc_mkdir(vnode_t, char *, int, struct vattr *, + struct ucred *, NFSPROC_T *, struct nfsvattr *, struct nfsvattr *, + struct nfsfh **, int *, int *, void *); +int nfsrpc_rmdir(vnode_t, char *, int, struct ucred *, NFSPROC_T *, + struct nfsvattr *, int *, void *); +int nfsrpc_readdir(vnode_t, struct uio *, nfsuint64 *, struct ucred *, + NFSPROC_T *, struct nfsvattr *, int *, int *, void *); +int nfsrpc_readdirplus(vnode_t, struct uio *, nfsuint64 *, + struct ucred *, NFSPROC_T *, struct nfsvattr *, int *, int *, void *); +int nfsrpc_commit(vnode_t, u_quad_t, int, struct ucred *, + NFSPROC_T *, u_char *, struct nfsvattr *, int *, void *); +int nfsrpc_advlock(vnode_t, off_t, int, struct flock *, int, + struct ucred *, NFSPROC_T *); +int nfsrpc_lockt(struct nfsrv_descript *, vnode_t, + struct nfsclclient *, u_int64_t, u_int64_t, struct flock *, + struct ucred *, NFSPROC_T *); +int nfsrpc_lock(struct nfsrv_descript *, struct nfsmount *, vnode_t, + u_int8_t *, int, struct nfscllockowner *, int, int, u_int64_t, + u_int64_t, short, struct ucred *, NFSPROC_T *, int); +int nfsrpc_statfs(vnode_t, struct nfsstatfs *, struct nfsfsinfo *, + struct ucred *, NFSPROC_T *, struct nfsvattr *, int *, void *); +int nfsrpc_fsinfo(vnode_t, struct nfsfsinfo *, struct ucred *, + NFSPROC_T *, struct nfsvattr *, int *, void *); +int nfsrpc_pathconf(vnode_t, struct nfsv3_pathconf *, + struct ucred *, NFSPROC_T *, struct nfsvattr *, int *, void *); +int nfsrpc_renew(struct nfsclclient *, struct ucred *, + NFSPROC_T *); +int nfsrpc_rellockown(struct nfsmount *, struct nfscllockowner *, + struct ucred *, NFSPROC_T *); +int nfsrpc_getdirpath(struct nfsmount *, u_char *, struct ucred *, + NFSPROC_T *); +int nfsrpc_delegreturn(struct nfscldeleg *, struct ucred *, + struct nfsmount *, NFSPROC_T *, int); +int nfsrpc_getacl(vnode_t, struct ucred *, NFSPROC_T *, NFSACL_T *, void *); +int nfsrpc_setacl(vnode_t, struct ucred *, NFSPROC_T *, NFSACL_T *, void *); + +/* nfscl_state.c */ +int nfscl_open(vnode_t, u_int8_t *, int, u_int32_t, int, + struct ucred *, NFSPROC_T *, struct nfsclowner **, struct nfsclopen **, + int *, int *, int); +int nfscl_getstateid(vnode_t, u_int8_t *, int, u_int32_t, struct ucred *, + NFSPROC_T *, nfsv4stateid_t *, void **); +void nfscl_ownerrelease(struct nfsclowner *, int, int, int); +void nfscl_openrelease(struct nfsclopen *, int, int); +int nfscl_getcl(vnode_t, struct ucred *, NFSPROC_T *, + struct nfsclclient **); +struct nfsclclient *nfscl_findcl(struct nfsmount *); +void nfscl_clientrelease(struct nfsclclient *); +void nfscl_freelock(struct nfscllock *, int); +int nfscl_getbytelock(vnode_t, u_int64_t, u_int64_t, short, + struct ucred *, NFSPROC_T *, struct nfsclclient *, int, u_int8_t *, + u_int8_t *, struct nfscllockowner **, int *, int *); +int nfscl_relbytelock(vnode_t, u_int64_t, u_int64_t, + struct ucred *, NFSPROC_T *, int, struct nfsclclient *, + struct nfscllockowner **, int *); +int nfscl_checkwritelocked(vnode_t, struct flock *, + struct ucred *, NFSPROC_T *); +void nfscl_lockrelease(struct nfscllockowner *, int, int); +void nfscl_fillclid(u_int64_t, char *, u_int8_t *, u_int16_t); +void nfscl_filllockowner(NFSPROC_T *, u_int8_t *); +void nfscl_freeopen(struct nfsclopen *, int); +void nfscl_umount(struct nfsmount *, NFSPROC_T *); +void nfscl_renewthread(struct nfsclclient *, NFSPROC_T *); +void nfscl_initiate_recovery(struct nfsclclient *); +int nfscl_hasexpired(struct nfsclclient *, u_int32_t, NFSPROC_T *); +void nfscl_dumpstate(struct nfsmount *, int, int, int, int); +void nfscl_dupopen(vnode_t, int); +int nfscl_getclose(vnode_t, struct ucred *, NFSPROC_T *, + struct nfsclclient **, struct nfsclopenhead *); +int nfscl_deleg(mount_t, struct nfsclclient *, u_int8_t *, int, + struct ucred *, NFSPROC_T *, struct nfscldeleg **); +void nfscl_lockinit(struct nfsv4lock *); +void nfscl_lockexcl(struct nfsv4lock *, void *); +void nfscl_lockunlock(struct nfsv4lock *); +void nfscl_lockderef(struct nfsv4lock *); +void nfscl_docb(struct nfsrv_descript *, NFSPROC_T *); +void nfscl_releasealllocks(struct nfsclclient *, vnode_t, NFSPROC_T *); +int nfscl_lockt(vnode_t, struct nfsclclient *, u_int64_t, + u_int64_t, struct flock *, NFSPROC_T *); +int nfscl_mustflush(vnode_t); +int nfscl_nodeleg(vnode_t, int); +int nfscl_removedeleg(vnode_t, NFSPROC_T *, nfsv4stateid_t *); +int nfscl_getref(struct nfsmount *); +void nfscl_relref(struct nfsmount *); +int nfscl_renamedeleg(vnode_t, nfsv4stateid_t *, int *, vnode_t, + nfsv4stateid_t *, int *, NFSPROC_T *); +void nfscl_reclaimnode(vnode_t); +void nfscl_newnode(vnode_t); +void nfscl_delegmodtime(vnode_t); +void nfscl_deleggetmodtime(vnode_t, struct timespec *); +int nfscl_tryclose(struct nfsclopen *, struct ucred *, + struct nfsmount *, NFSPROC_T *); +void nfscl_cleanup(NFSPROC_T *); + +/* nfscl_port.c */ +int nfscl_nget(mount_t, vnode_t, struct nfsfh *, + struct componentname *, NFSPROC_T *, struct nfsnode **, void *); +NFSPROC_T *nfscl_getparent(NFSPROC_T *); +void nfscl_start_renewthread(struct nfsclclient *); +void nfscl_loadsbinfo(struct nfsmount *, struct nfsstatfs *, void *); +void nfscl_loadfsinfo (struct nfsmount *, struct nfsfsinfo *); +void nfscl_delegreturn(struct nfscldeleg *, int, struct nfsmount *, + struct ucred *, NFSPROC_T *); +void nfsrvd_cbinit(int); +int nfscl_checksattr(struct vattr *, struct nfsvattr *); +int nfscl_ngetreopen(mount_t, u_int8_t *, int, NFSPROC_T *, + struct nfsnode **); +int nfscl_procdoesntexist(u_int8_t *); +int nfscl_maperr(NFSPROC_T *, int, uid_t, gid_t); + +/* nfsclient/ncl_subs.c */ +void nfscl_init(void); + +/* nfsclient/ncl_bio.c */ +int ncl_flush(vnode_t, int, struct ucred *, NFSPROC_T *, int); + +/* nfsclient/ncl_node.c */ +void ncl_invalcaches(vnode_t); + +/* nfsd/nfsd_port.c */ +int nfsvno_getattr(vnode_t, struct nfsvattr *, struct ucred *, + NFSPROC_T *); +int nfsvno_setattr(vnode_t, struct nfsvattr *, struct ucred *, + NFSPROC_T *, struct nfsexstuff *); +int nfsvno_getfh(vnode_t, fhandle_t *, NFSPROC_T *); +int nfsvno_accchk(vnode_t, u_int32_t, struct ucred *, + struct nfsexstuff *, NFSPROC_T *, int, int); +int nfsvno_namei(struct nfsrv_descript *, struct nameidata *, + vnode_t, int, struct nfsexstuff *, NFSPROC_T *, vnode_t *); +void nfsvno_setpathbuf(struct nameidata *, char **, u_long **); +void nfsvno_relpathbuf(struct nameidata *); +int nfsvno_readlink(vnode_t, struct ucred *, NFSPROC_T *, mbuf_t *, + mbuf_t *, int *); +int nfsvno_read(vnode_t, off_t, int, struct ucred *, NFSPROC_T *, + mbuf_t *, mbuf_t *); +int nfsvno_write(vnode_t, off_t, int, int, int, mbuf_t, + char *, struct ucred *, NFSPROC_T *); +int nfsvno_createsub(struct nfsrv_descript *, struct nameidata *, + vnode_t *, struct nfsvattr *, int *, u_char *, NFSDEV_T, NFSPROC_T *, + struct nfsexstuff *); +int nfsvno_mknod(struct nameidata *, struct nfsvattr *, struct ucred *, + NFSPROC_T *); +int nfsvno_mkdir(struct nameidata *, + struct nfsvattr *, uid_t, struct ucred *, NFSPROC_T *, + struct nfsexstuff *); +int nfsvno_symlink(struct nameidata *, struct nfsvattr *, char *, int, int, + uid_t, struct ucred *, NFSPROC_T *, struct nfsexstuff *); +int nfsvno_getsymlink(struct nfsrv_descript *, struct nfsvattr *, + NFSPROC_T *, char **, int *); +int nfsvno_removesub(struct nameidata *, int, struct ucred *, NFSPROC_T *, + struct nfsexstuff *); +int nfsvno_rmdirsub(struct nameidata *, int, struct ucred *, NFSPROC_T *, + struct nfsexstuff *); +int nfsvno_rename(struct nameidata *, struct nameidata *, u_int32_t, + u_int32_t, struct ucred *, NFSPROC_T *); +int nfsvno_link(struct nameidata *, vnode_t, struct ucred *, + NFSPROC_T *, struct nfsexstuff *); +int nfsvno_fsync(vnode_t, u_int64_t, int, struct ucred *, NFSPROC_T *); +int nfsvno_statfs(vnode_t, struct statfs *, struct ucred *, NFSPROC_T *); +void nfsvno_getfs(struct nfsfsinfo *, int); +void nfsvno_open(struct nfsrv_descript *, struct nameidata *, nfsquad_t, + nfsv4stateid_t *, struct nfsstate *, int *, struct nfsvattr *, u_char *, + int, NFSACL_T *, nfsattrbit_t *, struct ucred *, NFSPROC_T *, + struct nfsexstuff *, vnode_t *); +void nfsvno_updfilerev(vnode_t, struct nfsvattr *, struct ucred *, + NFSPROC_T *); +int nfsvno_fillattr(struct nfsrv_descript *, vnode_t, + struct nfsvattr *, fhandle_t *, int, nfsattrbit_t *, + struct ucred *, NFSPROC_T *, int, int); +int nfsrv_sattr(struct nfsrv_descript *, struct nfsvattr *, nfsattrbit_t *, + NFSACL_T *, NFSPROC_T *); +int nfsv4_sattr(struct nfsrv_descript *, struct nfsvattr *, nfsattrbit_t *, + NFSACL_T *, NFSPROC_T *); +int nfsvno_checkexp(mount_t, NFSSOCKADDR_T, struct nfsexstuff *, + struct ucred **); +int nfsvno_fhtovp(mount_t, fhandle_t *, NFSSOCKADDR_T, + vnode_t *, struct nfsexstuff *, struct ucred **); +int nfsvno_pathconf(vnode_t, int, register_t *, struct ucred *, + NFSPROC_T *); +vnode_t nfsvno_getvp(fhandle_t *); +int nfsvno_localconflict(vnode_t, int, u_int64_t, u_int64_t, + struct nfslockconflict *, NFSPROC_T *); +int nfsvno_advlock(vnode_t, int, u_int64_t, u_int64_t, NFSPROC_T *); +void nfsvno_unlockvfs(mount_t); +int nfsvno_lockvfs(mount_t); +int nfsrv_v4rootexport(void *, struct ucred *, NFSPROC_T *); + +/* newnfs_krpc.c */ +int newnfs_nmcancelreqs(struct nfsmount *); +void newnfs_set_sigmask(struct thread *, sigset_t *); +void newnfs_restore_sigmask(struct thread *, sigset_t *); +int newnfs_msleep(struct thread *, void *, struct mtx *, int, char *, int); + +/* nfsd_srvkrpc.c */ +int nfsrvd_addsock(struct file *); +int nfsrvd_nfsd(NFSPROC_T *, struct nfsd_nfsd_args *); +void nfsrvd_init(int); + +/* nfscl_srvkrpc.c */ +int nfscbd_addsock(struct file *); +int nfscbd_nfsd(NFSPROC_T *, struct nfsd_nfscbd_args *); + diff --git a/sys/fs/nfs/nfscl.h b/sys/fs/nfs/nfscl.h new file mode 100644 index 0000000..1c459ad --- /dev/null +++ b/sys/fs/nfs/nfscl.h @@ -0,0 +1,71 @@ +/*- + * Copyright (c) 2009 Rick Macklem, University of Guelph + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#ifndef _NFS_NFSCL_H +#define _NFS_NFSCL_H + +/* + * Extra stuff for a NFSv4 nfsnode. + * MALLOC'd to the correct length for the name and file handle. + * n4_data has the file handle, followed by the file name. + * The macro NFS4NODENAME() returns a pointer to the start of the + * name. + */ +struct nfsv4node { + u_int16_t n4_fhlen; + u_int16_t n4_namelen; + u_int8_t n4_data[1]; +}; + +#define NFS4NODENAME(n) (&((n)->n4_data[(n)->n4_fhlen])) + +/* + * Just a macro to convert the nfscl_reqstart arguments. + */ +#define NFSCL_REQSTART(n, p, v) \ + nfscl_reqstart((n), (p), VFSTONFS((v)->v_mount), \ + VTONFS(v)->n_fhp->nfh_fh, VTONFS(v)->n_fhp->nfh_len, NULL) + +/* + * These two macros convert between a lease duration and renew interval. + * For now, just make the renew interval 1/2 the lease duration. + * (They should be inverse operators.) + */ +#define NFSCL_RENEW(l) (((l) < 2) ? 1 : ((l) / 2)) +#define NFSCL_LEASE(r) ((r) * 2) + +/* + * These flag bits are used for the argument to nfscl_fillsattr() to + * indicate special handling of the attributes. + */ +#define NFSSATTR_FULL 0x1 +#define NFSSATTR_SIZE0 0x2 +#define NFSSATTR_SIZENEG1 0x4 +#define NFSSATTR_SIZERDEV 0x8 + +#endif /* _NFS_NFSCL_H */ diff --git a/sys/fs/nfs/nfsclstate.h b/sys/fs/nfs/nfsclstate.h new file mode 100644 index 0000000..10747af --- /dev/null +++ b/sys/fs/nfs/nfsclstate.h @@ -0,0 +1,175 @@ +/*- + * Copyright (c) 2009 Rick Macklem, University of Guelph + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#ifndef _NFS_NFSCLSTATE_H_ +#define _NFS_NFSCLSTATE_H_ + +/* + * Definitions for NFS V4 client state handling. + */ +LIST_HEAD(nfsclopenhead, nfsclopen); +LIST_HEAD(nfscllockownerhead, nfscllockowner); +LIST_HEAD(nfscllockhead, nfscllock); +LIST_HEAD(nfsclhead, nfsclclient); +LIST_HEAD(nfsclownerhead, nfsclowner); +TAILQ_HEAD(nfscldeleghead, nfscldeleg); +LIST_HEAD(nfscldeleghash, nfscldeleg); +#define NFSCLDELEGHASHSIZE 256 +#define NFSCLDELEGHASH(c, f, l) \ + (&((c)->nfsc_deleghash[ncl_hash((f), (l)) % NFSCLDELEGHASHSIZE])) + +struct nfsclclient { + LIST_ENTRY(nfsclclient) nfsc_list; + struct nfsclownerhead nfsc_owner; + struct nfscldeleghead nfsc_deleg; + struct nfscldeleghash nfsc_deleghash[NFSCLDELEGHASHSIZE]; + struct nfscllockownerhead nfsc_defunctlockowner; + struct nfsv4lock nfsc_lock; + struct proc *nfsc_renewthread; + struct nfsmount *nfsc_nmp; + nfsquad_t nfsc_clientid; + time_t nfsc_expire; + u_int32_t nfsc_clientidrev; + u_int32_t nfsc_renew; + u_int32_t nfsc_cbident; + u_int16_t nfsc_flags; + u_int16_t nfsc_idlen; + u_int8_t nfsc_id[1]; /* Malloc'd to correct length */ +}; + +/* + * Bits for nfsc_flags. + */ +#define NFSCLFLAGS_INITED 0x0001 +#define NFSCLFLAGS_HASCLIENTID 0x0002 +#define NFSCLFLAGS_RECOVER 0x0004 +#define NFSCLFLAGS_UMOUNT 0x0008 +#define NFSCLFLAGS_HASTHREAD 0x0010 +#define NFSCLFLAGS_AFINET6 0x0020 +#define NFSCLFLAGS_EXPIREIT 0x0040 +#define NFSCLFLAGS_FIRSTDELEG 0x0080 +#define NFSCLFLAGS_GOTDELEG 0x0100 + +struct nfsclowner { + LIST_ENTRY(nfsclowner) nfsow_list; + struct nfsclopenhead nfsow_open; + struct nfsclclient *nfsow_clp; + u_int32_t nfsow_seqid; + u_int32_t nfsow_defunct; + struct nfsv4lock nfsow_rwlock; + u_int8_t nfsow_owner[NFSV4CL_LOCKNAMELEN]; +}; + +/* + * MALLOC'd to the correct length to accommodate the file handle. + */ +struct nfscldeleg { + TAILQ_ENTRY(nfscldeleg) nfsdl_list; + LIST_ENTRY(nfscldeleg) nfsdl_hash; + struct nfsclownerhead nfsdl_owner; /* locally issued state */ + struct nfscllockownerhead nfsdl_lock; + nfsv4stateid_t nfsdl_stateid; + struct acl_entry nfsdl_ace; /* Delegation ace */ + struct nfsclclient *nfsdl_clp; + struct nfsv4lock nfsdl_rwlock; /* for active I/O ops */ + struct nfscred nfsdl_cred; /* Cred. used for Open */ + time_t nfsdl_timestamp; /* used for stale cleanup */ + u_int64_t nfsdl_sizelimit; /* Limit for file growth */ + u_int64_t nfsdl_size; /* saved copy of file size */ + u_int64_t nfsdl_change; /* and change attribute */ + struct timespec nfsdl_modtime; /* local modify time */ + u_int16_t nfsdl_fhlen; + u_int8_t nfsdl_flags; + u_int8_t nfsdl_fh[1]; /* must be last */ +}; + +/* + * nfsdl_flags bits. + */ +#define NFSCLDL_READ 0x01 +#define NFSCLDL_WRITE 0x02 +#define NFSCLDL_RECALL 0x04 +#define NFSCLDL_NEEDRECLAIM 0x08 +#define NFSCLDL_ZAPPED 0x10 +#define NFSCLDL_MODTIMESET 0x20 + +/* + * MALLOC'd to the correct length to accommodate the file handle. + */ +struct nfsclopen { + LIST_ENTRY(nfsclopen) nfso_list; + struct nfscllockownerhead nfso_lock; + nfsv4stateid_t nfso_stateid; + struct nfsclowner *nfso_own; + struct nfscred nfso_cred; /* Cred. used for Open */ + u_int32_t nfso_mode; + u_int32_t nfso_opencnt; + u_int16_t nfso_fhlen; + u_int8_t nfso_posixlock; /* 1 for POSIX type locking */ + u_int8_t nfso_fh[1]; /* must be last */ +}; + +/* + * Return values for nfscl_open(). NFSCLOPEN_OK must == 0. + */ +#define NFSCLOPEN_OK 0 +#define NFSCLOPEN_DOOPEN 1 +#define NFSCLOPEN_DOOPENDOWNGRADE 2 + +struct nfscllockowner { + LIST_ENTRY(nfscllockowner) nfsl_list; + struct nfscllockhead nfsl_lock; + struct nfsclopen *nfsl_open; + NFSPROC_T *nfsl_inprog; + nfsv4stateid_t nfsl_stateid; + u_int32_t nfsl_seqid; + u_int32_t nfsl_defunct; + struct nfsv4lock nfsl_rwlock; + u_int8_t nfsl_owner[NFSV4CL_LOCKNAMELEN]; + u_int8_t nfsl_openowner[NFSV4CL_LOCKNAMELEN]; +}; + +/* + * Byte range entry for the above lock owner. + */ +struct nfscllock { + LIST_ENTRY(nfscllock) nfslo_list; + u_int64_t nfslo_first; + u_int64_t nfslo_end; + short nfslo_type; +}; + +/* + * Macro for incrementing the seqid#. + */ +#define NFSCL_INCRSEQID(s, n) do { \ + if (((n)->nd_flag & ND_INCRSEQID)) \ + (s)++; \ + } while (0) + +#endif /* _NFS_NFSCLSTATE_H_ */ diff --git a/sys/fs/nfs/nfsdport.h b/sys/fs/nfs/nfsdport.h new file mode 100644 index 0000000..f8ee445 --- /dev/null +++ b/sys/fs/nfs/nfsdport.h @@ -0,0 +1,105 @@ +/*- + * Copyright (c) 2009 Rick Macklem, University of Guelph + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +/* + * These macros handle nfsvattr fields. They look a bit silly here, but + * are quite different for the Darwin port. + */ +#define NFSVNO_ATTRINIT(n) (VATTR_NULL(&((n)->na_vattr))) +#define NFSVNO_SETATTRVAL(n, f, v) ((n)->na_##f = (v)) +#define NFSVNO_SETACTIVE(n, f) +#define NFSVNO_UNSET(n, f) ((n)->na_##f = VNOVAL) +#define NFSVNO_NOTSETMODE(n) ((n)->na_mode == ((mode_t)VNOVAL)) +#define NFSVNO_ISSETMODE(n) ((n)->na_mode != ((mode_t)VNOVAL)) +#define NFSVNO_NOTSETUID(n) ((n)->na_uid == ((uid_t)VNOVAL)) +#define NFSVNO_ISSETUID(n) ((n)->na_uid != ((uid_t)VNOVAL)) +#define NFSVNO_NOTSETGID(n) ((n)->na_gid == ((gid_t)VNOVAL)) +#define NFSVNO_ISSETGID(n) ((n)->na_gid != ((gid_t)VNOVAL)) +#define NFSVNO_NOTSETSIZE(n) ((n)->na_size == VNOVAL) +#define NFSVNO_ISSETSIZE(n) ((n)->na_size != VNOVAL) +#define NFSVNO_NOTSETATIME(n) ((n)->na_atime.tv_sec == VNOVAL) +#define NFSVNO_ISSETATIME(n) ((n)->na_atime.tv_sec != VNOVAL) +#define NFSVNO_NOTSETMTIME(n) ((n)->na_mtime.tv_sec == VNOVAL) +#define NFSVNO_ISSETMTIME(n) ((n)->na_mtime.tv_sec != VNOVAL) + +/* + * This structure acts as a "catch-all" for information that + * needs to be returned by nfsd_fhtovp(). + */ +struct nfsexstuff { + int nes_vfslocked; /* required for all ports */ + int nes_exflag; +}; + +#define NFSVNO_EXINIT(e) ((e)->nes_exflag = 0) +#define NFSVNO_EXPORTED(e) ((e)->nes_exflag & MNT_EXPORTED) +#define NFSVNO_EXRDONLY(e) ((e)->nes_exflag & MNT_EXRDONLY) +#define NFSVNO_EXPORTANON(e) ((e)->nes_exflag & MNT_EXPORTANON) +#define NFSVNO_EXSTRICTACCESS(e) ((e)->nes_exflag & MNT_EXSTRICTACCESS) +#define NFSVNO_EXGSSONLY(e) ((e)->nes_exflag & MNT_EXGSSONLY) +#define NFSVNO_EXV4ONLY(e) ((e)->nes_exflag & MNT_EXV4ONLY) + +#define NFSVNO_SETEXRDONLY(e) ((e)->nes_exflag = (MNT_EXPORTED|MNT_EXRDONLY)) +#define NFSVNO_SETEXGSSONLY(e) ((e)->nes_exflag |= MNT_EXGSSONLY) + +#define NFSVNO_CMPFH(f1, f2) \ + ((f1)->fh_fsid.val[0] == (f2)->fh_fsid.val[0] && \ + (f1)->fh_fsid.val[1] == (f2)->fh_fsid.val[1] && \ + !bcmp((f1)->fh_fid.fid_data, (f2)->fh_fid.fid_data, \ + (f1)->fh_fid.fid_len)) + +#define NFSLOCKHASH(f) \ + (&nfslockhash[(*((u_int32_t *)((f)->fh_fid.fid_data))) % NFSLOCKHASHSIZE]) + +#define NFSFPVNODE(f) ((struct vnode *)((f)->f_data)) +#define NFSFPCRED(f) ((f)->f_cred) +#define NFSFPFLAG(f) ((f)->f_flag) + +int fp_getfvp(NFSPROC_T *, int, struct file **, struct vnode **); + +#define NFSNAMEICNDSET(n, c, o, f) do { \ + (n)->cn_cred = (c); \ + (n)->cn_nameiop = (o); \ + (n)->cn_flags = (f); \ + } while (0) + +/* + * A little bit of Darwin vfs kpi. + */ +#define vnode_mount(v) ((v)->v_mount) +#define vfs_statfs(m) (&((m)->mnt_stat)) + +#define NFSPATHLEN_T size_t + +/* + * These are set to the minimum and maximum size of a server file + * handle. + */ +#define NFSRV_MINFH (sizeof (fhandle_t)) +#define NFSRV_MAXFH (sizeof (fhandle_t)) + diff --git a/sys/fs/nfs/nfskpiport.h b/sys/fs/nfs/nfskpiport.h new file mode 100644 index 0000000..1e1fb9c --- /dev/null +++ b/sys/fs/nfs/nfskpiport.h @@ -0,0 +1,73 @@ +/*- + * Copyright (c) 2009 Rick Macklem, University of Guelph + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#ifndef _NFS_NFSKPIPORT_H_ +#define _NFSKPIPORT_NFS_H_ +/* + * These definitions are needed since the generic code is now using Darwin8 + * KPI stuff. (I know, seems a bit silly, but I want the code to build on + * Darwin8 and hopefully subsequent releases from Apple.) + */ +typedef struct mount * mount_t; +#define vfs_statfs(m) (&((m)->mnt_stat)) +#define vfs_flags(m) ((m)->mnt_flag) + +typedef struct vnode * vnode_t; +#define vnode_mount(v) ((v)->v_mount) +#define vnode_vtype(v) ((v)->v_type) + +typedef struct mbuf * mbuf_t; +#define mbuf_freem(m) m_freem(m) +#define mbuf_data(m) mtod((m), void *) +#define mbuf_len(m) ((m)->m_len) +#define mbuf_next(m) ((m)->m_next) +#define mbuf_setlen(m, l) ((m)->m_len = (l)) +#define mbuf_setnext(m, p) ((m)->m_next = (p)) +#define mbuf_pkthdr_len(m) ((m)->m_pkthdr.len) +#define mbuf_pkthdr_setlen(m, l) ((m)->m_pkthdr.len = (l)) +#define mbuf_pkthdr_setrcvif(m, p) ((m)->m_pkthdr.rcvif = (p)) + +/* + * This stuff is needed by Darwin for handling the uio structure. + */ +#define CAST_USER_ADDR_T(a) (a) +#define CAST_DOWN(c, a) ((c) (a)) +#define uio_uio_resid(p) ((p)->uio_resid) +#define uio_uio_resid_add(p, v) ((p)->uio_resid += (v)) +#define uio_uio_resid_set(p, v) ((p)->uio_resid = (v)) +#define uio_iov_base(p) ((p)->uio_iov->iov_base) +#define uio_iov_base_add(p, v) do { \ + char *pp; \ + pp = (char *)(p)->uio_iov->iov_base; \ + pp += (v); \ + (p)->uio_iov->iov_base = (void *)pp; \ + } while (0) +#define uio_iov_len(p) ((p)->uio_iov->iov_len) +#define uio_iov_len_add(p, v) ((p)->uio_iov->iov_len += (v)) + +#endif /* _NFSKPIPORT_NFS_H */ diff --git a/sys/fs/nfs/nfsm_subs.h b/sys/fs/nfs/nfsm_subs.h new file mode 100644 index 0000000..a2777a0 --- /dev/null +++ b/sys/fs/nfs/nfsm_subs.h @@ -0,0 +1,129 @@ +/*- + * 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. + * + * $FreeBSD$ + */ + +#ifndef _NFS_NFSM_SUBS_H_ +#define _NFS_NFSM_SUBS_H_ + + +/* + * These macros do strange and peculiar things to mbuf chains for + * the assistance of the nfs code. To attempt to use them for any + * other purpose will be dangerous. (they make weird assumptions) + */ + +#ifndef APPLE +/* + * First define what the actual subs. return + */ +#define M_HASCL(m) ((m)->m_flags & M_EXT) +#define NFSMINOFF(m) \ + if (M_HASCL(m)) \ + (m)->m_data = (m)->m_ext.ext_buf; \ + else if ((m)->m_flags & M_PKTHDR) \ + (m)->m_data = (m)->m_pktdat; \ + else \ + (m)->m_data = (m)->m_dat +#define NFSMSIZ(m) ((M_HASCL(m))?MCLBYTES: \ + (((m)->m_flags & M_PKTHDR)?MHLEN:MLEN)) +#define NFSM_DATAP(m, s) (m)->m_data += (s) + +/* + * Now for the macros that do the simple stuff and call the functions + * for the hard stuff. + * They use fields in struct nfsrv_descript to handle the mbuf queues. + * Replace most of the macro with an inline function, to minimize + * the machine code. The inline functions in lower case can be called + * directly, bypassing the macro. + */ +static __inline void * +nfsm_build(struct nfsrv_descript *nd, int siz) +{ + void *retp; + struct mbuf *mb2; + + if (siz > M_TRAILINGSPACE(nd->nd_mb)) { + NFSMCLGET(mb2, M_DONTWAIT); + if (siz > MLEN) + panic("build > MLEN"); + mbuf_setlen(mb2, 0); + nd->nd_bpos = NFSMTOD(mb2, caddr_t); + nd->nd_mb->m_next = mb2; + nd->nd_mb = mb2; + } + retp = (void *)(nd->nd_bpos); + nd->nd_mb->m_len += siz; + nd->nd_bpos += siz; + return (retp); +} + +#define NFSM_BUILD(a, c, s) ((a) = (c)nfsm_build(nd, (s))) + +static __inline void * +nfsm_dissect(struct nfsrv_descript *nd, int siz) +{ + int tt1; + void *retp; + + tt1 = NFSMTOD(nd->nd_md, caddr_t) + nd->nd_md->m_len - nd->nd_dpos; + if (tt1 >= siz) { + retp = (void *)nd->nd_dpos; + nd->nd_dpos += siz; + } else { + retp = nfsm_dissct(nd, siz); + } + return (retp); +} + +#define NFSM_DISSECT(a, c, s) \ + do { \ + (a) = (c)nfsm_dissect(nd, (s)); \ + if ((a) == NULL) { \ + error = EBADRPC; \ + goto nfsmout; \ + } \ + } while (0) +#endif /* !APPLE */ + +#define NFSM_STRSIZ(s, m) \ + do { \ + tl = (u_int32_t *)nfsm_dissect(nd, NFSX_UNSIGNED); \ + if (!tl || ((s) = fxdr_unsigned(int32_t, *tl)) > (m)) { \ + error = EBADRPC; \ + goto nfsmout; \ + } \ + } while (0) + +#define NFSM_RNDUP(a) (((a)+3)&(~0x3)) + +#endif /* _NFS_NFSM_SUBS_H_ */ diff --git a/sys/fs/nfs/nfsport.h b/sys/fs/nfs/nfsport.h new file mode 100644 index 0000000..e4b3d0a --- /dev/null +++ b/sys/fs/nfs/nfsport.h @@ -0,0 +1,751 @@ +/*- + * 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. + * + * $FreeBSD$ + */ + +#ifndef _NFS_NFSPORT_H_ +#define _NFSPORT_NFS_H_ + +/* + * In general, I'm not fond of #includes in .h files, but this seems + * to be the cleanest way to handle #include files for the ports. + */ +#ifdef _KERNEL +#include <sys/unistd.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/conf.h> +#include <sys/dirent.h> +#include <sys/domain.h> +#include <sys/fcntl.h> +#include <sys/file.h> +#include <sys/filedesc.h> +#include <sys/kernel.h> +#include <sys/lockf.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/mount.h> +#include <sys/namei.h> +#include <sys/proc.h> +#include <sys/protosw.h> +#include <sys/reboot.h> +#include <sys/resourcevar.h> +#include <sys/signalvar.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/stat.h> +#include <sys/syslog.h> +#include <sys/sysproto.h> +#include <sys/time.h> +#include <sys/uio.h> +#include <sys/vnode.h> +#include <sys/bio.h> +#include <sys/buf.h> +#include <sys/acl.h> +#include <sys/module.h> +#include <sys/sysent.h> +#include <sys/syscall.h> +#include <sys/priv.h> +#include <sys/kthread.h> +#include <sys/syscallsubr.h> +#include <fs/fifofs/fifo.h> +#include <net/if.h> +#include <net/radix.h> +#include <net/route.h> +#include <net/if_dl.h> +#include <netinet/in.h> +#include <netinet/in_pcb.h> +#include <netinet/in_systm.h> +#include <netinet/in_var.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> +#include <netinet/tcp.h> +#include <netinet/tcp_fsm.h> +#include <netinet/tcp_seq.h> +#include <netinet/tcp_timer.h> +#include <netinet/tcp_var.h> +#include <netinet/vinet.h> +#include <machine/in_cksum.h> +#include <crypto/des/des.h> +#include <sys/md5.h> +#include <rpc/rpc.h> +#include <rpc/rpcclnt.h> +#include <rpc/rpcsec_gss.h> + +/* + * For Darwin, these functions should be "static" when built in a kext. + * (This is always defined as nil otherwise.) + */ +#define APPLESTATIC +#include <ufs/ufs/dir.h> +#include <ufs/ufs/quota.h> +#include <ufs/ufs/inode.h> +#include <ufs/ufs/extattr.h> +#include <ufs/ufs/ufsmount.h> +#include <vm/uma.h> +#include <vm/vm.h> +#include <vm/vm_object.h> +#include <vm/vm_extern.h> +#include <nfs/nfssvc.h> +#include "opt_nfs.h" +#include "opt_ufs.h" + +/* + * These types must be defined before the nfs includes. + */ +#define NFSSOCKADDR_T struct sockaddr * +#define NFSPROC_T struct thread +#define NFSDEV_T dev_t +#define NFSSVCARGS nfssvc_args +#ifdef NFS4_ACL_EXTATTR_NAME +#define NFSACL_T struct acl +#else +#define NFSACL_T void +#endif + +/* + * These should be defined as the types used for the corresponding VOP's + * argument type. + */ +#define NFS_ACCESS_ARGS struct vop_access_args +#define NFS_OPEN_ARGS struct vop_open_args +#define NFS_GETATTR_ARGS struct vop_getattr_args +#define NFS_LOOKUP_ARGS struct vop_lookup_args +#define NFS_READDIR_ARGS struct vop_readdir_args + +/* + * Allocate mbufs. Must succeed and never set the mbuf ptr to NULL. + */ +#define NFSMGET(m) do { \ + MGET((m), M_TRYWAIT, MT_DATA); \ + while ((m) == NULL ) { \ + (void) nfs_catnap(PZERO, "nfsmget"); \ + MGET((m), M_TRYWAIT, MT_DATA); \ + } \ + } while (0) +#define NFSMGETHDR(m) do { \ + MGETHDR((m), M_TRYWAIT, MT_DATA); \ + while ((m) == NULL ) { \ + (void) nfs_catnap(PZERO, "nfsmget"); \ + MGETHDR((m), M_TRYWAIT, MT_DATA); \ + } \ + } while (0) +#define NFSMCLGET(m, w) do { \ + MGET((m), M_TRYWAIT, MT_DATA); \ + while ((m) == NULL ) { \ + (void) nfs_catnap(PZERO, "nfsmget"); \ + MGET((m), M_TRYWAIT, MT_DATA); \ + } \ + MCLGET((m), (w)); \ + } while (0) +#define NFSMCLGETHDR(m, w) do { \ + MGETHDR((m), M_TRYWAIT, MT_DATA); \ + while ((m) == NULL ) { \ + (void) nfs_catnap(PZERO, "nfsmget"); \ + MGETHDR((m), M_TRYWAIT, MT_DATA); \ + } \ + } while (0) +#define NFSMTOD mtod + +/* + * Client side constant for size of a lockowner name. + */ +#define NFSV4CL_LOCKNAMELEN 12 + +/* + * Type for a mutex lock. + */ +#define NFSMUTEX_T struct mtx + +#include <fs/nfs/nfskpiport.h> +#include <fs/nfs/nfsdport.h> +#include <fs/nfs/rpcv2.h> +#include <fs/nfs/nfsproto.h> +#include <fs/nfs/nfs.h> +#include <fs/nfs/nfs_var.h> +#include <fs/nfs/nfsm_subs.h> +#include <fs/nfs/nfsrvcache.h> +#include <fs/nfs/nfsrvstate.h> +#include <fs/nfs/xdr_subs.h> +#include <fs/nfs/nfscl.h> +#include <fs/nfs/nfsclstate.h> +#include <fs/nfsclient/nfsargs.h> +#include <fs/nfsclient/nfsmount.h> + +/* + * Just to keep nfs_var.h happy. + */ +struct nfs_vattr { + int junk; +}; + +struct nfsvattr { + struct vattr na_vattr; + nfsattrbit_t na_suppattr; + u_int32_t na_mntonfileno; + u_int64_t na_filesid[2]; +}; + +#define na_type na_vattr.va_type +#define na_mode na_vattr.va_mode +#define na_nlink na_vattr.va_nlink +#define na_uid na_vattr.va_uid +#define na_gid na_vattr.va_gid +#define na_fsid na_vattr.va_fsid +#define na_fileid na_vattr.va_fileid +#define na_size na_vattr.va_size +#define na_blocksize na_vattr.va_blocksize +#define na_atime na_vattr.va_atime +#define na_mtime na_vattr.va_mtime +#define na_ctime na_vattr.va_ctime +#define na_gen na_vattr.va_gen +#define na_flags na_vattr.va_flags +#define na_rdev na_vattr.va_rdev +#define na_bytes na_vattr.va_bytes +#define na_filerev na_vattr.va_filerev +#define na_vaflags na_vattr.va_vaflags + +#include <fs/nfsclient/nfsnode.h> + +/* + * This is the header structure used for the lists, etc. (It has the + * above record in it. + */ +struct nfsrv_stablefirst { + LIST_HEAD(, nfsrv_stable) nsf_head; /* Head of nfsrv_stable list */ + time_t nsf_eograce; /* Time grace period ends */ + time_t *nsf_bootvals; /* Previous boottime values */ + struct file *nsf_fp; /* File table pointer */ + u_char nsf_flags; /* NFSNSF_ flags */ + struct nfsf_rec nsf_rec; /* and above first record */ +}; +#define nsf_lease nsf_rec.lease +#define nsf_numboots nsf_rec.numboots + +/* NFSNSF_xxx flags */ +#define NFSNSF_UPDATEDONE 0x01 +#define NFSNSF_GRACEOVER 0x02 +#define NFSNSF_NEEDLOCK 0x04 +#define NFSNSF_EXPIREDCLIENT 0x08 +#define NFSNSF_NOOPENS 0x10 +#define NFSNSF_OK 0x20 + +/* + * Maximum number of boot times allowed in record. Although there is + * really no need for a fixed upper bound, this serves as a sanity check + * for a corrupted file. + */ +#define NFSNSF_MAXNUMBOOTS 10000 + +/* + * This structure defines the other records in the file. The + * nst_client array is actually the size of the client string name. + */ +struct nfst_rec { + u_int16_t len; + u_char flag; + u_char client[1]; +}; +/* and the values for flag */ +#define NFSNST_NEWSTATE 0x1 +#define NFSNST_REVOKE 0x2 +#define NFSNST_GOTSTATE 0x4 + +/* + * This structure is linked onto nfsrv_stablefirst for the duration of + * reclaim. + */ +struct nfsrv_stable { + LIST_ENTRY(nfsrv_stable) nst_list; + struct nfsclient *nst_clp; + struct nfst_rec nst_rec; +}; +#define nst_timestamp nst_rec.timestamp +#define nst_len nst_rec.len +#define nst_flag nst_rec.flag +#define nst_client nst_rec.client + +/* + * At some point the server will run out of kernel storage for + * state structures. For FreeBSD5.2, this results in a panic + * kmem_map is full. It happens at well over 1000000 opens plus + * locks on a PIII-800 with 256Mbytes, so that is where I've set + * the limit. If your server panics due to too many opens/locks, + * decrease the size of NFSRV_V4STATELIMIT. If you find the server + * returning NFS4ERR_RESOURCE a lot and have lots of memory, try + * increasing it. + */ +#define NFSRV_V4STATELIMIT 500000 /* Max # of Opens + Locks */ + +/* + * The type required differs with BSDen (just the second arg). + */ +void nfsrvd_rcv(struct socket *, void *, int); + +/* + * Macros for handling socket addresses. (Hopefully this makes the code + * more portable, since I've noticed some 'BSD don't have sockaddrs in + * mbufs any more.) + */ +#define NFSSOCKADDR(a, t) ((t)(a)) +#define NFSSOCKADDRALLOC(a) \ + do { \ + MALLOC((a), struct sockaddr *, sizeof (struct sockaddr), \ + M_SONAME, M_WAITOK); \ + NFSBZERO((a), sizeof (struct sockaddr)); \ + } while (0) +#define NFSSOCKADDRSIZE(a, s) ((a)->sa_len = (s)) +#define NFSSOCKADDRFREE(a) \ + do { \ + if (a) \ + FREE((caddr_t)(a), M_SONAME); \ + } while (0) + +/* + * These should be defined as a process or thread structure, as required + * for signal handling, etc. + */ +#define NFSNEWCRED(c) (crdup(c)) +#define NFSPROCCRED(p) ((p)->td_ucred) +#define NFSFREECRED(c) (crfree(c)) +#define NFSUIOPROC(u, p) ((u)->uio_td = NULL) +#define NFSPROCP(p) ((p)->td_proc) + +/* + * Define these so that cn_hash and its length is ignored. + */ +#define NFSCNHASHZERO(c) +#define NFSCNHASH(c, v) +#define NCHNAMLEN 9999999 + +/* + * Define these to use the time of day clock. + */ +#define NFSGETTIME(t) (getmicrotime(t)) +#define NFSGETNANOTIME(t) (getnanotime(t)) + +/* + * These macros are defined to initialize and set the timer routine. + */ +#define NFS_TIMERINIT \ + newnfs_timer(NULL) + +/* + * Handle SMP stuff: + */ +#define NFSSTATESPINLOCK extern struct mtx nfs_state_mutex +#define NFSLOCKSTATE() mtx_lock(&nfs_state_mutex) +#define NFSUNLOCKSTATE() mtx_unlock(&nfs_state_mutex) +#define NFSREQSPINLOCK extern struct mtx nfs_req_mutex +#define NFSLOCKREQ() mtx_lock(&nfs_req_mutex) +#define NFSUNLOCKREQ() mtx_unlock(&nfs_req_mutex) +#define NFSCACHEMUTEX extern struct mtx nfs_cache_mutex +#define NFSCACHEMUTEXPTR (&nfs_cache_mutex) +#define NFSLOCKCACHE() mtx_lock(&nfs_cache_mutex) +#define NFSUNLOCKCACHE() mtx_unlock(&nfs_cache_mutex) +#define NFSCACHELOCKREQUIRED() mtx_assert(&nfs_cache_mutex, MA_OWNED) +#define NFSSOCKMUTEX extern struct mtx nfs_slock_mutex +#define NFSSOCKMUTEXPTR (&nfs_slock_mutex) +#define NFSLOCKSOCK() mtx_lock(&nfs_slock_mutex) +#define NFSUNLOCKSOCK() mtx_unlock(&nfs_slock_mutex) +#define NFSNAMEIDMUTEX extern struct mtx nfs_nameid_mutex +#define NFSLOCKNAMEID() mtx_lock(&nfs_nameid_mutex) +#define NFSUNLOCKNAMEID() mtx_unlock(&nfs_nameid_mutex) +#define NFSNAMEIDREQUIRED() mtx_assert(&nfs_nameid_mutex, MA_OWNED) +#define NFSCLSTATEMUTEX extern struct mtx nfs_clstate_mutex +#define NFSCLSTATEMUTEXPTR (&nfs_clstate_mutex) +#define NFSLOCKCLSTATE() mtx_lock(&nfs_clstate_mutex) +#define NFSUNLOCKCLSTATE() mtx_unlock(&nfs_clstate_mutex) +#define NFSDLOCKMUTEX extern struct mtx newnfsd_mtx +#define NFSDLOCKMUTEXPTR (&newnfsd_mtx) +#define NFSD_LOCK() mtx_lock(&newnfsd_mtx) +#define NFSD_UNLOCK() mtx_unlock(&newnfsd_mtx) +#define NFSD_LOCK_ASSERT() mtx_assert(&newnfsd_mtx, MA_OWNED) +#define NFSD_UNLOCK_ASSERT() mtx_assert(&newnfsd_mtx, MA_NOTOWNED) +#define NFSV4ROOTLOCKMUTEX extern struct mtx nfs_v4root_mutex +#define NFSV4ROOTLOCKMUTEXPTR (&nfs_v4root_mutex) +#define NFSLOCKV4ROOTMUTEX() mtx_lock(&nfs_v4root_mutex) +#define NFSUNLOCKV4ROOTMUTEX() mtx_unlock(&nfs_v4root_mutex) +#define NFSLOCKNODE(n) mtx_lock(&((n)->n_mtx)) +#define NFSUNLOCKNODE(n) mtx_unlock(&((n)->n_mtx)) +#define NFSLOCKMNT(m) mtx_lock(&((m)->nm_mtx)) +#define NFSUNLOCKMNT(m) mtx_unlock(&((m)->nm_mtx)) +#define NFSLOCKREQUEST(r) mtx_lock(&((r)->r_mtx)) +#define NFSUNLOCKREQUEST(r) mtx_unlock(&((r)->r_mtx)) +#define NFSPROCLISTLOCK() sx_slock(&allproc_lock) +#define NFSPROCLISTUNLOCK() sx_sunlock(&allproc_lock) +#define NFSLOCKSOCKREQ(r) mtx_lock(&((r)->nr_mtx)) +#define NFSUNLOCKSOCKREQ(r) mtx_unlock(&((r)->nr_mtx)) + +/* + * Use these macros to initialize/free a mutex. + */ +#define NFSINITSOCKMUTEX(m) mtx_init((m), "nfssock", NULL, MTX_DEF) +#define NFSFREEMUTEX(m) mtx_destroy((m)) + +int nfsmsleep(void *, void *, int, const char *, struct timespec *); + +/* + * And weird vm stuff in the nfs server. + */ +#define PDIRUNLOCK 0x0 +#define MAX_COMMIT_COUNT (1024 * 1024) + +/* + * These macros are called at the start and end of operations that + * might modify the underlying file system. + */ +#define NFS_STARTWRITE(v, m) vn_start_write((v), (m), V_WAIT) +#define NFS_ENDWRITE(m) vn_finished_write(m) + +/* + * Define these to handle the type of va_rdev. + */ +#define NFSMAKEDEV(m, n) makedev((m), (n)) +#define NFSMAJOR(d) major(d) +#define NFSMINOR(d) minor(d) + +/* + * Define this to be the macro that returns the minimum size required + * for a directory entry. + */ +#define DIRENT_SIZE(dp) GENERIC_DIRSIZ(dp) + +/* + * The vnode tag for nfsv4root. + */ +#define VT_NFSV4ROOT "nfsv4root" + +/* + * XXX - not in any system .h file, just vfs_export.c + * Network address lookup element + */ +struct netcred { + struct radix_node netc_rnodes[2]; + int netc_exflags; + struct ucred netc_anon; +}; + +/* + * Define whatever it takes to do a vn_rdwr(). + */ +#define NFSD_RDWR(r, v, b, l, o, s, i, c, a, p) \ + vn_rdwr((r), (v), (b), (l), (o), (s), (i), (c), NULL, (int *)(a), (p)) + +/* + * Macros for handling memory for different BSDen. + * NFSBCOPY(src, dst, len) - copies len bytes, non-overlapping + * NFSOVBCOPY(src, dst, len) - ditto, but data areas might overlap + * NFSBCMP(cp1, cp2, len) - compare len bytes, return 0 if same + * NFSBZERO(cp, len) - set len bytes to 0x0 + */ +#define NFSBCOPY(s, d, l) bcopy((s), (d), (l)) +#define NFSOVBCOPY(s, d, l) ovbcopy((s), (d), (l)) +#define NFSBCMP(s, d, l) bcmp((s), (d), (l)) +#define NFSBZERO(s, l) bzero((s), (l)) + +/* + * Some queue.h files don't have these dfined in them. + */ +#define LIST_END(head) NULL +#define SLIST_END(head) NULL +#define TAILQ_END(head) NULL + +/* + * This must be defined to be a global variable the increments once + * per second, but never stops or goes backwards, even when a "date" + * command changes the tod clock. It is used for delta times for + * leases, etc. + */ +#define NFSD_MONOSEC time_uptime + +/* + * Declare the malloc types. + */ +MALLOC_DECLARE(M_NEWNFSRVCACHE); +MALLOC_DECLARE(M_NEWNFSDCLIENT); +MALLOC_DECLARE(M_NEWNFSDSTATE); +MALLOC_DECLARE(M_NEWNFSDLOCK); +MALLOC_DECLARE(M_NEWNFSDLOCKFILE); +MALLOC_DECLARE(M_NEWNFSSTRING); +MALLOC_DECLARE(M_NEWNFSUSERGROUP); +MALLOC_DECLARE(M_NEWNFSDREQ); +MALLOC_DECLARE(M_NEWNFSFH); +MALLOC_DECLARE(M_NEWNFSCLOWNER); +MALLOC_DECLARE(M_NEWNFSCLOPEN); +MALLOC_DECLARE(M_NEWNFSCLDELEG); +MALLOC_DECLARE(M_NEWNFSCLCLIENT); +MALLOC_DECLARE(M_NEWNFSCLLOCKOWNER); +MALLOC_DECLARE(M_NEWNFSCLLOCK); +MALLOC_DECLARE(M_NEWNFSDIROFF); +MALLOC_DECLARE(M_NEWNFSV4NODE); +MALLOC_DECLARE(M_NEWNFSDIRECTIO); +MALLOC_DECLARE(M_NEWNFSMNT); +#define M_NFSRVCACHE M_NEWNFSRVCACHE +#define M_NFSDCLIENT M_NEWNFSDCLIENT +#define M_NFSDSTATE M_NEWNFSDSTATE +#define M_NFSDLOCK M_NEWNFSDLOCK +#define M_NFSDLOCKFILE M_NEWNFSDLOCKFILE +#define M_NFSSTRING M_NEWNFSSTRING +#define M_NFSUSERGROUP M_NEWNFSUSERGROUP +#define M_NFSDREQ M_NEWNFSDREQ +#define M_NFSFH M_NEWNFSFH +#define M_NFSCLOWNER M_NEWNFSCLOWNER +#define M_NFSCLOPEN M_NEWNFSCLOPEN +#define M_NFSCLDELEG M_NEWNFSCLDELEG +#define M_NFSCLCLIENT M_NEWNFSCLCLIENT +#define M_NFSCLLOCKOWNER M_NEWNFSCLLOCKOWNER +#define M_NFSCLLOCK M_NEWNFSCLLOCK +#define M_NFSDIROFF M_NEWNFSDIROFF +#define M_NFSV4NODE M_NEWNFSV4NODE +#define M_NFSDIRECTIO M_NEWNFSDIRECTIO + +#define NFSINT_SIGMASK(set) \ + (SIGISMEMBER(set, SIGINT) || SIGISMEMBER(set, SIGTERM) || \ + SIGISMEMBER(set, SIGHUP) || SIGISMEMBER(set, SIGKILL) || \ + SIGISMEMBER(set, SIGQUIT)) + +/* + * Convert a quota block count to byte count. + */ +#define NFSQUOTABLKTOBYTE(q, b) (q) *= (b) + +/* + * Define this as the largest file size supported. (It should probably + * be available via a VFS_xxx Op, but it isn't. + */ +#define NFSRV_MAXFILESIZE ((u_int64_t)0x800000000000) + +/* + * Set this macro to index() or strchr(), whichever is supported. + */ +#define STRCHR(s, c) index((s), (c)) + +/* + * Set the n_time in the client write rpc, as required. + */ +#define NFSWRITERPC_SETTIME(w, n, v4) \ + do { \ + if (w) { \ + (n)->n_mtime = (n)->n_vattr.na_vattr.va_mtime; \ + if (v4) \ + (n)->n_change = (n)->n_vattr.na_vattr.va_filerev; \ + } \ + } while (0) + +/* + * Fake value, just to make the client work. + */ +#define NFS_LATTR_NOSHRINK 1 + +/* + * Prototypes for functions where the arguments vary for different ports. + */ +int nfscl_loadattrcache(struct vnode **, struct nfsvattr *, void *, void *, + int, int); +void newnfs_realign(struct mbuf **); + +/* + * If the port runs on an SMP box that can enforce Atomic ops with low + * overheads, define these as atomic increments/decrements. If not, + * don't worry about it, since these are used for stats that can be + * "out by one" without disastrous consequences. + */ +#define NFSINCRGLOBAL(a) ((a)++) + +/* + * Assorted funky stuff to make things work under Darwin8. + */ +/* + * These macros checks for a field in vattr being set. + */ +#define NFSATTRISSET(t, v, a) ((v)->a != (t)VNOVAL) +#define NFSATTRISSETTIME(v, a) ((v)->a.tv_sec != VNOVAL) + +/* + * Manipulate mount flags. + */ +#define NFSSTA_HASWRITEVERF 0x00040000 /* Has write verifier */ +#define NFSSTA_GOTFSINFO 0x00100000 /* Got the fsinfo */ +#define NFSSTA_TIMEO 0x10000000 /* Experiencing a timeout */ +#define NFSSTA_LOCKTIMEO 0x20000000 /* Experiencing a lockd timeout */ +#define NFSSTA_HASSETFSID 0x40000000 /* Has set the fsid */ + +#define NFSHASNFSV3(n) ((n)->nm_flag & NFSMNT_NFSV3) +#define NFSHASNFSV4(n) ((n)->nm_flag & NFSMNT_NFSV4) +#define NFSHASNFSV3OR4(n) ((n)->nm_flag & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) +#define NFSHASGOTFSINFO(n) ((n)->nm_state & NFSSTA_GOTFSINFO) +#define NFSHASHASSETFSID(n) ((n)->nm_state & NFSSTA_HASSETFSID) +#define NFSHASSTRICT3530(n) ((n)->nm_flag & NFSMNT_STRICT3530) +#define NFSHASWRITEVERF(n) ((n)->nm_state & NFSSTA_HASWRITEVERF) +#define NFSHASINT(n) ((n)->nm_flag & NFSMNT_INT) +#define NFSHASSOFT(n) ((n)->nm_flag & NFSMNT_SOFT) +#define NFSHASINTORSOFT(n) ((n)->nm_flag & (NFSMNT_INT | NFSMNT_SOFT)) +#define NFSHASDUMBTIMR(n) ((n)->nm_flag & NFSMNT_DUMBTIMR) +#define NFSHASNOCONN(n) ((n)->nm_flag & NFSMNT_MNTD) +#define NFSHASKERB(n) ((n)->nm_flag & NFSMNT_KERB) +#define NFSHASALLGSSNAME(n) ((n)->nm_flag & NFSMNT_ALLGSSNAME) +#define NFSHASINTEGRITY(n) ((n)->nm_flag & NFSMNT_INTEGRITY) +#define NFSHASPRIVACY(n) ((n)->nm_flag & NFSMNT_PRIVACY) +#define NFSSETWRITEVERF(n) ((n)->nm_state |= NFSSTA_HASWRITEVERF) +#define NFSSETHASSETFSID(n) ((n)->nm_state |= NFSSTA_HASSETFSID) +#ifdef NFS4_ACL_EXTATTR_NAME +#define NFSHASNFS4ACL(m) ((m)->mnt_flag & MNT_NFS4ACLS) +#else +#define NFSHASNFS4ACL(m) 0 +#endif + +/* + * Gets the stats field out of the mount structure. + */ +#define vfs_statfs(m) (&((m)->mnt_stat)) + +/* + * Set boottime. + */ +#define NFSSETBOOTTIME(b) ((b) = boottime) + +/* + * The size of directory blocks in the buffer cache. + * MUST BE in the range of PAGE_SIZE <= NFS_DIRBLKSIZ <= MAXBSIZE!! + */ +#define NFS_DIRBLKSIZ (16 * DIRBLKSIZ) /* Must be a multiple of DIRBLKSIZ */ + +/* + * Define these macros to access mnt_flag fields. + */ +#define NFSMNT_RDONLY(m) ((m)->mnt_flag & MNT_RDONLY) +#endif /* _KERNEL */ + +/* + * Define a structure similar to ufs_args for use in exporting the V4 root. + */ +struct nfsex_args { + char *fspec; + struct export_args export; +}; + +/* + * Define these here, so they don't have to be in mount.h, for now. + */ +#define MNT_EXGSSKRB5 MNT_EXKERB + +/* + * These export flags should be defined, but there are no bits left. + * Maybe a separate mnt_exflag field could be added or the mnt_flag + * field increased to 64 bits? + */ +#ifndef MNT_EXSTRICTACCESS +#define MNT_EXSTRICTACCESS 0x0 +#endif +#ifndef MNT_EXV4ONLY +#define MNT_EXV4ONLY 0x0 +#endif + +#ifdef _KERNEL +/* + * Define this to invalidate the attribute cache for the nfs node. + */ +#define NFSINVALATTRCACHE(n) ((n)->n_attrstamp = 0) + +/* Used for FreeBSD only */ +void nfsd_mntinit(void); + +/* + * Define these for vnode lock/unlock ops. + */ +#define NFSVOPLOCK(v, f, p) vn_lock((v), (f)) +#define NFSVOPUNLOCK(v, f, p) VOP_UNLOCK((v), (f)) +#define NFSVOPISLOCKED(v, p) VOP_ISLOCKED((v)) + +/* + * Define ncl_hash(). + */ +#define ncl_hash(f, l) (fnv_32_buf((f), (l), FNV1_32_INIT)) + +int newnfs_iosize(struct nfsmount *); + +#ifdef NFS_DEBUG + +extern int nfs_debug; +#define NFS_DEBUG_ASYNCIO 1 /* asynchronous i/o */ +#define NFS_DEBUG_WG 2 /* server write gathering */ +#define NFS_DEBUG_RC 4 /* server request caching */ + +#define NFS_DPF(cat, args) \ + do { \ + if (nfs_debug & NFS_DEBUG_##cat) printf args; \ + } while (0) + +#else + +#define NFS_DPF(cat, args) + +#endif + +int newnfs_vncmpf(struct vnode *, void *); + +#ifndef NFS_MINDIRATTRTIMO +#define NFS_MINDIRATTRTIMO 3 /* VDIR attrib cache timeout in sec */ +#endif +#ifndef NFS_MAXDIRATTRTIMO +#define NFS_MAXDIRATTRTIMO 60 +#endif + +/* + * Nfs outstanding request list element + */ +struct nfsreq { + TAILQ_ENTRY(nfsreq) r_chain; + u_int32_t r_flags; /* flags on request, see below */ + struct nfsmount *r_nmp; /* Client mnt ptr */ + struct mtx r_mtx; /* Mutex lock for this structure */ +}; + +#ifndef NFS_MAXBSIZE +#define NFS_MAXBSIZE MAXBSIZE +#endif + +/* + * This macro checks to see if issuing of delegations is allowed for this + * vnode. + */ +#ifdef VV_DISABLEDELEG +#define NFSVNO_DELEGOK(v) \ + ((v) == NULL || ((v)->v_vflag & VV_DISABLEDELEG) == 0) +#else +#define NFSVNO_DELEGOK(v) (1) +#endif + +#endif /* _KERNEL */ + +#endif /* _NFSPORT_NFS_H */ diff --git a/sys/fs/nfs/nfsproto.h b/sys/fs/nfs/nfsproto.h new file mode 100644 index 0000000..a092790 --- /dev/null +++ b/sys/fs/nfs/nfsproto.h @@ -0,0 +1,1129 @@ +/*- + * 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. + * + * $FreeBSD$ + */ + +#ifndef _NFS_NFSPROTO_H_ +#define _NFS_NFSPROTO_H_ + +/* + * nfs definitions as per the Version 2, 3 and 4 specs + */ + +/* + * Constants as defined in the NFS Version 2, 3 and 4 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_CALLBCKPROG 0x40000000 /* V4 only */ +#define NFS_VER2 2 +#define NFS_VER3 3 +#define NFS_VER4 4 +#define NFS_V2MAXDATA 8192 +#define NFS_MAXDGRAMDATA 16384 +#define NFS_MAXDATA NFS_MAXBSIZE +#define NFS_MAXPATHLEN 1024 +#define NFS_MAXNAMLEN 255 +#define NFS_MAXPKTHDR 404 +#define NFS_MAXPACKET (NFS_MAXDATA + 2048) +#define NFS_MINPACKET 20 +#define NFS_FABLKSIZE 512 /* Size in bytes of a block wrt fa_blocks */ +#define NFSV4_MINORVERSION 0 /* V4 Minor version */ +#define NFSV4_CBVERS 1 /* V4 CB Version */ +#define NFSV4_SMALLSTR 50 /* Strings small enough for stack */ + +/* Stat numbers for rpc returns (version 2, 3 and 4) */ +#define NFSERR_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, 4 only */ +#define NFSERR_NODEV 19 +#define NFSERR_NOTDIR 20 +#define NFSERR_ISDIR 21 +#define NFSERR_INVAL 22 /* Version 3, 4 only */ +#define NFSERR_FBIG 27 +#define NFSERR_NOSPC 28 +#define NFSERR_ROFS 30 +#define NFSERR_MLINK 31 /* Version 3, 4 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 /* These are Version 3, 4 only */ +#define NFSERR_NOT_SYNC 10002 /* Version 3 Only */ +#define NFSERR_BAD_COOKIE 10003 +#define NFSERR_NOTSUPP 10004 +#define NFSERR_TOOSMALL 10005 +#define NFSERR_SERVERFAULT 10006 +#define NFSERR_BADTYPE 10007 +#define NFSERR_DELAY 10008 /* Called NFSERR_JUKEBOX for V3 */ +#define NFSERR_SAME 10009 /* These are Version 4 only */ +#define NFSERR_DENIED 10010 +#define NFSERR_EXPIRED 10011 +#define NFSERR_LOCKED 10012 +#define NFSERR_GRACE 10013 +#define NFSERR_FHEXPIRED 10014 +#define NFSERR_SHAREDENIED 10015 +#define NFSERR_WRONGSEC 10016 +#define NFSERR_CLIDINUSE 10017 +#define NFSERR_RESOURCE 10018 +#define NFSERR_MOVED 10019 +#define NFSERR_NOFILEHANDLE 10020 +#define NFSERR_MINORVERMISMATCH 10021 +#define NFSERR_STALECLIENTID 10022 +#define NFSERR_STALESTATEID 10023 +#define NFSERR_OLDSTATEID 10024 +#define NFSERR_BADSTATEID 10025 +#define NFSERR_BADSEQID 10026 +#define NFSERR_NOTSAME 10027 +#define NFSERR_LOCKRANGE 10028 +#define NFSERR_SYMLINK 10029 +#define NFSERR_RESTOREFH 10030 +#define NFSERR_LEASEMOVED 10031 +#define NFSERR_ATTRNOTSUPP 10032 +#define NFSERR_NOGRACE 10033 +#define NFSERR_RECLAIMBAD 10034 +#define NFSERR_RECLAIMCONFLICT 10035 +#define NFSERR_BADXDR 10036 +#define NFSERR_LOCKSHELD 10037 +#define NFSERR_OPENMODE 10038 +#define NFSERR_BADOWNER 10039 +#define NFSERR_BADCHAR 10040 +#define NFSERR_BADNAME 10041 +#define NFSERR_BADRANGE 10042 +#define NFSERR_LOCKNOTSUPP 10043 +#define NFSERR_OPILLEGAL 10044 +#define NFSERR_DEADLOCK 10045 +#define NFSERR_FILEOPEN 10046 +#define NFSERR_ADMINREVOKED 10047 +#define NFSERR_CBPATHDOWN 10048 + +#define NFSERR_STALEWRITEVERF 30001 /* Fake return for nfs_commit() */ +#define NFSERR_DONTREPLY 30003 /* Don't process request */ +#define NFSERR_RETVOID 30004 /* Return void, not error */ +#define NFSERR_REPLYFROMCACHE 30005 /* Reply from recent request cache */ +#define NFSERR_STALEDONTRECOVER 30006 /* Don't initiate recovery */ + +#define NFSERR_RPCERR 0x40000000 /* Mark an RPC layer error */ +#define NFSERR_AUTHERR 0x80000000 /* Mark an authentication error */ + +#define NFSERR_RPCMISMATCH (NFSERR_RPCERR | RPC_MISMATCH) +#define NFSERR_PROGUNAVAIL (NFSERR_RPCERR | RPC_PROGUNAVAIL) +#define NFSERR_PROGMISMATCH (NFSERR_RPCERR | RPC_PROGMISMATCH) +#define NFSERR_PROGNOTV4 (NFSERR_RPCERR | 0xffff) +#define NFSERR_PROCUNAVAIL (NFSERR_RPCERR | RPC_PROCUNAVAIL) +#define NFSERR_GARBAGE (NFSERR_RPCERR | RPC_GARBAGE) + +/* Sizes in bytes of various nfs rpc components */ +#define NFSX_UNSIGNED 4 +#define NFSX_HYPER (2 * NFSX_UNSIGNED) + +/* 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_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_V3STATFS 52 +#define NFSX_V3FSINFO 48 +#define NFSX_V3PATHCONF 24 + +/* specific to NFS Version 4 */ +#define NFSX_V4FHMAX 128 +#define NFSX_V4FSID (2 * NFSX_HYPER) +#define NFSX_V4SPECDATA (2 * NFSX_UNSIGNED) +#define NFSX_V4TIME (NFSX_HYPER + NFSX_UNSIGNED) +#define NFSX_V4SETTIME (NFSX_UNSIGNED + NFSX_V4TIME) + +/* sizes common to multiple NFS versions */ +#define NFSX_FHMAX (NFSX_V4FHMAX) +#define NFSX_MYFH (sizeof (fhandle_t)) /* size this server uses */ +#define NFSX_VERF 8 +#define NFSX_STATEIDOTHER 12 +#define NFSX_STATEID (NFSX_UNSIGNED + NFSX_STATEIDOTHER) +#define NFSX_GSSH 12 + +/* variants for multiple versions */ +#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 + +/* + * These cover all the procedures for V2 and 3. The higher numbers are + * used to reference other V4 ops. + * NFS_V3NPROCS is one greater than the last V3 op and NFS_NPROCS is + * one greater than the last number. + */ +#define NFS_V3NPROCS 22 + +#define NFSPROC_LOOKUPP 22 +#define NFSPROC_SETCLIENTID 23 +#define NFSPROC_SETCLIENTIDCFRM 24 +#define NFSPROC_LOCK 25 +#define NFSPROC_LOCKU 26 +#define NFSPROC_OPEN 27 +#define NFSPROC_CLOSE 28 +#define NFSPROC_OPENCONFIRM 29 +#define NFSPROC_LOCKT 30 +#define NFSPROC_OPENDOWNGRADE 31 +#define NFSPROC_RENEW 32 +#define NFSPROC_PUTROOTFH 33 +#define NFSPROC_RELEASELCKOWN 34 +#define NFSPROC_DELEGRETURN 35 +#define NFSPROC_RETDELEGREMOVE 36 +#define NFSPROC_RETDELEGRENAME1 37 +#define NFSPROC_RETDELEGRENAME2 38 +#define NFSPROC_GETACL 39 +#define NFSPROC_SETACL 40 + +#define NFS_NPROCS 41 + +/* + * NFSPROC_NOOP is a fake op# that can't be the same as any V2/3/4 Procedure + * or Operation#. Since the NFS V4 Op #s go higher, use NFSV4OP_NOPS, which + * is one greater than the highest Op#. + */ +#define NFSPROC_NOOP NFSV4OP_NOPS + +/* 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 + +/* + * V4 Procedure and suboperation numbers + */ +#define NFSV4PROC_COMPOUND 1 +#define NFSV4PROC_CBNULL 0 +#define NFSV4PROC_CBCOMPOUND 1 + +#define NFSV4OP_ACCESS 3 +#define NFSV4OP_CLOSE 4 +#define NFSV4OP_COMMIT 5 +#define NFSV4OP_CREATE 6 +#define NFSV4OP_DELEGPURGE 7 +#define NFSV4OP_DELEGRETURN 8 +#define NFSV4OP_GETATTR 9 +#define NFSV4OP_GETFH 10 +#define NFSV4OP_LINK 11 +#define NFSV4OP_LOCK 12 +#define NFSV4OP_LOCKT 13 +#define NFSV4OP_LOCKU 14 +#define NFSV4OP_LOOKUP 15 +#define NFSV4OP_LOOKUPP 16 +#define NFSV4OP_NVERIFY 17 +#define NFSV4OP_OPEN 18 +#define NFSV4OP_OPENATTR 19 +#define NFSV4OP_OPENCONFIRM 20 +#define NFSV4OP_OPENDOWNGRADE 21 +#define NFSV4OP_PUTFH 22 +#define NFSV4OP_PUTPUBFH 23 +#define NFSV4OP_PUTROOTFH 24 +#define NFSV4OP_READ 25 +#define NFSV4OP_READDIR 26 +#define NFSV4OP_READLINK 27 +#define NFSV4OP_REMOVE 28 +#define NFSV4OP_RENAME 29 +#define NFSV4OP_RENEW 30 +#define NFSV4OP_RESTOREFH 31 +#define NFSV4OP_SAVEFH 32 +#define NFSV4OP_SECINFO 33 +#define NFSV4OP_SETATTR 34 +#define NFSV4OP_SETCLIENTID 35 +#define NFSV4OP_SETCLIENTIDCFRM 36 +#define NFSV4OP_VERIFY 37 +#define NFSV4OP_WRITE 38 +#define NFSV4OP_RELEASELCKOWN 39 + +/* + * and the Callback OPs + */ +#define NFSV4OP_CBGETATTR 3 +#define NFSV4OP_CBRECALL 4 + +/* + * NFSV4OP_NOPS is one greater than the largest V4 Op#. (Used for sizing + * arrays, etc.) + */ +#define NFSV4OP_NOPS 40 +#define NFSV4OP_CBNOPS 5 + +/* + * Fake NFSV4OP_xxx used for nfsstat. Start at NFSV4OP_NOPS. + */ +#define NFSV4OP_SYMLINK (NFSV4OP_NOPS) +#define NFSV4OP_MKDIR (NFSV4OP_NOPS + 1) +#define NFSV4OP_RMDIR (NFSV4OP_NOPS + 2) +#define NFSV4OP_READDIRPLUS (NFSV4OP_NOPS + 3) +#define NFSV4OP_MKNOD (NFSV4OP_NOPS + 4) +#define NFSV4OP_FSSTAT (NFSV4OP_NOPS + 5) +#define NFSV4OP_FSINFO (NFSV4OP_NOPS + 6) +#define NFSV4OP_PATHCONF (NFSV4OP_NOPS + 7) +#define NFSV4OP_V3CREATE (NFSV4OP_NOPS + 8) + +#define NFSV4OP_FAKENOPS 9 + +/* + * Constants used by the Version 3 and 4 protocols for various RPCs + */ +#define NFSV3SATTRTIME_DONTCHANGE 0 +#define NFSV3SATTRTIME_TOSERVER 1 +#define NFSV3SATTRTIME_TOCLIENT 2 + +#define NFSV4SATTRTIME_TOSERVER 0 +#define NFSV4SATTRTIME_TOCLIENT 1 + +#define NFSV4LOCKT_READ 1 +#define NFSV4LOCKT_WRITE 2 +#define NFSV4LOCKT_READW 3 +#define NFSV4LOCKT_WRITEW 4 +#define NFSV4LOCKT_RELEASE 5 + +#define NFSV4OPEN_NOCREATE 0 +#define NFSV4OPEN_CREATE 1 +#define NFSV4OPEN_CLAIMNULL 0 +#define NFSV4OPEN_CLAIMPREVIOUS 1 +#define NFSV4OPEN_CLAIMDELEGATECUR 2 +#define NFSV4OPEN_CLAIMDELEGATEPREV 3 +#define NFSV4OPEN_DELEGATENONE 0 +#define NFSV4OPEN_DELEGATEREAD 1 +#define NFSV4OPEN_DELEGATEWRITE 2 +#define NFSV4OPEN_LIMITSIZE 1 +#define NFSV4OPEN_LIMITBLOCKS 2 + +/* + * Nfs V4 ACE stuff + */ +#define NFSV4ACE_ALLOWEDTYPE 0x00000000 +#define NFSV4ACE_DENIEDTYPE 0x00000001 +#define NFSV4ACE_AUDITTYPE 0x00000002 +#define NFSV4ACE_ALARMTYPE 0x00000003 + +#define NFSV4ACE_SUPALLOWED 0x00000001 +#define NFSV4ACE_SUPDENIED 0x00000002 +#define NFSV4ACE_SUPAUDIT 0x00000004 +#define NFSV4ACE_SUPALARM 0x00000008 + +#define NFSV4ACE_SUPTYPES (NFSV4ACE_SUPALLOWED | NFSV4ACE_SUPDENIED) + +#define NFSV4ACE_FILEINHERIT 0x00000001 +#define NFSV4ACE_DIRECTORYINHERIT 0x00000002 +#define NFSV4ACE_NOPROPAGATEINHERIT 0x00000004 +#define NFSV4ACE_INHERITONLY 0x00000008 +#define NFSV4ACE_SUCCESSFULACCESS 0x00000010 +#define NFSV4ACE_FAILEDACCESS 0x00000020 +#define NFSV4ACE_IDENTIFIERGROUP 0x00000040 + +#define NFSV4ACE_READDATA 0x00000001 +#define NFSV4ACE_LISTDIRECTORY 0x00000001 +#define NFSV4ACE_WRITEDATA 0x00000002 +#define NFSV4ACE_ADDFILE 0x00000002 +#define NFSV4ACE_APPENDDATA 0x00000004 +#define NFSV4ACE_ADDSUBDIRECTORY 0x00000004 +#define NFSV4ACE_READNAMEDATTR 0x00000008 +#define NFSV4ACE_WRITENAMEDATTR 0x00000010 +#define NFSV4ACE_EXECUTE 0x00000020 +#define NFSV4ACE_SEARCH 0x00000020 +#define NFSV4ACE_DELETECHILD 0x00000040 +#define NFSV4ACE_READATTRIBUTES 0x00000080 +#define NFSV4ACE_WRITEATTRIBUTES 0x00000100 +#define NFSV4ACE_DELETE 0x00010000 +#define NFSV4ACE_READACL 0x00020000 +#define NFSV4ACE_WRITEACL 0x00040000 +#define NFSV4ACE_WRITEOWNER 0x00080000 +#define NFSV4ACE_SYNCHRONIZE 0x00100000 + +/* + * Here are the mappings between mode bits and acl mask bits for + * directories and other files. + * (Named attributes have not been included, since named attributes are + * not yet supported.) + * The mailing list seems to indicate that NFSV4ACE_EXECUTE refers to + * searching a directory, although I can't find a statement of that in + * the RFC. + */ +#define NFSV4ACE_ALLFILESMASK (NFSV4ACE_READATTRIBUTES | NFSV4ACE_READACL) +#define NFSV4ACE_OWNERMASK (NFSV4ACE_WRITEATTRIBUTES | NFSV4ACE_WRITEACL) +#define NFSV4ACE_DIRREADMASK NFSV4ACE_LISTDIRECTORY +#define NFSV4ACE_DIREXECUTEMASK NFSV4ACE_EXECUTE +#define NFSV4ACE_DIRWRITEMASK (NFSV4ACE_ADDFILE | \ + NFSV4ACE_ADDSUBDIRECTORY | NFSV4ACE_DELETECHILD) +#define NFSV4ACE_READMASK NFSV4ACE_READDATA +#define NFSV4ACE_WRITEMASK (NFSV4ACE_WRITEDATA | NFSV4ACE_APPENDDATA) +#define NFSV4ACE_EXECUTEMASK NFSV4ACE_EXECUTE +#define NFSV4ACE_ALLFILEBITS (NFSV4ACE_READMASK | NFSV4ACE_WRITEMASK | \ + NFSV4ACE_EXECUTEMASK | NFSV4ACE_SYNCHRONIZE) +#define NFSV4ACE_ALLDIRBITS (NFSV4ACE_DIRREADMASK | \ + NFSV4ACE_DIRWRITEMASK | NFSV4ACE_DIREXECUTEMASK) +#define NFSV4ACE_AUDITMASK 0x0 + +/* + * These GENERIC masks are not used and are no longer believed to be useful. + */ +#define NFSV4ACE_GENERICREAD 0x00120081 +#define NFSV4ACE_GENERICWRITE 0x00160106 +#define NFSV4ACE_GENERICEXECUTE 0x001200a0 + +#define NFSSTATEID_PUTALLZERO 0 +#define NFSSTATEID_PUTALLONE 1 +#define NFSSTATEID_PUTSTATEID 2 + +/* + * Bits for share access and deny. + */ +#define NFSV4OPEN_ACCESSREAD 0x00000001 +#define NFSV4OPEN_ACCESSWRITE 0x00000002 +#define NFSV4OPEN_ACCESSBOTH 0x00000003 + +#define NFSV4OPEN_DENYNONE 0x00000000 +#define NFSV4OPEN_DENYREAD 0x00000001 +#define NFSV4OPEN_DENYWRITE 0x00000002 +#define NFSV4OPEN_DENYBOTH 0x00000003 + +/* + * Open result flags + * (The first two are in the spec. The rest are used internally.) + */ +#define NFSV4OPEN_RESULTCONFIRM 0x00000002 +#define NFSV4OPEN_LOCKTYPEPOSIX 0x00000004 +#define NFSV4OPEN_RFLAGS \ + (NFSV4OPEN_RESULTCONFIRM | NFSV4OPEN_LOCKTYPEPOSIX) +#define NFSV4OPEN_RECALL 0x00010000 +#define NFSV4OPEN_READDELEGATE 0x00020000 +#define NFSV4OPEN_WRITEDELEGATE 0x00040000 + +/* + * NFS V4 File Handle types + */ +#define NFSV4FHTYPE_PERSISTENT 0x0 +#define NFSV4FHTYPE_NOEXPIREWITHOPEN 0x1 +#define NFSV4FHTYPE_VOLATILEANY 0x2 +#define NFSV4FHTYPE_VOLATILEMIGRATE 0x4 +#define NFSV4FHTYPE_VOLATILERENAME 0x8 + +/* + * Maximum size of V4 opaque strings. + */ +#define NFSV4_OPAQUELIMIT 1024 + +/* + * These are the same for V3 and V4. + */ +#define NFSACCESS_READ 0x01 +#define NFSACCESS_LOOKUP 0x02 +#define NFSACCESS_MODIFY 0x04 +#define NFSACCESS_EXTEND 0x08 +#define NFSACCESS_DELETE 0x10 +#define NFSACCESS_EXECUTE 0x20 + +#define NFSWRITE_UNSTABLE 0 +#define NFSWRITE_DATASYNC 1 +#define NFSWRITE_FILESYNC 2 + +#define NFSCREATE_UNCHECKED 0 +#define NFSCREATE_GUARDED 1 +#define NFSCREATE_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 vtonfsv34_mode(m) txdr_unsigned((m) & 07777) +#define nfstov_mode(a) (fxdr_unsigned(u_int16_t, (a))&07777) +#define vtonfsv2_type(a) (((u_int32_t)(a)) >= 9 ? txdr_unsigned(NFNON) : \ + txdr_unsigned(newnfsv2_type[((u_int32_t)(a))])) +#define vtonfsv34_type(a) (((u_int32_t)(a)) >= 9 ? txdr_unsigned(NFNON) : \ + txdr_unsigned(nfsv34_type[((u_int32_t)(a))])) +#define nfsv2tov_type(a) newnv2tov_type[fxdr_unsigned(u_int32_t,(a))&0x7] +#define nfsv34tov_type(a) nv34tov_type[fxdr_unsigned(u_int32_t,(a))&0x7] +#define vtonfs_dtype(a) (((u_int32_t)(a)) >= 9 ? IFTODT(VTTOIF(VNON)) : \ + IFTODT(VTTOIF(a))) + +/* File types */ +typedef enum { NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5, + NFSOCK=6, NFFIFO=7, NFATTRDIR=8, NFNAMEDATTR=9 } nfstype; + +/* Structs for common parts of the rpc's */ + +struct nfsv2_time { + u_int32_t nfsv2_sec; + u_int32_t nfsv2_usec; +}; +typedef struct nfsv2_time nfstime2; + +struct nfsv3_time { + u_int32_t nfsv3_sec; + u_int32_t nfsv3_nsec; +}; +typedef struct nfsv3_time nfstime3; + +struct nfsv4_time { + u_int32_t nfsv4_highsec; + u_int32_t nfsv4_sec; + u_int32_t nfsv4_nsec; +}; +typedef struct nfsv4_time nfstime4; + +/* + * Quads are defined as arrays of 2 longs to ensure dense packing for the + * protocol and to facilitate xdr conversion. + */ +struct nfs_uquad { + u_int32_t nfsuquad[2]; +}; +typedef struct nfs_uquad nfsuint64; + +/* + * Used to convert between two u_longs and a u_quad_t. + */ +union nfs_quadconvert { + u_int32_t lval[2]; + u_quad_t qval; +}; +typedef union nfs_quadconvert nfsquad_t; + +/* + * NFS Version 3 special file number. + */ +struct nfsv3_spec { + u_int32_t specdata1; + u_int32_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 { + u_int32_t fa_type; + u_int32_t fa_mode; + u_int32_t fa_nlink; + u_int32_t fa_uid; + u_int32_t fa_gid; + union { + struct { + u_int32_t nfsv2fa_size; + u_int32_t nfsv2fa_blocksize; + u_int32_t nfsv2fa_rdev; + u_int32_t nfsv2fa_blocks; + u_int32_t nfsv2fa_fsid; + u_int32_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 { + u_int32_t sa_mode; + u_int32_t sa_uid; + u_int32_t sa_gid; + u_int32_t sa_size; + nfstime2 sa_atime; + nfstime2 sa_mtime; +}; + +/* + * NFS Version 3 sattr structure for the new node creation case. + */ +struct nfsv3_sattr { + u_int32_t sa_modetrue; + u_int32_t sa_mode; + u_int32_t sa_uidfalse; + u_int32_t sa_gidfalse; + u_int32_t sa_sizefalse; + u_int32_t sa_atimetype; + nfstime3 sa_atime; + u_int32_t sa_mtimetype; + nfstime3 sa_mtime; +}; + +/* + * The attribute bits used for V4. + * NFSATTRBIT_xxx defines the attribute# (and its bit position) + * NFSATTRBM_xxx is a 32bit mask with the correct bit set within the + * appropriate 32bit word. + * NFSATTRBIT_MAX is one greater than the largest NFSATTRBIT_xxx + */ +#define NFSATTRBIT_SUPPORTEDATTRS 0 +#define NFSATTRBIT_TYPE 1 +#define NFSATTRBIT_FHEXPIRETYPE 2 +#define NFSATTRBIT_CHANGE 3 +#define NFSATTRBIT_SIZE 4 +#define NFSATTRBIT_LINKSUPPORT 5 +#define NFSATTRBIT_SYMLINKSUPPORT 6 +#define NFSATTRBIT_NAMEDATTR 7 +#define NFSATTRBIT_FSID 8 +#define NFSATTRBIT_UNIQUEHANDLES 9 +#define NFSATTRBIT_LEASETIME 10 +#define NFSATTRBIT_RDATTRERROR 11 +#define NFSATTRBIT_ACL 12 +#define NFSATTRBIT_ACLSUPPORT 13 +#define NFSATTRBIT_ARCHIVE 14 +#define NFSATTRBIT_CANSETTIME 15 +#define NFSATTRBIT_CASEINSENSITIVE 16 +#define NFSATTRBIT_CASEPRESERVING 17 +#define NFSATTRBIT_CHOWNRESTRICTED 18 +#define NFSATTRBIT_FILEHANDLE 19 +#define NFSATTRBIT_FILEID 20 +#define NFSATTRBIT_FILESAVAIL 21 +#define NFSATTRBIT_FILESFREE 22 +#define NFSATTRBIT_FILESTOTAL 23 +#define NFSATTRBIT_FSLOCATIONS 24 +#define NFSATTRBIT_HIDDEN 25 +#define NFSATTRBIT_HOMOGENEOUS 26 +#define NFSATTRBIT_MAXFILESIZE 27 +#define NFSATTRBIT_MAXLINK 28 +#define NFSATTRBIT_MAXNAME 29 +#define NFSATTRBIT_MAXREAD 30 +#define NFSATTRBIT_MAXWRITE 31 +#define NFSATTRBIT_MIMETYPE 32 +#define NFSATTRBIT_MODE 33 +#define NFSATTRBIT_NOTRUNC 34 +#define NFSATTRBIT_NUMLINKS 35 +#define NFSATTRBIT_OWNER 36 +#define NFSATTRBIT_OWNERGROUP 37 +#define NFSATTRBIT_QUOTAHARD 38 +#define NFSATTRBIT_QUOTASOFT 39 +#define NFSATTRBIT_QUOTAUSED 40 +#define NFSATTRBIT_RAWDEV 41 +#define NFSATTRBIT_SPACEAVAIL 42 +#define NFSATTRBIT_SPACEFREE 43 +#define NFSATTRBIT_SPACETOTAL 44 +#define NFSATTRBIT_SPACEUSED 45 +#define NFSATTRBIT_SYSTEM 46 +#define NFSATTRBIT_TIMEACCESS 47 +#define NFSATTRBIT_TIMEACCESSSET 48 +#define NFSATTRBIT_TIMEBACKUP 49 +#define NFSATTRBIT_TIMECREATE 50 +#define NFSATTRBIT_TIMEDELTA 51 +#define NFSATTRBIT_TIMEMETADATA 52 +#define NFSATTRBIT_TIMEMODIFY 53 +#define NFSATTRBIT_TIMEMODIFYSET 54 +#define NFSATTRBIT_MOUNTEDONFILEID 55 + +#define NFSATTRBM_SUPPORTEDATTRS 0x00000001 +#define NFSATTRBM_TYPE 0x00000002 +#define NFSATTRBM_FHEXPIRETYPE 0x00000004 +#define NFSATTRBM_CHANGE 0x00000008 +#define NFSATTRBM_SIZE 0x00000010 +#define NFSATTRBM_LINKSUPPORT 0x00000020 +#define NFSATTRBM_SYMLINKSUPPORT 0x00000040 +#define NFSATTRBM_NAMEDATTR 0x00000080 +#define NFSATTRBM_FSID 0x00000100 +#define NFSATTRBM_UNIQUEHANDLES 0x00000200 +#define NFSATTRBM_LEASETIME 0x00000400 +#define NFSATTRBM_RDATTRERROR 0x00000800 +#define NFSATTRBM_ACL 0x00001000 +#define NFSATTRBM_ACLSUPPORT 0x00002000 +#define NFSATTRBM_ARCHIVE 0x00004000 +#define NFSATTRBM_CANSETTIME 0x00008000 +#define NFSATTRBM_CASEINSENSITIVE 0x00010000 +#define NFSATTRBM_CASEPRESERVING 0x00020000 +#define NFSATTRBM_CHOWNRESTRICTED 0x00040000 +#define NFSATTRBM_FILEHANDLE 0x00080000 +#define NFSATTRBM_FILEID 0x00100000 +#define NFSATTRBM_FILESAVAIL 0x00200000 +#define NFSATTRBM_FILESFREE 0x00400000 +#define NFSATTRBM_FILESTOTAL 0x00800000 +#define NFSATTRBM_FSLOCATIONS 0x01000000 +#define NFSATTRBM_HIDDEN 0x02000000 +#define NFSATTRBM_HOMOGENEOUS 0x04000000 +#define NFSATTRBM_MAXFILESIZE 0x08000000 +#define NFSATTRBM_MAXLINK 0x10000000 +#define NFSATTRBM_MAXNAME 0x20000000 +#define NFSATTRBM_MAXREAD 0x40000000 +#define NFSATTRBM_MAXWRITE 0x80000000 +#define NFSATTRBM_MIMETYPE 0x00000001 +#define NFSATTRBM_MODE 0x00000002 +#define NFSATTRBM_NOTRUNC 0x00000004 +#define NFSATTRBM_NUMLINKS 0x00000008 +#define NFSATTRBM_OWNER 0x00000010 +#define NFSATTRBM_OWNERGROUP 0x00000020 +#define NFSATTRBM_QUOTAHARD 0x00000040 +#define NFSATTRBM_QUOTASOFT 0x00000080 +#define NFSATTRBM_QUOTAUSED 0x00000100 +#define NFSATTRBM_RAWDEV 0x00000200 +#define NFSATTRBM_SPACEAVAIL 0x00000400 +#define NFSATTRBM_SPACEFREE 0x00000800 +#define NFSATTRBM_SPACETOTAL 0x00001000 +#define NFSATTRBM_SPACEUSED 0x00002000 +#define NFSATTRBM_SYSTEM 0x00004000 +#define NFSATTRBM_TIMEACCESS 0x00008000 +#define NFSATTRBM_TIMEACCESSSET 0x00010000 +#define NFSATTRBM_TIMEBACKUP 0x00020000 +#define NFSATTRBM_TIMECREATE 0x00040000 +#define NFSATTRBM_TIMEDELTA 0x00080000 +#define NFSATTRBM_TIMEMETADATA 0x00100000 +#define NFSATTRBM_TIMEMODIFY 0x00200000 +#define NFSATTRBM_TIMEMODIFYSET 0x00400000 +#define NFSATTRBM_MOUNTEDONFILEID 0x00800000 + +#define NFSATTRBIT_MAX 56 + +/* + * Sets of attributes that are supported, by words in the bitmap. + */ +/* + * NFSATTRBIT_SUPPORTED - SUPP0 - bits 0<->31 + * SUPP1 - bits 32<->63 + */ +#define NFSATTRBIT_SUPP0 \ + (NFSATTRBM_SUPPORTEDATTRS | \ + NFSATTRBM_TYPE | \ + NFSATTRBM_FHEXPIRETYPE | \ + NFSATTRBM_CHANGE | \ + NFSATTRBM_SIZE | \ + NFSATTRBM_LINKSUPPORT | \ + NFSATTRBM_SYMLINKSUPPORT | \ + NFSATTRBM_NAMEDATTR | \ + NFSATTRBM_FSID | \ + NFSATTRBM_UNIQUEHANDLES | \ + NFSATTRBM_LEASETIME | \ + NFSATTRBM_RDATTRERROR | \ + NFSATTRBM_ACL | \ + NFSATTRBM_ACLSUPPORT | \ + NFSATTRBM_CANSETTIME | \ + NFSATTRBM_CASEINSENSITIVE | \ + NFSATTRBM_CASEPRESERVING | \ + NFSATTRBM_CHOWNRESTRICTED | \ + NFSATTRBM_FILEHANDLE | \ + NFSATTRBM_FILEID | \ + NFSATTRBM_FILESAVAIL | \ + NFSATTRBM_FILESFREE | \ + NFSATTRBM_FILESTOTAL | \ + NFSATTRBM_FSLOCATIONS | \ + NFSATTRBM_HOMOGENEOUS | \ + NFSATTRBM_MAXFILESIZE | \ + NFSATTRBM_MAXLINK | \ + NFSATTRBM_MAXNAME | \ + NFSATTRBM_MAXREAD | \ + NFSATTRBM_MAXWRITE) + +/* + * NFSATTRBIT_S1 - subset of SUPP1 - OR of the following bits: + */ +#define NFSATTRBIT_S1 \ + (NFSATTRBM_MODE | \ + NFSATTRBM_NOTRUNC | \ + NFSATTRBM_NUMLINKS | \ + NFSATTRBM_OWNER | \ + NFSATTRBM_OWNERGROUP | \ + NFSATTRBM_RAWDEV | \ + NFSATTRBM_SPACEAVAIL | \ + NFSATTRBM_SPACEFREE | \ + NFSATTRBM_SPACETOTAL | \ + NFSATTRBM_SPACEUSED | \ + NFSATTRBM_TIMEACCESS | \ + NFSATTRBM_TIMEDELTA | \ + NFSATTRBM_TIMEMETADATA | \ + NFSATTRBM_TIMEMODIFY | \ + NFSATTRBM_MOUNTEDONFILEID) + +#ifdef QUOTA +/* + * If QUOTA OR in NFSATTRBIT_QUOTAHARD, NFSATTRBIT_QUOTASOFT and + * NFSATTRBIT_QUOTAUSED. + */ +#define NFSATTRBIT_SUPP1 (NFSATTRBIT_S1 | \ + NFSATTRBM_QUOTAHARD | \ + NFSATTRBM_QUOTASOFT | \ + NFSATTRBM_QUOTAUSED) +#else +#define NFSATTRBIT_SUPP1 NFSATTRBIT_S1 +#endif + +/* + * NFSATTRBIT_SUPPSETONLY is the OR of NFSATTRBIT_TIMEACCESSSET and + * NFSATTRBIT_TIMEMODIFYSET. + */ +#define NFSATTRBIT_SUPPSETONLY (NFSATTRBM_TIMEACCESSSET | \ + NFSATTRBM_TIMEMODIFYSET) + +/* + * NFSATTRBIT_SETABLE - SETABLE0 - bits 0<->31 + * SETABLE1 - bits 32<->63 + */ +#define NFSATTRBIT_SETABLE0 \ + (NFSATTRBM_SIZE | \ + NFSATTRBM_ACL) +#define NFSATTRBIT_SETABLE1 \ + (NFSATTRBM_MODE | \ + NFSATTRBM_OWNER | \ + NFSATTRBM_OWNERGROUP | \ + NFSATTRBM_TIMEACCESSSET | \ + NFSATTRBM_TIMEMODIFYSET) + +/* + * Set of attributes that the getattr vnode op needs. + * OR of the following bits. + * NFSATTRBIT_GETATTR0 - bits 0<->31 + */ +#define NFSATTRBIT_GETATTR0 \ + (NFSATTRBM_SUPPORTEDATTRS | \ + NFSATTRBM_TYPE | \ + NFSATTRBM_CHANGE | \ + NFSATTRBM_SIZE | \ + NFSATTRBM_FSID | \ + NFSATTRBM_FILEID | \ + NFSATTRBM_MAXREAD) + +/* + * NFSATTRBIT_GETATTR1 - bits 32<->63 + */ +#define NFSATTRBIT_GETATTR1 \ + (NFSATTRBM_MODE | \ + NFSATTRBM_NUMLINKS | \ + NFSATTRBM_OWNER | \ + NFSATTRBM_OWNERGROUP | \ + NFSATTRBM_RAWDEV | \ + NFSATTRBM_SPACEUSED | \ + NFSATTRBM_TIMEACCESS | \ + NFSATTRBM_TIMEMETADATA | \ + NFSATTRBM_TIMEMODIFY) + +/* + * Subset of the above that the Write RPC gets. + * OR of the following bits. + * NFSATTRBIT_WRITEGETATTR0 - bits 0<->31 + */ +#define NFSATTRBIT_WRITEGETATTR0 \ + (NFSATTRBM_CHANGE | \ + NFSATTRBM_SIZE | \ + NFSATTRBM_FSID) + +/* + * NFSATTRBIT_WRITEGETATTR1 - bits 32<->63 + */ +#define NFSATTRBIT_WRITEGETATTR1 \ + (NFSATTRBM_TIMEMETADATA | \ + NFSATTRBM_TIMEMODIFY) + +/* + * Set of attributes that the wccattr operation op needs. + * OR of the following bits. + * NFSATTRBIT_WCCATTR0 - bits 0<->31 + */ +#define NFSATTRBIT_WCCATTR0 0 + +/* + * NFSATTRBIT_WCCATTR1 - bits 32<->63 + */ +#define NFSATTRBIT_WCCATTR1 \ + (NFSATTRBM_TIMEMODIFY) + +/* + * NFSATTRBIT_CBGETATTR0 - bits 0<->31 + */ +#define NFSATTRBIT_CBGETATTR0 (NFSATTRBM_CHANGE | NFSATTRBM_SIZE) + +/* + * NFSATTRBIT_CBGETATTR1 - bits 32<->63 + */ +#define NFSATTRBIT_CBGETATTR1 0x0 + +/* + * Sets of attributes that require a VFS_STATFS() call to get the + * values of. + * NFSATTRBIT_STATFS0 - bits 0<->31 + */ +#define NFSATTRBIT_STATFS0 \ + (NFSATTRBM_LINKSUPPORT | \ + NFSATTRBM_SYMLINKSUPPORT | \ + NFSATTRBM_CANSETTIME | \ + NFSATTRBM_FILESAVAIL | \ + NFSATTRBM_FILESFREE | \ + NFSATTRBM_FILESTOTAL | \ + NFSATTRBM_HOMOGENEOUS | \ + NFSATTRBM_MAXFILESIZE | \ + NFSATTRBM_MAXNAME | \ + NFSATTRBM_MAXREAD | \ + NFSATTRBM_MAXWRITE) + +/* + * NFSATTRBIT_STATFS1 - bits 32<->63 + */ +#define NFSATTRBIT_STATFS1 \ + (NFSATTRBM_QUOTAHARD | \ + NFSATTRBM_QUOTASOFT | \ + NFSATTRBM_QUOTAUSED | \ + NFSATTRBM_SPACEAVAIL | \ + NFSATTRBM_SPACEFREE | \ + NFSATTRBM_SPACETOTAL | \ + NFSATTRBM_SPACEUSED | \ + NFSATTRBM_TIMEDELTA) + +/* + * These are the bits that are needed by the nfs_statfs() call. + * (The regular getattr bits are or'd in so the vnode gets the correct + * type, etc.) + * NFSGETATTRBIT_STATFS0 - bits 0<->31 + */ +#define NFSGETATTRBIT_STATFS0 (NFSATTRBIT_GETATTR0 | \ + NFSATTRBM_LINKSUPPORT | \ + NFSATTRBM_SYMLINKSUPPORT | \ + NFSATTRBM_CANSETTIME | \ + NFSATTRBM_FILESFREE | \ + NFSATTRBM_FILESTOTAL | \ + NFSATTRBM_HOMOGENEOUS | \ + NFSATTRBM_MAXFILESIZE | \ + NFSATTRBM_MAXNAME | \ + NFSATTRBM_MAXREAD | \ + NFSATTRBM_MAXWRITE) + +/* + * NFSGETATTRBIT_STATFS1 - bits 32<->63 + */ +#define NFSGETATTRBIT_STATFS1 (NFSATTRBIT_GETATTR1 | \ + NFSATTRBM_SPACEAVAIL | \ + NFSATTRBM_SPACEFREE | \ + NFSATTRBM_SPACETOTAL | \ + NFSATTRBM_TIMEDELTA) + +/* + * Set of attributes for the equivalent of an nfsv3 pathconf rpc. + * NFSGETATTRBIT_PATHCONF0 - bits 0<->31 + */ +#define NFSGETATTRBIT_PATHCONF0 (NFSATTRBIT_GETATTR0 | \ + NFSATTRBM_CASEINSENSITIVE | \ + NFSATTRBM_CASEPRESERVING | \ + NFSATTRBM_CHOWNRESTRICTED | \ + NFSATTRBM_MAXLINK | \ + NFSATTRBM_MAXNAME) + +/* + * NFSGETATTRBIT_PATHCONF1 - bits 32<->63 + */ +#define NFSGETATTRBIT_PATHCONF1 (NFSATTRBIT_GETATTR1 | \ + NFSATTRBM_NOTRUNC) + +/* + * Sets of attributes required by readdir and readdirplus. + * NFSATTRBIT_READDIRPLUS0 (NFSATTRBIT_GETATTR0 | NFSATTRBIT_FILEHANDLE | + * NFSATTRBIT_RDATTRERROR) + */ +#define NFSATTRBIT_READDIRPLUS0 (NFSATTRBIT_GETATTR0 | NFSATTRBM_FILEHANDLE | \ + NFSATTRBM_RDATTRERROR) +#define NFSATTRBIT_READDIRPLUS1 NFSATTRBIT_GETATTR1 + +/* + * Set of attributes supported by Referral vnodes. + */ +#define NFSATTRBIT_REFERRAL0 (NFSATTRBM_TYPE | NFSATTRBM_FSID | \ + NFSATTRBM_RDATTRERROR | NFSATTRBM_FSLOCATIONS) +#define NFSATTRBIT_REFERRAL1 NFSATTRBM_MOUNTEDONFILEID + +/* + * Structure for data handled by the statfs rpc. Since some fields are + * u_int64_t, this cannot be used for copying data on/off the wire, due + * to alignment concerns. + */ +struct nfsstatfs { + union { + struct { + u_int32_t nfsv2sf_tsize; + u_int32_t nfsv2sf_bsize; + u_int32_t nfsv2sf_blocks; + u_int32_t nfsv2sf_bfree; + u_int32_t nfsv2sf_bavail; + } sf_nfsv2; + struct { + u_int64_t nfsv3sf_tbytes; + u_int64_t nfsv3sf_fbytes; + u_int64_t nfsv3sf_abytes; + u_int64_t nfsv3sf_tfiles; + u_int64_t nfsv3sf_ffiles; + u_int64_t nfsv3sf_afiles; + u_int32_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 + +/* + * Now defined using u_int64_t for the 64 bit field(s). + * (Cannot be used to move data on/off the wire, due to alignment concerns.) + */ +struct nfsfsinfo { + u_int32_t fs_rtmax; + u_int32_t fs_rtpref; + u_int32_t fs_rtmult; + u_int32_t fs_wtmax; + u_int32_t fs_wtpref; + u_int32_t fs_wtmult; + u_int32_t fs_dtpref; + u_int64_t fs_maxfilesize; + struct timespec fs_timedelta; + u_int32_t fs_properties; +}; + +/* + * Bits for fs_properties + */ +#define NFSV3_FSFLINK 0x1 +#define NFSV3_FSFSYMLINK 0x2 +#define NFSV3_FSFHOMOGENEOUS 0x4 +#define NFSV3_FSFCANSETTIME 0x8 + +/* + * Yikes, overload fs_rtmult as fs_maxname for V4. + */ +#define fs_maxname fs_rtmult + +struct nfsv3_pathconf { + u_int32_t pc_linkmax; + u_int32_t pc_namemax; + u_int32_t pc_notrunc; + u_int32_t pc_chownrestricted; + u_int32_t pc_caseinsensitive; + u_int32_t pc_casepreserving; +}; + +/* + * NFS V4 data structures. + */ +struct nfsv4stateid { + u_int32_t seqid; + u_int32_t other[NFSX_STATEIDOTHER / NFSX_UNSIGNED]; +}; +typedef struct nfsv4stateid nfsv4stateid_t; + +#endif /* _NFS_NFSPROTO_H_ */ diff --git a/sys/fs/nfs/nfsrvcache.h b/sys/fs/nfs/nfsrvcache.h new file mode 100644 index 0000000..30f757a --- /dev/null +++ b/sys/fs/nfs/nfsrvcache.h @@ -0,0 +1,107 @@ +/*- + * 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. + * + * $FreeBSD$ + */ + +#ifndef _NFS_NFSRVCACHE_H_ +#define _NFS_NFSRVCACHE_H_ + +/* + * Definitions for the server recent request cache + */ +#define NFSRVCACHE_MAX_SIZE 2048 +#define NFSRVCACHE_MIN_SIZE 64 + +#define NFSRVCACHE_HASHSIZE 20 + +struct nfsrvcache { + LIST_ENTRY(nfsrvcache) rc_hash; /* Hash chain */ + TAILQ_ENTRY(nfsrvcache) rc_lru; /* UDP lru chain */ + u_int32_t rc_xid; /* rpc id number */ + time_t rc_timestamp; /* Time done */ + union { + mbuf_t repmb; /* Reply mbuf list OR */ + int repstat; /* Reply status */ + } rc_un; + union { + struct { + union nethostaddr haddr; /* Host address */ + } udp; + struct { + u_int64_t sockref; + u_int32_t len; + u_int32_t tcpseq; + int16_t refcnt; + u_int16_t cksum; + time_t cachetime; + } ot; + } rc_un2; + u_int16_t rc_proc; /* rpc proc number */ + u_int16_t rc_flag; /* Flag bits */ +}; + +#define rc_reply rc_un.repmb +#define rc_status rc_un.repstat +#define rc_inet rc_un2.udp.haddr.had_inet.s_addr +#define rc_inet6 rc_un2.udp.haddr.had_inet6 +#define rc_haddr rc_un2.udp.haddr +#define rc_sockref rc_un2.ot.sockref +#define rc_tcpseq rc_un2.ot.tcpseq +#define rc_refcnt rc_un2.ot.refcnt +#define rc_reqlen rc_un2.ot.len +#define rc_cksum rc_un2.ot.cksum +#define rc_cachetime rc_un2.ot.cachetime + +/* Return values */ +#define RC_DROPIT 0 +#define RC_REPLY 1 +#define RC_DOIT 2 + +/* Flag bits */ +#define RC_LOCKED 0x0001 +#define RC_WANTED 0x0002 +#define RC_REPSTATUS 0x0004 +#define RC_REPMBUF 0x0008 +#define RC_UDP 0x0010 +#define RC_INETIPV6 0x0020 +#define RC_INPROG 0x0040 +#define RC_TCPSEQ 0x0080 +#define RC_NFSV2 0x0100 +#define RC_NFSV3 0x0200 +#define RC_NFSV4 0x0400 +#define RC_NFSVERS (RC_NFSV2 | RC_NFSV3 | RC_NFSV4) +#define RC_REFCNT 0x0800 +#define RC_SAMETCPCONN 0x1000 + +LIST_HEAD(nfsrvhashhead, nfsrvcache); + +#endif /* _NFS_NFSRVCACHE_H_ */ diff --git a/sys/fs/nfs/nfsrvstate.h b/sys/fs/nfs/nfsrvstate.h new file mode 100644 index 0000000..629b18c --- /dev/null +++ b/sys/fs/nfs/nfsrvstate.h @@ -0,0 +1,235 @@ +/*- + * Copyright (c) 2009 Rick Macklem, University of Guelph + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#ifndef _NFS_NFSRVSTATE_H_ +#define _NFS_NFSRVSTATE_H_ + +/* + * Definitions for NFS V4 server state handling. + */ + +/* + * List heads for nfsclient, nfsstate and nfslockfile. + * (Some systems seem to like to dynamically size these things, but I + * don't see any point in doing so for these ones.) + */ +LIST_HEAD(nfsclienthashhead, nfsclient); +LIST_HEAD(nfsstatehead, nfsstate); +LIST_HEAD(nfslockhead, nfslock); +LIST_HEAD(nfslockhashhead, nfslockfile); + +/* + * List head for nfsusrgrp. + */ +LIST_HEAD(nfsuserhashhead, nfsusrgrp); +TAILQ_HEAD(nfsuserlruhead, nfsusrgrp); + +#define NFSCLIENTHASH(id) \ + (&nfsclienthash[(id).lval[1] % NFSCLIENTHASHSIZE]) +#define NFSSTATEHASH(clp, id) \ + (&((clp)->lc_stateid[(id).other[2] % NFSSTATEHASHSIZE])) +#define NFSUSERHASH(id) \ + (&nfsuserhash[(id) % NFSUSERHASHSIZE]) +#define NFSUSERNAMEHASH(p, l) \ + (&nfsusernamehash[((l)>=4?(*(p)+*((p)+1)+*((p)+2)+*((p)+3)):*(p)) \ + % NFSUSERHASHSIZE]) +#define NFSGROUPHASH(id) \ + (&nfsgrouphash[(id) % NFSGROUPHASHSIZE]) +#define NFSGROUPNAMEHASH(p, l) \ + (&nfsgroupnamehash[((l)>=4?(*(p)+*((p)+1)+*((p)+2)+*((p)+3)):*(p)) \ + % NFSGROUPHASHSIZE]) + +/* + * Client server structure for V4. It is doubly linked into two lists. + * The first is a hash table based on the clientid and the second is a + * list of all clients maintained in LRU order. + * The actual size malloc'd is large enough to accomodate the id string. + */ +struct nfsclient { + LIST_ENTRY(nfsclient) lc_hash; /* Clientid hash list */ + struct nfsstatehead lc_stateid[NFSSTATEHASHSIZE]; /* stateid hash */ + struct nfsstatehead lc_open; /* Open owner list */ + struct nfsstatehead lc_deleg; /* Delegations */ + struct nfsstatehead lc_olddeleg; /* and old delegations */ + time_t lc_expiry; /* Expiry time (sec) */ + time_t lc_delegtime; /* Old deleg expiry (sec) */ + nfsquad_t lc_clientid; /* 64 bit clientid */ + nfsquad_t lc_confirm; /* 64 bit confirm value */ + u_int32_t lc_program; /* RPC Program # */ + u_int32_t lc_callback; /* Callback id */ + u_int32_t lc_stateindex; /* Current state index# */ + u_int32_t lc_statemaxindex; /* Max state index# */ + u_int32_t lc_cbref; /* Cnt of callbacks */ + uid_t lc_uid; /* User credential */ + gid_t lc_gid; + u_int16_t lc_namelen; + u_char *lc_name; + struct nfssockreq lc_req; /* Callback info */ + u_short lc_idlen; /* Length of id string */ + u_int32_t lc_flags; /* LCL_ flag bits */ + u_char lc_verf[NFSX_VERF]; /* client verifier */ + u_char lc_id[1]; /* Malloc'd correct size */ +}; + +#define CLOPS_CONFIRM 0x0001 +#define CLOPS_RENEW 0x0002 +#define CLOPS_RENEWOP 0x0004 + +/* + * Nfs state structure. I couldn't resist overloading this one, since + * it makes cleanup, etc. simpler. These structures are used in four ways: + * - open_owner structures chained off of nfsclient + * - open file structures chained off an open_owner structure + * - lock_owner structures chained off an open file structure + * - delegated file structures chained off of nfsclient and nfslockfile + * - the ls_list field is used for the chain it is in + * - the ls_head structure is used to chain off the sibling structure + * (it is a union between an nfsstate and nfslock structure head) + * If it is a lockowner stateid, nfslock structures hang off it. + * For the open file and lockowner cases, it is in the hash table in + * nfsclient for stateid. + */ +struct nfsstate { + LIST_ENTRY(nfsstate) ls_hash; /* Hash list entry */ + LIST_ENTRY(nfsstate) ls_list; /* List of opens/delegs */ + LIST_ENTRY(nfsstate) ls_file; /* Opens/Delegs for a file */ + union { + struct nfsstatehead open; /* Opens list */ + struct nfslockhead lock; /* Locks list */ + } ls_head; + nfsv4stateid_t ls_stateid; /* The state id */ + u_int32_t ls_seq; /* seq id */ + uid_t ls_uid; /* uid of locker */ + u_int32_t ls_flags; /* Type of lock, etc. */ + union { + struct nfsstate *openowner; /* Open only */ + u_int32_t opentolockseq; /* Lock call only */ + u_int32_t noopens; /* Openowner only */ + struct { + u_quad_t filerev; /* Delegations only */ + time_t expiry; + time_t limit; + u_int64_t compref; + } deleg; + } ls_un; + struct nfslockfile *ls_lfp; /* Back pointer */ + struct nfsrvcache *ls_op; /* Op cache reference */ + struct nfsclient *ls_clp; /* Back pointer */ + u_short ls_ownerlen; /* Length of ls_owner */ + u_char ls_owner[1]; /* malloc'd the correct size */ +}; +#define ls_lock ls_head.lock +#define ls_open ls_head.open +#define ls_opentolockseq ls_un.opentolockseq +#define ls_openowner ls_un.openowner +#define ls_openstp ls_un.openowner +#define ls_noopens ls_un.noopens +#define ls_filerev ls_un.deleg.filerev +#define ls_delegtime ls_un.deleg.expiry +#define ls_delegtimelimit ls_un.deleg.limit +#define ls_compref ls_un.deleg.compref + +/* + * Nfs lock structure. + * This structure is chained off of the nfsstate (the lockowner) and + * nfslockfile (the file) structures, for the file and owner it + * refers to. It holds flags and a byte range. + * It also has back pointers to the associated lock_owner and lockfile. + */ +struct nfslock { + LIST_ENTRY(nfslock) lo_lckowner; + LIST_ENTRY(nfslock) lo_lckfile; + struct nfsstate *lo_stp; + struct nfslockfile *lo_lfp; + u_int64_t lo_first; + u_int64_t lo_end; + u_int32_t lo_flags; +}; + +/* + * Structure used to return a conflicting lock. (Must be large + * enough for the largest lock owner we can have.) + */ +struct nfslockconflict { + nfsquad_t cl_clientid; + u_int64_t cl_first; + u_int64_t cl_end; + u_int32_t cl_flags; + u_short cl_ownerlen; + u_char cl_owner[NFSV4_OPAQUELIMIT]; +}; + +/* + * This structure refers to a file for which lock(s) and/or open(s) exist. + * Searched via hash table on file handle or found via the back pointer from an + * open or lock owner. + */ +struct nfslockfile { + LIST_HEAD(, nfsstate) lf_open; /* Open list */ + LIST_HEAD(, nfsstate) lf_deleg; /* Delegation list */ + LIST_HEAD(, nfslock) lf_lock; /* Lock list */ + LIST_ENTRY(nfslockfile) lf_hash; /* Hash list entry */ + fhandle_t lf_fh; /* The file handle */ +}; + +/* + * This structure is malloc'd an chained off hash lists for user/group + * names. + */ +struct nfsusrgrp { + TAILQ_ENTRY(nfsusrgrp) lug_lru; /* LRU list */ + LIST_ENTRY(nfsusrgrp) lug_numhash; /* Hash by id# */ + LIST_ENTRY(nfsusrgrp) lug_namehash; /* and by name */ + time_t lug_expiry; /* Expiry time in sec */ + union { + uid_t un_uid; /* id# */ + gid_t un_gid; + } lug_un; + int lug_namelen; /* Name length */ + u_char lug_name[1]; /* malloc'd correct length */ +}; +#define lug_uid lug_un.un_uid +#define lug_gid lug_un.un_gid + +/* + * These structures are used for the stable storage restart stuff. + */ +/* + * Record at beginning of file. + */ +struct nfsf_rec { + u_int32_t lease; /* Lease duration */ + u_int32_t numboots; /* Number of boottimes */ +}; + +#if defined(_KERNEL) || defined(KERNEL) +void nfsrv_cleanclient(struct nfsclient *, NFSPROC_T *); +void nfsrv_freedeleglist(struct nfsstatehead *); +#endif + +#endif /* _NFS_NFSRVSTATE_H_ */ diff --git a/sys/fs/nfs/nfsv4_errstr.h b/sys/fs/nfs/nfsv4_errstr.h new file mode 100644 index 0000000..4f6460d --- /dev/null +++ b/sys/fs/nfs/nfsv4_errstr.h @@ -0,0 +1,101 @@ +/*- + * Copyright (c) 2009 Rick Macklem, University of Guelph + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#ifndef _NFS_NFSV4ERRSTR_H_ +#define _NFS_NFSV4ERRSTR_H_ + +/* + * Defines static storage in the C file, but I can't be bothered creating + * a library of one function for this, since it is only currently used by + * mount_newnfs.c. + */ +static const char *nfsv4_errstr[48] = { + "Illegal filehandle", + "Undefined NFSv4 err", + "READDIR cookie is stale", + "operation not supported", + "response limit exceeded", + "undefined server error", + "type invalid for CREATE", + "file busy - retry", + "nverify says attrs same", + "lock unavailable", + "lock lease expired", + "I/O failed due to lock", + "in grace period", + "filehandle expired", + "share reserve denied", + "wrong security flavor", + "clientid in use", + "resource exhaustion", + "filesystem relocated", + "current FH is not set", + "minor vers not supp", + "server has rebooted", + "server has rebooted", + "state is out of sync", + "incorrect stateid", + "request is out of seq", + "verify - attrs not same", + "lock range not supported", + "should be file/directory", + "no saved filehandle", + "some filesystem moved", + "recommended attr not sup", + "reclaim outside of grace", + "reclaim error at server", + "conflict on reclaim", + "XDR decode failed", + "file locks held at CLOSE", + "conflict in OPEN and I/O", + "owner translation bad", + "utf-8 char not supported", + "name not supported", + "lock range not supported", + "no atomic up/downgrade", + "undefined operation", + "file locking deadlock", + "open file blocks op", + "lockowner state revoked", + "callback path down" +}; + +/* + * Return the error string for the NFS4ERR_xxx. The pointers returned are + * static and must not be free'd. + */ +static const char * +nfsv4_geterrstr(int errval) +{ + + if (errval < NFSERR_BADHANDLE || errval > NFSERR_CBPATHDOWN) + return (NULL); + return (nfsv4_errstr[errval - NFSERR_BADHANDLE]); +} + +#endif /* _NFS_NFSV4ERRSTR_H_ */ diff --git a/sys/fs/nfs/rpcv2.h b/sys/fs/nfs/rpcv2.h new file mode 100644 index 0000000..d2174ac --- /dev/null +++ b/sys/fs/nfs/rpcv2.h @@ -0,0 +1,207 @@ +/*- + * 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. + * + * $FreeBSD$ + */ + +#ifndef _NFS_RPCV2_H_ +#define _NFS_RPCV2_H_ + +/* + * Definitions for Sun RPC Version 2, from + * "RPC: Remote Procedure Call Protocol Specification" RFC1057 + */ + +/* Version # */ +#define RPC_VER2 2 + +/* Authentication flavours */ +#define RPCAUTH_NULL 0 +#define RPCAUTH_UNIX 1 +#define RPCAUTH_SHORT 2 +#define RPCAUTH_KERB4 4 +#define RPCAUTH_GSS 6 +#define RPCAUTH_GSSKRB5 390003 +#define RPCAUTH_GSSKRB5INTEGRITY 390004 +#define RPCAUTH_GSSKRB5PRIVACY 390005 + +#define RPCAUTH_MAXSIZ 400 +#define RPCVERF_MAXSIZ 12 /* For Kerb, can actually be 400 */ + +/* + * RPCAUTH_UNIX defs. + */ +#define RPCAUTHUNIX_MINSIZ (5 * NFSX_UNSIGNED) +#define RPCAUTH_UNIXGIDS 16 + +/* + * RPCAUTH_GSS defs. + */ +#define RPCAUTHGSS_VERS1 1 + +#define RPCAUTHGSS_DATA 0 +#define RPCAUTHGSS_INIT 1 +#define RPCAUTHGSS_CONTINIT 2 +#define RPCAUTHGSS_DESTROY 3 + +#define RPCAUTHGSS_SVCNONE 1 +#define RPCAUTHGSS_SVCINTEGRITY 2 +#define RPCAUTHGSS_SVCPRIVACY 3 + +#define RPCAUTHGSS_MAXSEQ 0x80000000 + +#define RPCAUTHGSS_WINDOW 64 /* # of bits in u_int64_t */ +#define RPCAUTHGSS_SEQWINDOW (RPCAUTHGSS_WINDOW + 1) + +#define RPCAUTHGSS_MIC 1 +#define RPCAUTHGSS_WRAP 2 + +/* + * Qop values for the types of security services. + */ +#define GSS_KERBV_QOP 0 + +/* + * Sizes of GSS stuff. + */ +#define RPCGSS_KEYSIZ 8 + +#define GSSX_AUTHHEAD (5 * NFSX_UNSIGNED) +#define GSSX_MYHANDLE (sizeof (long) + sizeof (u_int64_t)) +#define GSSX_RPCHEADER (13 * NFSX_UNSIGNED + GSSX_MYHANDLE) +#define GSSX_MINWRAP (2 * NFSX_UNSIGNED) +#define GSSX_KERBVTOKEN 24 +#define GSSX_LOCALHANDLE (sizeof (void *)) + +/* + * Stuff for the gssd. + */ +#define RPCPROG_GSSD 0x20101010 +#define RPCGSSD_VERS 1 +#define RPCGSSD_INIT 1 +#define RPCGSSD_CONTINIT 2 +#define RPCGSSD_CONTINITDESTROY 3 +#define RPCGSSD_CLINIT 4 +#define RPCGSSD_CLINITUID 5 +#define RPCGSSD_CLCONT 6 +#define RPCGSSD_CLCONTUID 7 +#define RPCGSSD_CLINITNAME 8 +#define RPCGSSD_CLCONTNAME 9 + +/* + * Stuff for the nfsuserd + */ +#define RPCPROG_NFSUSERD 0x21010101 +#define RPCNFSUSERD_VERS 1 +#define RPCNFSUSERD_GETUID 1 +#define RPCNFSUSERD_GETGID 2 +#define RPCNFSUSERD_GETUSER 3 +#define RPCNFSUSERD_GETGROUP 4 + +/* + * Some major status codes. + */ +#if !defined(_GSSAPI_H_) && !defined(GSSAPI_H_) && !defined(_GSSAPI_GSSAPI_H_) && !defined(_RPCSEC_GSS_H) +#define GSS_S_COMPLETE 0x00000000 +#define GSS_S_CONTINUE_NEEDED 0x00000001 +#define GSS_S_DUPLICATE_TOKEN 0x00000002 +#define GSS_S_OLD_TOKEN 0x00000004 +#define GSS_S_UNSEQ_TOKEN 0x00000008 +#define GSS_S_GAP_TOKEN 0x00000010 +#define GSS_S_BAD_MECH 0x00010000 +#define GSS_S_BAD_NAME 0x00020000 +#define GSS_S_BAD_NAMETYPE 0x00030000 +#define GSS_S_BAD_BINDINGS 0x00040000 +#define GSS_S_BAD_STATUS 0x00050000 +#define GSS_S_BAD_MIC 0x00060000 +#define GSS_S_BAD_SIG 0x00060000 +#define GSS_S_NO_CRED 0x00070000 +#define GSS_S_NO_CONTEXT 0x00080000 +#define GSS_S_DEFECTIVE_TOKEN 0x00090000 +#define GSS_S_DEFECTIVE_CREDENTIAL 0x000a0000 +#define GSS_S_CREDENTIALS_EXPIRED 0x000b0000 +#define GSS_S_CONTEXT_EXPIRED 0x000c0000 +#define GSS_S_FAILURE 0x000d0000 +#define GSS_S_BAD_QOP 0x000e0000 +#define GSS_S_UNAUTHORIZED 0x000f0000 +#define GSS_S_UNAVAILABLE 0x00100000 +#define GSS_S_DUPLICATE_ELEMENT 0x00110000 +#define GSS_S_NAME_NOT_MN 0x00120000 +#define GSS_S_CALL_INACCESSIBLE_READ 0x01000000 +#define GSS_S_CALL_INACCESSIBLE_WRITE 0x02000000 +#define GSS_S_CALL_BAD_STRUCTURE 0x03000000 +#endif /* _GSSAPI_H_ */ + +/* Rpc Constants */ +#define RPC_CALL 0 +#define RPC_REPLY 1 +#define RPC_MSGACCEPTED 0 +#define RPC_MSGDENIED 1 +#define RPC_PROGUNAVAIL 1 +#define RPC_PROGMISMATCH 2 +#define RPC_PROCUNAVAIL 3 +#define RPC_GARBAGE 4 /* I like this one */ +#define RPC_MISMATCH 0 +#define RPC_AUTHERR 1 + +/* Authentication failures */ +#define AUTH_BADCRED 1 +#define AUTH_REJECTCRED 2 +#define AUTH_BADVERF 3 +#define AUTH_REJECTVERF 4 +#define AUTH_TOOWEAK 5 /* Give em wheaties */ +#define AUTH_PROBCRED 13 +#define AUTH_CTXCRED 14 + +/* Sizes of rpc header parts */ +#define RPC_SIZ 24 +#define RPC_REPLYSIZ 28 + +/* RPC Prog definitions */ +#define RPCPROG_MNT 100005 +#define RPCMNT_VER1 1 +#define RPCMNT_VER3 3 +#define RPCMNT_MOUNT 1 +#define RPCMNT_DUMP 2 +#define RPCMNT_UMOUNT 3 +#define RPCMNT_UMNTALL 4 +#define RPCMNT_EXPORT 5 +#define RPCMNT_NAMELEN 255 +#define RPCMNT_PATHLEN 1024 +#define RPCPROG_NFS 100003 + +/* Structs for common parts of the rpc's */ +struct rpcv2_time { + u_int32_t rpc_sec; + u_int32_t rpc_usec; +}; + +#endif /* _NFS_RPCV2_H_ */ diff --git a/sys/fs/nfs/xdr_subs.h b/sys/fs/nfs/xdr_subs.h new file mode 100644 index 0000000..a3e69f9 --- /dev/null +++ b/sys/fs/nfs/xdr_subs.h @@ -0,0 +1,99 @@ +/*- + * 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. + * + * $FreeBSD$ + */ + +#ifndef _NFS_XDR_SUBS_H_ +#define _NFS_XDR_SUBS_H_ + +/* + * Macros used for conversion to/from xdr representation by nfs... + * These use the MACHINE DEPENDENT routines ntohl, htonl + * As defined by "XDR: External Data Representation Standard" RFC1014 + * + * To simplify the implementation, we use ntohl/htonl even on big-endian + * machines, and count on them being `#define'd away. Some of these + * might be slightly more efficient as quad_t copies on a big-endian, + * but we cannot count on their alignment anyway. + */ + +#define fxdr_unsigned(t, v) ((t)ntohl((int32_t)(v))) +#define txdr_unsigned(v) (htonl((int32_t)(v))) + +#define fxdr_nfsv2time(f, t) do { \ + (t)->tv_sec = ntohl(((struct nfsv2_time *)(f))->nfsv2_sec); \ + if (((struct nfsv2_time *)(f))->nfsv2_usec != 0xffffffff) \ + (t)->tv_nsec = 1000 * ntohl(((struct nfsv2_time *)(f))->nfsv2_usec); \ + else \ + (t)->tv_nsec = 0; \ + } while (0) + +#define txdr_nfsv2time(f, t) do { \ + ((struct nfsv2_time *)(t))->nfsv2_sec = htonl((f)->tv_sec); \ + if ((f)->tv_nsec != -1) \ + ((struct nfsv2_time *)(t))->nfsv2_usec = htonl((f)->tv_nsec / 1000); \ + else \ + ((struct nfsv2_time *)(t))->nfsv2_usec = 0xffffffff; \ + } while (0) + +#define fxdr_nfsv3time(f, t) do { \ + (t)->tv_sec = ntohl(((struct nfsv3_time *)(f))->nfsv3_sec); \ + (t)->tv_nsec = ntohl(((struct nfsv3_time *)(f))->nfsv3_nsec); \ + } while (0) + +#define txdr_nfsv3time(f, t) do { \ + ((struct nfsv3_time *)(t))->nfsv3_sec = htonl((f)->tv_sec); \ + ((struct nfsv3_time *)(t))->nfsv3_nsec = htonl((f)->tv_nsec); \ + } while (0) + +#define fxdr_nfsv4time(f, t) do { \ + (t)->tv_sec = ntohl(((struct nfsv4_time *)(f))->nfsv4_sec); \ + (t)->tv_nsec = (ntohl(((struct nfsv4_time *)(f))->nfsv4_nsec) % \ + 1000000000); \ + } while (0) + +#define txdr_nfsv4time(f, t) do { \ + ((struct nfsv4_time *)(t))->nfsv4_highsec = 0; \ + ((struct nfsv4_time *)(t))->nfsv4_sec = htonl((f)->tv_sec); \ + ((struct nfsv4_time *)(t))->nfsv4_nsec = htonl((f)->tv_nsec); \ + } while (0) + +#define fxdr_hyper(f) \ + ((((u_quad_t)ntohl(((u_int32_t *)(f))[0])) << 32) | \ + (u_quad_t)(ntohl(((u_int32_t *)(f))[1]))) + +#define txdr_hyper(f, t) do { \ + ((u_int32_t *)(t))[0] = htonl((u_int32_t)((f) >> 32)); \ + ((u_int32_t *)(t))[1] = htonl((u_int32_t)((f) & 0xffffffff)); \ + } while (0) + +#endif /* _NFS_XDR_SUBS_H_ */ |