欢迎来到虫虫下载站 | 资源下载 资源专辑 关于我们
虫虫下载站

nfs4state.c

Linux Kernel 2.6.9 for OMAP1710
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/nfs4.h>#include <linux/nfsd/state.h>#include <linux/nfsd/xdr4.h>#define NFSDDBG_FACILITY                NFSDDBG_PROC/* Globals */static time_t lease_time = 90;     /* default lease time */static time_t old_lease_time = 90; /* past incarnation lease time */static u32 nfs4_reclaim_init = 0;time_t boot_time;static time_t grace_end = 0;static u32 current_clientid = 1;static u32 current_ownerid;static u32 current_fileid;static u32 nfs4_init;stateid_t zerostateid;             /* bits all 0 */stateid_t onestateid;              /* bits all 1 *//* debug counters */u32 list_add_perfile = 0; u32 list_del_perfile = 0;u32 add_perclient = 0;u32 del_perclient = 0;u32 alloc_file = 0;u32 free_file = 0;u32 alloc_sowner = 0;u32 free_sowner = 0;u32 vfsopen = 0;u32 vfsclose = 0;u32 alloc_lsowner= 0;/* forward declarations */struct nfs4_stateid * find_stateid(stateid_t *stid, int flags);/* Locking: * * client_sema:  * 	protects clientid_hashtbl[], clientstr_hashtbl[], * 	unconfstr_hashtbl[], uncofid_hashtbl[]. */static DECLARE_MUTEX(client_sema);voidnfs4_lock_state(void){	down(&client_sema);}/* * nfs4_unlock_state(); called in encode */voidnfs4_unlock_state(void){	up(&client_sema);}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);static void release_file(struct nfs4_file *fp);/*  * 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, namelen) \	(opaque_hashval((name), (namelen)) & 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;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 = kmalloc(sizeof(struct nfs4_client), GFP_KERNEL))!= NULL) {		memset(clp, 0, sizeof(*clp));		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 inline voidfree_client(struct nfs4_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);}static voidexpire_client(struct nfs4_client *clp){	struct nfs4_stateowner *sop;	dprintk("NFSD: expire_client\n");	list_del(&clp->cl_idhash);	list_del(&clp->cl_strhash);	list_del(&clp->cl_lru);	while (!list_empty(&clp->cl_perclient)) {		sop = list_entry(clp->cl_perclient.next, struct nfs4_stateowner, so_perclient);		release_stateowner(sop);	}	free_client(clp);}static struct nfs4_client *create_client(struct xdr_netobj name) {	struct nfs4_client *clp;	if (!(clp = alloc_client(name)))		goto out;	INIT_LIST_HEAD(&clp->cl_idhash);	INIT_LIST_HEAD(&clp->cl_strhash);	INIT_LIST_HEAD(&clp->cl_perclient);	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 intcmp_name(struct xdr_netobj *n1, struct xdr_netobj *n2) {	if (!n1 || !n2)		return 0;	return((n1->len == n2->len) && !memcmp(n1->data, n2->data, n2->len));}static intcmp_verf(nfs4_verifier *v1, nfs4_verifier *v2) {	return(!memcmp(v1->data,v2->data,sizeof(v1->data)));}static intcmp_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 intcmp_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;	clp->cl_clientid.cl_id = current_clientid++; }static voidgen_confirm(struct nfs4_client *clp) {	struct timespec 	tv;	u32 *			p;	tv = CURRENT_TIME;	p = (u32 *)clp->cl_confirm.data;	*p++ = tv.tv_sec;	*p++ = tv.tv_nsec;}static intcheck_name(struct xdr_netobj name) {	if (name.len == 0) 		return 0;	if (name.len > NFS4_OPAQUE_LIMIT) {		printk("NFSD: check_name: name too long(%d)!\n", name.len);		return 0;	}	return 1;}voidadd_to_unconfirmed(struct nfs4_client *clp, unsigned int strhashval){	unsigned int idhashval;	list_add(&clp->cl_strhash, &unconf_str_hashtbl[strhashval]);	idhashval = clientid_hashval(clp->cl_clientid.cl_id);	list_add(&clp->cl_idhash, &unconf_id_hashtbl[idhashval]);	list_add_tail(&clp->cl_lru, &client_lru);	clp->cl_time = get_seconds();}voidmove_to_confirmed(struct nfs4_client *clp, unsigned int idhashval){	unsigned int strhashval;	dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp);	list_del_init(&clp->cl_strhash);	list_del_init(&clp->cl_idhash);	list_add(&clp->cl_idhash, &conf_id_hashtbl[idhashval]);	strhashval = clientstr_hashval(clp->cl_name.data, 			clp->cl_name.len);	list_add(&clp->cl_strhash, &conf_str_hashtbl[strhashval]);	renew_client(clp);}/* a helper function for parse_callback */static intparse_octet(unsigned int *lenp, char **addrp){	unsigned int len = *lenp;	char *p = *addrp;	int n = -1;	char c;	for (;;) {		if (!len)			break;		len--;		c = *p++;		if (c == '.')			break;		if ((c < '0') || (c > '9')) {			n = -1;			break;		}		if (n < 0)			n = 0;		n = (n * 10) + (c - '0');		if (n > 255) {			n = -1;			break;		}	}	*lenp = len;	*addrp = p;	return n;}/* parse and set the setclientid ipv4 callback address */intparse_ipv4(unsigned int addr_len, char *addr_val, unsigned int *cbaddrp, unsigned short *cbportp){	int temp = 0;	u32 cbaddr = 0;	u16 cbport = 0;	u32 addrlen = addr_len;	char *addr = addr_val;	int i, shift;	/* ipaddress */	shift = 24;	for(i = 4; i > 0  ; i--) {		if ((temp = parse_octet(&addrlen, &addr)) < 0) {			return 0;		}		cbaddr |= (temp << shift);		if (shift > 0)		shift -= 8;	}	*cbaddrp = cbaddr;	/* port */	shift = 8;	for(i = 2; i > 0  ; i--) {		if ((temp = parse_octet(&addrlen, &addr)) < 0) {			return 0;		}		cbport |= (temp << shift);		if (shift > 0)			shift -= 8;	}	*cbportp = cbport;	return 1;}voidgen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se){	struct nfs4_callback *cb = &clp->cl_callback;	if ( !(parse_ipv4(se->se_callback_addr_len, se->se_callback_addr_val,		         &cb->cb_addr, &cb->cb_port))) {		printk(KERN_INFO "NFSD: BAD callback address. client will not receive delegations\n");		cb->cb_parsed = 0;		return;	}	cb->cb_netid.len = se->se_callback_netid_len;	cb->cb_netid.data = se->se_callback_netid_val;	cb->cb_prog = se->se_callback_prog;	cb->cb_ident = se->se_callback_ident;	cb->cb_parsed = 1;}/* * RFC 3010 has a complex implmentation description of processing a  * SETCLIENTID request consisting of 5 bullets, labeled as  * CASE0 - CASE4 below. * * NOTES: * 	callback information will be processed in a future patch * *	an unconfirmed record is added when: *      NORMAL (part of CASE 4): there is no confirmed nor unconfirmed record. *	CASE 1: confirmed record found with matching name, principal, *		verifier, and clientid. *	CASE 2: confirmed record found with matching name, principal, *		and there is no unconfirmed record with matching *		name and principal * *      an unconfirmed record is replaced when: *	CASE 3: confirmed record found with matching name, principal, *		and an unconfirmed record is found with matching  *		name, principal, and with clientid and *		confirm that does not match the confirmed record. *	CASE 4: there is no confirmed record with matching name and  *		principal. there is an unconfirmed record with  *		matching name, principal. * *	an unconfirmed record is deleted when: *	CASE 1: an unconfirmed record that matches input name, verifier, *		and confirmed clientid. *	CASE 4: any unconfirmed records with matching name and principal *		that exist after an unconfirmed record has been replaced *		as described above. * */intnfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid){	u32 			ip_addr = rqstp->rq_addr.sin_addr.s_addr;	struct xdr_netobj 	clname = { 		.len = setclid->se_namelen,		.data = setclid->se_name,	};	nfs4_verifier		clverifier = setclid->se_verf;	unsigned int 		strhashval;	struct nfs4_client *	conf, * unconf, * new, * clp;	int 			status;		status = nfserr_inval;

⌨️ 快捷键说明

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