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)
This commit is contained in:
Rick Macklem 2009-05-04 15:23:58 +00:00
parent 3382ac3233
commit 9ec7b004d0
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=191783
44 changed files with 44521 additions and 0 deletions

704
sys/fs/nfs/nfs.h Normal file
View File

@ -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 */

750
sys/fs/nfs/nfs_commonacl.c Normal file
View File

@ -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 */

901
sys/fs/nfs/nfs_commonkrpc.c Normal file
View File

@ -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);
}

486
sys/fs/nfs/nfs_commonport.c Normal file
View File

@ -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);

3404
sys/fs/nfs/nfs_commonsubs.c Normal file

File diff suppressed because it is too large Load Diff

604
sys/fs/nfs/nfs_var.h Normal file
View File

@ -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 *);

71
sys/fs/nfs/nfscl.h Normal file
View File

@ -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 */

175
sys/fs/nfs/nfsclstate.h Normal file
View File

@ -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_ */

105
sys/fs/nfs/nfsdport.h Normal file
View File

@ -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))

73
sys/fs/nfs/nfskpiport.h Normal file
View File

@ -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 */

129
sys/fs/nfs/nfsm_subs.h Normal file
View File

@ -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_ */

751
sys/fs/nfs/nfsport.h Normal file
View File

@ -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 */

1129
sys/fs/nfs/nfsproto.h Normal file

File diff suppressed because it is too large Load Diff

107
sys/fs/nfs/nfsrvcache.h Normal file
View File

@ -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_ */

235
sys/fs/nfs/nfsrvstate.h Normal file
View File

@ -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_ */

101
sys/fs/nfs/nfsv4_errstr.h Normal file
View File

@ -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_ */

207
sys/fs/nfs/rpcv2.h Normal file
View File

@ -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_ */

99
sys/fs/nfs/xdr_subs.h Normal file
View File

@ -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_ */

95
sys/fs/nfsclient/nfs.h Normal file
View File

@ -0,0 +1,95 @@
/*-
* 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 _NFSCLIENT_NFS_H_
#define _NFSCLIENT_NFS_H_
#if defined(_KERNEL)
#ifndef NFS_TPRINTF_INITIAL_DELAY
#define NFS_TPRINTF_INITIAL_DELAY 12
#endif
#ifndef NFS_TPRINTF_DELAY
#define NFS_TPRINTF_DELAY 30
#endif
/*
* Nfs version macros.
*/
#define NFS_ISV3(v) \
(VFSTONFS((v)->v_mount)->nm_flag & NFSMNT_NFSV3)
#define NFS_ISV4(v) \
(VFSTONFS((v)->v_mount)->nm_flag & NFSMNT_NFSV4)
#define NFS_ISV34(v) \
(VFSTONFS((v)->v_mount)->nm_flag & (NFSMNT_NFSV3 | NFSMNT_NFSV4))
/*
* Function prototypes.
*/
int ncl_meta_setsize(struct vnode *, struct ucred *, struct thread *,
u_quad_t);
void ncl_doio_directwrite(struct buf *);
int ncl_bioread(struct vnode *, struct uio *, int, struct ucred *);
int ncl_biowrite(struct vnode *, struct uio *, int, struct ucred *);
int ncl_vinvalbuf(struct vnode *, int, struct thread *, int);
int ncl_asyncio(struct nfsmount *, struct buf *, struct ucred *,
struct thread *);
int ncl_doio(struct vnode *, struct buf *, struct ucred *, struct thread *);
int ncl_msleep(struct thread *, void *, struct mtx *, int, char *, int);
void ncl_nhinit(void);
void ncl_nhuninit(void);
void ncl_nodelock(struct nfsnode *);
void ncl_nodeunlock(struct nfsnode *);
int ncl_getattrcache(struct vnode *, struct vattr *);
int ncl_readrpc(struct vnode *, struct uio *, struct ucred *);
int ncl_writerpc(struct vnode *, struct uio *, struct ucred *, int *, int *);
int ncl_readlinkrpc(struct vnode *, struct uio *, struct ucred *);
int ncl_readdirrpc(struct vnode *, struct uio *, struct ucred *,
struct thread *);
int ncl_readdirplusrpc(struct vnode *, struct uio *, struct ucred *,
struct thread *);
int ncl_writebp(struct buf *, int, struct thread *);
int ncl_commit(struct vnode *, u_quad_t, int, struct ucred *, struct thread *);
void ncl_clearcommit(struct mount *);
int ncl_fsinfo(struct nfsmount *, struct vnode *, struct ucred *,
struct thread *);
int ncl_init(struct vfsconf *);
int ncl_uninit(struct vfsconf *);
int ncl_mountroot(struct mount *, struct thread *);
int ncl_nfsiodnew(void);
#endif /* _KERNEL */
#endif /* _NFSCLIENT_NFS_H_ */

1934
sys/fs/nfsclient/nfs_clbio.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,521 @@
/*-
* 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>
extern struct nfsstats newnfsstats;
extern struct nfsv4_opflag nfsv4_opflag[NFSV4OP_NOPS];
extern int ncl_mbuf_mlen;
extern enum vtype newnv2tov_type[8];
extern enum vtype nv34tov_type[8];
NFSCLSTATEMUTEX;
#endif /* !APPLEKEXT */
static nfsuint64 nfs_nullcookie = {{ 0, 0 }};
static struct {
int op;
int opcnt;
const u_char *tag;
int taglen;
} nfsv4_opmap[NFS_NPROCS] = {
{ 0, 1, "Null", 4 },
{ NFSV4OP_GETATTR, 1, "Getattr", 7, },
{ NFSV4OP_SETATTR, 2, "Setattr", 7, },
{ NFSV4OP_LOOKUP, 3, "Lookup", 6, },
{ NFSV4OP_ACCESS, 2, "Access", 6, },
{ NFSV4OP_READLINK, 2, "Readlink", 8, },
{ NFSV4OP_READ, 1, "Read", 4, },
{ NFSV4OP_WRITE, 2, "Write", 5, },
{ NFSV4OP_OPEN, 3, "Open", 4, },
{ NFSV4OP_CREATE, 3, "Create", 6, },
{ NFSV4OP_CREATE, 1, "Create", 6, },
{ NFSV4OP_CREATE, 3, "Create", 6, },
{ NFSV4OP_REMOVE, 1, "Remove", 6, },
{ NFSV4OP_REMOVE, 1, "Remove", 6, },
{ NFSV4OP_SAVEFH, 5, "Rename", 6, },
{ NFSV4OP_SAVEFH, 4, "Link", 4, },
{ NFSV4OP_READDIR, 2, "Readdir", 7, },
{ NFSV4OP_READDIR, 2, "Readdir", 7, },
{ NFSV4OP_GETATTR, 1, "Getattr", 7, },
{ NFSV4OP_GETATTR, 1, "Getattr", 7, },
{ NFSV4OP_GETATTR, 1, "Getattr", 7, },
{ NFSV4OP_COMMIT, 2, "Commit", 6, },
{ NFSV4OP_LOOKUPP, 3, "Lookupp", 7, },
{ NFSV4OP_SETCLIENTID, 1, "SetClientID", 11, },
{ NFSV4OP_SETCLIENTIDCFRM, 1, "SetClientIDConfirm", 18, },
{ NFSV4OP_LOCK, 1, "Lock", 4, },
{ NFSV4OP_LOCKU, 1, "LockU", 5, },
{ NFSV4OP_OPEN, 2, "Open", 4, },
{ NFSV4OP_CLOSE, 1, "Close", 5, },
{ NFSV4OP_OPENCONFIRM, 1, "Openconfirm", 11, },
{ NFSV4OP_LOCKT, 1, "LockT", 5, },
{ NFSV4OP_OPENDOWNGRADE, 1, "Opendowngrade", 13, },
{ NFSV4OP_RENEW, 1, "Renew", 5, },
{ NFSV4OP_PUTROOTFH, 1, "Dirpath", 7, },
{ NFSV4OP_RELEASELCKOWN, 1, "Rellckown", 9, },
{ NFSV4OP_DELEGRETURN, 1, "Delegret", 8, },
{ NFSV4OP_DELEGRETURN, 3, "DelegRemove", 11, },
{ NFSV4OP_DELEGRETURN, 7, "DelegRename1", 12, },
{ NFSV4OP_DELEGRETURN, 9, "DelegRename2", 12, },
{ NFSV4OP_GETATTR, 1, "Getacl", 6, },
{ NFSV4OP_SETATTR, 1, "Setacl", 6, },
};
/*
* NFS RPCS that have large request message size.
*/
static int nfs_bigrequest[NFS_NPROCS] = {
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
/*
* Start building a request. Mostly just put the first file handle in
* place.
*/
APPLESTATIC void
nfscl_reqstart(struct nfsrv_descript *nd, int procnum, struct nfsmount *nmp,
u_int8_t *nfhp, int fhlen, u_int32_t **opcntpp)
{
struct mbuf *mb;
u_int32_t *tl;
int opcnt;
nfsattrbit_t attrbits;
/*
* First, fill in some of the fields of nd.
*/
if (NFSHASNFSV4(nmp))
nd->nd_flag = ND_NFSV4;
else if (NFSHASNFSV3(nmp))
nd->nd_flag = ND_NFSV3;
else
nd->nd_flag = ND_NFSV2;
nd->nd_procnum = procnum;
nd->nd_repstat = 0;
/*
* Get the first mbuf for the request.
*/
if (nfs_bigrequest[procnum])
NFSMCLGET(mb, M_WAIT);
else
NFSMGET(mb);
mbuf_setlen(mb, 0);
nd->nd_mreq = nd->nd_mb = mb;
nd->nd_bpos = NFSMTOD(mb, caddr_t);
/*
* And fill the first file handle into the request.
*/
if (nd->nd_flag & ND_NFSV4) {
opcnt = nfsv4_opmap[procnum].opcnt +
nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh;
/*
* What should the tag really be?
*/
(void) nfsm_strtom(nd, nfsv4_opmap[procnum].tag,
nfsv4_opmap[procnum].taglen);
NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
*tl++ = txdr_unsigned(NFSV4_MINORVERSION);
if (opcntpp != NULL)
*opcntpp = tl;
*tl++ = txdr_unsigned(opcnt);
if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh > 0) {
*tl = txdr_unsigned(NFSV4OP_PUTFH);
(void) nfsm_fhtom(nd, nfhp, fhlen, 0);
if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh==2){
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
*tl = txdr_unsigned(NFSV4OP_GETATTR);
NFSWCCATTR_ATTRBIT(&attrbits);
(void) nfsrv_putattrbit(nd, &attrbits);
nd->nd_flag |= ND_V4WCCATTR;
}
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
}
*tl = txdr_unsigned(nfsv4_opmap[procnum].op);
} else {
(void) nfsm_fhtom(nd, nfhp, fhlen, 0);
}
NFSINCRGLOBAL(newnfsstats.rpccnt[procnum]);
}
#ifndef APPLE
/*
* copies a uio scatter/gather list to an mbuf chain.
* NOTE: can ony handle iovcnt == 1
*/
APPLESTATIC void
nfsm_uiombuf(struct nfsrv_descript *nd, struct uio *uiop, int siz)
{
char *uiocp;
struct mbuf *mp, *mp2;
int xfer, left, mlen;
int uiosiz, clflg, rem;
char *cp, *tcp;
#ifdef DIAGNOSTIC
if (uiop->uio_iovcnt != 1)
panic("nfsm_uiotombuf: iovcnt != 1");
#endif
if (siz > ncl_mbuf_mlen) /* or should it >= MCLBYTES ?? */
clflg = 1;
else
clflg = 0;
rem = NFSM_RNDUP(siz) - siz;
mp = mp2 = nd->nd_mb;
while (siz > 0) {
left = uiop->uio_iov->iov_len;
uiocp = uiop->uio_iov->iov_base;
if (left > siz)
left = siz;
uiosiz = left;
while (left > 0) {
mlen = M_TRAILINGSPACE(mp);
if (mlen == 0) {
if (clflg)
NFSMCLGET(mp, M_WAIT);
else
NFSMGET(mp);
mbuf_setlen(mp, 0);
mbuf_setnext(mp2, mp);
mp2 = mp;
mlen = M_TRAILINGSPACE(mp);
}
xfer = (left > mlen) ? mlen : left;
#ifdef notdef
/* Not Yet.. */
if (uiop->uio_iov->iov_op != NULL)
(*(uiop->uio_iov->iov_op))
(uiocp, NFSMTOD(mp, caddr_t) + mbuf_len(mp),
xfer);
else
#endif
if (uiop->uio_segflg == UIO_SYSSPACE)
NFSBCOPY(uiocp, NFSMTOD(mp, caddr_t) + mbuf_len(mp),
xfer);
else
copyin(CAST_USER_ADDR_T(uiocp), NFSMTOD(mp, caddr_t)
+ mbuf_len(mp), xfer);
mbuf_setlen(mp, mbuf_len(mp) + xfer);
left -= xfer;
uiocp += xfer;
uiop->uio_offset += xfer;
uiop->uio_resid -= xfer;
}
tcp = (char *)uiop->uio_iov->iov_base;
tcp += uiosiz;
uiop->uio_iov->iov_base = (void *)tcp;
uiop->uio_iov->iov_len -= uiosiz;
siz -= uiosiz;
}
if (rem > 0) {
if (rem > M_TRAILINGSPACE(mp)) {
NFSMGET(mp);
mbuf_setlen(mp, 0);
mbuf_setnext(mp2, mp);
}
cp = NFSMTOD(mp, caddr_t) + mbuf_len(mp);
for (left = 0; left < rem; left++)
*cp++ = '\0';
mbuf_setlen(mp, mbuf_len(mp) + rem);
nd->nd_bpos = cp;
} else
nd->nd_bpos = NFSMTOD(mp, caddr_t) + mbuf_len(mp);
nd->nd_mb = mp;
}
#endif /* !APPLE */
/*
* Load vnode attributes from the xdr file attributes.
* Returns EBADRPC if they can't be parsed, 0 otherwise.
*/
APPLESTATIC int
nfsm_loadattr(struct nfsrv_descript *nd, struct nfsvattr *nap)
{
struct nfs_fattr *fp;
int error = 0;
if (nd->nd_flag & ND_NFSV4) {
error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, NULL,
NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL);
} else if (nd->nd_flag & ND_NFSV3) {
NFSM_DISSECT(fp, struct nfs_fattr *, NFSX_V3FATTR);
nap->na_type = nfsv34tov_type(fp->fa_type);
nap->na_mode = fxdr_unsigned(u_short, fp->fa_mode);
nap->na_rdev = makedev(fxdr_unsigned(u_char, fp->fa3_rdev.specdata1),
fxdr_unsigned(u_char, fp->fa3_rdev.specdata2));
nap->na_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
nap->na_uid = fxdr_unsigned(uid_t, fp->fa_uid);
nap->na_gid = fxdr_unsigned(gid_t, fp->fa_gid);
nap->na_size = fxdr_hyper(&fp->fa3_size);
nap->na_blocksize = NFS_FABLKSIZE;
nap->na_bytes = fxdr_hyper(&fp->fa3_used);
nap->na_fileid = fxdr_unsigned(int32_t,
fp->fa3_fileid.nfsuquad[1]);
fxdr_nfsv3time(&fp->fa3_atime, &nap->na_atime);
fxdr_nfsv3time(&fp->fa3_ctime, &nap->na_ctime);
fxdr_nfsv3time(&fp->fa3_mtime, &nap->na_mtime);
nap->na_flags = 0;
nap->na_filerev = 0;
} else {
NFSM_DISSECT(fp, struct nfs_fattr *, NFSX_V2FATTR);
nap->na_type = nfsv2tov_type(fp->fa_type);
nap->na_mode = fxdr_unsigned(u_short, fp->fa_mode);
if (nap->na_type == VNON || nap->na_type == VREG)
nap->na_type = IFTOVT(nap->na_mode);
nap->na_rdev = fxdr_unsigned(dev_t, fp->fa2_rdev);
/*
* Really ugly NFSv2 kludge.
*/
if (nap->na_type == VCHR && nap->na_rdev == ((dev_t)-1))
nap->na_type = VFIFO;
nap->na_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
nap->na_uid = fxdr_unsigned(uid_t, fp->fa_uid);
nap->na_gid = fxdr_unsigned(gid_t, fp->fa_gid);
nap->na_size = fxdr_unsigned(u_int32_t, fp->fa2_size);
nap->na_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize);
nap->na_bytes =
(u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks) *
NFS_FABLKSIZE;
nap->na_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid);
fxdr_nfsv2time(&fp->fa2_atime, &nap->na_atime);
fxdr_nfsv2time(&fp->fa2_mtime, &nap->na_mtime);
nap->na_flags = 0;
nap->na_ctime.tv_sec = fxdr_unsigned(u_int32_t,
fp->fa2_ctime.nfsv2_sec);
nap->na_ctime.tv_nsec = 0;
nap->na_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec);
nap->na_filerev = 0;
}
nfsmout:
return (error);
}
/*
* This function finds the directory cookie that corresponds to the
* logical byte offset given.
*/
APPLESTATIC nfsuint64 *
nfscl_getcookie(struct nfsnode *np, off_t off, int add)
{
struct nfsdmap *dp, *dp2;
int pos;
pos = off / NFS_DIRBLKSIZ;
if (pos == 0) {
#ifdef DIAGNOSTIC
if (add)
panic("nfs getcookie add at 0");
#endif
return (&nfs_nullcookie);
}
pos--;
dp = LIST_FIRST(&np->n_cookies);
if (!dp) {
if (add) {
MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap),
M_NFSDIROFF, M_WAITOK);
dp->ndm_eocookie = 0;
LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list);
} else
return (NULL);
}
while (pos >= NFSNUMCOOKIES) {
pos -= NFSNUMCOOKIES;
if (LIST_NEXT(dp, ndm_list) != NULL) {
if (!add && dp->ndm_eocookie < NFSNUMCOOKIES &&
pos >= dp->ndm_eocookie)
return (NULL);
dp = LIST_NEXT(dp, ndm_list);
} else if (add) {
MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap),
M_NFSDIROFF, M_WAITOK);
dp2->ndm_eocookie = 0;
LIST_INSERT_AFTER(dp, dp2, ndm_list);
dp = dp2;
} else
return (NULL);
}
if (pos >= dp->ndm_eocookie) {
if (add)
dp->ndm_eocookie = pos + 1;
else
return (NULL);
}
return (&dp->ndm_cookies[pos]);
}
/*
* Gets a file handle out of an nfs reply sent to the client and returns
* the file handle and the file's attributes.
* For V4, it assumes that Getfh and Getattr Op's results are here.
*/
APPLESTATIC int
nfscl_mtofh(struct nfsrv_descript *nd, struct nfsfh **nfhpp,
struct nfsvattr *nap, int *attrflagp)
{
u_int32_t *tl;
int error = 0, flag = 1;
*nfhpp = NULL;
*attrflagp = 0;
/*
* First get the file handle and vnode.
*/
if (nd->nd_flag & ND_NFSV3) {
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
flag = fxdr_unsigned(int, *tl);
} else if (nd->nd_flag & ND_NFSV4) {
NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
}
if (flag) {
error = nfsm_getfh(nd, nfhpp);
if (error)
return (error);
}
/*
* Now, get the attributes.
*/
if (nd->nd_flag & ND_NFSV4) {
NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
} else if (nd->nd_flag & ND_NFSV3) {
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
if (flag) {
flag = fxdr_unsigned(int, *tl);
} else if (fxdr_unsigned(int, *tl)) {
error = nfsm_advance(nd, NFSX_V3FATTR, -1);
if (error)
return (error);
}
}
if (flag) {
error = nfsm_loadattr(nd, nap);
if (!error)
*attrflagp = 1;
}
nfsmout:
return (error);
}
/*
* Put a state Id in the mbuf list.
*/
APPLESTATIC void
nfsm_stateidtom(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp, int flag)
{
nfsv4stateid_t *st;
NFSM_BUILD(st, nfsv4stateid_t *, NFSX_STATEID);
if (flag == NFSSTATEID_PUTALLZERO) {
st->seqid = 0;
st->other[0] = 0;
st->other[1] = 0;
st->other[2] = 0;
} else if (flag == NFSSTATEID_PUTALLONE) {
st->seqid = 0xffffffff;
st->other[0] = 0xffffffff;
st->other[1] = 0xffffffff;
st->other[2] = 0xffffffff;
} else {
st->seqid = stateidp->seqid;
st->other[0] = stateidp->other[0];
st->other[1] = stateidp->other[1];
st->other[2] = stateidp->other[2];
}
}
/*
* Initialize the owner/delegation sleep lock.
*/
APPLESTATIC void
nfscl_lockinit(struct nfsv4lock *lckp)
{
lckp->nfslock_usecnt = 0;
lckp->nfslock_lock = 0;
}
/*
* Get an exclusive lock. (Not needed for OpenBSD4, since there is only one
* thread for each posix process in the kernel.)
*/
APPLESTATIC void
nfscl_lockexcl(struct nfsv4lock *lckp, void *mutex)
{
int igotlock;
do {
igotlock = nfsv4_lock(lckp, 1, NULL, mutex);
} while (!igotlock);
}
/*
* Release an exclusive lock.
*/
APPLESTATIC void
nfscl_lockunlock(struct nfsv4lock *lckp)
{
nfsv4_unlock(lckp, 0);
}
/*
* Called to derefernce a lock on a stateid (delegation or open owner).
*/
APPLESTATIC void
nfscl_lockderef(struct nfsv4lock *lckp)
{
NFSLOCKCLSTATE();
lckp->nfslock_usecnt--;
if (lckp->nfslock_usecnt == 0 && (lckp->nfslock_lock & NFSV4LOCK_WANTED)) {
lckp->nfslock_lock &= ~NFSV4LOCK_WANTED;
wakeup((caddr_t)lckp);
}
NFSUNLOCKCLSTATE();
}

