⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nfs4state.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/**  linux/fs/nfsd/nfs4state.c**  Copyright (c) 2001 The Regents of the University of Michigan.*  All rights reserved.**  Kendrick Smith <kmsmith@umich.edu>*  Andy Adamson <kandros@umich.edu>**  Redistribution and use in source and binary forms, with or without*  modification, are permitted provided that the following conditions*  are met:**  1. Redistributions of source code must retain the above copyright*     notice, this list of conditions and the following disclaimer.*  2. Redistributions in binary form must reproduce the above copyright*     notice, this list of conditions and the following disclaimer in the*     documentation and/or other materials provided with the distribution.*  3. Neither the name of the University nor the names of its*     contributors may be used to endorse or promote products derived*     from this software without specific prior written permission.**  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED*  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF*  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE*  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE*  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR*  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF*  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR*  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF*  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING*  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS*  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.**/#include <linux/param.h>#include <linux/major.h>#include <linux/slab.h>#include <linux/sunrpc/svc.h>#include <linux/nfsd/nfsd.h>#include <linux/nfsd/cache.h>#include <linux/mount.h>#include <linux/workqueue.h>#include <linux/smp_lock.h>#include <linux/kthread.h>#include <linux/nfs4.h>#include <linux/nfsd/state.h>#include <linux/nfsd/xdr4.h>#include <linux/namei.h>#include <linux/swap.h>#include <linux/mutex.h>#include <linux/lockd/bind.h>#include <linux/module.h>#define NFSDDBG_FACILITY                NFSDDBG_PROC/* Globals */static time_t lease_time = 90;     /* default lease time */static time_t user_lease_time = 90;static time_t boot_time;static int in_grace = 1;static u32 current_clientid = 1;static u32 current_ownerid = 1;static u32 current_fileid = 1;static u32 current_delegid = 1;static u32 nfs4_init;static stateid_t zerostateid;             /* bits all 0 */static stateid_t onestateid;              /* bits all 1 */#define ZERO_STATEID(stateid) (!memcmp((stateid), &zerostateid, sizeof(stateid_t)))#define ONE_STATEID(stateid)  (!memcmp((stateid), &onestateid, sizeof(stateid_t)))/* forward declarations */static struct nfs4_stateid * find_stateid(stateid_t *stid, int flags);static struct nfs4_delegation * find_delegation_stateid(struct inode *ino, stateid_t *stid);static void release_stateid_lockowners(struct nfs4_stateid *open_stp);static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery";static void nfs4_set_recdir(char *recdir);/* Locking: * * client_mutex: * 	protects clientid_hashtbl[], clientstr_hashtbl[], * 	unconfstr_hashtbl[], uncofid_hashtbl[]. */static DEFINE_MUTEX(client_mutex);static struct kmem_cache *stateowner_slab = NULL;static struct kmem_cache *file_slab = NULL;static struct kmem_cache *stateid_slab = NULL;static struct kmem_cache *deleg_slab = NULL;voidnfs4_lock_state(void){	mutex_lock(&client_mutex);}voidnfs4_unlock_state(void){	mutex_unlock(&client_mutex);}static inline u32opaque_hashval(const void *ptr, int nbytes){	unsigned char *cptr = (unsigned char *) ptr;	u32 x = 0;	while (nbytes--) {		x *= 37;		x += *cptr++;	}	return x;}/* forward declarations */static void release_stateowner(struct nfs4_stateowner *sop);static void release_stateid(struct nfs4_stateid *stp, int flags);/* * Delegation state *//* recall_lock protects the del_recall_lru */static DEFINE_SPINLOCK(recall_lock);static struct list_head del_recall_lru;static voidfree_nfs4_file(struct kref *kref){	struct nfs4_file *fp = container_of(kref, struct nfs4_file, fi_ref);	list_del(&fp->fi_hash);	iput(fp->fi_inode);	kmem_cache_free(file_slab, fp);}static inline voidput_nfs4_file(struct nfs4_file *fi){	kref_put(&fi->fi_ref, free_nfs4_file);}static inline voidget_nfs4_file(struct nfs4_file *fi){	kref_get(&fi->fi_ref);}static int num_delegations;unsigned int max_delegations;/* * Open owner state (share locks) *//* hash tables for nfs4_stateowner */#define OWNER_HASH_BITS              8#define OWNER_HASH_SIZE             (1 << OWNER_HASH_BITS)#define OWNER_HASH_MASK             (OWNER_HASH_SIZE - 1)#define ownerid_hashval(id) \        ((id) & OWNER_HASH_MASK)#define ownerstr_hashval(clientid, ownername) \        (((clientid) + opaque_hashval((ownername.data), (ownername.len))) & OWNER_HASH_MASK)static struct list_head	ownerid_hashtbl[OWNER_HASH_SIZE];static struct list_head	ownerstr_hashtbl[OWNER_HASH_SIZE];/* hash table for nfs4_file */#define FILE_HASH_BITS                   8#define FILE_HASH_SIZE                  (1 << FILE_HASH_BITS)#define FILE_HASH_MASK                  (FILE_HASH_SIZE - 1)/* hash table for (open)nfs4_stateid */#define STATEID_HASH_BITS              10#define STATEID_HASH_SIZE              (1 << STATEID_HASH_BITS)#define STATEID_HASH_MASK              (STATEID_HASH_SIZE - 1)#define file_hashval(x) \        hash_ptr(x, FILE_HASH_BITS)#define stateid_hashval(owner_id, file_id)  \        (((owner_id) + (file_id)) & STATEID_HASH_MASK)static struct list_head file_hashtbl[FILE_HASH_SIZE];static struct list_head stateid_hashtbl[STATEID_HASH_SIZE];static struct nfs4_delegation *alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_fh *current_fh, u32 type){	struct nfs4_delegation *dp;	struct nfs4_file *fp = stp->st_file;	struct nfs4_callback *cb = &stp->st_stateowner->so_client->cl_callback;	dprintk("NFSD alloc_init_deleg\n");	if (fp->fi_had_conflict)		return NULL;	if (num_delegations > max_delegations)		return NULL;	dp = kmem_cache_alloc(deleg_slab, GFP_KERNEL);	if (dp == NULL)		return dp;	num_delegations++;	INIT_LIST_HEAD(&dp->dl_perfile);	INIT_LIST_HEAD(&dp->dl_perclnt);	INIT_LIST_HEAD(&dp->dl_recall_lru);	dp->dl_client = clp;	get_nfs4_file(fp);	dp->dl_file = fp;	dp->dl_flock = NULL;	get_file(stp->st_vfs_file);	dp->dl_vfs_file = stp->st_vfs_file;	dp->dl_type = type;	dp->dl_recall.cbr_dp = NULL;	dp->dl_recall.cbr_ident = cb->cb_ident;	dp->dl_recall.cbr_trunc = 0;	dp->dl_stateid.si_boot = boot_time;	dp->dl_stateid.si_stateownerid = current_delegid++;	dp->dl_stateid.si_fileid = 0;	dp->dl_stateid.si_generation = 0;	dp->dl_fhlen = current_fh->fh_handle.fh_size;	memcpy(dp->dl_fhval, &current_fh->fh_handle.fh_base,		        current_fh->fh_handle.fh_size);	dp->dl_time = 0;	atomic_set(&dp->dl_count, 1);	list_add(&dp->dl_perfile, &fp->fi_delegations);	list_add(&dp->dl_perclnt, &clp->cl_delegations);	return dp;}voidnfs4_put_delegation(struct nfs4_delegation *dp){	if (atomic_dec_and_test(&dp->dl_count)) {		dprintk("NFSD: freeing dp %p\n",dp);		put_nfs4_file(dp->dl_file);		kmem_cache_free(deleg_slab, dp);		num_delegations--;	}}/* Remove the associated file_lock first, then remove the delegation. * lease_modify() is called to remove the FS_LEASE file_lock from * the i_flock list, eventually calling nfsd's lock_manager * fl_release_callback. */static voidnfs4_close_delegation(struct nfs4_delegation *dp){	struct file *filp = dp->dl_vfs_file;	dprintk("NFSD: close_delegation dp %p\n",dp);	dp->dl_vfs_file = NULL;	/* The following nfsd_close may not actually close the file,	 * but we want to remove the lease in any case. */	if (dp->dl_flock)		vfs_setlease(filp, F_UNLCK, &dp->dl_flock);	nfsd_close(filp);}/* Called under the state lock. */static voidunhash_delegation(struct nfs4_delegation *dp){	list_del_init(&dp->dl_perfile);	list_del_init(&dp->dl_perclnt);	spin_lock(&recall_lock);	list_del_init(&dp->dl_recall_lru);	spin_unlock(&recall_lock);	nfs4_close_delegation(dp);	nfs4_put_delegation(dp);}/*  * SETCLIENTID state  *//* Hash tables for nfs4_clientid state */#define CLIENT_HASH_BITS                 4#define CLIENT_HASH_SIZE                (1 << CLIENT_HASH_BITS)#define CLIENT_HASH_MASK                (CLIENT_HASH_SIZE - 1)#define clientid_hashval(id) \	((id) & CLIENT_HASH_MASK)#define clientstr_hashval(name) \	(opaque_hashval((name), 8) & CLIENT_HASH_MASK)/* * reclaim_str_hashtbl[] holds known client info from previous reset/reboot * used in reboot/reset lease grace period processing * * conf_id_hashtbl[], and conf_str_hashtbl[] hold confirmed * setclientid_confirmed info.  * * unconf_str_hastbl[] and unconf_id_hashtbl[] hold unconfirmed  * setclientid info. * * client_lru holds client queue ordered by nfs4_client.cl_time * for lease renewal. * * close_lru holds (open) stateowner queue ordered by nfs4_stateowner.so_time * for last close replay. */static struct list_head	reclaim_str_hashtbl[CLIENT_HASH_SIZE];static int reclaim_str_hashtbl_size = 0;static struct list_head	conf_id_hashtbl[CLIENT_HASH_SIZE];static struct list_head	conf_str_hashtbl[CLIENT_HASH_SIZE];static struct list_head	unconf_str_hashtbl[CLIENT_HASH_SIZE];static struct list_head	unconf_id_hashtbl[CLIENT_HASH_SIZE];static struct list_head client_lru;static struct list_head close_lru;static inline voidrenew_client(struct nfs4_client *clp){	/*	* Move client to the end to the LRU list.	*/	dprintk("renewing client (clientid %08x/%08x)\n", 			clp->cl_clientid.cl_boot, 			clp->cl_clientid.cl_id);	list_move_tail(&clp->cl_lru, &client_lru);	clp->cl_time = get_seconds();}/* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */static intSTALE_CLIENTID(clientid_t *clid){	if (clid->cl_boot == boot_time)		return 0;	dprintk("NFSD stale clientid (%08x/%08x)\n", 			clid->cl_boot, clid->cl_id);	return 1;}/*  * XXX Should we use a slab cache ? * This type of memory management is somewhat inefficient, but we use it * anyway since SETCLIENTID is not a common operation. */static inline struct nfs4_client *alloc_client(struct xdr_netobj name){	struct nfs4_client *clp;	if ((clp = kzalloc(sizeof(struct nfs4_client), GFP_KERNEL))!= NULL) {		if ((clp->cl_name.data = kmalloc(name.len, GFP_KERNEL)) != NULL) {			memcpy(clp->cl_name.data, name.data, name.len);			clp->cl_name.len = name.len;		}		else {			kfree(clp);			clp = NULL;		}	}	return clp;}static voidshutdown_callback_client(struct nfs4_client *clp){	struct rpc_clnt *clnt = clp->cl_callback.cb_client;	/* shutdown rpc client, ending any outstanding recall rpcs */	if (clnt) {		clp->cl_callback.cb_client = NULL;		rpc_shutdown_client(clnt);	}}static inline voidfree_client(struct nfs4_client *clp){	shutdown_callback_client(clp);	if (clp->cl_cred.cr_group_info)		put_group_info(clp->cl_cred.cr_group_info);	kfree(clp->cl_name.data);	kfree(clp);}voidput_nfs4_client(struct nfs4_client *clp){	if (atomic_dec_and_test(&clp->cl_count))		free_client(clp);}static voidexpire_client(struct nfs4_client *clp){	struct nfs4_stateowner *sop;	struct nfs4_delegation *dp;	struct list_head reaplist;	dprintk("NFSD: expire_client cl_count %d\n",	                    atomic_read(&clp->cl_count));	INIT_LIST_HEAD(&reaplist);	spin_lock(&recall_lock);	while (!list_empty(&clp->cl_delegations)) {		dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt);		dprintk("NFSD: expire client. dp %p, fp %p\n", dp,				dp->dl_flock);		list_del_init(&dp->dl_perclnt);		list_move(&dp->dl_recall_lru, &reaplist);	}	spin_unlock(&recall_lock);	while (!list_empty(&reaplist)) {		dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru);		list_del_init(&dp->dl_recall_lru);		unhash_delegation(dp);	}	list_del(&clp->cl_idhash);	list_del(&clp->cl_strhash);	list_del(&clp->cl_lru);	while (!list_empty(&clp->cl_openowners)) {		sop = list_entry(clp->cl_openowners.next, struct nfs4_stateowner, so_perclient);		release_stateowner(sop);	}	put_nfs4_client(clp);}static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir) {	struct nfs4_client *clp;	if (!(clp = alloc_client(name)))		goto out;	memcpy(clp->cl_recdir, recdir, HEXDIR_LEN);	atomic_set(&clp->cl_count, 1);	atomic_set(&clp->cl_callback.cb_set, 0);	INIT_LIST_HEAD(&clp->cl_idhash);	INIT_LIST_HEAD(&clp->cl_strhash);	INIT_LIST_HEAD(&clp->cl_openowners);	INIT_LIST_HEAD(&clp->cl_delegations);	INIT_LIST_HEAD(&clp->cl_lru);out:	return clp;}static voidcopy_verf(struct nfs4_client *target, nfs4_verifier *source) {	memcpy(target->cl_verifier.data, source->data, sizeof(target->cl_verifier.data));}static voidcopy_clid(struct nfs4_client *target, struct nfs4_client *source) {	target->cl_clientid.cl_boot = source->cl_clientid.cl_boot; 	target->cl_clientid.cl_id = source->cl_clientid.cl_id; }static voidcopy_cred(struct svc_cred *target, struct svc_cred *source) {	target->cr_uid = source->cr_uid;	target->cr_gid = source->cr_gid;	target->cr_group_info = source->cr_group_info;	get_group_info(target->cr_group_info);}static inline intsame_name(const char *n1, const char *n2){	return 0 == memcmp(n1, n2, HEXDIR_LEN);}static intsame_verf(nfs4_verifier *v1, nfs4_verifier *v2){	return 0 == memcmp(v1->data, v2->data, sizeof(v1->data));}static intsame_clid(clientid_t *cl1, clientid_t *cl2){	return (cl1->cl_boot == cl2->cl_boot) && (cl1->cl_id == cl2->cl_id);}/* XXX what about NGROUP */static intsame_creds(struct svc_cred *cr1, struct svc_cred *cr2){	return cr1->cr_uid == cr2->cr_uid;}static voidgen_clid(struct nfs4_client *clp) {	clp->cl_clientid.cl_boot = boot_time;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -