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

nfs4state.c

Linux Kernel 2.6.9 for OMAP1710
C
第 1 页 / 共 5 页
字号:
	if (!check_name(clname))		goto out;	/* 	 * XXX The Duplicate Request Cache (DRC) has been checked (??)	 * We get here on a DRC miss.	 */	strhashval = clientstr_hashval(clname.data, clname.len);	conf = NULL;	nfs4_lock_state();	list_for_each_entry(clp, &conf_str_hashtbl[strhashval], cl_strhash) {		if (!cmp_name(&clp->cl_name, &clname))			continue;		/* 		 * CASE 0:		 * clname match, confirmed, different principal		 * or different ip_address		 */		status = nfserr_clid_inuse;		if (!cmp_creds(&clp->cl_cred,&rqstp->rq_cred)) {			printk("NFSD: setclientid: string in use by client"			"(clientid %08x/%08x)\n",			clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);			goto out;		}		if (clp->cl_addr != ip_addr) { 			printk("NFSD: setclientid: string in use by client"			"(clientid %08x/%08x)\n",			clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);			goto out;		}		/* 	 	 * cl_name match from a previous SETCLIENTID operation	 	 * XXX check for additional matches?		 */		conf = clp;		break;	}	unconf = NULL;	list_for_each_entry(clp, &unconf_str_hashtbl[strhashval], cl_strhash) {		if (!cmp_name(&clp->cl_name, &clname))			continue;		/* cl_name match from a previous SETCLIENTID operation */		unconf = clp;		break;	}	status = nfserr_resource;	if (!conf) {		/* 		 * CASE 4:		 * placed first, because it is the normal case.		 */		if (unconf)			expire_client(unconf);		if (!(new = create_client(clname)))			goto out;		copy_verf(new, &clverifier);		new->cl_addr = ip_addr;		copy_cred(&new->cl_cred,&rqstp->rq_cred);		gen_clid(new);		gen_confirm(new);		gen_callback(new, setclid);		add_to_unconfirmed(new, strhashval);	} else if (cmp_verf(&conf->cl_verifier, &clverifier)) {		/*		 * CASE 1:		 * cl_name match, confirmed, principal match		 * verifier match: probable callback update		 *		 * remove any unconfirmed nfs4_client with 		 * matching cl_name, cl_verifier, and cl_clientid		 *		 * create and insert an unconfirmed nfs4_client with same 		 * cl_name, cl_verifier, and cl_clientid as existing 		 * nfs4_client,  but with the new callback info and a 		 * new cl_confirm		 */		if ((unconf) && 		    cmp_verf(&unconf->cl_verifier, &conf->cl_verifier) &&		     cmp_clid(&unconf->cl_clientid, &conf->cl_clientid)) {				expire_client(unconf);		}		if (!(new = create_client(clname)))			goto out;		copy_verf(new,&conf->cl_verifier);		new->cl_addr = ip_addr;		copy_cred(&new->cl_cred,&rqstp->rq_cred);		copy_clid(new, conf);		gen_confirm(new);		gen_callback(new, setclid);		add_to_unconfirmed(new,strhashval);	} else if (!unconf) {		/*		 * CASE 2:		 * clname match, confirmed, principal match		 * verfier does not match		 * no unconfirmed. create a new unconfirmed nfs4_client		 * using input clverifier, clname, and callback info		 * and generate a new cl_clientid and cl_confirm.		 */		if (!(new = create_client(clname)))			goto out;		copy_verf(new,&clverifier);		new->cl_addr = ip_addr;		copy_cred(&new->cl_cred,&rqstp->rq_cred);		gen_clid(new);		gen_confirm(new);		gen_callback(new, setclid);		add_to_unconfirmed(new, strhashval);	} else if (!cmp_verf(&conf->cl_confirm, &unconf->cl_confirm)) {		/*			 * CASE3:		 * confirmed found (name, principal match)		 * confirmed verifier does not match input clverifier		 *		 * unconfirmed found (name match)		 * confirmed->cl_confirm != unconfirmed->cl_confirm		 *		 * remove unconfirmed.		 *		 * create an unconfirmed nfs4_client 		 * with same cl_name as existing confirmed nfs4_client, 		 * but with new callback info, new cl_clientid,		 * new cl_verifier and a new cl_confirm		 */		expire_client(unconf);		if (!(new = create_client(clname)))			goto out;		copy_verf(new,&clverifier);		new->cl_addr = ip_addr;		copy_cred(&new->cl_cred,&rqstp->rq_cred);		gen_clid(new);		gen_confirm(new);		gen_callback(new, setclid);		add_to_unconfirmed(new, strhashval);	} else {		/* No cases hit !!! */		status = nfserr_inval;		goto out;	}	setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot;	setclid->se_clientid.cl_id = new->cl_clientid.cl_id;	memcpy(setclid->se_confirm.data, new->cl_confirm.data, sizeof(setclid->se_confirm.data));	status = nfs_ok;out:	nfs4_unlock_state();	return status;}/* * RFC 3010 has a complex implmentation description of processing a  * SETCLIENTID_CONFIRM request consisting of 4 bullets describing * processing on a DRC miss, labeled as CASE1 - CASE4 below. * * NOTE: callback information will be processed here in a future patch */intnfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confirm *setclientid_confirm){	u32 ip_addr = rqstp->rq_addr.sin_addr.s_addr;	unsigned int idhashval;	struct nfs4_client *clp, *conf = NULL, *unconf = NULL;	nfs4_verifier confirm = setclientid_confirm->sc_confirm; 	clientid_t * clid = &setclientid_confirm->sc_clientid;	int status;	status = nfserr_stale_clientid;	if (STALE_CLIENTID(clid))		goto out;	/* 	 * XXX The Duplicate Request Cache (DRC) has been checked (??)	 * We get here on a DRC miss.	 */	idhashval = clientid_hashval(clid->cl_id);	nfs4_lock_state();	list_for_each_entry(clp, &conf_id_hashtbl[idhashval], cl_idhash) {		if (!cmp_clid(&clp->cl_clientid, clid))			continue;		status = nfserr_inval;		/* 		 * Found a record for this clientid. If the IP addresses		 * don't match, return ERR_INVAL just as if the record had		 * not been found.		 */		if (clp->cl_addr != ip_addr) { 			printk("NFSD: setclientid: string in use by client"			"(clientid %08x/%08x)\n",			clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);			goto out;		}		conf = clp;		break;	}	list_for_each_entry(clp, &unconf_id_hashtbl[idhashval], cl_idhash) {		if (!cmp_clid(&clp->cl_clientid, clid))			continue;		status = nfserr_inval;		if (clp->cl_addr != ip_addr) { 			printk("NFSD: setclientid: string in use by client"			"(clientid %08x/%08x)\n",			clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);			goto out;		}		unconf = clp;		break;	}	/* CASE 1: 	* unconf record that matches input clientid and input confirm.	* conf record that matches input clientid.	* conf  and unconf records match names, verifiers 	*/	if ((conf && unconf) && 	    (cmp_verf(&unconf->cl_confirm, &confirm)) &&	    (cmp_verf(&conf->cl_verifier, &unconf->cl_verifier)) &&	    (cmp_name(&conf->cl_name,&unconf->cl_name))  &&	    (!cmp_verf(&conf->cl_confirm, &unconf->cl_confirm))) {		if (!cmp_creds(&conf->cl_cred, &unconf->cl_cred)) 			status = nfserr_clid_inuse;		else {			expire_client(conf);			move_to_confirmed(unconf, idhashval);			status = nfs_ok;		}		goto out;	} 	/* CASE 2:	 * conf record that matches input clientid.	 * if unconf record that matches input clientid, then unconf->cl_name	 * or unconf->cl_verifier don't match the conf record.	 */	if ((conf && !unconf) || 	    ((conf && unconf) && 	     (!cmp_verf(&conf->cl_verifier, &unconf->cl_verifier) ||	      !cmp_name(&conf->cl_name, &unconf->cl_name)))) {		if (!cmp_creds(&conf->cl_cred,&rqstp->rq_cred)) {			status = nfserr_clid_inuse;		} else {			status = nfs_ok;		}		goto out;	}	/* CASE 3:	 * conf record not found.	 * unconf record found. 	 * unconf->cl_confirm matches input confirm	 */ 	if (!conf && unconf && cmp_verf(&unconf->cl_confirm, &confirm)) {		if (!cmp_creds(&unconf->cl_cred, &rqstp->rq_cred)) {			status = nfserr_clid_inuse;		} else {			status = nfs_ok;			move_to_confirmed(unconf, idhashval);		}		goto out;	}	/* CASE 4:	 * conf record not found, or if conf, then conf->cl_confirm does not	 * match input confirm.	 * unconf record not found, or if unconf, then unconf->cl_confirm 	 * does not match input confirm.	 */	if ((!conf || (conf && !cmp_verf(&conf->cl_confirm, &confirm))) &&	    (!unconf || (unconf && !cmp_verf(&unconf->cl_confirm, &confirm)))) {		status = nfserr_stale_clientid;		goto out;	}	/* check that we have hit one of the cases...*/	status = nfserr_inval;	goto out;out:	/* XXX if status == nfs_ok, probe callback path */	nfs4_unlock_state();	return status;}/*  * 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];/* OPEN Share state helper functions */static inline struct nfs4_file *alloc_init_file(unsigned int hashval, struct inode *ino) {	struct nfs4_file *fp;	if ((fp = kmalloc(sizeof(struct nfs4_file),GFP_KERNEL))) {		INIT_LIST_HEAD(&fp->fi_hash);		INIT_LIST_HEAD(&fp->fi_perfile);		list_add(&fp->fi_hash, &file_hashtbl[hashval]);		fp->fi_inode = igrab(ino);		fp->fi_id = current_fileid++;		alloc_file++;		return fp;	}	return NULL;}static voidrelease_all_files(void){	int i;	struct nfs4_file *fp;	for (i=0;i<FILE_HASH_SIZE;i++) {		while (!list_empty(&file_hashtbl[i])) {			fp = list_entry(file_hashtbl[i].next, struct nfs4_file, fi_hash);			/* this should never be more than once... */			if (!list_empty(&fp->fi_perfile)) {				printk("ERROR: release_all_files: file %p is open, creating dangling state !!!\n",fp);			}			release_file(fp);		}	}}static inline struct nfs4_stateowner *alloc_stateowner(struct xdr_netobj *owner){	struct nfs4_stateowner *sop;	if ((sop = kmalloc(sizeof(struct nfs4_stateowner),GFP_KERNEL))) {		if ((sop->so_owner.data = kmalloc(owner->len, GFP_KERNEL))) {			memcpy(sop->so_owner.data, owner->data, owner->len);			sop->so_owner.len = owner->len;			return sop;		} 		kfree(sop);	}	return NULL;}/* should use a slab cache */static voidfree_stateowner(struct nfs4_stateowner *sop) {	if (sop) {		kfree(sop->so_owner.data);		kfree(sop);		sop = NULL;		free_sowner++;	}}static struct nfs4_stateowner *alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfsd4_open *open) {	struct nfs4_stateowner *sop;	struct nfs4_replay *rp;	unsigned int idhashval;	if (!(sop = alloc_stateowner(&open->op_owner)))		return NULL;	idhashval = ownerid_hashval(current_ownerid);	INIT_LIST_HEAD(&sop->so_idhash);	INIT_LIST_HEAD(&sop->so_strhash);	INIT_LIST_HEAD(&sop->so_perclient);	INIT_LIST_HEAD(&sop->so_perfilestate);	INIT_LIST_HEAD(&sop->so_perlockowner);  /* not used */	INIT_LIST_HEAD(&sop->so_close_lru);	sop->so_time = 0;	list_add(&sop->so_idhash, &ownerid_hashtbl[idhashval]);	list_add(&sop->so_strhash, &ownerstr_hashtbl[strhashval]);	list_add(&sop->so_perclient, &clp->cl_perclient);	add_perclient++;	sop->so_is_open_owner = 1;	sop->so_id = current_ownerid++;	sop->so_client = clp;	sop->so_seqid = open->op_seqid;	sop->so_confirmed = 0;	rp = &sop->so_replay;	rp->rp_status = NFSERR_SERVERFAULT;	rp->rp_buflen = 0;	rp->rp_buf = rp->rp_ibuf;	alloc_sowner++;	return sop;}static voidrelease_stateid_lockowner(struct nfs4_stateid *open_stp){	struct nfs4_stateowner *lock_sop;	while (!list_empty(&open_stp->st_perlockowner)) {		lock_sop = list_entry(open_stp->st_perlockowner.next,				struct nfs4_stateowner, so_perlockowner);		/* list_del(&open_stp->st_perlockowner);  */		BUG_ON(lock_sop->so_is_open_owner);		release_stateowner(lock_sop);	}}static voidunhash_stateowner(struct nfs4_stateowner *sop){	struct nfs4_stateid *stp;	list_del(&sop->so_idhash);	list_del(&sop->so_strhash);	list_del(&sop->so_perclient);	list_del(&sop->so_perlockowner);	del_perclient++;	while (!list_empty(&sop->so_perfilestate)) {		stp = list_entry(sop->so_perfilestate.next, 			struct nfs4_stateid, st_perfilestate);		if (sop->so_is_open_owner)			release_stateid(stp, OPEN_STATE);		else			release_stateid(stp, LOCK_STATE);	}}static voidrelease_stateowner(struct nfs4_stateowner *sop){	unhash_stateowner(sop);	list_del(&sop->so_close_lru);	free_stateowner(sop);}static inline voidinit_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfs4_stateowner *sop, struct nfsd4_open *open) {	unsigned int hashval = stateid_hashval(sop->so_id, fp->fi_id);	INIT_LIST_HEAD(&stp->st_hash);	INIT_LIST_HEAD(&stp->st_perfilestate);	INIT_LIST_HEAD(&stp->st_perlockowner);	INIT_LIST_HEAD(&stp->st_perfile);	list_add(&stp->st_hash, &stateid_hashtbl[hashval]);	list_add(&stp->st_perfilestate, &sop->so_perfilestate);	list_add_perfile++;	list_add(&stp->st_perfile, &fp->fi_perfile);	stp->st_stateowner = sop;	stp->st_file = fp;	stp->st_stateid.si_boot = boot_time;	stp->st_stateid.si_stateownerid = sop->so_id;	stp->st_stateid.si_fileid = fp->fi_id;	stp->st_stateid.si_generation = 0;	stp->st_access_bmap = 0;	stp->st_deny_bmap = 0;	__set_bit(open->op_share_access, &stp->st_access_bmap);	__set_bit(open->op_share_deny, &stp->st_deny_bmap);}static voidrelease_stateid(struct nfs4_stateid *stp, int flags) {	list_del(&stp->st_hash);	list_del_perfile++;	list_del(&stp->st_perfile);	list_del(&stp->st_perfilestate);	if ((stp->st_vfs_set) && (flags & OPEN_STATE)) {		release_stateid_lockowner(stp);

⌨️ 快捷键说明

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