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

nfs4state.c

Linux Kernel 2.6.9 for OMAP1710
C
第 1 页 / 共 5 页
字号:
			if (close_val > u)				close_val = u;			break;		}		dprintk("NFSD: purging unused open stateowner (so_id %d)\n",			sop->so_id);		list_del(&sop->so_close_lru);		free_stateowner(sop);	}	if (clientid_val < NFSD_LAUNDROMAT_MINTIMEOUT)		clientid_val = NFSD_LAUNDROMAT_MINTIMEOUT;	nfs4_unlock_state();	return clientid_val;}voidlaundromat_main(void *not_used){	time_t t;	t = nfs4_laundromat();	dprintk("NFSD: laundromat_main - sleeping for %ld seconds\n", t);	schedule_delayed_work(&laundromat_work, t*HZ);}/* search ownerid_hashtbl[] and close_lru for stateid owner * (stateid->si_stateownerid) */struct nfs4_stateowner *find_openstateowner_id(u32 st_id, int flags) {	struct nfs4_stateowner *local = NULL;	dprintk("NFSD: find_openstateowner_id %d\n", st_id);	if (flags & CLOSE_STATE) {		list_for_each_entry(local, &close_lru, so_close_lru) {			if (local->so_id == st_id)				return local;		}	}	return NULL;}static inline intnfs4_check_fh(struct svc_fh *fhp, struct nfs4_stateid *stp){	return (stp->st_vfs_set == 0 ||		fhp->fh_dentry->d_inode != stp->st_vfs_file->f_dentry->d_inode);}static intSTALE_STATEID(stateid_t *stateid){	if (stateid->si_boot == boot_time)		return 0;	printk("NFSD: stale stateid (%08x/%08x/%08x/%08x)!\n",		stateid->si_boot, stateid->si_stateownerid, stateid->si_fileid,		stateid->si_generation);	return 1;}/** Checks for stateid operations*/intnfs4_preprocess_stateid_op(struct svc_fh *current_fh, stateid_t *stateid, int flags, struct nfs4_stateid **stpp){	struct nfs4_stateid *stp;	int status;	dprintk("NFSD: preprocess_stateid_op: stateid = (%08x/%08x/%08x/%08x)\n",		stateid->si_boot, stateid->si_stateownerid, 		stateid->si_fileid, stateid->si_generation); 	*stpp = NULL;	/* STALE STATEID */	status = nfserr_stale_stateid;	if (STALE_STATEID(stateid)) 		goto out;	/* BAD STATEID */	status = nfserr_bad_stateid;	if (!(stp = find_stateid(stateid, flags))) {		dprintk("NFSD: preprocess_stateid_op: no open stateid!\n");		goto out;	}	if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp)) {		dprintk("NFSD: preprocess_stateid_op: fh-stateid mismatch!\n");		stp->st_vfs_set = 0;		goto out;	}	if (!stp->st_stateowner->so_confirmed) {		dprintk("preprocess_stateid_op: lockowner not confirmed yet!\n");		goto out;	}	if (stateid->si_generation > stp->st_stateid.si_generation) {		dprintk("preprocess_stateid_op: future stateid?!\n");		goto out;	}	/* OLD STATEID */	status = nfserr_old_stateid;	if (stateid->si_generation < stp->st_stateid.si_generation) {		dprintk("preprocess_stateid_op: old stateid!\n");		goto out;	}	*stpp = stp;	status = nfs_ok;	renew_client(stp->st_stateowner->so_client);out:	return status;}/*  * Checks for sequence id mutating operations.  */intnfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *stateid, int flags, struct nfs4_stateowner **sopp, struct nfs4_stateid **stpp, clientid_t *lockclid){	int status;	struct nfs4_stateid *stp;	struct nfs4_stateowner *sop;	dprintk("NFSD: preprocess_seqid_op: seqid=%d " 			"stateid = (%08x/%08x/%08x/%08x)\n", seqid,		stateid->si_boot, stateid->si_stateownerid, stateid->si_fileid,		stateid->si_generation);			        	*stpp = NULL;	*sopp = NULL;	status = nfserr_bad_stateid;	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) {		printk("NFSD: preprocess_seqid_op: magic stateid!\n");		goto out;	}	status = nfserr_stale_stateid;	if (STALE_STATEID(stateid))		goto out;	/*	* We return BAD_STATEID if filehandle doesn't match stateid, 	* the confirmed flag is incorrecly set, or the generation 	* number is incorrect.  	* If there is no entry in the openfile table for this id, 	* we can't always return BAD_STATEID;	* this might be a retransmitted CLOSE which has arrived after 	* the openfile has been released.	*/	if (!(stp = find_stateid(stateid, flags)))		goto no_nfs4_stateid;	status = nfserr_bad_stateid;	/* for new lock stateowners:	 * check that the lock->v.new.open_stateid	 * refers to an open stateowner	 *	 * check that the lockclid (nfs4_lock->v.new.clientid) is the same	 * as the open_stateid->st_stateowner->so_client->clientid	 */	if (lockclid) {		struct nfs4_stateowner *sop = stp->st_stateowner;		struct nfs4_client *clp = sop->so_client;		if (!sop->so_is_open_owner)			goto out;		if (!cmp_clid(&clp->cl_clientid, lockclid))			goto out;	}	if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp)) {		printk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n");		stp->st_vfs_set = 0;		goto out;	}	*stpp = stp;	*sopp = sop = stp->st_stateowner;	/*	*  We now validate the seqid and stateid generation numbers.	*  For the moment, we ignore the possibility of 	*  generation number wraparound.	*/	if (seqid != sop->so_seqid + 1)		goto check_replay;	if (sop->so_confirmed) {		if (flags & CONFIRM) {			printk("NFSD: preprocess_seqid_op: expected unconfirmed stateowner!\n");			goto out;		}	}	else {		if (!(flags & CONFIRM)) {			printk("NFSD: preprocess_seqid_op: stateowner not confirmed yet!\n");			goto out;		}	}	if (stateid->si_generation > stp->st_stateid.si_generation) {		printk("NFSD: preprocess_seqid_op: future stateid?!\n");		goto out;	}	status = nfserr_old_stateid;	if (stateid->si_generation < stp->st_stateid.si_generation) {		printk("NFSD: preprocess_seqid_op: old stateid!\n");		goto out;	}	/* XXX renew the client lease here */	status = nfs_ok;out:	return status;no_nfs4_stateid:	/*	* We determine whether this is a bad stateid or a replay, 	* starting by trying to look up the stateowner.	* If stateowner is not found - stateid is bad.	*/	if (!(sop = find_openstateowner_id(stateid->si_stateownerid, flags))) {		printk("NFSD: preprocess_seqid_op: no stateowner or nfs4_stateid!\n");		status = nfserr_bad_stateid;		goto out;	}	*sopp = sop;check_replay:	if (seqid == sop->so_seqid) {		printk("NFSD: preprocess_seqid_op: retransmission?\n");		/* indicate replay to calling function */		status = NFSERR_REPLAY_ME;	} else  {		printk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d\n", sop->so_seqid +1, seqid);		*sopp = NULL;		status = nfserr_bad_seqid;	}	goto out;}/* * eventually, this will perform an upcall to the 'state daemon' as well as * set the cl_first_state field. */voidfirst_state(struct nfs4_client *clp){	if (!clp->cl_first_state)		clp->cl_first_state = get_seconds();}/* * nfs4_unlock_state(); called in encode */intnfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_confirm *oc){	int status;	struct nfs4_stateowner *sop;	struct nfs4_stateid *stp;	dprintk("NFSD: nfsd4_open_confirm on file %.*s\n",			(int)current_fh->fh_dentry->d_name.len,			current_fh->fh_dentry->d_name.name);	if ((status = fh_verify(rqstp, current_fh, S_IFREG, 0)))		goto out;	oc->oc_stateowner = NULL;	nfs4_lock_state();	if ((status = nfs4_preprocess_seqid_op(current_fh, oc->oc_seqid,					&oc->oc_req_stateid,					CHECK_FH | CONFIRM | OPEN_STATE,					&oc->oc_stateowner, &stp, NULL)))		goto out; 	sop = oc->oc_stateowner;	sop->so_confirmed = 1;	update_stateid(&stp->st_stateid);	memcpy(&oc->oc_resp_stateid, &stp->st_stateid, sizeof(stateid_t));	dprintk("NFSD: nfsd4_open_confirm: success, seqid=%d " 		"stateid=(%08x/%08x/%08x/%08x)\n", oc->oc_seqid,		         stp->st_stateid.si_boot,		         stp->st_stateid.si_stateownerid,		         stp->st_stateid.si_fileid,		         stp->st_stateid.si_generation);	status = nfs_ok;	first_state(sop->so_client);out:	return status;}/* * unset all bits in union bitmap (bmap) that * do not exist in share (from successful OPEN_DOWNGRADE) */static voidreset_union_bmap_access(unsigned long access, unsigned long *bmap){	int i;	for (i = 1; i < 4; i++) {		if ((i & access) != i)			__clear_bit(i, bmap);	}}static voidreset_union_bmap_deny(unsigned long deny, unsigned long *bmap){	int i;	for (i = 0; i < 4; i++) {		if ((i & deny) != i)			__clear_bit(i, bmap);	}}/* * nfs4_unlock_state(); called in encode */intnfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_downgrade *od){	int status;	struct nfs4_stateid *stp;	unsigned int share_access;	dprintk("NFSD: nfsd4_open_downgrade on file %.*s\n", 			(int)current_fh->fh_dentry->d_name.len,			current_fh->fh_dentry->d_name.name);	od->od_stateowner = NULL;	status = nfserr_inval;	if (!TEST_ACCESS(od->od_share_access) || !TEST_DENY(od->od_share_deny))		goto out;	nfs4_lock_state();	if ((status = nfs4_preprocess_seqid_op(current_fh, od->od_seqid, 					&od->od_stateid, 					CHECK_FH | OPEN_STATE, 					&od->od_stateowner, &stp, NULL)))		goto out; 	status = nfserr_inval;	if (!test_bit(od->od_share_access, &stp->st_access_bmap)) {		dprintk("NFSD:access not a subset current bitmap: 0x%lx, input access=%08x\n",			stp->st_access_bmap, od->od_share_access);		goto out;	}	if (!test_bit(od->od_share_deny, &stp->st_deny_bmap)) {		dprintk("NFSD:deny not a subset current bitmap: 0x%lx, input deny=%08x\n",			stp->st_deny_bmap, od->od_share_deny);		goto out;	}	set_access(&share_access, stp->st_access_bmap);	nfs4_file_downgrade(stp->st_vfs_file,	                    share_access & ~od->od_share_access);	reset_union_bmap_access(od->od_share_access, &stp->st_access_bmap);	reset_union_bmap_deny(od->od_share_deny, &stp->st_deny_bmap);	update_stateid(&stp->st_stateid);	memcpy(&od->od_stateid, &stp->st_stateid, sizeof(stateid_t));	status = nfs_ok;out:	return status;}/* * nfs4_unlock_state() called after encode */intnfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_close *close){	int status;	struct nfs4_stateid *stp;	dprintk("NFSD: nfsd4_close on file %.*s\n", 			(int)current_fh->fh_dentry->d_name.len,			current_fh->fh_dentry->d_name.name);	close->cl_stateowner = NULL;	nfs4_lock_state();	/* check close_lru for replay */	if ((status = nfs4_preprocess_seqid_op(current_fh, close->cl_seqid, 					&close->cl_stateid, 					CHECK_FH | OPEN_STATE | CLOSE_STATE,					&close->cl_stateowner, &stp, NULL)))		goto out; 	/*	*  Return success, but first update the stateid.	*/	status = nfs_ok;	update_stateid(&stp->st_stateid);	memcpy(&close->cl_stateid, &stp->st_stateid, sizeof(stateid_t));	/* release_state_owner() calls nfsd_close() if needed */	release_state_owner(stp, &close->cl_stateowner, OPEN_STATE);out:	return status;}/*  * Lock owner state (byte-range locks) */#define LOFF_OVERFLOW(start, len)      ((u64)(len) > ~(u64)(start))#define LOCK_HASH_BITS              8#define LOCK_HASH_SIZE             (1 << LOCK_HASH_BITS)#define LOCK_HASH_MASK             (LOCK_HASH_SIZE - 1)#define lockownerid_hashval(id) \        ((id) & LOCK_HASH_MASK)#define lock_ownerstr_hashval(x, clientid, ownername) \        ((file_hashval(x) + (clientid) + opaque_hashval((ownername.data), (ownername.len))) & LOCK_HASH_MASK)static struct list_head lock_ownerid_hashtbl[LOCK_HASH_SIZE];static struct list_head	lock_ownerstr_hashtbl[LOCK_HASH_SIZE];static struct list_head lockstateid_hashtbl[STATEID_HASH_SIZE];struct nfs4_stateid *find_stateid(stateid_t *stid, int flags){	struct nfs4_stateid *local = NULL;	u32 st_id = stid->si_stateownerid;	u32 f_id = stid->si_fileid;	unsigned int hashval;	dprintk("NFSD: find_stateid flags 0x%x\n",flags);	if ((flags & LOCK_STATE) || (flags & RDWR_STATE)) {		hashval = stateid_hashval(st_id, f_id);		list_for_each_entry(local, &lockstateid_hashtbl[hashval], st_hash) {			if ((local->st_stateid.si_stateownerid == st_id) &&			    (local->st_stateid.si_fileid == f_id))				return local;		}	} 	if ((flags & OPEN_STATE) || (flags & RDWR_STATE)) {		hashval = stateid_hashval(st_id, f_id);		list_for_each_entry(local, &stateid_hashtbl[hashval], st_hash) {			if ((local->st_stateid.si_stateownerid == st_id) &&			    (local->st_stateid.si_fileid == f_id))				return local;		}	} else		printk("NFSD: find_stateid: ERROR: no state flag\n");	return NULL;}/* * TODO: Linux file offsets are _signed_ 64-bit quantities, which means that * we can't properly handle lock requests that go beyond the (2^63 - 1)-th * byte, because of sign extension problems.  Since NFSv4 calls for 64-bit * locking, this prevents us from being completely protocol-compliant.  The * real solution to this problem is to start using unsigned file offsets in * the VFS, but this is a very deep change! */static inline voidnfs4_transform_lock_offset(struct file_lock *lock){	if (lock->fl_start < 0)		lock->fl_start = OFFSET_MAX;	if (lock->fl_end < 0)		lock->fl_end = OFFSET_MAX;}intnfs4_verify_lock_stateowner(struct nfs4_stateowner *sop, unsigned int hashval){	struct nfs4_stateowner *local = NULL;	int status = 0;			        	if (hashval >= LOCK_HASH_SIZE)		goto out;	list_for_each_entry(local, &lock_ownerid_hashtbl[hashval], so_idhash) {		if (local == sop) {			status = 1;

⌨️ 快捷键说明

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