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

nfs4state.c

Linux Kernel 2.6.9 for OMAP1710
C
第 1 页 / 共 5 页
字号:
		nfsd_close(stp->st_vfs_file);		vfsclose++;	} else if ((stp->st_vfs_set) && (flags & LOCK_STATE)) {		struct file *filp = stp->st_vfs_file;		locks_remove_posix(filp, (fl_owner_t) stp->st_stateowner);	}	kfree(stp);	stp = NULL;}static voidrelease_file(struct nfs4_file *fp){	free_file++;	list_del(&fp->fi_hash);	iput(fp->fi_inode);	kfree(fp);}	voidmove_to_close_lru(struct nfs4_stateowner *sop){	dprintk("NFSD: move_to_close_lru nfs4_stateowner %p\n", sop);	unhash_stateowner(sop);	list_add_tail(&sop->so_close_lru, &close_lru);	sop->so_time = get_seconds();}voidrelease_state_owner(struct nfs4_stateid *stp, struct nfs4_stateowner **sopp,		int flag){	struct nfs4_stateowner *sop = stp->st_stateowner;	struct nfs4_file *fp = stp->st_file;	dprintk("NFSD: release_state_owner\n");	release_stateid(stp, flag);	/* place unused nfs4_stateowners on so_close_lru list to be	 * released by the laundromat service after the lease period	 * to enable us to handle CLOSE replay	 */	if (sop->so_confirmed && list_empty(&sop->so_perfilestate))		move_to_close_lru(sop);	/* unused nfs4_file's are releseed. XXX slab cache? */	if (list_empty(&fp->fi_perfile)) {		release_file(fp);	}}static intcmp_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner, clientid_t *clid) {	return ((sop->so_owner.len == owner->len) && 	 !memcmp(sop->so_owner.data, owner->data, owner->len) && 	  (sop->so_client->cl_clientid.cl_id == clid->cl_id));}/* search ownerstr_hashtbl[] for owner */static intfind_openstateowner_str(unsigned int hashval, struct nfsd4_open *open, struct nfs4_stateowner **op) {	struct nfs4_stateowner *local = NULL;	list_for_each_entry(local, &ownerstr_hashtbl[hashval], so_strhash) {		if (!cmp_owner_str(local, &open->op_owner, &open->op_clientid))			continue;		*op = local;		return(1);	}	return 0;}/* see if clientid is in confirmed hash table */static intverify_clientid(struct nfs4_client **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 (!cmp_clid(&clp->cl_clientid, clid))			continue;		*client = clp;		return 1;	}	*client = NULL;	return 0;}/* search file_hashtbl[] for file */static intfind_file(unsigned int hashval, struct inode *ino, struct nfs4_file **fp) {	struct nfs4_file *local = NULL;	list_for_each_entry(local, &file_hashtbl[hashval], fi_hash) {		if (local->fi_inode == ino) {			*fp = local;			return(1);		}	}	return 0;}#define TEST_ACCESS(x) ((x > 0 || x < 4)?1:0)#define TEST_DENY(x) ((x >= 0 || x < 5)?1:0)voidset_access(unsigned int *access, unsigned long bmap) {	int i;	*access = 0;	for (i = 1; i < 4; i++) {		if (test_bit(i, &bmap))			*access |= i;	}}voidset_deny(unsigned int *deny, unsigned long bmap) {	int i;	*deny = 0;	for (i = 0; i < 4; i++) {		if (test_bit(i, &bmap))			*deny |= i ;	}}static inttest_share(struct nfs4_stateid *stp, struct nfsd4_open *open) {	unsigned int access, deny;	set_access(&access, stp->st_access_bmap);	set_deny(&deny, stp->st_deny_bmap);	if ((access & open->op_share_deny) || (deny & open->op_share_access))		return 0;	return 1;}/* * Called to check deny when READ with all zero stateid or * WRITE with all zero or all one stateid */intnfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type){	struct inode *ino = current_fh->fh_dentry->d_inode;	unsigned int fi_hashval;	struct nfs4_file *fp;	struct nfs4_stateid *stp;	dprintk("NFSD: nfs4_share_conflict\n");	fi_hashval = file_hashval(ino);	if (find_file(fi_hashval, ino, &fp)) {	/* Search for conflicting share reservations */		list_for_each_entry(stp, &fp->fi_perfile, st_perfile) {			if (test_bit(deny_type, &stp->st_deny_bmap) ||			    test_bit(NFS4_SHARE_DENY_BOTH, &stp->st_deny_bmap))				return nfserr_share_denied;		}	}	return nfs_ok;}static inline intnfs4_file_upgrade(struct file *filp, unsigned int share_access){int status;	if (share_access & NFS4_SHARE_ACCESS_WRITE) {		status = get_write_access(filp->f_dentry->d_inode);		if (status)			return nfserrno(status);		filp->f_mode = (filp->f_mode | FMODE_WRITE) & ~FMODE_READ;	}	return nfs_ok;}static inline voidnfs4_file_downgrade(struct file *filp, unsigned int share_access){	if (share_access & NFS4_SHARE_ACCESS_WRITE) {		put_write_access(filp->f_dentry->d_inode);		filp->f_mode = (filp->f_mode | FMODE_READ) & ~FMODE_WRITE;	}}/* * nfsd4_process_open1() * 	lookup stateowner. * 		found: * 			check confirmed  * 				confirmed: * 					check seqid * 				not confirmed: * 					delete owner * 					create new owner * 		notfound: * 			verify clientid * 			create new owner * * called with nfs4_lock_state() held. */intnfsd4_process_open1(struct nfsd4_open *open){	int status;	clientid_t *clientid = &open->op_clientid;	struct nfs4_client *clp = NULL;	unsigned int strhashval;	struct nfs4_stateowner *sop = NULL;	status = nfserr_inval;	if (!check_name(open->op_owner))		goto out;	status = nfserr_stale_clientid;	if (STALE_CLIENTID(&open->op_clientid))		return status;	strhashval = ownerstr_hashval(clientid->cl_id, open->op_owner);	if (find_openstateowner_str(strhashval, open, &sop)) {		open->op_stateowner = sop;		/* check for replay */		if (open->op_seqid == sop->so_seqid){			if (!sop->so_replay.rp_buflen) {			/*			* The original OPEN failed in so spectacularly that we			* don't even have replay data saved!  Therefore, we			* have no choice but to continue processing			* this OPEN; presumably, we'll fail again for the same			* reason.			*/				dprintk("nfsd4_process_open1: replay with no replay cache\n");				status = NFS_OK;				goto renew;			}			/* replay: indicate to calling function */			status = NFSERR_REPLAY_ME;			return status;		}		if (sop->so_confirmed) {			if (open->op_seqid == sop->so_seqid + 1) { 				status = nfs_ok;				goto renew;			} 			status = nfserr_bad_seqid;			goto out;		}		/* If we get here, we received and OPEN for an unconfirmed		 * nfs4_stateowner. 		 * Since the sequid's are different, purge the 		 * existing nfs4_stateowner, and instantiate a new one.		 */		clp = sop->so_client;		release_stateowner(sop);		goto instantiate_new_owner;	} 	/* nfs4_stateowner not found. 	* verify clientid and instantiate new nfs4_stateowner	* if verify fails this is presumably the result of the 	* client's lease expiring.	*	* XXX compare clp->cl_addr with rqstp addr? 	*/	status = nfserr_expired;	if (!verify_clientid(&clp, clientid))		goto out;instantiate_new_owner:	status = nfserr_resource;	if (!(sop = alloc_init_open_stateowner(strhashval, clp, open))) 		goto out;	open->op_stateowner = sop;	status = nfs_ok;renew:	renew_client(sop->so_client);out:	if (status && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)		status = nfserr_reclaim_bad;	return status;}/* * called with nfs4_lock_state() held. */intnfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open){	struct iattr iattr;	struct nfs4_stateowner *sop = open->op_stateowner;	struct nfs4_file *fp = NULL;	struct inode *ino;	unsigned int fi_hashval;	struct nfs4_stateid *stq, *stp = NULL;	int status;	status = nfserr_resource;	if (!sop)		return status;	ino = current_fh->fh_dentry->d_inode;	status = nfserr_inval;	if (!TEST_ACCESS(open->op_share_access) || !TEST_DENY(open->op_share_deny))		goto out;	fi_hashval = file_hashval(ino);	if (find_file(fi_hashval, ino, &fp)) {		/* Search for conflicting share reservations */		status = nfserr_share_denied;		list_for_each_entry(stq, &fp->fi_perfile, st_perfile) {			if (stq->st_stateowner == sop) {				stp = stq;				continue;			}			/* ignore lock owners */			if (stq->st_stateowner->so_is_open_owner == 0)				continue;			if (!test_share(stq,open))					goto out;		}	} else {	/* No nfs4_file found; allocate and init a new one */		status = nfserr_resource;		if ((fp = alloc_init_file(fi_hashval, ino)) == NULL)			goto out;	}	if (!stp) {		int flags = 0;		status = nfserr_resource;		if ((stp = kmalloc(sizeof(struct nfs4_stateid),						GFP_KERNEL)) == NULL)			goto out;		if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)			flags = MAY_WRITE;		else			flags = MAY_READ;		if ((status = nfsd_open(rqstp, current_fh,  S_IFREG,			                      flags,			                      &stp->st_vfs_file)) != 0)			goto out_free;		vfsopen++;		init_stateid(stp, fp, sop, open);		stp->st_vfs_set = 1;	} else {		/* This is an upgrade of an existing OPEN. 		 * OR the incoming share with the existing 		 * nfs4_stateid share */		unsigned int share_access;		set_access(&share_access, stp->st_access_bmap);		share_access = ~share_access;		share_access &= open->op_share_access;		/* update the struct file */		if ((status = nfs4_file_upgrade(stp->st_vfs_file, share_access)))			goto out;		/* remember the open */		set_bit(open->op_share_access, &stp->st_access_bmap);		set_bit(open->op_share_deny, &stp->st_deny_bmap);		/* bump the stateid */		update_stateid(&stp->st_stateid);	}	dprintk("nfs4_process_open2: stateid=(%08x/%08x/%08x/%08x)\n\n",	            stp->st_stateid.si_boot, stp->st_stateid.si_stateownerid,	            stp->st_stateid.si_fileid, stp->st_stateid.si_generation);	if (open->op_truncate) {		iattr.ia_valid = ATTR_SIZE;		iattr.ia_size = 0;		status = nfsd_setattr(rqstp, current_fh, &iattr, 0, (time_t)0);		if (status)			goto out;	}	memcpy(&open->op_stateid, &stp->st_stateid, sizeof(stateid_t));	open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE;	status = nfs_ok;out:	if (fp && list_empty(&fp->fi_perfile))		release_file(fp);	if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) {		if (status)			status = nfserr_reclaim_bad;		else {		/* successful reclaim. so_seqid is decremented because		* it will be bumped in encode_open		*/			open->op_stateowner->so_confirmed = 1;			open->op_stateowner->so_seqid--;		}	}	/*	* To finish the open response, we just need to set the rflags.	*/	open->op_rflags = 0;	if (!open->op_stateowner->so_confirmed)		open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM;	return status;out_free:	kfree(stp);	goto out;}static struct work_struct laundromat_work;static void laundromat_main(void *);static DECLARE_WORK(laundromat_work, laundromat_main, NULL);int nfsd4_renew(clientid_t *clid){	struct nfs4_client *clp;	unsigned int idhashval;	int status;	nfs4_lock_state();	dprintk("process_renew(%08x/%08x): starting\n", 			clid->cl_boot, clid->cl_id);	status = nfserr_stale_clientid;	if (STALE_CLIENTID(clid))		goto out;	status = nfs_ok;	idhashval = clientid_hashval(clid->cl_id);	list_for_each_entry(clp, &conf_id_hashtbl[idhashval], cl_idhash) {		if (!cmp_clid(&clp->cl_clientid, clid))			continue;		renew_client(clp);		goto out;	}	list_for_each_entry(clp, &unconf_id_hashtbl[idhashval], cl_idhash) {		if (!cmp_clid(&clp->cl_clientid, clid))			continue;		renew_client(clp);	goto out;	}	/*	* Couldn't find an nfs4_client for this clientid.  	* Presumably this is because the client took too long to 	* RENEW, so return NFS4ERR_EXPIRED.	*/	dprintk("nfsd4_renew: clientid not found!\n");	status = nfserr_expired;out:	nfs4_unlock_state();	return status;}time_tnfs4_laundromat(void){	struct nfs4_client *clp;	struct nfs4_stateowner *sop;	struct list_head *pos, *next;	time_t cutoff = get_seconds() - NFSD_LEASE_TIME;	time_t t, clientid_val = NFSD_LEASE_TIME;	time_t u, close_val = NFSD_LEASE_TIME;	nfs4_lock_state();	dprintk("NFSD: laundromat service - starting, examining clients\n");	list_for_each_safe(pos, next, &client_lru) {		clp = list_entry(pos, struct nfs4_client, cl_lru);		if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) {			t = clp->cl_time - cutoff;			if (clientid_val > t)				clientid_val = t;			break;		}		dprintk("NFSD: purging unused client (clientid %08x)\n",			clp->cl_clientid.cl_id);		expire_client(clp);	}	list_for_each_safe(pos, next, &close_lru) {		sop = list_entry(pos, struct nfs4_stateowner, so_close_lru);		if (time_after((unsigned long)sop->so_time, (unsigned long)cutoff)) {			u = sop->so_time - cutoff;

⌨️ 快捷键说明

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