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:
parent
3382ac3233
commit
9ec7b004d0
704
sys/fs/nfs/nfs.h
Normal file
704
sys/fs/nfs/nfs.h
Normal 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
750
sys/fs/nfs/nfs_commonacl.c
Normal 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
901
sys/fs/nfs/nfs_commonkrpc.c
Normal 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
486
sys/fs/nfs/nfs_commonport.c
Normal 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
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
604
sys/fs/nfs/nfs_var.h
Normal 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
71
sys/fs/nfs/nfscl.h
Normal 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
175
sys/fs/nfs/nfsclstate.h
Normal 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
105
sys/fs/nfs/nfsdport.h
Normal 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
73
sys/fs/nfs/nfskpiport.h
Normal 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
129
sys/fs/nfs/nfsm_subs.h
Normal 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
751
sys/fs/nfs/nfsport.h
Normal 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
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
107
sys/fs/nfs/nfsrvcache.h
Normal 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
235
sys/fs/nfs/nfsrvstate.h
Normal 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
101
sys/fs/nfs/nfsv4_errstr.h
Normal 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
207
sys/fs/nfs/rpcv2.h
Normal 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
99
sys/fs/nfs/xdr_subs.h
Normal 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
95
sys/fs/nfsclient/nfs.h
Normal 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
1934
sys/fs/nfsclient/nfs_clbio.c
Normal file
File diff suppressed because it is too large
Load Diff
521
sys/fs/nfsclient/nfs_clcomsubs.c
Normal file
521
sys/fs/nfsclient/nfs_clcomsubs.c
Normal 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();
|
||||
}
|
||||
|
297
sys/fs/nfsclient/nfs_clkrpc.c
Normal file
297
sys/fs/nfsclient/nfs_clkrpc.c
Normal 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();
|
||||
}
|
||||
|
396
sys/fs/nfsclient/nfs_cllock.c
Normal file
396
sys/fs/nfsclient/nfs_cllock.c
Normal 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;
|
||||
}
|
308
sys/fs/nfsclient/nfs_clnfsiod.c
Normal file
308
sys/fs/nfsclient/nfs_clnfsiod.c
Normal 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);
|
||||
}
|
283
sys/fs/nfsclient/nfs_clnode.c
Normal file
283
sys/fs/nfsclient/nfs_clnode.c
Normal 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);
|
||||
}
|
||||
|
1271
sys/fs/nfsclient/nfs_clport.c
Normal file
1271
sys/fs/nfsclient/nfs_clport.c
Normal file
File diff suppressed because it is too large
Load Diff
4173
sys/fs/nfsclient/nfs_clrpcops.c
Normal file
4173
sys/fs/nfsclient/nfs_clrpcops.c
Normal file
File diff suppressed because it is too large
Load Diff
4133
sys/fs/nfsclient/nfs_clstate.c
Normal file
4133
sys/fs/nfsclient/nfs_clstate.c
Normal file
File diff suppressed because it is too large
Load Diff
402
sys/fs/nfsclient/nfs_clsubs.c
Normal file
402
sys/fs/nfsclient/nfs_clsubs.c
Normal 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);
|
||||
}
|
||||
|
1257
sys/fs/nfsclient/nfs_clvfsops.c
Normal file
1257
sys/fs/nfsclient/nfs_clvfsops.c
Normal file
File diff suppressed because it is too large
Load Diff
3131
sys/fs/nfsclient/nfs_clvnops.c
Normal file
3131
sys/fs/nfsclient/nfs_clvnops.c
Normal file
File diff suppressed because it is too large
Load Diff
89
sys/fs/nfsclient/nfs_lock.h
Normal file
89
sys/fs/nfsclient/nfs_lock.h
Normal 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
104
sys/fs/nfsclient/nfsargs.h
Normal 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_ */
|
108
sys/fs/nfsclient/nfsdiskless.h
Normal file
108
sys/fs/nfsclient/nfsdiskless.h
Normal 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
106
sys/fs/nfsclient/nfsmount.h
Normal 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
201
sys/fs/nfsclient/nfsnode.h
Normal 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_ */
|
41
sys/fs/nfsclient/nlminfo.h
Normal file
41
sys/fs/nfsclient/nlminfo.h
Normal 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 */
|
||||
};
|
867
sys/fs/nfsserver/nfs_nfsdcache.c
Normal file
867
sys/fs/nfsserver/nfs_nfsdcache.c
Normal 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)
|
||||
{
|
||||
}
|
||||
|
455
sys/fs/nfsserver/nfs_nfsdkrpc.c
Normal file
455
sys/fs/nfsserver/nfs_nfsdkrpc.c
Normal 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();
|
||||
}
|
||||
|
3060
sys/fs/nfsserver/nfs_nfsdport.c
Normal file
3060
sys/fs/nfsserver/nfs_nfsdport.c
Normal file
File diff suppressed because it is too large
Load Diff
3367
sys/fs/nfsserver/nfs_nfsdserv.c
Normal file
3367
sys/fs/nfsserver/nfs_nfsdserv.c
Normal file
File diff suppressed because it is too large
Load Diff
979
sys/fs/nfsserver/nfs_nfsdsocket.c
Normal file
979
sys/fs/nfsserver/nfs_nfsdsocket.c
Normal 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();
|
||||
}
|
4891
sys/fs/nfsserver/nfs_nfsdstate.c
Normal file
4891
sys/fs/nfsserver/nfs_nfsdstate.c
Normal file
File diff suppressed because it is too large
Load Diff
2021
sys/fs/nfsserver/nfs_nfsdsubs.c
Normal file
2021
sys/fs/nfsserver/nfs_nfsdsubs.c
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user