View File

@ -0,0 +1,297 @@
/*-
* 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$");
#include "opt_inet6.h"
#include "opt_kgssapi.h"
#include <fs/nfs/nfsport.h>
#include <rpc/rpc.h>
#include <rpc/rpcsec_gss.h>
#include <rpc/replay.h>
NFSDLOCKMUTEX;
SYSCTL_DECL(_vfs_newnfs);
SVCPOOL *nfscbd_pool;
static int nfs_cbproc(struct nfsrv_descript *, u_int32_t);
extern u_long sb_max_adj;
extern int nfs_numnfscbd;
/*
* NFS client system calls for handling callbacks.
*/
/*
* Handles server to client callbacks.
*/
static void
nfscb_program(struct svc_req *rqst, SVCXPRT *xprt)
{
struct nfsrv_descript nd;
int cacherep;
memset(&nd, 0, sizeof(nd));
if (rqst->rq_proc != NFSPROC_NULL &&
rqst->rq_proc != NFSV4PROC_CBCOMPOUND) {
svcerr_noproc(rqst);
svc_freereq(rqst);
return;
}
nd.nd_procnum = rqst->rq_proc;
nd.nd_flag = (ND_NFSCB | ND_NFSV4);
/*
* Note: we want rq_addr, not svc_getrpccaller for nd_nam2 -
* NFS_SRVMAXDATA uses a NULL value for nd_nam2 to detect TCP
* mounts.
*/
nd.nd_mrep = rqst->rq_args;
rqst->rq_args = NULL;
newnfs_realign(&nd.nd_mrep);
nd.nd_md = nd.nd_mrep;
nd.nd_dpos = mtod(nd.nd_md, caddr_t);
nd.nd_nam = svc_getrpccaller(rqst);
nd.nd_nam2 = rqst->rq_addr;
nd.nd_mreq = NULL;
nd.nd_cred = NULL;
if (nd.nd_procnum != NFSPROC_NULL) {
if (!svc_getcred(rqst, &nd.nd_cred, &nd.nd_credflavor)) {
svcerr_weakauth(rqst);
svc_freereq(rqst);
m_freem(nd.nd_mrep);
return;
}
#ifdef notyet
#ifdef MAC
mac_cred_associate_nfsd(nd.nd_cred);
#endif
#endif
cacherep = nfs_cbproc(&nd, rqst->rq_xid);
} else {
NFSMGET(nd.nd_mreq);
nd.nd_mreq->m_len = 0;
cacherep = RC_REPLY;
}
if (nd.nd_mrep != NULL)
m_freem(nd.nd_mrep);
if (nd.nd_cred != NULL)
crfree(nd.nd_cred);
if (cacherep == RC_DROPIT) {
if (nd.nd_mreq != NULL)
m_freem(nd.nd_mreq);
svc_freereq(rqst);
return;
}
if (nd.nd_mreq == NULL) {
svcerr_decode(rqst);
svc_freereq(rqst);
return;
}
if (nd.nd_repstat & NFSERR_AUTHERR) {
svcerr_auth(rqst, nd.nd_repstat & ~NFSERR_AUTHERR);
if (nd.nd_mreq != NULL)
m_freem(nd.nd_mreq);
} else if (!svc_sendreply_mbuf(rqst, nd.nd_mreq)) {
svcerr_systemerr(rqst);
}
svc_freereq(rqst);
}
/*
* Check the cache and, optionally, do the RPC.
* Return the appropriate cache response.
*/
static int
nfs_cbproc(struct nfsrv_descript *nd, u_int32_t xid)
{
struct thread *td = curthread;
int cacherep;
if (nd->nd_nam2 == NULL)
nd->nd_flag |= ND_STREAMSOCK;
nfscl_docb(nd, td);
if (nd->nd_repstat == NFSERR_DONTREPLY)
cacherep = RC_DROPIT;
else
cacherep = RC_REPLY;
return (cacherep);
}
/*
* Adds a socket to the list for servicing by nfscbds.
*/
int
nfscbd_addsock(struct file *fp)
{
int siz;
struct socket *so;
int error;
SVCXPRT *xprt;
so = fp->f_data;
siz = sb_max_adj;
error = soreserve(so, siz, siz);
if (error)
return (error);
/*
* Steal the socket from userland so that it doesn't close
* unexpectedly.
*/
if (so->so_type == SOCK_DGRAM)
xprt = svc_dg_create(nfscbd_pool, so, 0, 0);
else
xprt = svc_vc_create(nfscbd_pool, so, 0, 0);
if (xprt) {
fp->f_ops = &badfileops;
fp->f_data = NULL;
svc_reg(xprt, NFS_CALLBCKPROG, NFSV4_CBVERS, nfscb_program,
NULL);
}
return (0);
}
/*
* Called by nfssvc() for nfscbds. Just loops around servicing rpc requests
* until it is killed by a signal.
*
* For now, only support callbacks via RPCSEC_GSS if there is a KerberosV
* keytab entry with a host based entry in it on the client. (I'm not even
* sure that getting Acceptor credentials for a user principal with a
* credentials cache is possible, but even if it is, major changes to the
* kgssapi would be required.)
* I don't believe that this is a serious limitation since, as of 2009, most
* NFSv4 servers supporting callbacks are using AUTH_SYS for callbacks even
* when the client is using RPCSEC_GSS. (This BSD server uses AUTH_SYS
* for callbacks unless nfsrv_gsscallbackson is set non-zero.)
*/
int
nfscbd_nfsd(struct thread *td, struct nfsd_nfscbd_args *args)
{
#ifdef KGSSAPI
char principal[128];
int error;
#endif
#ifdef KGSSAPI
if (args != NULL) {
error = copyinstr(args->principal, principal,
sizeof(principal), NULL);
if (error)
return (error);
} else {
principal[0] = '\0';
}
#endif
/*
* Only the first nfsd actually does any work. The RPC code
* adds threads to it as needed. Any extra processes offered
* by nfsd just exit. If nfsd is new enough, it will call us
* once with a structure that specifies how many threads to
* use.
*/
NFSD_LOCK();
if (nfs_numnfscbd == 0) {
nfs_numnfscbd++;
NFSD_UNLOCK();
#ifdef KGSSAPI
if (principal[0] != '\0')
rpc_gss_set_svc_name(principal, "kerberosv5",
GSS_C_INDEFINITE, NFS_CALLBCKPROG, NFSV4_CBVERS);
#endif
nfscbd_pool->sp_minthreads = 4;
nfscbd_pool->sp_maxthreads = 4;
svc_run(nfscbd_pool);
#ifdef KGSSAPI
rpc_gss_clear_svc_name(NFS_CALLBCKPROG, NFSV4_CBVERS);
#endif
NFSD_LOCK();
nfs_numnfscbd--;
nfsrvd_cbinit(1);
}
NFSD_UNLOCK();
return (0);
}
/*
* Initialize the data structures for the server.
* Handshake with any new nfsds starting up to avoid any chance of
* corruption.
*/
void
nfsrvd_cbinit(int terminating)
{
NFSD_LOCK_ASSERT();
if (terminating) {
NFSD_UNLOCK();
svcpool_destroy(nfscbd_pool);
nfscbd_pool = NULL;
NFSD_LOCK();
}
NFSD_UNLOCK();
nfscbd_pool = svcpool_create("nfscbd", SYSCTL_STATIC_CHILDREN(_vfs_newnfs));
nfscbd_pool->sp_rcache = NULL;
nfscbd_pool->sp_assign = NULL;
nfscbd_pool->sp_done = NULL;
NFSD_LOCK();
}

View File

@ -0,0 +1,396 @@
/*-
* Copyright (c) 1997 Berkeley Software Design, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Berkeley Software Design Inc's name may not be used to endorse or
* promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN INC ``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 BERKELEY SOFTWARE DESIGN INC 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.
*
* from BSDI nfs_lock.c,v 2.4 1998/12/14 23:49:56 jch Exp
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/fcntl.h>
#include <sys/kernel.h> /* for hz */
#include <sys/limits.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/lockf.h> /* for hz */ /* Must come after sys/malloc.h */
#include <sys/mbuf.h>
#include <sys/mount.h>
#include <sys/namei.h>
#include <sys/priv.h>
#include <sys/proc.h>
#include <sys/resourcevar.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <sys/unistd.h>
#include <sys/vnode.h>
#include <net/if.h>
#include <fs/nfs/nfsport.h>
#include <fs/nfsclient/nfsmount.h>
#include <fs/nfsclient/nfs.h>
#include <fs/nfsclient/nfsnode.h>
#include <fs/nfsclient/nfs_lock.h>
#include <fs/nfsclient/nlminfo.h>
extern void (*nlminfo_release_p)(struct proc *p);
MALLOC_DEFINE(M_NEWNFSLOCK, "newnfsclient_lock", "NEWNFS lock request");
MALLOC_DEFINE(M_NEWNLMINFO, "newnfsclient_nlminfo", "NEWNFS lock process structure");
static int nfslockdans(struct thread *td, struct lockd_ans *ansp);
static void nlminfo_release(struct proc *p);
/*
* --------------------------------------------------------------------
* A miniature device driver which the userland uses to talk to us.
*
*/
static struct cdev *nfslock_dev;
static struct mtx nfslock_mtx;
static int nfslock_isopen;
static TAILQ_HEAD(,__lock_msg) nfslock_list;
static int
nfslock_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
{
int error;
error = priv_check(td, PRIV_NFS_LOCKD);
if (error)
return (error);
mtx_lock(&nfslock_mtx);
if (!nfslock_isopen) {
error = 0;
nfslock_isopen = 1;
} else {
error = EOPNOTSUPP;
}
mtx_unlock(&nfslock_mtx);
return (error);
}
static int
nfslock_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
{
struct __lock_msg *lm;
mtx_lock(&nfslock_mtx);
nfslock_isopen = 0;
while (!TAILQ_EMPTY(&nfslock_list)) {
lm = TAILQ_FIRST(&nfslock_list);
/* XXX: answer request */
TAILQ_REMOVE(&nfslock_list, lm, lm_link);
free(lm, M_NEWNFSLOCK);
}
mtx_unlock(&nfslock_mtx);
return (0);
}
static int
nfslock_read(struct cdev *dev, struct uio *uio, int ioflag)
{
int error;
struct __lock_msg *lm;
if (uio->uio_resid != sizeof *lm)
return (EOPNOTSUPP);
lm = NULL;
error = 0;
mtx_lock(&nfslock_mtx);
while (TAILQ_EMPTY(&nfslock_list)) {
error = msleep(&nfslock_list, &nfslock_mtx, PSOCK | PCATCH,
"nfslockd", 0);
if (error)
break;
}
if (!error) {
lm = TAILQ_FIRST(&nfslock_list);
TAILQ_REMOVE(&nfslock_list, lm, lm_link);
}
mtx_unlock(&nfslock_mtx);
if (!error) {
error = uiomove(lm, sizeof *lm, uio);
free(lm, M_NEWNFSLOCK);
}
return (error);
}
static int
nfslock_write(struct cdev *dev, struct uio *uio, int ioflag)
{
struct lockd_ans la;
int error;
if (uio->uio_resid != sizeof la)
return (EOPNOTSUPP);
error = uiomove(&la, sizeof la, uio);
if (!error)
error = nfslockdans(curthread, &la);
return (error);
}
static int
nfslock_send(struct __lock_msg *lm)
{
struct __lock_msg *lm2;
int error;
error = 0;
lm2 = malloc(sizeof *lm2, M_NEWNFSLOCK, M_WAITOK);
mtx_lock(&nfslock_mtx);
if (nfslock_isopen) {
memcpy(lm2, lm, sizeof *lm2);
TAILQ_INSERT_TAIL(&nfslock_list, lm2, lm_link);
wakeup(&nfslock_list);
} else {
error = EOPNOTSUPP;
}
mtx_unlock(&nfslock_mtx);
if (error)
free(lm2, M_NEWNFSLOCK);
return (error);
}
static struct cdevsw nfslock_cdevsw = {
.d_version = D_VERSION,
.d_open = nfslock_open,
.d_close = nfslock_close,
.d_read = nfslock_read,
.d_write = nfslock_write,
.d_name = "nfslock"
};
static int
newnfslock_modevent(module_t mod __unused, int type, void *data __unused)
{
switch (type) {
case MOD_LOAD:
if (bootverbose)
printf("nfslock: pseudo-device\n");
mtx_init(&nfslock_mtx, "nfslock", NULL, MTX_DEF);
TAILQ_INIT(&nfslock_list);
nlminfo_release_p = nlminfo_release;
nfslock_dev = make_dev(&nfslock_cdevsw, 0,
UID_ROOT, GID_KMEM, 0600, _PATH_NFSLCKDEV);
return (0);
default:
return (EOPNOTSUPP);
}
}
DEV_MODULE(newnfslock, newnfslock_modevent, NULL);
MODULE_VERSION(newnfslock, 1);
/*
* XXX
* We have to let the process know if the call succeeded. I'm using an extra
* field in the p_nlminfo field in the proc structure, as it is already for
* lockd stuff.
*/
/*
* nfs_advlock --
* NFS advisory byte-level locks.
*
* The vnode shall be (shared) locked on the entry, it is
* unconditionally unlocked after.
*/
int
ncl_dolock(struct vop_advlock_args *ap)
{
LOCKD_MSG msg;
struct thread *td;
struct vnode *vp;
int error;
struct flock *fl;
struct proc *p;
td = curthread;
p = td->td_proc;
vp = ap->a_vp;
fl = ap->a_fl;
ASSERT_VOP_LOCKED(vp, "nfs_dolock");
bcopy(VFSTONFS(vp->v_mount)->nm_nam, &msg.lm_addr,
min(sizeof msg.lm_addr, VFSTONFS(vp->v_mount)->nm_nam->sa_len));
msg.lm_fh_len = NFS_ISV3(vp) ? VTONFS(vp)->n_fhsize : NFSX_V2FH;
bcopy(VTONFS(vp)->n_fhp->nfh_fh, msg.lm_fh, msg.lm_fh_len);
msg.lm_nfsv3 = NFS_ISV3(vp);
VOP_UNLOCK(vp, 0);
/*
* the NLM protocol doesn't allow the server to return an error
* on ranges, so we do it.
*/
if (fl->l_whence != SEEK_END) {
if ((fl->l_whence != SEEK_CUR && fl->l_whence != SEEK_SET) ||
fl->l_start < 0 ||
(fl->l_len < 0 &&
(fl->l_start == 0 || fl->l_start + fl->l_len < 0)))
return (EINVAL);
if (fl->l_len > 0 &&
(fl->l_len - 1 > OFF_MAX - fl->l_start))
return (EOVERFLOW);
}
/*
* Fill in the information structure.
*/
msg.lm_version = LOCKD_MSG_VERSION;
msg.lm_msg_ident.pid = p->p_pid;
mtx_lock(&Giant);
/*
* if there is no nfsowner table yet, allocate one.
*/
if (p->p_nlminfo == NULL) {
p->p_nlminfo = malloc(sizeof(struct nlminfo),
M_NEWNLMINFO, M_WAITOK | M_ZERO);
p->p_nlminfo->pid_start = p->p_stats->p_start;
timevaladd(&p->p_nlminfo->pid_start, &boottime);
}
msg.lm_msg_ident.pid_start = p->p_nlminfo->pid_start;
msg.lm_msg_ident.msg_seq = ++(p->p_nlminfo->msg_seq);
msg.lm_fl = *fl;
msg.lm_wait = ap->a_flags & F_WAIT;
msg.lm_getlk = ap->a_op == F_GETLK;
cru2x(td->td_ucred, &msg.lm_cred);
for (;;) {
error = nfslock_send(&msg);
if (error)
goto out;
/* Unlocks succeed immediately. */
if (fl->l_type == F_UNLCK)
goto out;
/*
* Retry after 20 seconds if we haven't gotten a response yet.
* This number was picked out of thin air... but is longer
* then even a reasonably loaded system should take (at least
* on a local network). XXX Probably should use a back-off
* scheme.
*
* XXX: No PCATCH here since we currently have no useful
* way to signal to the userland rpc.lockd that the request
* has been aborted. Once the rpc.lockd implementation
* can handle aborts, and we report them properly,
* PCATCH can be put back. In the mean time, if we did
* permit aborting, the lock attempt would "get lost"
* and the lock would get stuck in the locked state.
*/
error = tsleep(p->p_nlminfo, PUSER, "lockd", 20*hz);
if (error != 0) {
if (error == EWOULDBLOCK) {
/*
* We timed out, so we rewrite the request
* to the fifo.
*/
continue;
}
break;
}
if (msg.lm_getlk && p->p_nlminfo->retcode == 0) {
if (p->p_nlminfo->set_getlk_pid) {
fl->l_sysid = 0; /* XXX */
fl->l_pid = p->p_nlminfo->getlk_pid;
} else {
fl->l_type = F_UNLCK;
}
}
error = p->p_nlminfo->retcode;
break;
}
out:
mtx_unlock(&Giant);
return (error);
}
/*
* nfslockdans --
* NFS advisory byte-level locks answer from the lock daemon.
*/
static int
nfslockdans(struct thread *td, struct lockd_ans *ansp)
{
struct proc *targetp;
/* the version should match, or we're out of sync */
if (ansp->la_vers != LOCKD_ANS_VERSION)
return (EINVAL);
/* Find the process, set its return errno and wake it up. */
if ((targetp = pfind(ansp->la_msg_ident.pid)) == NULL)
return (ESRCH);
/* verify the pid hasn't been reused (if we can), and it isn't waiting
* for an answer from a more recent request. We return an EPIPE if
* the match fails, because we've already used ESRCH above, and this
* is sort of like writing on a pipe after the reader has closed it.
*/
if (targetp->p_nlminfo == NULL ||
((ansp->la_msg_ident.msg_seq != -1) &&
(timevalcmp(&targetp->p_nlminfo->pid_start,
&ansp->la_msg_ident.pid_start, !=) ||
targetp->p_nlminfo->msg_seq != ansp->la_msg_ident.msg_seq))) {
PROC_UNLOCK(targetp);
return (EPIPE);
}
targetp->p_nlminfo->retcode = ansp->la_errno;
targetp->p_nlminfo->set_getlk_pid = ansp->la_set_getlk_pid;
targetp->p_nlminfo->getlk_pid = ansp->la_getlk_pid;
wakeup(targetp->p_nlminfo);
PROC_UNLOCK(targetp);
return (0);
}
/*
* Free nlminfo attached to process.
*/
static void
nlminfo_release(struct proc *p)
{
free(p->p_nlminfo, M_NEWNLMINFO);
p->p_nlminfo = NULL;
}

