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

📄 nfs4state.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	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) {		dprintk("NFSD: check_name: name too long(%d)!\n", name.len);		return 0;	}	return 1;}static 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();}static voidmove_to_confirmed(struct nfs4_client *clp){	unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id);	unsigned int strhashval;	dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp);	list_del_init(&clp->cl_strhash);	list_move(&clp->cl_idhash, &conf_id_hashtbl[idhashval]);	strhashval = clientstr_hashval(clp->cl_recdir);	list_add(&clp->cl_strhash, &conf_str_hashtbl[strhashval]);	renew_client(clp);}static struct nfs4_client *find_confirmed_client(clientid_t *clid){	struct nfs4_client *clp;	unsigned int idhashval = clientid_hashval(clid->cl_id);	list_for_each_entry(clp, &conf_id_hashtbl[idhashval], cl_idhash) {		if (same_clid(&clp->cl_clientid, clid))			return clp;	}	return NULL;}static struct nfs4_client *find_unconfirmed_client(clientid_t *clid){	struct nfs4_client *clp;	unsigned int idhashval = clientid_hashval(clid->cl_id);	list_for_each_entry(clp, &unconf_id_hashtbl[idhashval], cl_idhash) {		if (same_clid(&clp->cl_clientid, clid))			return clp;	}	return NULL;}static struct nfs4_client *find_confirmed_client_by_str(const char *dname, unsigned int hashval){	struct nfs4_client *clp;	list_for_each_entry(clp, &conf_str_hashtbl[hashval], cl_strhash) {		if (same_name(clp->cl_recdir, dname))			return clp;	}	return NULL;}static struct nfs4_client *find_unconfirmed_client_by_str(const char *dname, unsigned int hashval){	struct nfs4_client *clp;	list_for_each_entry(clp, &unconf_str_hashtbl[hashval], cl_strhash) {		if (same_name(clp->cl_recdir, dname))			return clp;	}	return NULL;}/* 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 */static 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;}static voidgen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se){	struct nfs4_callback *cb = &clp->cl_callback;	/* Currently, we only support tcp for the callback channel */	if ((se->se_callback_netid_len != 3) || memcmp((char *)se->se_callback_netid_val, "tcp", 3))		goto out_err;	if ( !(parse_ipv4(se->se_callback_addr_len, se->se_callback_addr_val,	                 &cb->cb_addr, &cb->cb_port)))		goto out_err;	cb->cb_prog = se->se_callback_prog;	cb->cb_ident = se->se_callback_ident;	return;out_err:	dprintk(KERN_INFO "NFSD: this client (clientid %08x/%08x) "		"will not receive delegations\n",		clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);	return;}/* * 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. * */__be32nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,		  struct nfsd4_setclientid *setclid){	struct sockaddr_in	*sin = svc_addr_in(rqstp);	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;	__be32 			status;	char                    dname[HEXDIR_LEN];		if (!check_name(clname))		return nfserr_inval;	status = nfs4_make_rec_clidname(dname, &clname);	if (status)		return status;	/* 	 * XXX The Duplicate Request Cache (DRC) has been checked (??)	 * We get here on a DRC miss.	 */	strhashval = clientstr_hashval(dname);	nfs4_lock_state();	conf = find_confirmed_client_by_str(dname, strhashval);	if (conf) {		/* 		 * CASE 0:		 * clname match, confirmed, different principal		 * or different ip_address		 */		status = nfserr_clid_inuse;		if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)				|| conf->cl_addr != sin->sin_addr.s_addr) {			dprintk("NFSD: setclientid: string in use by client"				"at %u.%u.%u.%u\n", NIPQUAD(conf->cl_addr));			goto out;		}	}	unconf = find_unconfirmed_client_by_str(dname, strhashval);	status = nfserr_resource;	if (!conf) {		/* 		 * CASE 4:		 * placed first, because it is the normal case.		 */		if (unconf)			expire_client(unconf);		new = create_client(clname, dname);		if (new == NULL)			goto out;		gen_clid(new);	} else if (same_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) {			/* Note this is removing unconfirmed {*x***},			 * which is stronger than RFC recommended {vxc**}.			 * This has the advantage that there is at most			 * one {*x***} in either list at any time.			 */			expire_client(unconf);		}		new = create_client(clname, dname);		if (new == NULL)			goto out;		copy_clid(new, conf);	} 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.		 */		new = create_client(clname, dname);		if (new == NULL)			goto out;		gen_clid(new);	} else if (!same_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);		new = create_client(clname, dname);		if (new == NULL)			goto out;		gen_clid(new);	} else {		/* No cases hit !!! */		status = nfserr_inval;		goto out;	}	copy_verf(new, &clverifier);	new->cl_addr = sin->sin_addr.s_addr;	copy_cred(&new->cl_cred, &rqstp->rq_cred);	gen_confirm(new);	gen_callback(new, setclid);	add_to_unconfirmed(new, strhashval);	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 */__be32nfsd4_setclientid_confirm(struct svc_rqst *rqstp,			 struct nfsd4_compound_state *cstate,			 struct nfsd4_setclientid_confirm *setclientid_confirm){	struct sockaddr_in *sin = svc_addr_in(rqstp);	struct nfs4_client *conf, *unconf;	nfs4_verifier confirm = setclientid_confirm->sc_confirm; 	clientid_t * clid = &setclientid_confirm->sc_clientid;	__be32 status;	if (STALE_CLIENTID(clid))		return nfserr_stale_clientid;	/* 	 * XXX The Duplicate Request Cache (DRC) has been checked (??)	 * We get here on a DRC miss.	 */	nfs4_lock_state();	conf = find_confirmed_client(clid);	unconf = find_unconfirmed_client(clid);	status = nfserr_clid_inuse;	if (conf && conf->cl_addr != sin->sin_addr.s_addr)		goto out;	if (unconf && unconf->cl_addr != sin->sin_addr.s_addr)		goto out;	if ((conf && unconf) && 	    (same_verf(&unconf->cl_confirm, &confirm)) &&	    (same_verf(&conf->cl_verifier, &unconf->cl_verifier)) &&	    (same_name(conf->cl_recdir,unconf->cl_recdir))  &&	    (!same_verf(&conf->cl_confirm, &unconf->cl_confirm))) {		/* 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 (!same_creds(&conf->cl_cred, &unconf->cl_cred))			status = nfserr_clid_inuse;		else {			/* XXX: We just turn off callbacks until we can handle			  * change request correctly. */			atomic_set(&conf->cl_callback.cb_set, 0);			gen_confirm(conf);			nfsd4_remove_clid_dir(unconf);			expire_client(unconf);			status = nfs_ok;		}	} else if ((conf && !unconf) ||	    ((conf && unconf) && 	     (!same_verf(&conf->cl_verifier, &unconf->cl_verifier) ||	      !same_name(conf->cl_recdir, unconf->cl_recdir)))) {		/* CASE 2:		 * conf record that matches input clientid.		 * if unconf record matches input clientid, then		 * unconf->cl_name or unconf->cl_verifier don't match the		 * conf record.		 */		if (!same_creds(&conf->cl_cred, &rqstp->rq_cred))			status = nfserr_clid_inuse;		else			status = nfs_ok;	} else if (!conf && unconf			&& same_verf(&unconf->cl_confirm, &confirm)) {		/* CASE 3:		 * conf record not found.		 * unconf record found.		 * unconf->cl_confirm matches input confirm		 */		if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred)) {			status = nfserr_clid_inuse;		} else {			unsigned int hash =				clientstr_hashval(unconf->cl_recdir);			conf = find_confirmed_client_by_str(unconf->cl_recdir,									hash);			if (conf) {				nfsd4_remove_clid_dir(conf);				expire_client(conf);			}			move_to_confirmed(unconf);			conf = unconf;			status = nfs_ok;		}	} else if ((!conf || (conf && !same_verf(&conf->cl_confirm, &confirm)))	    && (!unconf || (unconf && !same_verf(&unconf->cl_confirm,				    				&confirm)))) {		/* CASE 4:		 * conf record not found, or if conf, conf->cl_confirm does not		 * match input confirm.		 * unconf record not found, or if unconf, unconf->cl_confirm		 * does not match input confirm.		 */		status = nfserr_stale_clientid;	} else {		/* check that we have hit one of the cases...*/		status = nfserr_clid_inuse;	}out:	if (!status)		nfsd4_probe_callback(conf);	nfs4_unlock_state();	return status;}/* OPEN Share state helper functions */static inline struct nfs4_file *alloc_init_file(struct inode *ino){	struct nfs4_file *fp;	unsigned int hashval = file_hashval(ino);

⌨️ 快捷键说明

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