diff options
Diffstat (limited to 'fs/nfsd/state.h')
| -rw-r--r-- | fs/nfsd/state.h | 336 | 
1 files changed, 180 insertions, 156 deletions
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 39adc27b068..374c66283ac 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -35,8 +35,8 @@  #ifndef _NFSD4_STATE_H  #define _NFSD4_STATE_H +#include <linux/idr.h>  #include <linux/sunrpc/svc_xprt.h> -#include <linux/nfsd/nfsfh.h>  #include "nfsfh.h"  typedef struct { @@ -45,47 +45,56 @@ typedef struct {  } clientid_t;  typedef struct { -	u32             so_boot; -	u32             so_stateownerid; -	u32             so_fileid; +	clientid_t	so_clid; +	u32		so_id;  } stateid_opaque_t;  typedef struct {  	u32                     si_generation;  	stateid_opaque_t        si_opaque;  } stateid_t; -#define si_boot           si_opaque.so_boot -#define si_stateownerid   si_opaque.so_stateownerid -#define si_fileid         si_opaque.so_fileid  #define STATEID_FMT	"(%08x/%08x/%08x/%08x)"  #define STATEID_VAL(s) \ -	(s)->si_boot, \ -	(s)->si_stateownerid, \ -	(s)->si_fileid, \ +	(s)->si_opaque.so_clid.cl_boot, \ +	(s)->si_opaque.so_clid.cl_id, \ +	(s)->si_opaque.so_id, \  	(s)->si_generation  struct nfsd4_callback {  	void *cb_op;  	struct nfs4_client *cb_clp; +	struct list_head cb_per_client;  	u32 cb_minorversion;  	struct rpc_message cb_msg;  	const struct rpc_call_ops *cb_ops;  	struct work_struct cb_work; +	bool cb_done; +}; + +struct nfs4_stid { +#define NFS4_OPEN_STID 1 +#define NFS4_LOCK_STID 2 +#define NFS4_DELEG_STID 4 +/* For an open stateid kept around *only* to process close replays: */ +#define NFS4_CLOSED_STID 8 +/* For a deleg stateid kept around only to process free_stateid's: */ +#define NFS4_REVOKED_DELEG_STID 16 +	unsigned char sc_type; +	stateid_t sc_stateid; +	struct nfs4_client *sc_client;  };  struct nfs4_delegation { +	struct nfs4_stid	dl_stid; /* must be first field */  	struct list_head	dl_perfile;  	struct list_head	dl_perclnt;  	struct list_head	dl_recall_lru;  /* delegation recalled */  	atomic_t		dl_count;       /* ref count */ -	struct nfs4_client	*dl_client;  	struct nfs4_file	*dl_file; -	struct file_lock	*dl_flock;  	u32			dl_type;  	time_t			dl_time;  /* For recall: */ -	stateid_t		dl_stateid;  	struct knfsd_fh		dl_fh;  	int			dl_retries;  	struct nfsd4_callback	dl_recall; @@ -95,6 +104,7 @@ struct nfs4_delegation {  struct nfs4_cb_conn {  	/* SETCLIENTID info */  	struct sockaddr_storage	cb_addr; +	struct sockaddr_storage	cb_saddr;  	size_t			cb_addrlen;  	u32                     cb_prog; /* used only in 4.0 case;  					    per-session otherwise */ @@ -102,24 +112,31 @@ struct nfs4_cb_conn {  	struct svc_xprt		*cb_xprt;	/* minorversion 1 only */  }; +static inline struct nfs4_delegation *delegstateid(struct nfs4_stid *s) +{ +	return container_of(s, struct nfs4_delegation, dl_stid); +} +  /* Maximum number of slots per session. 160 is useful for long haul TCP */  #define NFSD_MAX_SLOTS_PER_SESSION     160  /* Maximum number of operations per session compound */  #define NFSD_MAX_OPS_PER_COMPOUND	16  /* Maximum  session per slot cache size */ -#define NFSD_SLOT_CACHE_SIZE		1024 +#define NFSD_SLOT_CACHE_SIZE		2048  /* Maximum number of NFSD_SLOT_CACHE_SIZE slots per session */  #define NFSD_CACHE_SIZE_SLOTS_PER_SESSION	32  #define NFSD_MAX_MEM_PER_SESSION  \  		(NFSD_CACHE_SIZE_SLOTS_PER_SESSION * NFSD_SLOT_CACHE_SIZE)  struct nfsd4_slot { -	bool	sl_inuse; -	bool	sl_cachethis; -	u16	sl_opcnt;  	u32	sl_seqid;  	__be32	sl_status;  	u32	sl_datalen; +	u16	sl_opcnt; +#define NFSD4_SLOT_INUSE	(1 << 0) +#define NFSD4_SLOT_CACHETHIS	(1 << 1) +#define NFSD4_SLOT_INITIALIZED	(1 << 2) +	u8	sl_flags;  	char	sl_data[];  }; @@ -134,6 +151,12 @@ struct nfsd4_channel_attrs {  	u32		rdma_attrs;  }; +struct nfsd4_cb_sec { +	u32	flavor; /* (u32)(-1) used to mean "no valid flavor" */ +	kuid_t	uid; +	kgid_t	gid; +}; +  struct nfsd4_create_session {  	clientid_t			clientid;  	struct nfs4_sessionid		sessionid; @@ -142,8 +165,17 @@ struct nfsd4_create_session {  	struct nfsd4_channel_attrs	fore_channel;  	struct nfsd4_channel_attrs	back_channel;  	u32				callback_prog; -	u32				uid; -	u32				gid; +	struct nfsd4_cb_sec		cb_sec; +}; + +struct nfsd4_backchannel_ctl { +	u32	bc_cb_program; +	struct nfsd4_cb_sec		bc_cb_sec; +}; + +struct nfsd4_bind_conn_to_session { +	struct nfs4_sessionid		sessionid; +	u32				dir;  };  /* The single slot clientid cache structure */ @@ -163,32 +195,24 @@ struct nfsd4_conn {  };  struct nfsd4_session { -	struct kref		se_ref; +	atomic_t		se_ref;  	struct list_head	se_hash;	/* hash by sessionid */  	struct list_head	se_perclnt; +/* See SESSION4_PERSIST, etc. for standard flags; this is internal-only: */ +#define NFS4_SESSION_DEAD	0x010  	u32			se_flags;  	struct nfs4_client	*se_client;  	struct nfs4_sessionid	se_sessionid;  	struct nfsd4_channel_attrs se_fchannel;  	struct nfsd4_channel_attrs se_bchannel; +	struct nfsd4_cb_sec	se_cb_sec;  	struct list_head	se_conns;  	u32			se_cb_prog;  	u32			se_cb_seq_nr;  	struct nfsd4_slot	*se_slots[];	/* forward channel slots */  }; -static inline void -nfsd4_put_session(struct nfsd4_session *ses) -{ -	extern void free_session(struct kref *kref); -	kref_put(&ses->se_ref, free_session); -} - -static inline void -nfsd4_get_session(struct nfsd4_session *ses) -{ -	kref_get(&ses->se_ref); -} +extern void nfsd4_put_session(struct nfsd4_session *ses);  /* formatted contents of nfs4_sessionid */  struct nfsd4_sessionid { @@ -211,33 +235,43 @@ struct nfsd4_sessionid {   */  struct nfs4_client {  	struct list_head	cl_idhash; 	/* hash by cl_clientid.id */ -	struct list_head	cl_strhash; 	/* hash by cl_name */ +	struct rb_node		cl_namenode;	/* link into by-name trees */  	struct list_head	cl_openowners; +	struct idr		cl_stateids;	/* stateid lookup */  	struct list_head	cl_delegations; +	struct list_head	cl_revoked;	/* unacknowledged, revoked 4.1 state */  	struct list_head        cl_lru;         /* tail queue */  	struct xdr_netobj	cl_name; 	/* id generated by client */ -	char                    cl_recdir[HEXDIR_LEN]; /* recovery dir */  	nfs4_verifier		cl_verifier; 	/* generated by client */  	time_t                  cl_time;        /* time of last lease renewal */  	struct sockaddr_storage	cl_addr; 	/* client ipaddress */ -	u32			cl_flavor;	/* setclientid pseudoflavor */ -	char			*cl_principal;	/* setclientid principal name */ +	bool			cl_mach_cred;	/* SP4_MACH_CRED in force */  	struct svc_cred		cl_cred; 	/* setclientid principal */  	clientid_t		cl_clientid;	/* generated by server */  	nfs4_verifier		cl_confirm;	/* generated by server */ -	u32			cl_firststate;	/* recovery dir creation */  	u32			cl_minorversion;  	/* for v4.0 and v4.1 callbacks: */  	struct nfs4_cb_conn	cl_cb_conn; -#define NFSD4_CLIENT_CB_UPDATE	1 -#define NFSD4_CLIENT_KILL	2 -	unsigned long		cl_cb_flags; +#define NFSD4_CLIENT_CB_UPDATE		(0) +#define NFSD4_CLIENT_CB_KILL		(1) +#define NFSD4_CLIENT_STABLE		(2)	/* client on stable storage */ +#define NFSD4_CLIENT_RECLAIM_COMPLETE	(3)	/* reclaim_complete done */ +#define NFSD4_CLIENT_CONFIRMED		(4)	/* client is confirmed */ +#define NFSD4_CLIENT_CB_FLAG_MASK	(1 << NFSD4_CLIENT_CB_UPDATE | \ +					 1 << NFSD4_CLIENT_CB_KILL) +	unsigned long		cl_flags; +	struct rpc_cred		*cl_cb_cred;  	struct rpc_clnt		*cl_cb_client;  	u32			cl_cb_ident; -	atomic_t		cl_cb_set; +#define NFSD4_CB_UP		0 +#define NFSD4_CB_UNKNOWN	1 +#define NFSD4_CB_DOWN		2 +#define NFSD4_CB_FAULT		3 +	int			cl_cb_state;  	struct nfsd4_callback	cl_cb_null;  	struct nfsd4_session	*cl_cb_session; +	struct list_head	cl_callbacks; /* list of in-progress callbacks */  	/* for all client information that callback code might need: */  	spinlock_t		cl_lock; @@ -254,20 +288,9 @@ struct nfs4_client {  	unsigned long		cl_cb_slot_busy;  	struct rpc_wait_queue	cl_cb_waitq;	/* backchannel callers may */  						/* wait here for slots */ +	struct net		*net;  }; -static inline void -mark_client_expired(struct nfs4_client *clp) -{ -	clp->cl_time = 0; -} - -static inline bool -is_client_expired(struct nfs4_client *clp) -{ -	return clp->cl_time == 0; -} -  /* struct nfs4_client_reset   * one per old client. Populates reset_str_hashtbl. Filled from conf_id_hashtbl   * upon lease reset, or from upcall to state_daemon (to read in state @@ -275,6 +298,7 @@ is_client_expired(struct nfs4_client *clp)   */  struct nfs4_client_reclaim {  	struct list_head	cr_strhash;	/* hash by cr_name */ +	struct nfs4_client	*cr_clp;	/* pointer to associated clp */  	char			cr_recdir[HEXDIR_LEN]; /* recover dir */  }; @@ -282,6 +306,9 @@ static inline void  update_stateid(stateid_t *stateid)  {  	stateid->si_generation++; +	/* Wraparound recommendation from 3530bis-13 9.1.3.2: */ +	if (stateid->si_generation == 0) +		stateid->si_generation = 1;  }  /* A reasonable value for REPLAY_ISIZE was estimated as follows:   @@ -301,74 +328,77 @@ struct nfs4_replay {  	__be32			rp_status;  	unsigned int		rp_buflen;  	char			*rp_buf; -	unsigned		intrp_allocated;  	struct knfsd_fh		rp_openfh;  	char			rp_ibuf[NFSD4_REPLAY_ISIZE];  }; -/* -* nfs4_stateowner can either be an open_owner, or a lock_owner -* -*    so_idhash:  stateid_hashtbl[] for open owner, lockstateid_hashtbl[] -*         for lock_owner -*    so_strhash: ownerstr_hashtbl[] for open_owner, lock_ownerstr_hashtbl[] -*         for lock_owner -*    so_perclient: nfs4_client->cl_perclient entry - used when nfs4_client -*         struct is reaped. -*    so_perfilestate: heads the list of nfs4_stateid (either open or lock)  -*         and is used to ensure no dangling nfs4_stateid references when we  -*         release a stateowner. -*    so_perlockowner: (open) nfs4_stateid->st_perlockowner entry - used when -*         close is called to reap associated byte-range locks -*    so_close_lru: (open) stateowner is placed on this list instead of being -*         reaped (when so_perfilestate is empty) to hold the last close replay. -*         reaped by laundramat thread after lease period. -*/  struct nfs4_stateowner { -	struct kref		so_ref; -	struct list_head        so_idhash;   /* hash by so_id */  	struct list_head        so_strhash;   /* hash by op_name */ -	struct list_head        so_perclient;  	struct list_head        so_stateids; -	struct list_head        so_perstateid; /* for lockowners only */ -	struct list_head	so_close_lru; /* tail queue */ -	time_t			so_time; /* time of placement on so_close_lru */ -	int			so_is_open_owner; /* 1=openowner,0=lockowner */ -	u32                     so_id;  	struct nfs4_client *    so_client;  	/* after increment in ENCODE_SEQID_OP_TAIL, represents the next  	 * sequence id expected from the client: */  	u32                     so_seqid;  	struct xdr_netobj       so_owner;     /* open owner name */ -	int                     so_confirmed; /* successful OPEN_CONFIRM? */  	struct nfs4_replay	so_replay; +	bool			so_is_open_owner;  }; -/* -*  nfs4_file: a file opened by some number of (open) nfs4_stateowners. -*    o fi_perfile list is used to search for conflicting  -*      share_acces, share_deny on the file. -*/ +struct nfs4_openowner { +	struct nfs4_stateowner	oo_owner; /* must be first field */ +	struct list_head        oo_perclient; +	/* +	 * We keep around openowners a little while after last close, +	 * which saves clients from having to confirm, and allows us to +	 * handle close replays if they come soon enough.  The close_lru +	 * is a list of such openowners, to be reaped by the laundromat +	 * thread eventually if they remain unused: +	 */ +	struct list_head	oo_close_lru; +	struct nfs4_ol_stateid *oo_last_closed_stid; +	time_t			oo_time; /* time of placement on so_close_lru */ +#define NFS4_OO_CONFIRMED   1 +#define NFS4_OO_NEW         4 +	unsigned char		oo_flags; +}; + +struct nfs4_lockowner { +	struct nfs4_stateowner	lo_owner; /* must be first element */ +	struct list_head	lo_owner_ino_hash; /* hash by owner,file */ +	struct list_head        lo_perstateid; +	struct list_head	lo_list; /* for temporary uses */ +}; + +static inline struct nfs4_openowner * openowner(struct nfs4_stateowner *so) +{ +	return container_of(so, struct nfs4_openowner, oo_owner); +} + +static inline struct nfs4_lockowner * lockowner(struct nfs4_stateowner *so) +{ +	return container_of(so, struct nfs4_lockowner, lo_owner); +} + +/* nfs4_file: a file opened by some number of (open) nfs4_stateowners. */  struct nfs4_file {  	atomic_t		fi_ref; -	struct list_head        fi_hash;    /* hash by "struct inode *" */ +	struct hlist_node       fi_hash;    /* hash by "struct inode *" */  	struct list_head        fi_stateids;  	struct list_head	fi_delegations;  	/* One each for O_RDONLY, O_WRONLY, O_RDWR: */  	struct file *		fi_fds[3]; -	/* One each for O_RDONLY, O_WRONLY: */ -	atomic_t		fi_access[2];  	/* -	 * Each open stateid contributes 1 to either fi_readers or -	 * fi_writers, or both, depending on the open mode.  A -	 * delegation also takes an fi_readers reference.  Lock -	 * stateid's take none. +	 * Each open or lock stateid contributes 0-4 to the counts +	 * below depending on which bits are set in st_access_bitmap: +	 *     1 to fi_access[O_RDONLY] if NFS4_SHARE_ACCES_READ is set +	 *   + 1 to fi_access[O_WRONLY] if NFS4_SHARE_ACCESS_WRITE is set +	 *   + 1 to both of the above if NFS4_SHARE_ACCESS_BOTH is set.  	 */ -	atomic_t		fi_readers; -	atomic_t		fi_writers; +	atomic_t		fi_access[2]; +	struct file		*fi_deleg_file; +	struct file_lock	*fi_lease; +	atomic_t		fi_delegees;  	struct inode		*fi_inode; -	u32                     fi_id;      /* used with stateowner->so_id  -					     * for stateid_hashtbl hash */  	bool			fi_had_conflict;  }; @@ -398,90 +428,84 @@ static inline struct file *find_any_file(struct nfs4_file *f)  		return f->fi_fds[O_RDONLY];  } -/* -* nfs4_stateid can either be an open stateid or (eventually) a lock stateid -* -* (open)nfs4_stateid: one per (open)nfs4_stateowner, nfs4_file -* -* 	st_hash: stateid_hashtbl[] entry or lockstateid_hashtbl entry -* 	st_perfile: file_hashtbl[] entry. -* 	st_perfile_state: nfs4_stateowner->so_perfilestate -*       st_perlockowner: (open stateid) list of lock nfs4_stateowners -* 	st_access_bmap: used only for open stateid -* 	st_deny_bmap: used only for open stateid -*	st_openstp: open stateid lock stateid was derived from -* -* XXX: open stateids and lock stateids have diverged sufficiently that -* we should consider defining separate structs for the two cases. -*/ - -struct nfs4_stateid { -	struct list_head              st_hash;  +/* "ol" stands for "Open or Lock".  Better suggestions welcome. */ +struct nfs4_ol_stateid { +	struct nfs4_stid    st_stid; /* must be first field */  	struct list_head              st_perfile;  	struct list_head              st_perstateowner;  	struct list_head              st_lockowners;  	struct nfs4_stateowner      * st_stateowner;  	struct nfs4_file            * st_file; -	stateid_t                     st_stateid;  	unsigned long                 st_access_bmap;  	unsigned long                 st_deny_bmap; -	struct nfs4_stateid         * st_openstp; +	struct nfs4_ol_stateid         * st_openstp;  }; +static inline struct nfs4_ol_stateid *openlockstateid(struct nfs4_stid *s) +{ +	return container_of(s, struct nfs4_ol_stateid, st_stid); +} +  /* flags for preprocess_seqid_op() */ -#define HAS_SESSION             0x00000001 -#define CONFIRM                 0x00000002 -#define OPEN_STATE              0x00000004 -#define LOCK_STATE              0x00000008  #define RD_STATE	        0x00000010  #define WR_STATE	        0x00000020 -#define CLOSE_STATE             0x00000040 - -#define seqid_mutating_err(err)                       \ -	(((err) != nfserr_stale_clientid) &&    \ -	((err) != nfserr_bad_seqid) &&          \ -	((err) != nfserr_stale_stateid) &&      \ -	((err) != nfserr_bad_stateid))  struct nfsd4_compound_state; +struct nfsd_net; -extern __be32 nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, +extern __be32 nfs4_preprocess_stateid_op(struct net *net, +		struct nfsd4_compound_state *cstate,  		stateid_t *stateid, int flags, struct file **filp);  extern void nfs4_lock_state(void);  extern void nfs4_unlock_state(void); -extern int nfs4_in_grace(void); -extern __be32 nfs4_check_open_reclaim(clientid_t *clid); -extern void nfs4_free_stateowner(struct kref *kref); +void nfs4_remove_reclaim_record(struct nfs4_client_reclaim *, struct nfsd_net *); +extern void nfs4_release_reclaim(struct nfsd_net *); +extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(const char *recdir, +							struct nfsd_net *nn); +extern __be32 nfs4_check_open_reclaim(clientid_t *clid, bool sessions, struct nfsd_net *nn);  extern int set_callback_cred(void); +extern void nfsd4_init_callback(struct nfsd4_callback *);  extern void nfsd4_probe_callback(struct nfs4_client *clp); +extern void nfsd4_probe_callback_sync(struct nfs4_client *clp);  extern void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *); -extern void nfsd4_do_callback_rpc(struct work_struct *);  extern void nfsd4_cb_recall(struct nfs4_delegation *dp);  extern int nfsd4_create_callback_queue(void);  extern void nfsd4_destroy_callback_queue(void);  extern void nfsd4_shutdown_callback(struct nfs4_client *);  extern void nfs4_put_delegation(struct nfs4_delegation *dp); -extern __be32 nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname); -extern void nfsd4_init_recdir(char *recdir_name); -extern int nfsd4_recdir_load(void); -extern void nfsd4_shutdown_recdir(void); -extern int nfs4_client_to_reclaim(const char *name); -extern int nfs4_has_reclaimed_state(const char *name, bool use_exchange_id); -extern void nfsd4_recdir_purge_old(void); -extern int nfsd4_create_clid_dir(struct nfs4_client *clp); -extern void nfsd4_remove_clid_dir(struct nfs4_client *clp); -extern void release_session_client(struct nfsd4_session *); - -static inline void -nfs4_put_stateowner(struct nfs4_stateowner *so) -{ -	kref_put(&so->so_ref, nfs4_free_stateowner); -} - -static inline void -nfs4_get_stateowner(struct nfs4_stateowner *so) -{ -	kref_get(&so->so_ref); -} +extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(const char *name, +							struct nfsd_net *nn); +extern bool nfs4_has_reclaimed_state(const char *name, struct nfsd_net *nn); +extern void put_client_renew(struct nfs4_client *clp); + +/* nfs4recover operations */ +extern int nfsd4_client_tracking_init(struct net *net); +extern void nfsd4_client_tracking_exit(struct net *net); +extern void nfsd4_client_record_create(struct nfs4_client *clp); +extern void nfsd4_client_record_remove(struct nfs4_client *clp); +extern int nfsd4_client_record_check(struct nfs4_client *clp); +extern void nfsd4_record_grace_done(struct nfsd_net *nn, time_t boot_time); + +/* nfs fault injection functions */ +#ifdef CONFIG_NFSD_FAULT_INJECTION +int nfsd_fault_inject_init(void); +void nfsd_fault_inject_cleanup(void); +u64 nfsd_for_n_state(u64, u64 (*)(struct nfs4_client *, u64)); +struct nfs4_client *nfsd_find_client(struct sockaddr_storage *, size_t); + +u64 nfsd_forget_client(struct nfs4_client *, u64); +u64 nfsd_forget_client_locks(struct nfs4_client*, u64); +u64 nfsd_forget_client_openowners(struct nfs4_client *, u64); +u64 nfsd_forget_client_delegations(struct nfs4_client *, u64); +u64 nfsd_recall_client_delegations(struct nfs4_client *, u64); + +u64 nfsd_print_client(struct nfs4_client *, u64); +u64 nfsd_print_client_locks(struct nfs4_client *, u64); +u64 nfsd_print_client_openowners(struct nfs4_client *, u64); +u64 nfsd_print_client_delegations(struct nfs4_client *, u64); +#else /* CONFIG_NFSD_FAULT_INJECTION */ +static inline int nfsd_fault_inject_init(void) { return 0; } +static inline void nfsd_fault_inject_cleanup(void) {} +#endif /* CONFIG_NFSD_FAULT_INJECTION */  #endif   /* NFSD4_STATE_H */  | 