View File

@ -0,0 +1,308 @@
/*-
* 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.
*
* from nfs_syscalls.c 8.5 (Berkeley) 3/30/95
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/sysproto.h>
#include <sys/kernel.h>
#include <sys/sysctl.h>
#include <sys/file.h>
#include <sys/filedesc.h>
#include <sys/vnode.h>
#include <sys/malloc.h>
#include <sys/mount.h>
#include <sys/proc.h>
#include <sys/bio.h>
#include <sys/buf.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/domain.h>
#include <sys/protosw.h>
#include <sys/namei.h>
#include <sys/unistd.h>
#include <sys/kthread.h>
#include <sys/fcntl.h>
#include <sys/lockf.h>
#include <sys/mutex.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <fs/nfs/nfsport.h>
#include <fs/nfsclient/nfsmount.h>
#include <fs/nfsclient/nfs.h>
#include <fs/nfsclient/nfsnode.h>
#include <fs/nfsclient/nfs_lock.h>
extern struct mtx ncl_iod_mutex;
int ncl_numasync;
struct proc *ncl_iodwant[NFS_MAXRAHEAD];
struct nfsmount *ncl_iodmount[NFS_MAXRAHEAD];
static void nfssvc_iod(void *);
static int nfs_asyncdaemon[NFS_MAXRAHEAD];
SYSCTL_DECL(_vfs_newnfs);
/* Maximum number of seconds a nfsiod kthread will sleep before exiting */
static unsigned int ncl_iodmaxidle = 120;
SYSCTL_UINT(_vfs_newnfs, OID_AUTO, iodmaxidle, CTLFLAG_RW, &ncl_iodmaxidle, 0, "");
/* Maximum number of nfsiod kthreads */
unsigned int ncl_iodmax = NFS_MAXRAHEAD;
/* Minimum number of nfsiod kthreads to keep as spares */
static unsigned int nfs_iodmin = 0;
static int
sysctl_iodmin(SYSCTL_HANDLER_ARGS)
{
int error, i;
int newmin;
newmin = nfs_iodmin;
error = sysctl_handle_int(oidp, &newmin, 0, req);
if (error || (req->newptr == NULL))
return (error);
mtx_lock(&ncl_iod_mutex);
if (newmin > ncl_iodmax) {
error = EINVAL;
goto out;
}
nfs_iodmin = newmin;
if (ncl_numasync >= nfs_iodmin)
goto out;
/*
* If the current number of nfsiod is lower
* than the new minimum, create some more.
*/
for (i = nfs_iodmin - ncl_numasync; i > 0; i--)
ncl_nfsiodnew();
out:
mtx_unlock(&ncl_iod_mutex);
return (0);
}
SYSCTL_PROC(_vfs_newnfs, OID_AUTO, iodmin, CTLTYPE_UINT | CTLFLAG_RW, 0,
sizeof (nfs_iodmin), sysctl_iodmin, "IU", "");
static int
sysctl_iodmax(SYSCTL_HANDLER_ARGS)
{
int error, i;
int iod, newmax;
newmax = ncl_iodmax;
error = sysctl_handle_int(oidp, &newmax, 0, req);
if (error || (req->newptr == NULL))
return (error);
if (newmax > NFS_MAXRAHEAD)
return (EINVAL);
mtx_lock(&ncl_iod_mutex);
ncl_iodmax = newmax;
if (ncl_numasync <= ncl_iodmax)
goto out;
/*
* If there are some asleep nfsiods that should
* exit, wakeup() them so that they check ncl_iodmax
* and exit. Those who are active will exit as
* soon as they finish I/O.
*/
iod = ncl_numasync - 1;
for (i = 0; i < ncl_numasync - ncl_iodmax; i++) {
if (ncl_iodwant[iod])
wakeup(&ncl_iodwant[iod]);
iod--;
}
out:
mtx_unlock(&ncl_iod_mutex);
return (0);
}
SYSCTL_PROC(_vfs_newnfs, OID_AUTO, iodmax, CTLTYPE_UINT | CTLFLAG_RW, 0,
sizeof (ncl_iodmax), sysctl_iodmax, "IU", "");
int
ncl_nfsiodnew(void)
{
int error, i;
int newiod;
if (ncl_numasync >= ncl_iodmax)
return (-1);
newiod = -1;
for (i = 0; i < ncl_iodmax; i++)
if (nfs_asyncdaemon[i] == 0) {
nfs_asyncdaemon[i]++;
newiod = i;
break;
}
if (newiod == -1)
return (-1);
mtx_unlock(&ncl_iod_mutex);
error = kproc_create(nfssvc_iod, nfs_asyncdaemon + i, NULL, RFHIGHPID,
0, "nfsiod %d", newiod);
mtx_lock(&ncl_iod_mutex);
if (error)
return (-1);
ncl_numasync++;
return (newiod);
}
static void
nfsiod_setup(void *dummy)
{
int i;
int error;
TUNABLE_INT_FETCH("vfs.newnfs.iodmin", &nfs_iodmin);
nfscl_init();
mtx_lock(&ncl_iod_mutex);
/* Silently limit the start number of nfsiod's */
if (nfs_iodmin > NFS_MAXRAHEAD)
nfs_iodmin = NFS_MAXRAHEAD;
for (i = 0; i < nfs_iodmin; i++) {
error = ncl_nfsiodnew();
if (error == -1)
panic("newnfsiod_setup: ncl_nfsiodnew failed");
}
mtx_unlock(&ncl_iod_mutex);
}
SYSINIT(newnfsiod, SI_SUB_KTHREAD_IDLE, SI_ORDER_ANY, nfsiod_setup, NULL);
static int nfs_defect = 0;
SYSCTL_INT(_vfs_newnfs, OID_AUTO, defect, CTLFLAG_RW, &nfs_defect, 0, "");
/*
* Asynchronous I/O daemons for client nfs.
* They do read-ahead and write-behind operations on the block I/O cache.
* Returns if we hit the timeout defined by the iodmaxidle sysctl.
*/
static void
nfssvc_iod(void *instance)
{
struct buf *bp;
struct nfsmount *nmp;
int myiod, timo;
int error = 0;
mtx_lock(&ncl_iod_mutex);
myiod = (int *)instance - nfs_asyncdaemon;
/*
* Main loop
*/
for (;;) {
while (((nmp = ncl_iodmount[myiod]) == NULL)
|| !TAILQ_FIRST(&nmp->nm_bufq)) {
if (myiod >= ncl_iodmax)
goto finish;
if (nmp)
nmp->nm_bufqiods--;
ncl_iodwant[myiod] = curthread->td_proc;
ncl_iodmount[myiod] = NULL;
/*
* Always keep at least nfs_iodmin kthreads.
*/
timo = (myiod < nfs_iodmin) ? 0 : ncl_iodmaxidle * hz;
error = msleep(&ncl_iodwant[myiod], &ncl_iod_mutex, PWAIT | PCATCH,
"-", timo);
if (error) {
nmp = ncl_iodmount[myiod];
/*
* Rechecking the nm_bufq closes a rare race where the
* nfsiod is woken up at the exact time the idle timeout
* fires
*/
if (nmp && TAILQ_FIRST(&nmp->nm_bufq))
error = 0;
break;
}
}
if (error)
break;
while ((bp = TAILQ_FIRST(&nmp->nm_bufq)) != NULL) {
/* Take one off the front of the list */
TAILQ_REMOVE(&nmp->nm_bufq, bp, b_freelist);
nmp->nm_bufqlen--;
if (nmp->nm_bufqwant && nmp->nm_bufqlen <= ncl_numasync) {
nmp->nm_bufqwant = 0;
wakeup(&nmp->nm_bufq);
}
mtx_unlock(&ncl_iod_mutex);
if (bp->b_flags & B_DIRECT) {
KASSERT((bp->b_iocmd == BIO_WRITE), ("nfscvs_iod: BIO_WRITE not set"));
(void)ncl_doio_directwrite(bp);
} else {
if (bp->b_iocmd == BIO_READ)
(void) ncl_doio(bp->b_vp, bp, bp->b_rcred, NULL);
else
(void) ncl_doio(bp->b_vp, bp, bp->b_wcred, NULL);
}
mtx_lock(&ncl_iod_mutex);
/*
* If there are more than one iod on this mount, then defect
* so that the iods can be shared out fairly between the mounts
*/
if (nfs_defect && nmp->nm_bufqiods > 1) {
NFS_DPF(ASYNCIO,
("nfssvc_iod: iod %d defecting from mount %p\n",
myiod, nmp));
ncl_iodmount[myiod] = NULL;
nmp->nm_bufqiods--;
break;
}
}
}
finish:
nfs_asyncdaemon[myiod] = 0;
if (nmp)
nmp->nm_bufqiods--;
ncl_iodwant[myiod] = NULL;
ncl_iodmount[myiod] = NULL;
/* Someone may be waiting for the last nfsiod to terminate. */
if (--ncl_numasync == 0)
wakeup(&ncl_numasync);
mtx_unlock(&ncl_iod_mutex);
if ((error == 0) || (error == EWOULDBLOCK))
kproc_exit(0);
/* Abnormal termination */
kproc_exit(1);
}

View File

@ -0,0 +1,283 @@
/*-
* 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.
*
* from nfs_node.c 8.6 (Berkeley) 5/22/95
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/mount.h>
#include <sys/namei.h>
#include <sys/proc.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <sys/vnode.h>
#include <vm/uma.h>
#include <fs/nfs/nfsport.h>
#include <fs/nfsclient/nfsnode.h>
#include <fs/nfsclient/nfsmount.h>
#include <fs/nfsclient/nfs.h>
extern struct vop_vector newnfs_vnodeops;
extern struct buf_ops buf_ops_newnfs;
MALLOC_DECLARE(M_NEWNFSREQ);
uma_zone_t newnfsnode_zone;
vop_reclaim_t *ncl_reclaim_p = NULL;
void
ncl_nhinit(void)
{
newnfsnode_zone = uma_zcreate("NCLNODE", sizeof(struct nfsnode), NULL,
NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
}
void
ncl_nhuninit(void)
{
uma_zdestroy(newnfsnode_zone);
}
/*
* ONLY USED FOR THE ROOT DIRECTORY. nfscl_nget() does the rest. If this
* function is going to be used to get Regular Files, code must be added
* to fill in the "struct nfsv4node".
* Look up a vnode/nfsnode by file handle.
* Callers must check for mount points!!
* In all cases, a pointer to a
* nfsnode structure is returned.
*/
int
ncl_nget(struct mount *mntp, u_int8_t *fhp, int fhsize, struct nfsnode **npp)
{
struct thread *td = curthread; /* XXX */
struct nfsnode *np;
struct vnode *vp;
struct vnode *nvp;
int error;
u_int hash;
struct nfsmount *nmp;
struct nfsfh *nfhp;
nmp = VFSTONFS(mntp);
*npp = NULL;
hash = fnv_32_buf(fhp, fhsize, FNV1_32_INIT);
MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + fhsize,
M_NFSFH, M_WAITOK);
bcopy(fhp, &nfhp->nfh_fh[0], fhsize);
nfhp->nfh_len = fhsize;
error = vfs_hash_get(mntp, hash, LK_EXCLUSIVE,
td, &nvp, newnfs_vncmpf, nfhp);
FREE(nfhp, M_NFSFH);
if (error)
return (error);
if (nvp != NULL) {
*npp = VTONFS(nvp);
return (0);
}
/*
* Allocate before getnewvnode since doing so afterward
* might cause a bogus v_data pointer to get dereferenced
* elsewhere if zalloc should block.
*/
np = uma_zalloc(newnfsnode_zone, M_WAITOK | M_ZERO);
error = getnewvnode("newnfs", mntp, &newnfs_vnodeops, &nvp);
if (error) {
uma_zfree(newnfsnode_zone, np);
return (error);
}
vp = nvp;
vp->v_bufobj.bo_ops = &buf_ops_newnfs;
vp->v_data = np;
np->n_vnode = vp;
/*
* Initialize the mutex even if the vnode is going to be a loser.
* This simplifies the logic in reclaim, which can then unconditionally
* destroy the mutex (in the case of the loser, or if hash_insert
* happened to return an error no special casing is needed).
*/
mtx_init(&np->n_mtx, "NEWNFSnode lock", NULL, MTX_DEF | MTX_DUPOK);
/*
* NFS supports recursive and shared locking.
*/
VN_LOCK_AREC(vp);
VN_LOCK_ASHARE(vp);
/*
* Are we getting the root? If so, make sure the vnode flags
* are correct
*/
if ((fhsize == nmp->nm_fhsize) &&
!bcmp(fhp, nmp->nm_fh, fhsize)) {
if (vp->v_type == VNON)
vp->v_type = VDIR;
vp->v_vflag |= VV_ROOT;
}
MALLOC(np->n_fhp, struct nfsfh *, sizeof (struct nfsfh) + fhsize,
M_NFSFH, M_WAITOK);
bcopy(fhp, np->n_fhp->nfh_fh, fhsize);
np->n_fhp->nfh_len = fhsize;
lockmgr(vp->v_vnlock, LK_EXCLUSIVE, NULL);
error = insmntque(vp, mntp);
if (error != 0) {
*npp = NULL;
FREE((caddr_t)np->n_fhp, M_NFSFH);
mtx_destroy(&np->n_mtx);
uma_zfree(newnfsnode_zone, np);
return (error);
}
error = vfs_hash_insert(vp, hash, LK_EXCLUSIVE,
td, &nvp, newnfs_vncmpf, np->n_fhp);
if (error)
return (error);
if (nvp != NULL) {
*npp = VTONFS(nvp);
/* vfs_hash_insert() vput()'s the losing vnode */
return (0);
}
*npp = np;
return (0);
}
int
ncl_inactive(struct vop_inactive_args *ap)
{
struct nfsnode *np;
struct sillyrename *sp;
struct thread *td = curthread; /* XXX */
np = VTONFS(ap->a_vp);
if (prtactive && vrefcnt(ap->a_vp) != 0)
vprint("ncl_inactive: pushing active", ap->a_vp);
if (ap->a_vp->v_type != VDIR) {
sp = np->n_sillyrename;
np->n_sillyrename = NULL;
} else
sp = NULL;
if (sp) {
(void)ncl_vinvalbuf(ap->a_vp, 0, td, 1);
/*
* Remove the silly file that was rename'd earlier
*/
ncl_removeit(sp, ap->a_vp);
crfree(sp->s_cred);
vrele(sp->s_dvp);
FREE((caddr_t)sp, M_NEWNFSREQ);
}
np->n_flag &= NMODIFIED;
return (0);
}
/*
* Reclaim an nfsnode so that it can be used for other purposes.
*/
int
ncl_reclaim(struct vop_reclaim_args *ap)
{
struct vnode *vp = ap->a_vp;
struct nfsnode *np = VTONFS(vp);
struct nfsdmap *dp, *dp2;
if (prtactive && vrefcnt(vp) != 0)
vprint("ncl_reclaim: pushing active", vp);
/*
* If the NLM is running, give it a chance to abort pending
* locks.
*/
if (ncl_reclaim_p)
ncl_reclaim_p(ap);
/*
* Destroy the vm object and flush associated pages.
*/
vnode_destroy_vobject(vp);
vfs_hash_remove(vp);
/*
* Call nfscl_reclaimnode() to save attributes in the delegation,
* as required.
*/
if (vp->v_type == VREG)
nfscl_reclaimnode(vp);
/*
* Free up any directory cookie structures and
* large file handle structures that might be associated with
* this nfs node.
*/
if (vp->v_type == VDIR) {
dp = LIST_FIRST(&np->n_cookies);
while (dp) {
dp2 = dp;
dp = LIST_NEXT(dp, ndm_list);
FREE((caddr_t)dp2, M_NFSDIROFF);
}
}
FREE((caddr_t)np->n_fhp, M_NFSFH);
if (np->n_v4 != NULL)
FREE((caddr_t)np->n_v4, M_NFSV4NODE);
mtx_destroy(&np->n_mtx);
uma_zfree(newnfsnode_zone, vp->v_data);
vp->v_data = NULL;
return (0);
}
/*
* Invalidate both the access and attribute caches for this vnode.
*/
void
ncl_invalcaches(struct vnode *vp)
{
struct nfsnode *np = VTONFS(vp);
int i;
mtx_lock(&np->n_mtx);
for (i = 0; i < NFS_ACCESSCACHESIZE; i++)
np->n_accesscache[i].stamp = 0;
np->n_attrstamp = 0;
mtx_unlock(&np->n_mtx);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,402 @@
/*-
* 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.
*
* from nfs_subs.c 8.8 (Berkeley) 5/22/95
*/
#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.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/bio.h>
#include <sys/buf.h>
#include <sys/proc.h>
#include <sys/mount.h>
#include <sys/vnode.h>
#include <sys/namei.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/malloc.h>
#include <sys/sysent.h>
#include <sys/syscall.h>
#include <sys/sysproto.h>
#include <vm/vm.h>
#include <vm/vm_object.h>
#include <vm/vm_extern.h>
#include <vm/uma.h>
#include <fs/nfs/nfsport.h>
#include <fs/nfsclient/nfsnode.h>
#include <fs/nfsclient/nfsmount.h>
#include <fs/nfsclient/nfs.h>
#include <fs/nfsclient/nfs_lock.h>
#include <netinet/in.h>
/*
* Note that stdarg.h and the ANSI style va_start macro is used for both
* ANSI and traditional C compilers.
*/
#include <machine/stdarg.h>
extern struct mtx ncl_iod_mutex;
extern struct proc *ncl_iodwant[NFS_MAXRAHEAD];
extern struct nfsmount *ncl_iodmount[NFS_MAXRAHEAD];
extern int ncl_numasync;
extern unsigned int ncl_iodmax;
extern struct nfsstats newnfsstats;
int
ncl_uninit(struct vfsconf *vfsp)
{
int i;
/*
* Tell all nfsiod processes to exit. Clear ncl_iodmax, and wakeup
* any sleeping nfsiods so they check ncl_iodmax and exit.
*/
mtx_lock(&ncl_iod_mutex);
ncl_iodmax = 0;
for (i = 0; i < ncl_numasync; i++)
if (ncl_iodwant[i])
wakeup(&ncl_iodwant[i]);
/* The last nfsiod to exit will wake us up when ncl_numasync hits 0 */
while (ncl_numasync)
msleep(&ncl_numasync, &ncl_iod_mutex, PWAIT, "ioddie", 0);
mtx_unlock(&ncl_iod_mutex);
ncl_nhuninit();
return (0);
}
void
ncl_dircookie_lock(struct nfsnode *np)
{
mtx_lock(&np->n_mtx);
while (np->n_flag & NDIRCOOKIELK)
(void) msleep(&np->n_flag, &np->n_mtx, PZERO, "nfsdirlk", 0);
np->n_flag |= NDIRCOOKIELK;
mtx_unlock(&np->n_mtx);
}
void
ncl_dircookie_unlock(struct nfsnode *np)
{
mtx_lock(&np->n_mtx);
np->n_flag &= ~NDIRCOOKIELK;
wakeup(&np->n_flag);
mtx_unlock(&np->n_mtx);
}
int
ncl_upgrade_vnlock(struct vnode *vp)
{
int old_lock;
if ((old_lock = VOP_ISLOCKED(vp)) != LK_EXCLUSIVE) {
if (old_lock == LK_SHARED) {
/* Upgrade to exclusive lock, this might block */
vn_lock(vp, LK_UPGRADE | LK_RETRY);
} else {
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
}
}
return old_lock;
}
void
ncl_downgrade_vnlock(struct vnode *vp, int old_lock)
{
if (old_lock != LK_EXCLUSIVE) {
if (old_lock == LK_SHARED) {
/* Downgrade from exclusive lock, this might block */
vn_lock(vp, LK_DOWNGRADE);
} else {
VOP_UNLOCK(vp, 0);
}
}
}
void
ncl_printf(const char *fmt, ...)
{
va_list ap;
mtx_lock(&Giant);
va_start(ap, fmt);
printf(fmt, ap);
va_end(ap);
mtx_unlock(&Giant);
}
#ifdef NFS_ACDEBUG
#include <sys/sysctl.h>
SYSCTL_DECL(_vfs_newnfs);
static int nfs_acdebug;
SYSCTL_INT(_vfs_newnfs, OID_AUTO, acdebug, CTLFLAG_RW, &nfs_acdebug, 0, "");
#endif
/*
* Check the time stamp
* If the cache is valid, copy contents to *vap and return 0
* otherwise return an error
*/
int
ncl_getattrcache(struct vnode *vp, struct vattr *vaper)
{
struct nfsnode *np;
struct vattr *vap;
struct nfsmount *nmp;
int timeo;
np = VTONFS(vp);
vap = &np->n_vattr.na_vattr;
nmp = VFSTONFS(vp->v_mount);
#ifdef NFS_ACDEBUG
mtx_lock(&Giant); /* ncl_printf() */
#endif
mtx_lock(&np->n_mtx);
/* XXX n_mtime doesn't seem to be updated on a miss-and-reload */
timeo = (time_second - np->n_mtime.tv_sec) / 10;
#ifdef NFS_ACDEBUG
if (nfs_acdebug>1)
ncl_printf("nfs_getattrcache: initial timeo = %d\n", timeo);
#endif
if (vap->va_type == VDIR) {
if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acdirmin)
timeo = nmp->nm_acdirmin;
else if (timeo > nmp->nm_acdirmax)
timeo = nmp->nm_acdirmax;
} else {
if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acregmin)
timeo = nmp->nm_acregmin;
else if (timeo > nmp->nm_acregmax)
timeo = nmp->nm_acregmax;
}
#ifdef NFS_ACDEBUG
if (nfs_acdebug > 2)
ncl_printf("acregmin %d; acregmax %d; acdirmin %d; acdirmax %d\n",
nmp->nm_acregmin, nmp->nm_acregmax,
nmp->nm_acdirmin, nmp->nm_acdirmax);
if (nfs_acdebug)
ncl_printf("nfs_getattrcache: age = %d; final timeo = %d\n",
(time_second - np->n_attrstamp), timeo);
#endif
if ((time_second - np->n_attrstamp) >= timeo) {
newnfsstats.attrcache_misses++;
mtx_unlock(&np->n_mtx);
return( ENOENT);
}
newnfsstats.attrcache_hits++;
if (vap->va_size != np->n_size) {
if (vap->va_type == VREG) {
if (np->n_flag & NMODIFIED) {
if (vap->va_size < np->n_size)
vap->va_size = np->n_size;
else
np->n_size = vap->va_size;
} else {
np->n_size = vap->va_size;
}
vnode_pager_setsize(vp, np->n_size);
} else {
np->n_size = vap->va_size;
}
}
bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr));
if (np->n_flag & NCHG) {
if (np->n_flag & NACC)
vaper->va_atime = np->n_atim;
if (np->n_flag & NUPD)
vaper->va_mtime = np->n_mtim;
}
mtx_unlock(&np->n_mtx);
#ifdef NFS_ACDEBUG
mtx_unlock(&Giant); /* ncl_printf() */
#endif
return (0);
}
static nfsuint64 nfs_nullcookie = { { 0, 0 } };
/*
* This function finds the directory cookie that corresponds to the
* logical byte offset given.
*/
nfsuint64 *
ncl_getcookie(struct nfsnode *np, off_t off, int add)
{
struct nfsdmap *dp, *dp2;
int pos;
nfsuint64 *retval = NULL;
pos = (uoff_t)off / NFS_DIRBLKSIZ;
if (pos == 0 || off < 0) {
#ifdef DIAGNOSTIC
if (add)
panic("nfs getcookie add at <= 0");
#endif
return (&nfs_nullcookie);
}
pos--;
dp = LIST_FIRST(&np->n_cookies);
if (!dp) {
if (add) {
MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap),
M_NFSDIROFF, M_WAITOK);
dp->ndm_eocookie = 0;
LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list);
} else
goto out;
}
while (pos >= NFSNUMCOOKIES) {
pos -= NFSNUMCOOKIES;
if (LIST_NEXT(dp, ndm_list)) {
if (!add && dp->ndm_eocookie < NFSNUMCOOKIES &&
pos >= dp->ndm_eocookie)
goto out;
dp = LIST_NEXT(dp, ndm_list);
} else if (add) {
MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap),
M_NFSDIROFF, M_WAITOK);
dp2->ndm_eocookie = 0;
LIST_INSERT_AFTER(dp, dp2, ndm_list);
dp = dp2;
} else
goto out;
}
if (pos >= dp->ndm_eocookie) {
if (add)
dp->ndm_eocookie = pos + 1;
else
goto out;
}
retval = &dp->ndm_cookies[pos];
out:
return (retval);
}
/*
* Invalidate cached directory information, except for the actual directory
* blocks (which are invalidated separately).
* Done mainly to avoid the use of stale offset cookies.
*/
void
ncl_invaldir(struct vnode *vp)
{
struct nfsnode *np = VTONFS(vp);
#ifdef DIAGNOSTIC
if (vp->v_type != VDIR)
panic("nfs: invaldir not dir");
#endif
ncl_dircookie_lock(np);
np->n_direofoffset = 0;
np->n_cookieverf.nfsuquad[0] = 0;
np->n_cookieverf.nfsuquad[1] = 0;
if (LIST_FIRST(&np->n_cookies))
LIST_FIRST(&np->n_cookies)->ndm_eocookie = 0;
ncl_dircookie_unlock(np);
}
/*
* The write verifier has changed (probably due to a server reboot), so all
* B_NEEDCOMMIT blocks will have to be written again. Since they are on the
* dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT
* and B_CLUSTEROK flags. Once done the new write verifier can be set for the
* mount point.
*
* B_CLUSTEROK must be cleared along with B_NEEDCOMMIT because stage 1 data
* writes are not clusterable.
*/
void
ncl_clearcommit(struct mount *mp)
{
struct vnode *vp, *nvp;
struct buf *bp, *nbp;
struct bufobj *bo;
MNT_ILOCK(mp);
MNT_VNODE_FOREACH(vp, mp, nvp) {
bo = &vp->v_bufobj;
VI_LOCK(vp);
if (vp->v_iflag & VI_DOOMED) {
VI_UNLOCK(vp);
continue;
}
vholdl(vp);
VI_UNLOCK(vp);
MNT_IUNLOCK(mp);
BO_LOCK(bo);
TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, nbp) {
if (!BUF_ISLOCKED(bp) &&
(bp->b_flags & (B_DELWRI | B_NEEDCOMMIT))
== (B_DELWRI | B_NEEDCOMMIT))
bp->b_flags &= ~(B_NEEDCOMMIT | B_CLUSTEROK);
}
BO_UNLOCK(bo);
vdrop(vp);
MNT_ILOCK(mp);
}
MNT_IUNLOCK(mp);
}
/*
* Called once to initialize data structures...
*/
int
ncl_init(struct vfsconf *vfsp)
{
int i;
/* Ensure async daemons disabled */
for (i = 0; i < NFS_MAXRAHEAD; i++) {
ncl_iodwant[i] = NULL;
ncl_iodmount[i] = NULL;
}
ncl_nhinit(); /* Init the nfsnode table */
return (0);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,89 @@
/*-
* Copyright (c) 1998 Berkeley Software Design, Inc. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Berkeley Software Design Inc's name may not be used to endorse or
* promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN INC ``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 BERKELEY SOFTWARE DESIGN INC 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$
*/
/*
* lockd uses the nfssvc system call to get the unique kernel services it needs.
* It passes in a request structure with a version number at the start.
* This prevents libc from needing to change if the information passed
* between lockd and the kernel needs to change.
*
* If a structure changes, you must bump the version number.
*/
/*
* The fifo where the kernel writes requests for locks on remote NFS files,
* and where lockd reads these requests.
*
*/
#define _PATH_NFSLCKDEV "nfslock"
/*
* This structure is used to uniquely identify the process which originated
* a particular message to lockd. A sequence number is used to differentiate
* multiple messages from the same process. A process start time is used to
* detect the unlikely, but possible, event of the recycling of a pid.
*/
struct lockd_msg_ident {
pid_t pid; /* The process ID. */
struct timeval pid_start; /* Start time of process id */
int msg_seq; /* Sequence number of message */
};
#define LOCKD_MSG_VERSION 3
/*
* The structure that the kernel hands us for each lock request.
*/
typedef struct __lock_msg {
TAILQ_ENTRY(__lock_msg) lm_link; /* internal linkage */
int lm_version; /* which version is this */
struct lockd_msg_ident lm_msg_ident; /* originator of the message */
struct flock lm_fl; /* The lock request. */
int lm_wait; /* The F_WAIT flag. */
int lm_getlk; /* is this a F_GETLK request */
struct sockaddr_storage lm_addr; /* The address. */
int lm_nfsv3; /* If NFS version 3. */
size_t lm_fh_len; /* The file handle length. */
struct xucred lm_cred; /* user cred for lock req */
u_int8_t lm_fh[NFSX_V3FHMAX];/* The file handle. */
} LOCKD_MSG;
#define LOCKD_ANS_VERSION 1
struct lockd_ans {
int la_vers;
struct lockd_msg_ident la_msg_ident; /* originator of the message */
int la_errno;
int la_set_getlk_pid; /* use returned pid */
int la_getlk_pid; /* returned pid for F_GETLK */
};
#ifdef _KERNEL
int ncl_dolock(struct vop_advlock_args *ap);
#endif

104
sys/fs/nfsclient/nfsargs.h Normal file
View File

@ -0,0 +1,104 @@
/*-
* Copyright (c) 1989, 1993, 1995
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Rick Macklem at The University of Guelph.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 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 _NFSCLIENT_NFSARGS_H_
#define _NFSCLIENT_NFSARGS_H_
/*
* Arguments to mount NFS
*/
#define NFS_ARGSVERSION 4 /* change when nfs_args changes */
struct nfs_args {
int version; /* args structure version number */
struct sockaddr *addr; /* file server address */
int addrlen; /* length of address */
int sotype; /* Socket type */
int proto; /* and Protocol */
u_char *fh; /* File handle to be mounted */
int fhsize; /* Size, in bytes, of fh */
int flags; /* flags */
int wsize; /* write size in bytes */
int rsize; /* read size in bytes */
int readdirsize; /* readdir size in bytes */
int timeo; /* initial timeout in .1 secs */
int retrans; /* times to retry send */
int readahead; /* # of blocks to readahead */
int iothreadcnt; /* and count of assoc threads */
int wcommitsize; /* Max. write commit size in bytes */
char *hostname; /* server's name */
int acregmin; /* cache attrs for reg files min time */
int acregmax; /* cache attrs for reg files max time */
int acdirmin; /* cache attrs for dirs min time */
int acdirmax; /* cache attrs for dirs max time */
int krbnamelen; /* KerberosV principal name "-P" */
char *krbname;
int dirlen; /* Mount pt path for NFSv4 */
char *dirpath;
int srvkrbnamelen; /* Server kerberos target principal */
char *srvkrbname; /* and the name */
};
/*
* NFS mount option flags
*/
#define NFSMNT_SOFT 0x00000001 /* soft mount (hard is default) */
#define NFSMNT_WSIZE 0x00000002 /* set write size */
#define NFSMNT_RSIZE 0x00000004 /* set read size */
#define NFSMNT_TIMEO 0x00000008 /* set initial timeout */
#define NFSMNT_RETRANS 0x00000010 /* set number of request retries */
#define NFSMNT_DIRECTIO 0x00000020 /* set maximum grouplist size */
#define NFSMNT_INT 0x00000040 /* allow interrupts on hard mount */
#define NFSMNT_NOCONN 0x00000080 /* Don't Connect the socket */
#define NFSMNT_NFSV4 0x00000100 /* Use NFSv4 */
#define NFSMNT_NFSV3 0x00000200 /* Use NFS Version 3 protocol */
#define NFSMNT_KERB 0x00000400 /* Use Kerberos authentication */
#define NFSMNT_STRICT3530 0x00000800 /* Follow RFC3530 strictly */
#define NFSMNT_WCOMMITSIZE 0x00001000 /* set max write commit size */
#define NFSMNT_READAHEAD 0x00002000 /* set read ahead */
#define NFSMNT_INTEGRITY 0x00004000 /* Use Integrity cksum - krb5i */
#define NFSMNT_PRIVACY 0x00008000 /* Encrypt RPCs - krb5p */
#define NFSMNT_RDIRPLUS 0x00010000 /* Use Readdirplus for V3 */
#define NFSMNT_READDIRSIZE 0x00020000 /* Set readdir size */
#define NFSMNT_ACREGMIN 0x00040000
#define NFSMNT_ACREGMAX 0x00080000
#define NFSMNT_ACDIRMIN 0x00100000
#define NFSMNT_ACDIRMAX 0x00200000
#define NFSMNT_NOLOCKD 0x00400000 /* Locks are local */
#define NFSMNT_ALLGSSNAME 0x00800000 /* All RPCs use host principal */
#define NFSMNT_HASWRITEVERF 0x01000000 /* NFSv4 Write verifier */
#define NFSMNT_HASSETFSID 0x02000000 /* Has set FSID */
#define NFSMNT_RESVPORT 0x04000000 /* Use a reserved port (Bunk!!) */
#define NFSMNT_AUTOM 0x08000000 /* Done by autofs */
#endif /* _NFSCLIENT_NFSARGS_H_ */

View File

@ -0,0 +1,108 @@
/*-
* Copyright (c) 1991, 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 _NFSCLIENT_NFSDISKLESS_H_
#define _NFSCLIENT_NFSDISKLESS_H_
/*
* Structure that must be initialized for a diskless nfs client.
* This structure is used by nfs_mountroot() to set up the root vnode,
* and to do a partial ifconfig(8) and route(8) so that the critical net
* interface can communicate with the server.
* The primary bootstrap is expected to fill in the appropriate fields before
* starting the kernel.
* Currently only works for AF_INET protocols.
* NB: All fields are stored in net byte order to avoid hassles with
* client/server byte ordering differences.
*/
/*
* I have defined a new structure that can handle an NFS Version 3 file handle
* but the kernel still expects the old Version 2 one to be provided. The
* changes required in nfs_vfsops.c for using the new are documented there in
* comments. (I felt that breaking network booting code by changing this
* structure would not be prudent at this time, since almost all servers are
* still Version 2 anyhow.)
*/
struct nfsv3_diskless {
struct ifaliasreq myif; /* Default interface */
struct sockaddr_in mygateway; /* Default gateway */
struct nfs_args root_args; /* Mount args for root fs */
int root_fhsize; /* Size of root file handle */
u_char root_fh[NFSX_FHMAX]; /* File handle of root dir */
struct sockaddr_in root_saddr; /* Address of root server */
char root_hostnam[MNAMELEN]; /* Host name for mount pt */
long root_time; /* Timestamp of root fs */
char my_hostnam[MAXHOSTNAMELEN]; /* Client host name */
};
/*
* Old arguments to mount NFS
*/
struct onfs_args {
struct sockaddr *addr; /* file server address */
int addrlen; /* length of address */
int sotype; /* Socket type */
int proto; /* and Protocol */
u_char *fh; /* File handle to be mounted */
int fhsize; /* Size, in bytes, of fh */
int flags; /* flags */
int wsize; /* write size in bytes */
int rsize; /* read size in bytes */
int readdirsize; /* readdir size in bytes */
int timeo; /* initial timeout in .1 secs */
int retrans; /* times to retry send */
int readahead; /* # of blocks to readahead */
int leaseterm; /* Term (sec) of lease */
char *hostname; /* server's name */
};
struct nfs_diskless {
struct ifaliasreq myif; /* Default interface */
struct sockaddr_in mygateway; /* Default gateway */
struct onfs_args root_args; /* Mount args for root fs */
u_char root_fh[NFSX_V2FH]; /* File handle of root dir */
struct sockaddr_in root_saddr; /* Address of root server */
char root_hostnam[MNAMELEN]; /* Host name for mount pt */
long root_time; /* Timestamp of root fs */
char my_hostnam[MAXHOSTNAMELEN]; /* Client host name */
};
#ifdef _KERNEL
void bootpc_init(void);
void nfs_setup_diskless(void);
void nfs_parse_options(const char *, struct nfs_args *);
#endif
#endif /* _NFSCLIENT_NFSDISKLESS_H_ */

106
sys/fs/nfsclient/nfsmount.h Normal file
View File

@ -0,0 +1,106 @@
/*-
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Rick Macklem at The University of Guelph.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef _NFSCLIENT_NFSMOUNT_H_
#define _NFSCLIENT_NFSMOUNT_H_
/*
* Mount structure.
* One allocated on every NFS mount.
* Holds NFS specific information for mount.
*/
struct nfsmount {
struct mtx nm_mtx;
int nm_flag; /* Flags for soft/hard... */
int nm_state; /* Internal state flags */
struct mount *nm_mountp; /* Vfs structure for this filesystem */
int nm_numgrps; /* Max. size of groupslist */
u_char nm_fh[NFSX_FHMAX]; /* File handle of root dir */
int nm_fhsize; /* Size of root file handle */
struct nfssockreq nm_sockreq; /* Socket Info */
int nm_timeo; /* Init timer for NFSMNT_DUMBTIMR */
int nm_retry; /* Max retries */
int nm_timeouts; /* Request timeouts */
int nm_rsize; /* Max size of read rpc */
int nm_wsize; /* Max size of write rpc */
int nm_readdirsize; /* Size of a readdir rpc */
int nm_readahead; /* Num. of blocks to readahead */
int nm_wcommitsize; /* Max size of commit for write */
int nm_acdirmin; /* Directory attr cache min lifetime */
int nm_acdirmax; /* Directory attr cache max lifetime */
int nm_acregmin; /* Reg file attr cache min lifetime */
int nm_acregmax; /* Reg file attr cache max lifetime */
u_char nm_verf[NFSX_VERF]; /* write verifier */
TAILQ_HEAD(, buf) nm_bufq; /* async io buffer queue */
short nm_bufqlen; /* number of buffers in queue */
short nm_bufqwant; /* process wants to add to the queue */
int nm_bufqiods; /* number of iods processing queue */
u_int64_t nm_maxfilesize; /* maximum file size */
int nm_tprintf_initial_delay; /* initial delay */
int nm_tprintf_delay; /* interval for messages */
/* Newnfs additions */
int nm_iothreadcnt;
struct proc *nm_iodwant[NFS_MAXRAHEAD];
struct nfsclclient *nm_clp;
uid_t nm_uid; /* Uid for SetClientID etc. */
u_int64_t nm_clval; /* identifies which clientid */
u_int64_t nm_fsid[2]; /* NFSv4 fsid */
u_int16_t nm_krbnamelen; /* Krb5 host principal, if any */
u_int16_t nm_dirpathlen; /* and mount dirpath, for V4 */
u_int16_t nm_srvkrbnamelen; /* and the server's target name */
u_char nm_name[1]; /* malloc'd actual len of krbname + dirpath */
};
#define nm_nam nm_sockreq.nr_nam
#define nm_sotype nm_sockreq.nr_sotype
#define nm_so nm_sockreq.nr_so
#define nm_soflags nm_sockreq.nr_soflags
#define nm_soproto nm_sockreq.nr_soproto
#define nm_client nm_sockreq.nr_client
#define nm_krbname nm_name
#define NFSMNT_DIRPATH(m) (&((m)->nm_name[(m)->nm_krbnamelen + 1]))
#define NFSMNT_SRVKRBNAME(m) \
(&((m)->nm_name[(m)->nm_krbnamelen + (m)->nm_dirpathlen + 2]))
#if defined(_KERNEL)
/*
* Convert mount ptr to nfsmount ptr.
*/
#define VFSTONFS(mp) ((struct nfsmount *)((mp)->mnt_data))
#endif /* _KERNEL */
#endif /* _NFSCLIENT_NFSMOUNT_H_ */

201
sys/fs/nfsclient/nfsnode.h Normal file
View File

@ -0,0 +1,201 @@
/*-
* 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 _NFSCLIENT_NFSNODE_H_
#define _NFSCLIENT_NFSNODE_H_
/*
* Silly rename structure that hangs off the nfsnode until the name
* can be removed by nfs_inactive()
*/
struct sillyrename {
struct ucred *s_cred;
struct vnode *s_dvp;
long s_namlen;
char s_name[32];
};
/*
* This structure is used to save the logical directory offset to
* NFS cookie mappings.
* The mappings are stored in a list headed
* by n_cookies, as required.
* There is one mapping for each NFS_DIRBLKSIZ bytes of directory information
* stored in increasing logical offset byte order.
*/
#define NFSNUMCOOKIES 31
struct nfsdmap {
LIST_ENTRY(nfsdmap) ndm_list;
int ndm_eocookie;
union {
nfsuint64 ndmu3_cookies[NFSNUMCOOKIES];
uint64_t ndmu4_cookies[NFSNUMCOOKIES];
} ndm_un1;
};
#define ndm_cookies ndm_un1.ndmu3_cookies
#define ndm4_cookies ndm_un1.ndmu4_cookies
#define n_ac_ts_tid n_ac_ts.nfs_ac_ts_tid
#define n_ac_ts_pid n_ac_ts.nfs_ac_ts_pid
#define n_ac_ts_syscalls n_ac_ts.nfs_ac_ts_syscalls
struct nfs_attrcache_timestamp {
lwpid_t nfs_ac_ts_tid;
pid_t nfs_ac_ts_pid;
unsigned long nfs_ac_ts_syscalls;
};
struct nfs_accesscache {
u_int32_t mode; /* ACCESS mode cache */
uid_t uid; /* credentials having mode */
time_t stamp; /* mode cache timestamp */
};
/*
* The nfsnode is the nfs equivalent to ufs's inode. Any similarity
* is purely coincidental.
* There is a unique nfsnode allocated for each active file,
* each current directory, each mounted-on file, text file, and the root.
* An nfsnode is 'named' by its file handle. (nget/nfs_node.c)
* If this structure exceeds 256 bytes (it is currently 256 using 4.4BSD-Lite
* type definitions), file handles of > 32 bytes should probably be split out
* into a separate MALLOC()'d data structure. (Reduce the size of nfsfh_t by
* changing the definition in nfsproto.h of NFS_SMALLFH.)
* NB: Hopefully the current order of the fields is such that everything will
* be well aligned and, therefore, tightly packed.
*/
struct nfsnode {
struct mtx n_mtx; /* Protects all of these members */
u_quad_t n_size; /* Current size of file */
u_quad_t n_brev; /* Modify rev when cached */
u_quad_t n_lrev; /* Modify rev for lease */
struct nfsvattr n_vattr; /* Vnode attribute cache */
time_t n_attrstamp; /* Attr. cache timestamp */
struct nfs_accesscache n_accesscache[NFS_ACCESSCACHESIZE];
struct timespec n_mtime; /* Prev modify time. */
time_t n_ctime; /* Prev create time. */
time_t n_dmtime; /* Prev dir modify time. */
time_t n_expiry; /* Lease expiry time */
struct nfsfh *n_fhp; /* NFS File Handle */
struct vnode *n_vnode; /* associated vnode */
struct vnode *n_dvp; /* parent vnode */
struct lockf *n_lockf; /* Locking record of file */
int n_error; /* Save write error value */
union {
struct timespec nf_atim; /* Special file times */
nfsuint64 nd_cookieverf; /* Cookie verifier (dir only) */
u_char nd4_cookieverf[NFSX_VERF];
} n_un1;
union {
struct timespec nf_mtim;
off_t nd_direof; /* Dir. EOF offset cache */
} n_un2;
union {
struct sillyrename *nf_silly; /* Ptr to silly rename struct */
LIST_HEAD(, nfsdmap) nd_cook; /* cookies */
} n_un3;
short n_fhsize; /* size in bytes, of fh */
u_int32_t n_flag; /* Flag for locking.. */
int n_directio_opens;
int n_directio_asyncwr;
struct nfs_attrcache_timestamp n_ac_ts;
u_int64_t n_change; /* old Change attribute */
struct nfsv4node *n_v4; /* extra V4 stuff */
};
#define n_atim n_un1.nf_atim
#define n_mtim n_un2.nf_mtim
#define n_sillyrename n_un3.nf_silly
#define n_cookieverf n_un1.nd_cookieverf
#define n4_cookieverf n_un1.nd4_cookieverf
#define n_direofoffset n_un2.nd_direof
#define n_cookies n_un3.nd_cook
/*
* Flags for n_flag
*/
#define NDIRCOOKIELK 0x00000001 /* Lock to serialize access to directory cookies */
#define NFSYNCWAIT 0x00000002 /* fsync waiting for all directio async
writes to drain */
#define NMODIFIED 0x00000004 /* Might have a modified buffer in bio */
#define NWRITEERR 0x00000008 /* Flag write errors so close will know */
#define NCREATED 0x00000010 /* Opened by nfs_create() */
#define NTRUNCATE 0x00000020 /* Opened by nfs_setattr() */
#define NSIZECHANGED 0x00000040 /* File size has changed: need cache inval */
#define NNONCACHE 0x00000080 /* Node marked as noncacheable */
#define NACC 0x00000100 /* Special file accessed */
#define NUPD 0x00000200 /* Special file updated */
#define NCHG 0x00000400 /* Special file times changed */
#define NDELEGMOD 0x00000800 /* Modified delegation */
#define NDELEGRECALL 0x00001000 /* Recall in progress */
#define NREMOVEINPROG 0x00002000 /* Remove in progress */
#define NREMOVEWANT 0x00004000 /* Want notification that remove is done */
#define NLOCK 0x00008000 /* Sleep lock the node */
#define NLOCKWANT 0x00010000 /* Want the sleep lock */
/*
* Convert between nfsnode pointers and vnode pointers
*/
#define VTONFS(vp) ((struct nfsnode *)(vp)->v_data)
#define NFSTOV(np) ((struct vnode *)(np)->n_vnode)
#define NFS_TIMESPEC_COMPARE(T1, T2) (((T1)->tv_sec != (T2)->tv_sec) || ((T1)->tv_nsec != (T2)->tv_nsec))
#if defined(_KERNEL)
/*
* Prototypes for NFS vnode operations
*/
int ncl_getpages(struct vop_getpages_args *);
int ncl_putpages(struct vop_putpages_args *);
int ncl_write(struct vop_write_args *);
int ncl_inactive(struct vop_inactive_args *);
int ncl_reclaim(struct vop_reclaim_args *);
/* other stuff */
int ncl_removeit(struct sillyrename *, struct vnode *);
int ncl_nget(struct mount *, u_int8_t *, int, struct nfsnode **);
nfsuint64 *ncl_getcookie(struct nfsnode *, off_t, int);
void ncl_invaldir(struct vnode *);
int ncl_upgrade_vnlock(struct vnode *);
void ncl_downgrade_vnlock(struct vnode *, int);
void ncl_printf(const char *, ...);
void ncl_dircookie_lock(struct nfsnode *);
void ncl_dircookie_unlock(struct nfsnode *);
#endif /* _KERNEL */
#endif /* _NFSCLIENT_NFSNODE_H_ */

View File

@ -0,0 +1,41 @@
/*-
* Copyright (c) 1998 Berkeley Software Design, Inc. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Berkeley Software Design Inc's name may not be used to endorse or
* promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN INC ``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 BERKELEY SOFTWARE DESIGN INC 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$
*/
/*
* Misc NLM informationi, some needed for the master lockd process, and some
* needed by every process doing nlm based locking.
*/
struct nlminfo {
/* these are used by any process doing nlm locking */
int msg_seq; /* sequence counter for lock requests */
int retcode; /* return code for lock requests */
int set_getlk_pid;
int getlk_pid;
struct timeval pid_start; /* process starting time */
};

View File

@ -0,0 +1,867 @@
/*-
* 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$");
/*
* Here is the basic algorithm:
* First, some design criteria I used:
* - I think a false hit is more serious than a false miss
* - A false hit for an RPC that has Op(s) that order via seqid# must be
* avoided at all cost
* - A valid hit will probably happen a long time after the original reply
* and the TCP socket that the original request was received on will no
* longer be active
* (The long time delay implies to me that LRU is not appropriate.)
* - The mechanism will satisfy the requirements of ordering Ops with seqid#s
* in them as well as minimizing the risk of redoing retried non-idempotent
* Ops.
* Because it is biased towards avoiding false hits, multiple entries with
* the same xid are to be expected, especially for the case of the entry
* in the cache being related to a seqid# sequenced Op.
*
* The basic algorithm I'm about to code up:
* - Null RPCs bypass the cache and are just done
* For TCP
* - key on <xid, NFS version> (as noted above, there can be several
* entries with the same key)
* When a request arrives:
* For all that match key
* - if RPC# != OR request_size !=
* - not a match with this one
* - if NFSv4 and received on same TCP socket OR
* received on a TCP connection created before the
* entry was cached
* - not a match with this one
* (V2,3 clients might retry on same TCP socket)
* - calculate checksum on first N bytes of NFS XDR
* - if checksum !=
* - not a match for this one
* If any of the remaining ones that match has a
* seqid_refcnt > 0
* - not a match (go do RPC, using new cache entry)
* If one match left
* - a hit (reply from cache)
* else
* - miss (go do RPC, using new cache entry)
*
* During processing of NFSv4 request:
* - set a flag when a non-idempotent Op is processed
* - when an Op that uses a seqid# (Open,...) is processed
* - if same seqid# as referenced entry in cache
* - free new cache entry
* - reply from referenced cache entry
* else if next seqid# in order
* - free referenced cache entry
* - increment seqid_refcnt on new cache entry
* - set pointer from Openowner/Lockowner to
* new cache entry (aka reference it)
* else if first seqid# in sequence
* - increment seqid_refcnt on new cache entry
* - set pointer from Openowner/Lockowner to
* new cache entry (aka reference it)
*
* At end of RPC processing:
* - if seqid_refcnt > 0 OR flagged non-idempotent on new
* cache entry
* - save reply in cache entry
* - calculate checksum on first N bytes of NFS XDR
* request
* - note op and length of XDR request (in bytes)
* - timestamp it
* else
* - free new cache entry
* - Send reply (noting info for socket activity check, below)
*
* For cache entries saved above:
* - if saved since seqid_refcnt was > 0
* - free when seqid_refcnt decrements to 0
* (when next one in sequence is processed above, or
* when Openowner/Lockowner is discarded)
* else { non-idempotent Op(s) }
* - free when
* - some further activity observed on same
* socket
* (I'm not yet sure how I'm going to do
* this. Maybe look at the TCP connection
* to see if the send_tcp_sequence# is well
* past sent reply OR K additional RPCs
* replied on same socket OR?)
* OR
* - when very old (hours, days, weeks?)
*
* For UDP (v2, 3 only), pretty much the old way:
* - key on <xid, NFS version, RPC#, Client host ip#>
* (at most one entry for each key)
*
* When a Request arrives:
* - if a match with entry via key
* - if RPC marked In_progress
* - discard request (don't send reply)
* else
* - reply from cache
* - timestamp cache entry
* else
* - add entry to cache, marked In_progress
* - do RPC
* - when RPC done
* - if RPC# non-idempotent
* - mark entry Done (not In_progress)
* - save reply
* - timestamp cache entry
* else
* - free cache entry
* - send reply
*
* Later, entries with saved replies are free'd a short time (few minutes)
* after reply sent (timestamp).
* Reference: Chet Juszczak, "Improving the Performance and Correctness
* of an NFS Server", in Proc. Winter 1989 USENIX Conference,
* pages 53-63. San Diego, February 1989.
* for the UDP case.
* nfsrc_floodlevel is set to the allowable upper limit for saved replies
* for TCP. For V3, a reply won't be saved when the flood level is
* hit. For V4, the non-idempotent Op will return NFSERR_RESOURCE in
* that case. This level should be set high enough that this almost
* never happens.
*/
#ifndef APPLEKEXT
#include <fs/nfs/nfsport.h>
extern struct nfsstats newnfsstats;
NFSCACHEMUTEX;
int nfsrc_floodlevel = NFSRVCACHE_FLOODLEVEL, nfsrc_tcpsavedreplies = 0;
#endif /* !APPLEKEXT */
static int nfsrc_tcpnonidempotent = 1;
static int nfsrc_udphighwater = NFSRVCACHE_UDPHIGHWATER, nfsrc_udpcachesize = 0;
static TAILQ_HEAD(, nfsrvcache) nfsrvudplru;
static struct nfsrvhashhead nfsrvhashtbl[NFSRVCACHE_HASHSIZE],
nfsrvudphashtbl[NFSRVCACHE_HASHSIZE];
/*
* and the reverse mapping from generic to Version 2 procedure numbers
*/
static int newnfsv2_procid[NFS_V3NPROCS] = {
NFSV2PROC_NULL,
NFSV2PROC_GETATTR,
NFSV2PROC_SETATTR,
NFSV2PROC_LOOKUP,
NFSV2PROC_NOOP,
NFSV2PROC_READLINK,
NFSV2PROC_READ,
NFSV2PROC_WRITE,
NFSV2PROC_CREATE,
NFSV2PROC_MKDIR,
NFSV2PROC_SYMLINK,
NFSV2PROC_CREATE,
NFSV2PROC_REMOVE,
NFSV2PROC_RMDIR,
NFSV2PROC_RENAME,
NFSV2PROC_LINK,
NFSV2PROC_READDIR,
NFSV2PROC_NOOP,
NFSV2PROC_STATFS,
NFSV2PROC_NOOP,
NFSV2PROC_NOOP,
NFSV2PROC_NOOP,
};
#define NFSRCUDPHASH(xid) \
(&nfsrvudphashtbl[((xid) + ((xid) >> 24)) % NFSRVCACHE_HASHSIZE])
#define NFSRCHASH(xid) \
(&nfsrvhashtbl[((xid) + ((xid) >> 24)) % NFSRVCACHE_HASHSIZE])
#define TRUE 1
#define FALSE 0
#define NFSRVCACHE_CHECKLEN 100
/* True iff the rpc reply is an nfs status ONLY! */
static int nfsv2_repstat[NFS_V3NPROCS] = {
FALSE,
FALSE,
FALSE,
FALSE,
FALSE,
FALSE,
FALSE,
FALSE,
FALSE,
FALSE,
TRUE,
TRUE,
TRUE,
TRUE,
FALSE,
TRUE,
FALSE,
FALSE,
FALSE,
FALSE,
FALSE,
FALSE,
};
/*
* Will NFS want to work over IPv6 someday?
*/
#define NETFAMILY(rp) \
(((rp)->rc_flag & RC_INETIPV6) ? AF_INET6 : AF_INET)
/* local functions */
static int nfsrc_getudp(struct nfsrv_descript *nd, struct nfsrvcache *newrp);
static int nfsrc_gettcp(struct nfsrv_descript *nd, struct nfsrvcache *newrp);
static void nfsrc_lock(struct nfsrvcache *rp);
static void nfsrc_unlock(struct nfsrvcache *rp);
static void nfsrc_wanted(struct nfsrvcache *rp);
static void nfsrc_freecache(struct nfsrvcache *rp);
static void nfsrc_trimcache(u_int64_t, struct socket *);
static int nfsrc_activesocket(struct nfsrvcache *rp, u_int64_t,
struct socket *);
static int nfsrc_getlenandcksum(mbuf_t m1, u_int16_t *cksum);
static void nfsrc_marksametcpconn(u_int64_t);
/*
* Initialize the server request cache list
*/
APPLESTATIC void
nfsrvd_initcache(void)
{
int i;
static int inited = 0;
if (inited)
return;
inited = 1;
for (i = 0; i < NFSRVCACHE_HASHSIZE; i++) {
LIST_INIT(&nfsrvudphashtbl[i]);
LIST_INIT(&nfsrvhashtbl[i]);
}
TAILQ_INIT(&nfsrvudplru);
nfsrc_tcpsavedreplies = 0;
nfsrc_udpcachesize = 0;
newnfsstats.srvcache_tcppeak = 0;
newnfsstats.srvcache_size = 0;
}
/*
* Get a cache entry for this request. Basically just malloc a new one
* and then call nfsrc_getudp() or nfsrc_gettcp() to do the rest.
* Call nfsrc_trimcache() to clean up the cache before returning.
*/
APPLESTATIC int
nfsrvd_getcache(struct nfsrv_descript *nd, struct socket *so)
{
struct nfsrvcache *newrp;
int ret;
if (nd->nd_procnum == NFSPROC_NULL)
panic("nfsd cache null");
MALLOC(newrp, struct nfsrvcache *, sizeof (struct nfsrvcache),
M_NFSRVCACHE, M_WAITOK);
NFSBZERO((caddr_t)newrp, sizeof (struct nfsrvcache));
if (nd->nd_flag & ND_NFSV4)
newrp->rc_flag = RC_NFSV4;
else if (nd->nd_flag & ND_NFSV3)
newrp->rc_flag = RC_NFSV3;
else
newrp->rc_flag = RC_NFSV2;
newrp->rc_xid = nd->nd_retxid;
newrp->rc_proc = nd->nd_procnum;
newrp->rc_sockref = nd->nd_sockref;
newrp->rc_cachetime = nd->nd_tcpconntime;
if (nd->nd_flag & ND_SAMETCPCONN)
newrp->rc_flag |= RC_SAMETCPCONN;
if (nd->nd_nam2 != NULL) {
newrp->rc_flag |= RC_UDP;
ret = nfsrc_getudp(nd, newrp);
} else {
ret = nfsrc_gettcp(nd, newrp);
}
nfsrc_trimcache(nd->nd_sockref, so);
return (ret);
}
/*
* For UDP (v2, v3):
* - key on <xid, NFS version, RPC#, Client host ip#>
* (at most one entry for each key)
*/
static int
nfsrc_getudp(struct nfsrv_descript *nd, struct nfsrvcache *newrp)
{
struct nfsrvcache *rp;
struct sockaddr_in *saddr;
struct sockaddr_in6 *saddr6;
struct nfsrvhashhead *hp;
int ret = 0;
hp = NFSRCUDPHASH(newrp->rc_xid);
loop:
NFSLOCKCACHE();
LIST_FOREACH(rp, hp, rc_hash) {
if (newrp->rc_xid == rp->rc_xid &&
newrp->rc_proc == rp->rc_proc &&
(newrp->rc_flag & rp->rc_flag & RC_NFSVERS) &&
nfsaddr_match(NETFAMILY(rp), &rp->rc_haddr, nd->nd_nam)) {
if ((rp->rc_flag & RC_LOCKED) != 0) {
rp->rc_flag |= RC_WANTED;
NFSUNLOCKCACHE();
(void) tsleep((caddr_t)rp, PZERO - 1,
"nfsrc", 10 * hz);
goto loop;
}
if (rp->rc_flag == 0)
panic("nfs udp cache0");
rp->rc_flag |= RC_LOCKED;
TAILQ_REMOVE(&nfsrvudplru, rp, rc_lru);
TAILQ_INSERT_TAIL(&nfsrvudplru, rp, rc_lru);
if (rp->rc_flag & RC_INPROG) {
newnfsstats.srvcache_inproghits++;
NFSUNLOCKCACHE();
ret = RC_DROPIT;
} else if (rp->rc_flag & RC_REPSTATUS) {
/*
* V2 only.
*/
newnfsstats.srvcache_nonidemdonehits++;
NFSUNLOCKCACHE();
nfsrvd_rephead(nd);
*(nd->nd_errp) = rp->rc_status;
ret = RC_REPLY;
rp->rc_timestamp = NFSD_MONOSEC +
NFSRVCACHE_UDPTIMEOUT;
} else if (rp->rc_flag & RC_REPMBUF) {
newnfsstats.srvcache_nonidemdonehits++;
NFSUNLOCKCACHE();
nd->nd_mreq = m_copym(rp->rc_reply, 0,
M_COPYALL, M_WAIT);
ret = RC_REPLY;
rp->rc_timestamp = NFSD_MONOSEC +
NFSRVCACHE_UDPTIMEOUT;
} else {
panic("nfs udp cache1");
}
nfsrc_unlock(rp);
free((caddr_t)newrp, M_NFSRVCACHE);
return (ret);
}
}
newnfsstats.srvcache_misses++;
newnfsstats.srvcache_size++;
nfsrc_udpcachesize++;
newrp->rc_flag |= RC_INPROG;
saddr = NFSSOCKADDR(nd->nd_nam, struct sockaddr_in *);
if (saddr->sin_family == AF_INET)
newrp->rc_inet = saddr->sin_addr.s_addr;
else if (saddr->sin_family == AF_INET6) {
saddr6 = (struct sockaddr_in6 *)saddr;
NFSBCOPY((caddr_t)&saddr6->sin6_addr,(caddr_t)&newrp->rc_inet6,
sizeof (struct in6_addr));
rp->rc_flag |= RC_INETIPV6;
}
LIST_INSERT_HEAD(hp, newrp, rc_hash);
TAILQ_INSERT_TAIL(&nfsrvudplru, newrp, rc_lru);
NFSUNLOCKCACHE();
nd->nd_rp = newrp;
return (RC_DOIT);
}
/*
* Update a request cache entry after the rpc has been done
*/
APPLESTATIC struct nfsrvcache *
nfsrvd_updatecache(struct nfsrv_descript *nd, struct socket *so)
{
struct nfsrvcache *rp;
struct nfsrvcache *retrp = NULL;
rp = nd->nd_rp;
if (!rp)
panic("nfsrvd_updatecache null rp");
nd->nd_rp = NULL;
NFSLOCKCACHE();
nfsrc_lock(rp);
if (!(rp->rc_flag & RC_INPROG))
panic("nfsrvd_updatecache not inprog");
rp->rc_flag &= ~RC_INPROG;
if (rp->rc_flag & RC_UDP) {
TAILQ_REMOVE(&nfsrvudplru, rp, rc_lru);
TAILQ_INSERT_TAIL(&nfsrvudplru, rp, rc_lru);
}
/*
* Reply from cache is a special case returned by nfsrv_checkseqid().
*/
if (nd->nd_repstat == NFSERR_REPLYFROMCACHE) {
newnfsstats.srvcache_nonidemdonehits++;
NFSUNLOCKCACHE();
nd->nd_repstat = 0;
if (nd->nd_mreq)
mbuf_freem(nd->nd_mreq);
if (!(rp->rc_flag & RC_REPMBUF))
panic("reply from cache");
nd->nd_mreq = m_copym(rp->rc_reply, 0,
M_COPYALL, M_WAIT);
rp->rc_timestamp = NFSD_MONOSEC + NFSRVCACHE_TCPTIMEOUT;
nfsrc_unlock(rp);
nfsrc_trimcache(nd->nd_sockref, so);
return (retrp);
}
/*
* If rc_refcnt > 0, save it
* For UDP, save it if ND_SAVEREPLY is set
* For TCP, save it if ND_SAVEREPLY and nfsrc_tcpnonidempotent is set
*/
if (nd->nd_repstat != NFSERR_DONTREPLY &&
(rp->rc_refcnt > 0 ||
((nd->nd_flag & ND_SAVEREPLY) && (rp->rc_flag & RC_UDP)) ||
((nd->nd_flag & ND_SAVEREPLY) && !(rp->rc_flag & RC_UDP) &&
nfsrc_tcpsavedreplies <= nfsrc_floodlevel &&
nfsrc_tcpnonidempotent))) {
if (rp->rc_refcnt > 0) {
if (!(rp->rc_flag & RC_NFSV4))
panic("update_cache refcnt");
rp->rc_flag |= RC_REFCNT;
}
if ((nd->nd_flag & ND_NFSV2) &&
nfsv2_repstat[newnfsv2_procid[nd->nd_procnum]]) {
NFSUNLOCKCACHE();
rp->rc_status = nd->nd_repstat;
rp->rc_flag |= RC_REPSTATUS;
} else {
if (!(rp->rc_flag & RC_UDP)) {
nfsrc_tcpsavedreplies++;
if (nfsrc_tcpsavedreplies >
newnfsstats.srvcache_tcppeak)
newnfsstats.srvcache_tcppeak =
nfsrc_tcpsavedreplies;
}
NFSUNLOCKCACHE();
rp->rc_reply = m_copym(nd->nd_mreq, 0, M_COPYALL,
M_WAIT);
rp->rc_flag |= RC_REPMBUF;
}
if (rp->rc_flag & RC_UDP) {
rp->rc_timestamp = NFSD_MONOSEC +
NFSRVCACHE_UDPTIMEOUT;
nfsrc_unlock(rp);
} else {
rp->rc_timestamp = NFSD_MONOSEC +
NFSRVCACHE_TCPTIMEOUT;
if (rp->rc_refcnt > 0)
nfsrc_unlock(rp);
else
retrp = rp;
}
} else {
nfsrc_freecache(rp);
NFSUNLOCKCACHE();
}
nfsrc_trimcache(nd->nd_sockref, so);
return (retrp);
}
/*
* Invalidate and, if possible, free an in prog cache entry.
* Must not sleep.
*/
APPLESTATIC void
nfsrvd_delcache(struct nfsrvcache *rp)
{
if (!(rp->rc_flag & RC_INPROG))
panic("nfsrvd_delcache not in prog");
NFSLOCKCACHE();
rp->rc_flag &= ~RC_INPROG;
if (rp->rc_refcnt == 0 && !(rp->rc_flag & RC_LOCKED))
nfsrc_freecache(rp);
NFSUNLOCKCACHE();
}
/*
* Called after nfsrvd_updatecache() once the reply is sent, to update
* the entry for nfsrc_activesocket() and unlock it. The argument is
* the pointer returned by nfsrvd_updatecache().
*/
APPLESTATIC void
nfsrvd_sentcache(struct nfsrvcache *rp, struct socket *so, int err)
{
if (!(rp->rc_flag & RC_LOCKED))
panic("nfsrvd_sentcache not locked");
if (!err) {
if (so->so_proto->pr_domain->dom_family != AF_INET ||
so->so_proto->pr_protocol != IPPROTO_TCP)
panic("nfs sent cache");
if (nfsrv_getsockseqnum(so, &rp->rc_tcpseq))
rp->rc_flag |= RC_TCPSEQ;
}
nfsrc_unlock(rp);
}
/*
* Get a cache entry for TCP
* - key on <xid, nfs version>
* (allow multiple entries for a given key)
*/
static int
nfsrc_gettcp(struct nfsrv_descript *nd, struct nfsrvcache *newrp)
{
struct nfsrvcache *rp, *nextrp;
int i;
struct nfsrvcache *hitrp;
struct nfsrvhashhead *hp, nfsrc_templist;
int hit, ret = 0;
hp = NFSRCHASH(newrp->rc_xid);
newrp->rc_reqlen = nfsrc_getlenandcksum(nd->nd_mrep, &newrp->rc_cksum);
tryagain:
NFSLOCKCACHE();
hit = 1;
LIST_INIT(&nfsrc_templist);
/*
* Get all the matches and put them on the temp list.
*/
rp = LIST_FIRST(hp);
while (rp != LIST_END(hp)) {
nextrp = LIST_NEXT(rp, rc_hash);
if (newrp->rc_xid == rp->rc_xid &&
(!(rp->rc_flag & RC_INPROG) ||
((newrp->rc_flag & RC_SAMETCPCONN) &&
newrp->rc_sockref == rp->rc_sockref)) &&
(newrp->rc_flag & rp->rc_flag & RC_NFSVERS) &&
newrp->rc_proc == rp->rc_proc &&
((newrp->rc_flag & RC_NFSV4) &&
newrp->rc_sockref != rp->rc_sockref &&
newrp->rc_cachetime >= rp->rc_cachetime)
&& newrp->rc_reqlen == rp->rc_reqlen &&
newrp->rc_cksum == rp->rc_cksum) {
LIST_REMOVE(rp, rc_hash);
LIST_INSERT_HEAD(&nfsrc_templist, rp, rc_hash);
}
rp = nextrp;
}
/*
* Now, use nfsrc_templist to decide if there is a match.
*/
i = 0;
LIST_FOREACH(rp, &nfsrc_templist, rc_hash) {
i++;
if (rp->rc_refcnt > 0) {
hit = 0;
break;
}
}
/*
* Can be a hit only if one entry left.
* Note possible hit entry and put nfsrc_templist back on hash
* list.
*/
if (i != 1)
hit = 0;
hitrp = rp = LIST_FIRST(&nfsrc_templist);
while (rp != LIST_END(&nfsrc_templist)) {
nextrp = LIST_NEXT(rp, rc_hash);
LIST_REMOVE(rp, rc_hash);
LIST_INSERT_HEAD(hp, rp, rc_hash);
rp = nextrp;
}
if (LIST_FIRST(&nfsrc_templist) != LIST_END(&nfsrc_templist))
panic("nfs gettcp cache templist");
if (hit) {
rp = hitrp;
if ((rp->rc_flag & RC_LOCKED) != 0) {
rp->rc_flag |= RC_WANTED;
NFSUNLOCKCACHE();
(void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 10 * hz);
goto tryagain;
}
if (rp->rc_flag == 0)
panic("nfs tcp cache0");
rp->rc_flag |= RC_LOCKED;
if (rp->rc_flag & RC_INPROG) {
newnfsstats.srvcache_inproghits++;
NFSUNLOCKCACHE();
if (newrp->rc_sockref == rp->rc_sockref)
nfsrc_marksametcpconn(rp->rc_sockref);
ret = RC_DROPIT;
} else if (rp->rc_flag & RC_REPSTATUS) {
/*
* V2 only.
*/
newnfsstats.srvcache_nonidemdonehits++;
NFSUNLOCKCACHE();
if (newrp->rc_sockref == rp->rc_sockref)
nfsrc_marksametcpconn(rp->rc_sockref);
ret = RC_REPLY;
nfsrvd_rephead(nd);
*(nd->nd_errp) = rp->rc_status;
rp->rc_timestamp = NFSD_MONOSEC +
NFSRVCACHE_TCPTIMEOUT;
} else if (rp->rc_flag & RC_REPMBUF) {
newnfsstats.srvcache_nonidemdonehits++;
NFSUNLOCKCACHE();
if (newrp->rc_sockref == rp->rc_sockref)
nfsrc_marksametcpconn(rp->rc_sockref);
ret = RC_REPLY;
nd->nd_mreq = m_copym(rp->rc_reply, 0,
M_COPYALL, M_WAIT);
rp->rc_timestamp = NFSD_MONOSEC +
NFSRVCACHE_TCPTIMEOUT;
} else {
panic("nfs tcp cache1");
}
nfsrc_unlock(rp);
free((caddr_t)newrp, M_NFSRVCACHE);
return (ret);
}
newnfsstats.srvcache_misses++;
newnfsstats.srvcache_size++;
/*
* For TCP, multiple entries for a key are allowed, so don't
* chain it into the hash table until done.
*/
newrp->rc_cachetime = NFSD_MONOSEC;
newrp->rc_flag |= RC_INPROG;
LIST_INSERT_HEAD(hp, newrp, rc_hash);
NFSUNLOCKCACHE();
nd->nd_rp = newrp;
return (RC_DOIT);
}
/*
* Lock a cache entry.
* Also puts a mutex lock on the cache list.
*/
static void
nfsrc_lock(struct nfsrvcache *rp)
{
NFSCACHELOCKREQUIRED();
while ((rp->rc_flag & RC_LOCKED) != 0) {
rp->rc_flag |= RC_WANTED;
(void) nfsmsleep((caddr_t)rp, NFSCACHEMUTEXPTR, PZERO - 1,
"nfsrc", 0);
}
rp->rc_flag |= RC_LOCKED;
}
/*
* Unlock a cache entry.
*/
static void
nfsrc_unlock(struct nfsrvcache *rp)
{
rp->rc_flag &= ~RC_LOCKED;
nfsrc_wanted(rp);
}
/*
* Wakeup anyone wanting entry.
*/
static void
nfsrc_wanted(struct nfsrvcache *rp)
{
if (rp->rc_flag & RC_WANTED) {
rp->rc_flag &= ~RC_WANTED;
wakeup((caddr_t)rp);
}
}
/*
* Free up the entry.
* Must not sleep.
*/
static void
nfsrc_freecache(struct nfsrvcache *rp)
{
NFSCACHELOCKREQUIRED();
LIST_REMOVE(rp, rc_hash);
if (rp->rc_flag & RC_UDP) {
TAILQ_REMOVE(&nfsrvudplru, rp, rc_lru);
nfsrc_udpcachesize--;
}
nfsrc_wanted(rp);
if (rp->rc_flag & RC_REPMBUF) {
mbuf_freem(rp->rc_reply);
if (!(rp->rc_flag & RC_UDP))
nfsrc_tcpsavedreplies--;
}
FREE((caddr_t)rp, M_NFSRVCACHE);
newnfsstats.srvcache_size--;
}
#ifdef notdef
/*
* Clean out the cache. Called when the last nfsd terminates.
*/
APPLESTATIC void
nfsrvd_cleancache(void)
{
struct nfsrvcache *rp, *nextrp;
int i;
NFSLOCKCACHE();
for (i = 0; i < NFSRVCACHE_HASHSIZE; i++) {
LIST_FOREACH_SAFE(rp, &nfsrvhashtbl[i], rc_hash, nextrp) {
nfsrc_freecache(rp);
}
}
for (i = 0; i < NFSRVCACHE_HASHSIZE; i++) {
LIST_FOREACH_SAFE(rp, &nfsrvudphashtbl[i], rc_hash, nextrp) {
nfsrc_freecache(rp);
}
}
newnfsstats.srvcache_size = 0;
nfsrc_tcpsavedreplies = 0;
NFSUNLOCKCACHE();
}
#endif /* notdef */
/*
* The basic rule is to get rid of entries that are expired.
*/
static void
nfsrc_trimcache(u_int64_t sockref, struct socket *so)
{
struct nfsrvcache *rp, *nextrp;
int i;
NFSLOCKCACHE();
TAILQ_FOREACH_SAFE(rp, &nfsrvudplru, rc_lru, nextrp) {
if (!(rp->rc_flag & (RC_INPROG|RC_LOCKED|RC_WANTED))
&& rp->rc_refcnt == 0
&& ((rp->rc_flag & RC_REFCNT) ||
NFSD_MONOSEC > rp->rc_timestamp ||
nfsrc_udpcachesize > nfsrc_udphighwater))
nfsrc_freecache(rp);
}
for (i = 0; i < NFSRVCACHE_HASHSIZE; i++) {
LIST_FOREACH_SAFE(rp, &nfsrvhashtbl[i], rc_hash, nextrp) {
if (!(rp->rc_flag & (RC_INPROG|RC_LOCKED|RC_WANTED))
&& rp->rc_refcnt == 0
&& ((rp->rc_flag & RC_REFCNT) ||
NFSD_MONOSEC > rp->rc_timestamp ||
nfsrc_activesocket(rp, sockref, so)))
nfsrc_freecache(rp);
}
}
NFSUNLOCKCACHE();
}
/*
* Add a seqid# reference to the cache entry.
*/
APPLESTATIC void
nfsrvd_refcache(struct nfsrvcache *rp)
{
NFSLOCKCACHE();
if (rp->rc_refcnt < 0)
panic("nfs cache refcnt");
rp->rc_refcnt++;
NFSUNLOCKCACHE();
}
/*
* Dereference a seqid# cache entry.
*/
APPLESTATIC void
nfsrvd_derefcache(struct nfsrvcache *rp)
{
NFSLOCKCACHE();
if (rp->rc_refcnt <= 0)
panic("nfs cache derefcnt");
rp->rc_refcnt--;
if (rp->rc_refcnt == 0 && !(rp->rc_flag & (RC_LOCKED | RC_INPROG)))
nfsrc_freecache(rp);
NFSUNLOCKCACHE();
}
/*
* Check to see if the socket is active.
* Return 1 if the reply has been received/acknowledged by the client,
* 0 otherwise.
* XXX - Uses tcp internals.
*/
static int
nfsrc_activesocket(struct nfsrvcache *rp, u_int64_t cur_sockref,
struct socket *cur_so)
{
int ret = 0;
if (!(rp->rc_flag & RC_TCPSEQ))
return (ret);
/*
* If the sockref is the same, it is the same TCP connection.
*/
if (cur_sockref == rp->rc_sockref)
ret = nfsrv_checksockseqnum(cur_so, rp->rc_tcpseq);
return (ret);
}
/*
* Calculate the length of the mbuf list and a checksum on the first up to
* NFSRVCACHE_CHECKLEN bytes.
*/
static int
nfsrc_getlenandcksum(mbuf_t m1, u_int16_t *cksum)
{
int len = 0, cklen;
mbuf_t m;
m = m1;
while (m) {
len += mbuf_len(m);
m = mbuf_next(m);
}
cklen = (len > NFSRVCACHE_CHECKLEN) ? NFSRVCACHE_CHECKLEN : len;
*cksum = in_cksum(m1, cklen);
return (len);
}
/*
* Mark a TCP connection that is seeing retries. Should never happen for
* NFSv4.
*/
static void
nfsrc_marksametcpconn(u_int64_t sockref)
{
}

View File

@ -0,0 +1,455 @@
/*-
* 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$");
#include "opt_inet6.h"
#include "opt_kgssapi.h"
#include <fs/nfs/nfsport.h>
#include <rpc/rpc.h>
#include <rpc/rpcsec_gss.h>
NFSDLOCKMUTEX;
/*
* Mapping of old NFS Version 2 RPC numbers to generic numbers.
*/
static int newnfs_nfsv3_procid[NFS_V3NPROCS] = {
NFSPROC_NULL,
NFSPROC_GETATTR,
NFSPROC_SETATTR,
NFSPROC_NOOP,
NFSPROC_LOOKUP,
NFSPROC_READLINK,
NFSPROC_READ,
NFSPROC_NOOP,
NFSPROC_WRITE,
NFSPROC_CREATE,
NFSPROC_REMOVE,
NFSPROC_RENAME,
NFSPROC_LINK,
NFSPROC_SYMLINK,
NFSPROC_MKDIR,
NFSPROC_RMDIR,
NFSPROC_READDIR,
NFSPROC_FSSTAT,
NFSPROC_NOOP,
NFSPROC_NOOP,
NFSPROC_NOOP,
NFSPROC_NOOP,
};
SYSCTL_DECL(_vfs_newnfs);
SVCPOOL *nfsrvd_pool;
static int nfs_privport = 0;
SYSCTL_INT(_vfs_newnfs, OID_AUTO, nfs_privport, CTLFLAG_RW,
&nfs_privport, 0,
"Only allow clients using a privileged port for NFSv2 and 3");
static int nfs_proc(struct nfsrv_descript *, u_int32_t, struct socket *,
u_int64_t, struct nfsrvcache **);
extern u_long sb_max_adj;
extern int newnfs_numnfsd;
/*
* NFS server system calls
*/
static void
nfssvc_program(struct svc_req *rqst, SVCXPRT *xprt)
{
struct nfsrv_descript nd;
struct nfsrvcache *rp = NULL;
int cacherep;
memset(&nd, 0, sizeof(nd));
if (rqst->rq_vers == NFS_VER2) {
if (rqst->rq_proc > NFSV2PROC_STATFS) {
svcerr_noproc(rqst);
svc_freereq(rqst);
return;
}
nd.nd_procnum = newnfs_nfsv3_procid[rqst->rq_proc];
nd.nd_flag = ND_NFSV2;
} else if (rqst->rq_vers == NFS_VER3) {
if (rqst->rq_proc >= NFS_V3NPROCS) {
svcerr_noproc(rqst);
svc_freereq(rqst);
return;
}
nd.nd_procnum = rqst->rq_proc;
nd.nd_flag = ND_NFSV3;
} else {
if (rqst->rq_proc != NFSPROC_NULL &&
rqst->rq_proc != NFSV4PROC_COMPOUND) {
svcerr_noproc(rqst);
svc_freereq(rqst);
return;
}
nd.nd_procnum = rqst->rq_proc;
nd.nd_flag = ND_NFSV4;
}
/*
* Note: we want rq_addr, not svc_getrpccaller for nd_nam2 -
* NFS_SRVMAXDATA uses a NULL value for nd_nam2 to detect TCP
* mounts.
*/
nd.nd_mrep = rqst->rq_args;
rqst->rq_args = NULL;
newnfs_realign(&nd.nd_mrep);
nd.nd_md = nd.nd_mrep;
nd.nd_dpos = mtod(nd.nd_md, caddr_t);
nd.nd_nam = svc_getrpccaller(rqst);
nd.nd_nam2 = rqst->rq_addr;
nd.nd_mreq = NULL;
nd.nd_cred = NULL;
if (nfs_privport && (nd.nd_flag & ND_NFSV4) == 0) {
/* Check if source port is privileged */
u_short port;
struct sockaddr *nam = nd.nd_nam;
struct sockaddr_in *sin;
sin = (struct sockaddr_in *)nam;
/*
* INET/INET6 - same code:
* sin_port and sin6_port are at same offset
*/
port = ntohs(sin->sin_port);
if (port >= IPPORT_RESERVED &&
nd.nd_procnum != NFSPROC_NULL) {
#ifdef INET6
char b6[INET6_ADDRSTRLEN];
#if defined(KLD_MODULE)
/* Do not use ip6_sprintf: the nfs module should work without INET6. */
#define ip6_sprintf(buf, a) \
(sprintf((buf), "%x:%x:%x:%x:%x:%x:%x:%x", \
(a)->s6_addr16[0], (a)->s6_addr16[1], \
(a)->s6_addr16[2], (a)->s6_addr16[3], \
(a)->s6_addr16[4], (a)->s6_addr16[5], \
(a)->s6_addr16[6], (a)->s6_addr16[7]), \
(buf))
#endif
#endif
printf("NFS request from unprivileged port (%s:%d)\n",
#ifdef INET6
sin->sin_family == AF_INET6 ?
ip6_sprintf(b6, &satosin6(sin)->sin6_addr) :
#if defined(KLD_MODULE)
#undef ip6_sprintf
#endif
#endif
inet_ntoa(sin->sin_addr), port);
svcerr_weakauth(rqst);
svc_freereq(rqst);
m_freem(nd.nd_mrep);
return;
}
}
if (nd.nd_procnum != NFSPROC_NULL) {
if (!svc_getcred(rqst, &nd.nd_cred, &nd.nd_credflavor)) {
svcerr_weakauth(rqst);
svc_freereq(rqst);
m_freem(nd.nd_mrep);
return;
}
#ifdef MAC
mac_cred_associate_nfsd(nd.nd_cred);
#endif
if ((nd.nd_flag & ND_NFSV4))
nd.nd_repstat = nfsvno_v4rootexport(&nd);
cacherep = nfs_proc(&nd, rqst->rq_xid, xprt->xp_socket,
xprt->xp_sockref, &rp);
} else {
NFSMGET(nd.nd_mreq);
nd.nd_mreq->m_len = 0;
cacherep = RC_REPLY;
}
if (nd.nd_mrep != NULL)
m_freem(nd.nd_mrep);
if (nd.nd_cred != NULL)
crfree(nd.nd_cred);
if (cacherep == RC_DROPIT) {
if (nd.nd_mreq != NULL)
m_freem(nd.nd_mreq);
svc_freereq(rqst);
return;
}
if (nd.nd_mreq == NULL) {
svcerr_decode(rqst);
svc_freereq(rqst);
return;
}
if (nd.nd_repstat & NFSERR_AUTHERR) {
svcerr_auth(rqst, nd.nd_repstat & ~NFSERR_AUTHERR);
if (nd.nd_mreq != NULL)
m_freem(nd.nd_mreq);
} else if (!svc_sendreply_mbuf(rqst, nd.nd_mreq)) {
svcerr_systemerr(rqst);
}
if (rp != NULL)
nfsrvd_sentcache(rp, xprt->xp_socket, 0);
svc_freereq(rqst);
}
/*
* Check the cache and, optionally, do the RPC.
* Return the appropriate cache response.
*/
static int
nfs_proc(struct nfsrv_descript *nd, u_int32_t xid, struct socket *so,
u_int64_t sockref, struct nfsrvcache **rpp)
{
struct thread *td = curthread;
int cacherep = RC_DOIT, isdgram;
*rpp = NULL;
if (nd->nd_nam2 == NULL) {
nd->nd_flag |= ND_STREAMSOCK;
isdgram = 0;
} else {
isdgram = 1;
}
NFSGETTIME(&nd->nd_starttime);
/*
* Several cases:
* 1 - For NFSv2 over UDP, if we are near our malloc/mget
* limit, just drop the request. There is no
* NFSERR_RESOURCE or NFSERR_DELAY for NFSv2 and the
* client will timeout/retry over UDP in a little while.
* 2 - nd_repstat set to some error, so generate the reply now.
* 3 - nd_repstat == 0 && nd_mreq == NULL, which
* means a normal nfs rpc, so check the cache
*/
if ((nd->nd_flag & ND_NFSV2) && nd->nd_nam2 != NULL &&
nfsrv_mallocmget_limit()) {
cacherep = RC_DROPIT;
} else if (nd->nd_repstat) {
cacherep = RC_REPLY;
} else {
/*
* For NFSv3, play it safe and assume that the client is
* doing retries on the same TCP connection.
*/
if ((nd->nd_flag & (ND_NFSV4 | ND_STREAMSOCK)) ==
ND_STREAMSOCK)
nd->nd_flag |= ND_SAMETCPCONN;
nd->nd_retxid = xid;
nd->nd_tcpconntime = NFSD_MONOSEC;
nd->nd_sockref = sockref;
cacherep = nfsrvd_getcache(nd, so);
}
/*
* Handle the request. There are three cases.
* RC_DOIT - do the RPC
* RC_REPLY - return the reply already created
* RC_DROPIT - just throw the request away
*/
if (cacherep == RC_DOIT) {
nfsrvd_dorpc(nd, isdgram, td);
if (nd->nd_repstat == NFSERR_DONTREPLY)
cacherep = RC_DROPIT;
else
cacherep = RC_REPLY;
*rpp = nfsrvd_updatecache(nd, so);
}
return (cacherep);
}
/*
* Adds a socket to the list for servicing by nfsds.
*/
int
nfsrvd_addsock(struct file *fp)
{
int siz;
struct socket *so;
int error;
SVCXPRT *xprt;
static u_int64_t sockref = 0;
so = fp->f_data;
siz = sb_max_adj;
error = soreserve(so, siz, siz);
if (error) {
return (error);
}
/*
* Steal the socket from userland so that it doesn't close
* unexpectedly.
*/
if (so->so_type == SOCK_DGRAM)
xprt = svc_dg_create(nfsrvd_pool, so, 0, 0);
else
xprt = svc_vc_create(nfsrvd_pool, so, 0, 0);
if (xprt) {
fp->f_ops = &badfileops;
fp->f_data = NULL;
xprt->xp_sockref = ++sockref;
svc_reg(xprt, NFS_PROG, NFS_VER2, nfssvc_program, NULL);
svc_reg(xprt, NFS_PROG, NFS_VER3, nfssvc_program, NULL);
svc_reg(xprt, NFS_PROG, NFS_VER4, nfssvc_program, NULL);
}
return (0);
}
/*
* Called by nfssvc() for nfsds. Just loops around servicing rpc requests
* until it is killed by a signal.
*/
int
nfsrvd_nfsd(struct thread *td, struct nfsd_nfsd_args *args)
{
#ifdef KGSSAPI
char principal[128];
int error;
bool_t ret2, ret3, ret4;
#endif
#ifdef KGSSAPI
if (args != NULL) {
error = copyinstr(args->principal, principal,
sizeof(principal), NULL);
if (error)
return (error);
} else {
snprintf(principal, sizeof(principal), "nfs@%s", hostname);
}
#endif
/*
* Only the first nfsd actually does any work. The RPC code
* adds threads to it as needed. Any extra processes offered
* by nfsd just exit. If nfsd is new enough, it will call us
* once with a structure that specifies how many threads to
* use.
*/
NFSD_LOCK();
if (newnfs_numnfsd == 0) {
newnfs_numnfsd++;
NFSD_UNLOCK();
#ifdef KGSSAPI
ret2 = rpc_gss_set_svc_name(principal, "kerberosv5",
GSS_C_INDEFINITE, NFS_PROG, NFS_VER2);
ret3 = rpc_gss_set_svc_name(principal, "kerberosv5",
GSS_C_INDEFINITE, NFS_PROG, NFS_VER3);
ret4 = rpc_gss_set_svc_name(principal, "kerberosv5",
GSS_C_INDEFINITE, NFS_PROG, NFS_VER4);
/*
* If the principal name was specified, these should have
* succeeded.
*/
if (args != NULL && principal[0] != '\0' &&
(!ret2 || !ret3 || !ret4)) {
NFSD_LOCK();
newnfs_numnfsd--;
NFSD_UNLOCK();
return (EAUTH);
}
#endif
if (args != NULL) {
nfsrvd_pool->sp_minthreads = args->minthreads;
nfsrvd_pool->sp_maxthreads = args->maxthreads;
} else {
nfsrvd_pool->sp_minthreads = 4;
nfsrvd_pool->sp_maxthreads = 4;
}
svc_run(nfsrvd_pool);
#ifdef KGSSAPI
rpc_gss_clear_svc_name(NFS_PROG, NFS_VER2);
rpc_gss_clear_svc_name(NFS_PROG, NFS_VER3);
rpc_gss_clear_svc_name(NFS_PROG, NFS_VER4);
#endif
NFSD_LOCK();
newnfs_numnfsd--;
nfsrvd_init(1);
}
NFSD_UNLOCK();
return (0);
}
/*
* Initialize the data structures for the server.
* Handshake with any new nfsds starting up to avoid any chance of
* corruption.
*/
void
nfsrvd_init(int terminating)
{
NFSD_LOCK_ASSERT();
if (terminating) {
NFSD_UNLOCK();
svcpool_destroy(nfsrvd_pool);
nfsrvd_pool = NULL;
NFSD_LOCK();
}
NFSD_UNLOCK();
nfsrvd_pool = svcpool_create("nfsd", SYSCTL_STATIC_CHILDREN(_vfs_newnfs));
nfsrvd_pool->sp_rcache = NULL;
nfsrvd_pool->sp_assign = NULL;
nfsrvd_pool->sp_done = NULL;
NFSD_LOCK();
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,979 @@
/*-
* 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$");
/*
* Socket operations for use by the nfs server.
*/
#ifndef APPLEKEXT
#include <fs/nfs/nfsport.h>
extern struct nfsstats newnfsstats;
extern struct nfsrvfh nfs_pubfh, nfs_rootfh;
extern int nfs_pubfhset, nfs_rootfhset;
extern struct nfsv4lock nfsv4rootfs_lock;
extern struct nfsrv_stablefirst nfsrv_stablefirst;
extern struct nfsclienthashhead nfsclienthash[NFSCLIENTHASHSIZE];
extern int nfsrc_floodlevel, nfsrc_tcpsavedreplies;
NFSV4ROOTLOCKMUTEX;
NFSSTATESPINLOCK;
vnode_t nfsv4root_vp = NULL;
int nfsv4root_set = 0;
int (*nfsrv3_procs0[NFS_V3NPROCS])(struct nfsrv_descript *,
int, vnode_t , NFSPROC_T *, struct nfsexstuff *) = {
(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
nfsrvd_getattr,
nfsrvd_setattr,
(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
nfsrvd_access,
nfsrvd_readlink,
nfsrvd_read,
nfsrvd_write,
nfsrvd_create,
(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
nfsrvd_remove,
nfsrvd_remove,
(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
nfsrvd_readdir,
nfsrvd_readdirplus,
nfsrvd_statfs,
nfsrvd_fsinfo,
nfsrvd_pathconf,
nfsrvd_commit,
};
int (*nfsrv3_procs1[NFS_V3NPROCS])(struct nfsrv_descript *,
int, vnode_t , vnode_t *, fhandle_t *,
NFSPROC_T *, struct nfsexstuff *) = {
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
nfsrvd_lookup,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
nfsrvd_mkdir,
nfsrvd_symlink,
nfsrvd_mknod,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
};
int (*nfsrv3_procs2[NFS_V3NPROCS])(struct nfsrv_descript *,
int, vnode_t , vnode_t , NFSPROC_T *,
struct nfsexstuff *, struct nfsexstuff *) = {
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
nfsrvd_rename,
nfsrvd_link,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
};
int (*nfsrv4_ops0[NFSV4OP_NOPS])(struct nfsrv_descript *,
int, vnode_t , NFSPROC_T *, struct nfsexstuff *) = {
(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
nfsrvd_access,
nfsrvd_close,
nfsrvd_commit,
(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
nfsrvd_delegpurge,
nfsrvd_delegreturn,
nfsrvd_getattr,
nfsrvd_getfh,
(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
nfsrvd_lock,
nfsrvd_lockt,
nfsrvd_locku,
(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
nfsrvd_verify,
(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
nfsrvd_openconfirm,
nfsrvd_opendowngrade,
(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
nfsrvd_read,
nfsrvd_readdirplus,
nfsrvd_readlink,
nfsrvd_remove,
(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
nfsrvd_renew,
(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
nfsrvd_secinfo,
nfsrvd_setattr,
nfsrvd_setclientid,
nfsrvd_setclientidcfrm,
nfsrvd_verify,
nfsrvd_write,
nfsrvd_releaselckown,
};
int (*nfsrv4_ops1[NFSV4OP_NOPS])(struct nfsrv_descript *,
int, vnode_t , vnode_t *, fhandle_t *,
NFSPROC_T *, struct nfsexstuff *) = {
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
nfsrvd_mknod,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
nfsrvd_lookup,
nfsrvd_lookup,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
nfsrvd_open,
nfsrvd_openattr,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
};
int (*nfsrv4_ops2[NFSV4OP_NOPS])(struct nfsrv_descript *,
int, vnode_t , vnode_t , NFSPROC_T *,
struct nfsexstuff *, struct nfsexstuff *) = {
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
nfsrvd_link,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
nfsrvd_rename,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
};
#endif /* !APPLEKEXT */
/*
* Static array that defines which nfs rpc's are nonidempotent
*/
static int nfsrv_nonidempotent[NFS_V3NPROCS] = {
FALSE,
FALSE,
TRUE,
FALSE,
FALSE,
FALSE,
FALSE,
TRUE,
TRUE,
TRUE,
TRUE,
TRUE,
TRUE,
TRUE,
TRUE,
TRUE,
FALSE,
FALSE,
FALSE,
FALSE,
FALSE,
FALSE,
};
/*
* This static array indicates whether or not the RPC modifies the
* file system.
*/
static int nfs_writerpc[NFS_NPROCS] = { 0, 0, 1, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
/* local functions */
static void nfsrvd_compound(struct nfsrv_descript *nd, int isdgram,
NFSPROC_T *p);
/*
* This static array indicates which server procedures require the extra
* arguments to return the current file handle for V2, 3.
*/
static int nfs_retfh[NFS_V3NPROCS] = { 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1,
1, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0 };
extern struct nfsv4_opflag nfsv4_opflag[NFSV4OP_NOPS];
static int nfsv3to4op[NFS_V3NPROCS] = {
NFSPROC_NULL,
NFSV4OP_GETATTR,
NFSV4OP_SETATTR,
NFSV4OP_LOOKUP,
NFSV4OP_ACCESS,
NFSV4OP_READLINK,
NFSV4OP_READ,
NFSV4OP_WRITE,
NFSV4OP_V3CREATE,
NFSV4OP_MKDIR,
NFSV4OP_SYMLINK,
NFSV4OP_MKNOD,
NFSV4OP_REMOVE,
NFSV4OP_RMDIR,
NFSV4OP_RENAME,
NFSV4OP_LINK,
NFSV4OP_READDIR,
NFSV4OP_READDIRPLUS,
NFSV4OP_FSSTAT,
NFSV4OP_FSINFO,
NFSV4OP_PATHCONF,
NFSV4OP_COMMIT,
};
/*
* Do an RPC. Basically, get the file handles translated to vnode pointers
* and then call the appropriate server routine. The server routines are
* split into groups, based on whether they use a file handle or file
* handle plus name or ...
* The NFS V4 Compound RPC is performed separately by nfsrvd_compound().
*/
APPLESTATIC void
nfsrvd_dorpc(struct nfsrv_descript *nd, int isdgram,
NFSPROC_T *p)
{
int error = 0;
vnode_t vp;
mount_t mp = NULL;
struct nfsrvfh fh;
struct nfsexstuff nes;
/*
* Get a locked vnode for the first file handle
*/
if (!(nd->nd_flag & ND_NFSV4)) {
#ifdef DIAGNOSTIC
if (nd->nd_repstat)
panic("nfsrvd_dorpc");
#endif
/*
* For NFSv3, if the malloc/mget allocation is near limits,
* return NFSERR_DELAY.
*/
if ((nd->nd_flag & ND_NFSV3) && nfsrv_mallocmget_limit()) {
nd->nd_repstat = NFSERR_DELAY;
vp = NULL;
} else {
error = nfsrv_mtofh(nd, &fh);
if (error) {
if (error != EBADRPC)
printf("nfs dorpc err1=%d\n", error);
nd->nd_repstat = NFSERR_GARBAGE;
return;
}
nes.nes_vfslocked = 0;
if (nd->nd_flag & ND_PUBLOOKUP)
nfsd_fhtovp(nd, &nfs_pubfh, &vp, &nes,
&mp, nfs_writerpc[nd->nd_procnum], p);
else
nfsd_fhtovp(nd, &fh, &vp, &nes,
&mp, nfs_writerpc[nd->nd_procnum], p);
if (nd->nd_repstat == NFSERR_PROGNOTV4)
return;
}
}
/*
* For V2 and 3, set the ND_SAVEREPLY flag for the recent request
* cache, as required.
* For V4, nfsrvd_compound() does this.
*/
if (!(nd->nd_flag & ND_NFSV4) && nfsrv_nonidempotent[nd->nd_procnum])
nd->nd_flag |= ND_SAVEREPLY;
nfsrvd_rephead(nd);
/*
* If nd_repstat is non-zero, just fill in the reply status
* to complete the RPC reply for V2. Otherwise, you must do
* the RPC.
*/
if (nd->nd_repstat && (nd->nd_flag & ND_NFSV2)) {
*nd->nd_errp = nfsd_errmap(nd);
NFSINCRGLOBAL(newnfsstats.srvrpccnt[nfsv3to4op[nd->nd_procnum]]);
if (mp != NULL) {
if (nfs_writerpc[nd->nd_procnum])
NFS_ENDWRITE(mp);
if (nes.nes_vfslocked)
nfsvno_unlockvfs(mp);
}
return;
}
/*
* Now the procedure can be performed. For V4, nfsrvd_compound()
* works through the sub-rpcs, otherwise just call the procedure.
* The procedures are in three groups with different arguments.
* The group is indicated by the value in nfs_retfh[].
*/
if (nd->nd_flag & ND_NFSV4) {
nfsrvd_compound(nd, isdgram, p);
} else {
if (nfs_retfh[nd->nd_procnum] == 1) {
if (vp)
NFSVOPUNLOCK(vp, 0, p);
error = (*(nfsrv3_procs1[nd->nd_procnum]))(nd, isdgram,
vp, NULL, (fhandle_t *)fh.nfsrvfh_data, p, &nes);
} else if (nfs_retfh[nd->nd_procnum] == 2) {
error = (*(nfsrv3_procs2[nd->nd_procnum]))(nd, isdgram,
vp, NULL, p, &nes, NULL);
} else {
error = (*(nfsrv3_procs0[nd->nd_procnum]))(nd, isdgram,
vp, p, &nes);
}
if (mp) {
if (nfs_writerpc[nd->nd_procnum])
NFS_ENDWRITE(mp);
if (nes.nes_vfslocked)
nfsvno_unlockvfs(mp);
}
NFSINCRGLOBAL(newnfsstats.srvrpccnt[nfsv3to4op[nd->nd_procnum]]);
}
if (error) {
if (error != EBADRPC)
printf("nfs dorpc err2=%d\n", error);
nd->nd_repstat = NFSERR_GARBAGE;
}
*nd->nd_errp = nfsd_errmap(nd);
/*
* Don't cache certain reply status values.
*/
if (nd->nd_repstat && (nd->nd_flag & ND_SAVEREPLY) &&
(nd->nd_repstat == NFSERR_GARBAGE ||
nd->nd_repstat == NFSERR_BADXDR ||
nd->nd_repstat == NFSERR_MOVED ||
nd->nd_repstat == NFSERR_DELAY ||
nd->nd_repstat == NFSERR_BADSEQID ||
nd->nd_repstat == NFSERR_RESOURCE ||
nd->nd_repstat == NFSERR_SERVERFAULT ||
nd->nd_repstat == NFSERR_STALECLIENTID ||
nd->nd_repstat == NFSERR_STALESTATEID ||
nd->nd_repstat == NFSERR_OLDSTATEID ||
nd->nd_repstat == NFSERR_BADSTATEID ||
nd->nd_repstat == NFSERR_GRACE ||
nd->nd_repstat == NFSERR_NOGRACE))
nd->nd_flag &= ~ND_SAVEREPLY;
}
/*
* Breaks down a compound RPC request and calls the server routines for
* the subprocedures.
* Some suboperations are performed directly here to simplify file handle<-->
* vnode pointer handling.
*/
static void
nfsrvd_compound(struct nfsrv_descript *nd, int isdgram,
NFSPROC_T *p)
{
int i, op;
u_int32_t *tl;
struct nfsclient *clp, *nclp;
int numops, taglen = -1, error = 0, igotlock;
u_int32_t minorvers, retops = 0, *retopsp = NULL, *repp;
u_char tag[NFSV4_SMALLSTR + 1], *tagstr;
vnode_t vp, nvp, savevp;
struct nfsrvfh fh;
mount_t mp, savemp;
struct ucred *credanon;
struct nfsexstuff nes, vpnes, savevpnes;
static u_int64_t compref = 0;
NFSVNO_EXINIT(&vpnes);
NFSVNO_EXINIT(&savevpnes);
/*
* Put the seq# of the current compound RPC in nfsrv_descript.
* (This is used by nfsrv_checkgetattr(), to see if the write
* delegation was created by the same compound RPC as the one
* with that Getattr in it.)
* Don't worry about the 64bit number wrapping around. It ain't
* gonna happen before this server gets shut down/rebooted.
*/
nd->nd_compref = compref++;
/*
* Check for and optionally get a lock on the root. This lock means that
* no nfsd will be fiddling with the V4 file system and state stuff. It
* is required when the V4 root is being changed, the stable storage
* restart file is being updated, or callbacks are being done.
* When any of the nfsd are processing an NFSv4 compound RPC, they must
* either hold a reference count (nfs_usecnt) or the lock. When
* nfsrv_unlock() is called to release the lock, it can optionally
* also get a reference count, which saves the need for a call to
* nfsrv_getref() after nfsrv_unlock().
*/
/*
* First, check to see if we need to wait for an update lock.
*/
igotlock = 0;
NFSLOCKV4ROOTMUTEX();
if (nfsrv_stablefirst.nsf_flags & NFSNSF_NEEDLOCK)
igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL,
NFSV4ROOTLOCKMUTEXPTR);
else
igotlock = nfsv4_lock(&nfsv4rootfs_lock, 0, NULL,
NFSV4ROOTLOCKMUTEXPTR);
NFSUNLOCKV4ROOTMUTEX();
if (igotlock) {
NFSLOCKSTATE(); /* to avoid a race with */
NFSUNLOCKSTATE(); /* nfsrv_servertimer() */
/*
* If I got the lock, I can update the stable storage file.
* Done when the grace period is over or a client has long
* since expired.
*/
nfsrv_stablefirst.nsf_flags &= ~NFSNSF_NEEDLOCK;
if ((nfsrv_stablefirst.nsf_flags &
(NFSNSF_GRACEOVER | NFSNSF_UPDATEDONE)) == NFSNSF_GRACEOVER)
nfsrv_updatestable(p);
/*
* If at least one client has long since expired, search
* the client list for them, write a REVOKE record on the
* stable storage file and then remove them from the client
* list.
*/
if (nfsrv_stablefirst.nsf_flags & NFSNSF_EXPIREDCLIENT) {
nfsrv_stablefirst.nsf_flags &= ~NFSNSF_EXPIREDCLIENT;
for (i = 0; i < NFSCLIENTHASHSIZE; i++) {
LIST_FOREACH_SAFE(clp, &nfsclienthash[i], lc_hash,
nclp) {
if (clp->lc_flags & LCL_EXPIREIT) {
if (!LIST_EMPTY(&clp->lc_open) ||
!LIST_EMPTY(&clp->lc_deleg))
nfsrv_writestable(clp->lc_id,
clp->lc_idlen, NFSNST_REVOKE, p);
nfsrv_cleanclient(clp, p);
nfsrv_freedeleglist(&clp->lc_deleg);
nfsrv_freedeleglist(&clp->lc_olddeleg);
LIST_REMOVE(clp, lc_hash);
nfsrv_zapclient(clp, p);
}
}
}
}
NFSLOCKV4ROOTMUTEX();
nfsv4_unlock(&nfsv4rootfs_lock, 1);
NFSUNLOCKV4ROOTMUTEX();
} else {
/*
* If we didn't get the lock, we need to get a refcnt,
* which also checks for and waits for the lock.
*/
NFSLOCKV4ROOTMUTEX();
nfsv4_getref(&nfsv4rootfs_lock, NULL,
NFSV4ROOTLOCKMUTEXPTR);
NFSUNLOCKV4ROOTMUTEX();
}
/*
* If flagged, search for open owners that haven't had any opens
* for a long time.
*/
if (nfsrv_stablefirst.nsf_flags & NFSNSF_NOOPENS) {
nfsrv_throwawayopens(p);
}
savevp = vp = NULL;
savevpnes.nes_vfslocked = vpnes.nes_vfslocked = 0;
savemp = mp = NULL;
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
taglen = fxdr_unsigned(int, *tl);
if (taglen < 0) {
error = EBADRPC;
goto nfsmout;
}
if (taglen <= NFSV4_SMALLSTR)
tagstr = tag;
else
tagstr = malloc(taglen + 1, M_TEMP, M_WAITOK);
error = nfsrv_mtostr(nd, tagstr, taglen);
if (error) {
if (taglen > NFSV4_SMALLSTR)
free(tagstr, M_TEMP);
taglen = -1;
goto nfsmout;
}
(void) nfsm_strtom(nd, tag, taglen);
if (taglen > NFSV4_SMALLSTR) {
free(tagstr, M_TEMP);
}
NFSM_BUILD(retopsp, u_int32_t *, NFSX_UNSIGNED);
NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
minorvers = fxdr_unsigned(u_int32_t, *tl++);
if (minorvers != NFSV4_MINORVERSION)
nd->nd_repstat = NFSERR_MINORVERMISMATCH;
if (nd->nd_repstat)
numops = 0;
else
numops = fxdr_unsigned(int, *tl);
/*
* Loop around doing the sub ops.
* vp - is an unlocked vnode pointer for the CFH
* savevp - is an unlocked vnode pointer for the SAVEDFH
* (at some future date, it might turn out to be more appropriate
* to keep the file handles instead of vnode pointers?)
* savevpnes and vpnes - are the export flags for the above.
*/
for (i = 0; i < numops; i++) {
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
NFSM_BUILD(repp, u_int32_t *, 2 * NFSX_UNSIGNED);
*repp++ = *tl;
op = fxdr_unsigned(int, *tl);
if (op < NFSV4OP_ACCESS || op >= NFSV4OP_NOPS) {
nd->nd_repstat = NFSERR_OPILLEGAL;
*repp = nfsd_errmap(nd);
retops++;
break;
}
/*
* Check for a referral on the current FH and, if so, return
* NFSERR_MOVED for all ops that allow it, except Getattr.
*/
if (vp != NULL && op != NFSV4OP_GETATTR &&
nfsv4root_getreferral(vp, NULL, 0) != NULL &&
nfsrv_errmoved(op)) {
nd->nd_repstat = NFSERR_MOVED;
*repp = nfsd_errmap(nd);
retops++;
break;
}
nd->nd_procnum = op;
/*
* If over flood level, reply NFSERR_RESOURCE, if at the first
* Op. (Since a client recovery from NFSERR_RESOURCE can get
* really nasty for certain Op sequences, I'll play it safe
* and only return the error at the beginning.) The cache
* will still function over flood level, but uses lots of
* mbufs.)
* If nfsrv_mallocmget_limit() returns True, the system is near
* to its limit for memory that malloc()/mget() can allocate.
*/
if (i == 0 && nd->nd_rp->rc_refcnt == 0 &&
(nfsrv_mallocmget_limit() ||
nfsrc_tcpsavedreplies > nfsrc_floodlevel)) {
if (nfsrc_tcpsavedreplies > nfsrc_floodlevel) {
printf("nfsd server cache flooded, try to");
printf(" increase nfsrc_floodlevel\n");
}
nd->nd_repstat = NFSERR_RESOURCE;
*repp = nfsd_errmap(nd);
if (op == NFSV4OP_SETATTR) {
/*
* Setattr replies require a bitmap.
* even for errors like these.
*/
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
*tl = 0;
}
retops++;
break;
}
if (nfsv4_opflag[op].savereply)
nd->nd_flag |= ND_SAVEREPLY;
NFSINCRGLOBAL(newnfsstats.srvrpccnt[nd->nd_procnum]);
switch (op) {
case NFSV4OP_PUTFH:
error = nfsrv_mtofh(nd, &fh);
if (error)
goto nfsmout;
if (!nd->nd_repstat) {
nes.nes_vfslocked = vpnes.nes_vfslocked;
nfsd_fhtovp(nd, &fh, &nvp, &nes, &mp,
0, p);
}
/* For now, allow this for non-export FHs */
if (!nd->nd_repstat) {
if (vp)
vrele(vp);
vp = nvp;
NFSVOPUNLOCK(vp, 0, p);
vpnes = nes;
}
break;
case NFSV4OP_PUTPUBFH:
if (nfs_pubfhset) {
nes.nes_vfslocked = vpnes.nes_vfslocked;
nfsd_fhtovp(nd, &nfs_pubfh, &nvp,
&nes, &mp, 0, p);
} else {
nd->nd_repstat = NFSERR_NOFILEHANDLE;
}
if (!nd->nd_repstat) {
if (vp)
vrele(vp);
vp = nvp;
NFSVOPUNLOCK(vp, 0, p);
vpnes = nes;
}
break;
case NFSV4OP_PUTROOTFH:
if (nfs_rootfhset) {
nes.nes_vfslocked = vpnes.nes_vfslocked;
nfsd_fhtovp(nd, &nfs_rootfh, &nvp,
&nes, &mp, 0, p);
if (!nd->nd_repstat) {
if (vp)
vrele(vp);
vp = nvp;
NFSVOPUNLOCK(vp, 0, p);
vpnes = nes;
}
} else if (nfsv4root_vp && nfsv4root_set) {
if (vp) {
if (vpnes.nes_vfslocked)
nfsvno_unlockvfs(mp);
vrele(vp);
}
vp = nfsv4root_vp;
VREF(vp);
NFSVNO_SETEXRDONLY(&vpnes);
vpnes.nes_vfslocked = 0;
mp = vnode_mount(vp);
} else {
nd->nd_repstat = NFSERR_NOFILEHANDLE;
}
break;
case NFSV4OP_SAVEFH:
if (vp && NFSVNO_EXPORTED(&vpnes)) {
nd->nd_repstat = 0;
/* If vp == savevp, a no-op */
if (vp != savevp) {
if (savevp)
vrele(savevp);
VREF(vp);
savevp = vp;
savevpnes = vpnes;
savemp = mp;
}
} else {
nd->nd_repstat = NFSERR_NOFILEHANDLE;
}
break;
case NFSV4OP_RESTOREFH:
if (savevp) {
nd->nd_repstat = 0;
/* If vp == savevp, a no-op */
if (vp != savevp) {
VREF(savevp);
if (mp == NULL || savemp == NULL)
panic("nfscmpmp");
if (!savevpnes.nes_vfslocked &&
vpnes.nes_vfslocked) {
if (mp == savemp)
panic("nfscmp2");
nfsvno_unlockvfs(mp);
} else if (savevpnes.nes_vfslocked &&
!vpnes.nes_vfslocked) {
if (mp == savemp)
panic("nfscmp3");
savevpnes.nes_vfslocked = nfsvno_lockvfs(savemp);
}
vrele(vp);
vp = savevp;
vpnes = savevpnes;
mp = savemp;
}
} else {
nd->nd_repstat = NFSERR_RESTOREFH;
}
break;
default:
/*
* Allow a Lookup, Getattr, GetFH, Secinfo on an
* non-exported directory if
* nfs_rootfhset. Do I need to allow any other Ops?
* (You can only have a non-exported vpnes if
* nfs_rootfhset is true. See nfsd_fhtovp())
* Allow AUTH_SYS to be used for file systems
* exported GSS only for certain Ops, to allow
* clients to do mounts more easily.
*/
if (nfsv4_opflag[op].needscfh && vp) {
if (!NFSVNO_EXPORTED(&vpnes) &&
op != NFSV4OP_LOOKUP &&
op != NFSV4OP_GETATTR &&
op != NFSV4OP_GETFH &&
op != NFSV4OP_SECINFO)
nd->nd_repstat = NFSERR_NOFILEHANDLE;
else if (NFSVNO_EXGSSONLY(&vpnes) &&
!(nd->nd_flag & ND_GSS) &&
op != NFSV4OP_LOOKUP &&
op != NFSV4OP_GETFH &&
op != NFSV4OP_GETATTR &&
op != NFSV4OP_SECINFO)
nd->nd_repstat = NFSERR_WRONGSEC;
if (nd->nd_repstat) {
if (op == NFSV4OP_SETATTR) {
/*
* Setattr reply requires a bitmap
* even for errors like these.
*/
NFSM_BUILD(tl, u_int32_t *,
NFSX_UNSIGNED);
*tl = 0;
}
break;
}
}
if (nfsv4_opflag[op].retfh == 1) {
if (!vp) {
nd->nd_repstat = NFSERR_NOFILEHANDLE;
break;
}
VREF(vp);
if (nfsv4_opflag[op].modifyfs)
NFS_STARTWRITE(NULL, &mp);
error = (*(nfsrv4_ops1[op]))(nd, isdgram, vp,
&nvp, (fhandle_t *)fh.nfsrvfh_data, p, &vpnes);
if (!error && !nd->nd_repstat) {
if (vfs_statfs(mp)->f_fsid.val[0] !=
vfs_statfs(vnode_mount(nvp))->f_fsid.val[0] ||
vfs_statfs(mp)->f_fsid.val[1] !=
vfs_statfs(vnode_mount(nvp))->f_fsid.val[1]) {
if (vfs_statfs(vnode_mount(nvp))->f_fsid.val[0] ==
NFSV4ROOT_FSID0 &&
vfs_statfs(vnode_mount(nvp))->f_fsid.val[1] ==
NFSV4ROOT_FSID1) {
if (vpnes.nes_vfslocked) {
nfsvno_unlockvfs(mp);
vpnes.nes_vfslocked = 0;
}
NFSVNO_SETEXRDONLY(&vpnes);
mp = vnode_mount(nvp);
} else {
nd->nd_repstat = nfsvno_checkexp(vnode_mount(nvp),
nd->nd_nam, &nes, &credanon);
if (!nd->nd_repstat)
nd->nd_repstat = nfsd_excred(nd,
&nes, credanon);
if (!nd->nd_repstat) {
if (vpnes.nes_vfslocked)
nfsvno_unlockvfs(mp);
mp = vnode_mount(nvp);
vpnes = nes;
vpnes.nes_vfslocked =
nfsvno_lockvfs(mp);
}
}
}
if (!nd->nd_repstat) {
vrele(vp);
vp = nvp;
}
}
if (nfsv4_opflag[op].modifyfs)
NFS_ENDWRITE(mp);
} else if (nfsv4_opflag[op].retfh == 2) {
if (vp == NULL || savevp == NULL) {
nd->nd_repstat = NFSERR_NOFILEHANDLE;
break;
} else if (mp != savemp) {
nd->nd_repstat = NFSERR_XDEV;
break;
}
VREF(vp);
VREF(savevp);
if (nfsv4_opflag[op].modifyfs)
NFS_STARTWRITE(NULL, &mp);
NFSVOPLOCK(savevp, LK_EXCLUSIVE | LK_RETRY, p);
error = (*(nfsrv4_ops2[op]))(nd, isdgram, savevp,
vp, p, &savevpnes, &vpnes);
if (nfsv4_opflag[op].modifyfs)
NFS_ENDWRITE(mp);
} else {
if (nfsv4_opflag[op].retfh != 0)
panic("nfsrvd_compound");
if (nfsv4_opflag[op].needscfh) {
if (vp) {
VREF(vp);
if (nfsv4_opflag[op].modifyfs)
NFS_STARTWRITE(NULL, &mp);
NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY, p);
} else {
nd->nd_repstat = NFSERR_NOFILEHANDLE;
if (op == NFSV4OP_SETATTR) {
/*
* Setattr reply requires a bitmap
* even for errors like these.
*/
NFSM_BUILD(tl, u_int32_t *,
NFSX_UNSIGNED);
*tl = 0;
}
break;
}
error = (*(nfsrv4_ops0[op]))(nd, isdgram, vp,
p, &vpnes);
if (nfsv4_opflag[op].modifyfs)
NFS_ENDWRITE(mp);
} else {
error = (*(nfsrv4_ops0[op]))(nd, isdgram,
NULL, p, &vpnes);
}
}
};
if (error) {
if (error == EBADRPC || error == NFSERR_BADXDR) {
nd->nd_repstat = NFSERR_BADXDR;
} else {
nd->nd_repstat = error;
printf("nfsv4 comperr0=%d\n", error);
}
error = 0;
}
retops++;
if (nd->nd_repstat) {
*repp = nfsd_errmap(nd);
break;
} else {
*repp = 0; /* NFS4_OK */
}
}
nfsmout:
if (error) {
if (error == EBADRPC || error == NFSERR_BADXDR)
nd->nd_repstat = NFSERR_BADXDR;
else
printf("nfsv4 comperr1=%d\n", error);
}
if (taglen == -1) {
NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
*tl++ = 0;
*tl = 0;
} else {
*retopsp = txdr_unsigned(retops);
}
if (mp && vpnes.nes_vfslocked)
nfsvno_unlockvfs(mp);
if (vp)
vrele(vp);
if (savevp)
vrele(savevp);
NFSLOCKV4ROOTMUTEX();
nfsv4_relref(&nfsv4rootfs_lock);
NFSUNLOCKV4ROOTMUTEX();
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff