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

nfs4state.c

Linux Kernel 2.6.9 for OMAP1710
C
第 1 页 / 共 5 页
字号:
			goto out;		}	}out:	return status;}static inline voidnfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny){	struct nfs4_stateowner *sop = (struct nfs4_stateowner *) fl->fl_owner;	unsigned int hval = lockownerid_hashval(sop->so_id);	deny->ld_sop = NULL;	if (nfs4_verify_lock_stateowner(sop, hval))		deny->ld_sop = sop;	deny->ld_start = fl->fl_start;	deny->ld_length = ~(u64)0;	if (fl->fl_end != ~(u64)0)		deny->ld_length = fl->fl_end - fl->fl_start + 1;        	deny->ld_type = NFS4_READ_LT;	if (fl->fl_type != F_RDLCK)		deny->ld_type = NFS4_WRITE_LT;}static struct nfs4_stateowner *find_lockstateowner(struct xdr_netobj *owner, clientid_t *clid){	struct nfs4_stateowner *local = NULL;	int i;	for (i = 0; i < LOCK_HASH_SIZE; i++) {		list_for_each_entry(local, &lock_ownerid_hashtbl[i], so_idhash) {			if (!cmp_owner_str(local, owner, clid))				continue;			return local;		}	}	return NULL;}static intfind_lockstateowner_str(unsigned int hashval, struct xdr_netobj *owner, clientid_t *clid, struct nfs4_stateowner **op) {	struct nfs4_stateowner *local = NULL;	list_for_each_entry(local, &lock_ownerstr_hashtbl[hashval], so_strhash) {		if (!cmp_owner_str(local, owner, clid))			continue;		*op = local;		return(1);	}	*op = NULL;	return 0;}/* * Alloc a lock owner structure. * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has  * occured.  * * strhashval = lock_ownerstr_hashval  * so_seqid = lock->lk_new_lock_seqid - 1: it gets bumped in encode  */static struct nfs4_stateowner *alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfs4_stateid *open_stp, struct nfsd4_lock *lock) {	struct nfs4_stateowner *sop;	struct nfs4_replay *rp;	unsigned int idhashval;	if (!(sop = alloc_stateowner(&lock->lk_new_owner)))		return NULL;	idhashval = lockownerid_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);	INIT_LIST_HEAD(&sop->so_close_lru); /* not used */	sop->so_time = 0;	list_add(&sop->so_idhash, &lock_ownerid_hashtbl[idhashval]);	list_add(&sop->so_strhash, &lock_ownerstr_hashtbl[strhashval]);	list_add(&sop->so_perclient, &clp->cl_perclient);	list_add(&sop->so_perlockowner, &open_stp->st_perlockowner);	add_perclient++;	sop->so_is_open_owner = 0;	sop->so_id = current_ownerid++;	sop->so_client = clp;	sop->so_seqid = lock->lk_new_lock_seqid - 1;	sop->so_confirmed = 1;	rp = &sop->so_replay;	rp->rp_status = NFSERR_SERVERFAULT;	rp->rp_buflen = 0;	rp->rp_buf = rp->rp_ibuf;	alloc_lsowner++;	return sop;}struct nfs4_stateid *alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struct nfs4_stateid *open_stp){	struct nfs4_stateid *stp;	unsigned int hashval = stateid_hashval(sop->so_id, fp->fi_id);	if ((stp = kmalloc(sizeof(struct nfs4_stateid), 					GFP_KERNEL)) == NULL)		goto out;	INIT_LIST_HEAD(&stp->st_hash);	INIT_LIST_HEAD(&stp->st_perfile);	INIT_LIST_HEAD(&stp->st_perfilestate);	INIT_LIST_HEAD(&stp->st_perlockowner); /* not used */	list_add(&stp->st_hash, &lockstateid_hashtbl[hashval]);	list_add(&stp->st_perfile, &fp->fi_perfile);	list_add_perfile++;	list_add(&stp->st_perfilestate, &sop->so_perfilestate);	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_vfs_file = open_stp->st_vfs_file; /* FIXME refcount?? */	stp->st_vfs_set = open_stp->st_vfs_set;	stp->st_access_bmap = open_stp->st_access_bmap;	stp->st_deny_bmap = open_stp->st_deny_bmap;out:	return stp;}intcheck_lock_length(u64 offset, u64 length){	return ((length == 0)  || ((length != ~(u64)0) &&	     LOFF_OVERFLOW(offset, length)));}/* *  LOCK operation  * * nfs4_unlock_state(); called in encode */intnfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock *lock){	struct nfs4_stateowner *lock_sop = NULL, *open_sop = NULL;	struct nfs4_stateid *lock_stp;	struct file *filp;	struct file_lock file_lock;	struct file_lock *conflock;	int status = 0;	unsigned int strhashval;	dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n",		(long long) lock->lk_offset,		(long long) lock->lk_length);	if (nfs4_in_grace() && !lock->lk_reclaim)		return nfserr_grace;	if (!nfs4_in_grace() && lock->lk_reclaim)		return nfserr_no_grace;	if (check_lock_length(lock->lk_offset, lock->lk_length))		 return nfserr_inval;	lock->lk_stateowner = NULL;	nfs4_lock_state();	if (lock->lk_is_new) {	/*	 * Client indicates that this is a new lockowner.	 * Use open owner and open stateid to create lock owner and lock 	 * stateid.	 */		struct nfs4_stateid *open_stp = NULL;		struct nfs4_file *fp;				status = nfserr_stale_clientid;		if (STALE_CLIENTID(&lock->lk_new_clientid)) {			printk("NFSD: nfsd4_lock: clientid is stale!\n");			goto out;		}		/* is the new lock seqid presented by the client zero? */		status = nfserr_bad_seqid;		if (lock->v.new.lock_seqid != 0)			goto out;		/* validate and update open stateid and open seqid */		status = nfs4_preprocess_seqid_op(current_fh, 				        lock->lk_new_open_seqid,		                        &lock->lk_new_open_stateid,		                        CHECK_FH | OPEN_STATE,		                        &open_sop, &open_stp,					&lock->v.new.clientid);		if (status) {			if (lock->lk_reclaim)				status = nfserr_reclaim_bad;			goto out;		}		/* create lockowner and lock stateid */		fp = open_stp->st_file;		strhashval = lock_ownerstr_hashval(fp->fi_inode, 				open_sop->so_client->cl_clientid.cl_id, 				lock->v.new.owner);		/* 		 * If we already have this lock owner, the client is in 		 * error (or our bookeeping is wrong!) 		 * for asking for a 'new lock'.		 */		status = nfserr_bad_stateid;		lock_sop = find_lockstateowner(&lock->v.new.owner,						&lock->v.new.clientid);		if (lock_sop)			goto out;		status = nfserr_resource;		if (!(lock->lk_stateowner = alloc_init_lock_stateowner(strhashval, open_sop->so_client, open_stp, lock)))			goto out;		if ((lock_stp = alloc_init_lock_stateid(lock->lk_stateowner, 						fp, open_stp)) == NULL) {			release_stateowner(lock->lk_stateowner);			goto out;		}		/* bump the open seqid used to create the lock */		open_sop->so_seqid++;	} else {		/* lock (lock owner + lock stateid) already exists */		status = nfs4_preprocess_seqid_op(current_fh,				       lock->lk_old_lock_seqid, 				       &lock->lk_old_lock_stateid, 				       CHECK_FH | LOCK_STATE, 				       &lock->lk_stateowner, &lock_stp, NULL);		if (status)			goto out;	}	/* lock->lk_stateowner and lock_stp have been created or found */	filp = lock_stp->st_vfs_file;	if ((status = fh_verify(rqstp, current_fh, S_IFREG, MAY_LOCK))) {		printk("NFSD: nfsd4_lock: permission denied!\n");		goto out;	}	locks_init_lock(&file_lock);	switch (lock->lk_type) {		case NFS4_READ_LT:		case NFS4_READW_LT:			file_lock.fl_type = F_RDLCK;		break;		case NFS4_WRITE_LT:		case NFS4_WRITEW_LT:			file_lock.fl_type = F_WRLCK;		break;		default:			status = nfserr_inval;		goto out;	}	file_lock.fl_owner = (fl_owner_t) lock->lk_stateowner;	file_lock.fl_pid = current->tgid;	file_lock.fl_file = filp;	file_lock.fl_flags = FL_POSIX;	file_lock.fl_start = lock->lk_offset;	if ((lock->lk_length == ~(u64)0) || 			LOFF_OVERFLOW(lock->lk_offset, lock->lk_length))		file_lock.fl_end = ~(u64)0;	else		file_lock.fl_end = lock->lk_offset + lock->lk_length - 1;	nfs4_transform_lock_offset(&file_lock);	/*	* Try to lock the file in the VFS.	* Note: locks.c uses the BKL to protect the inode's lock list.	*/	status = posix_lock_file(filp, &file_lock);	if (file_lock.fl_ops && file_lock.fl_ops->fl_release_private)		file_lock.fl_ops->fl_release_private(&file_lock);	dprintk("NFSD: nfsd4_lock: posix_lock_file status %d\n",status);	switch (-status) {	case 0: /* success! */		update_stateid(&lock_stp->st_stateid);		memcpy(&lock->lk_resp_stateid, &lock_stp->st_stateid, 				sizeof(stateid_t));		goto out;	case (EAGAIN):		goto conflicting_lock;	case (EDEADLK):		status = nfserr_deadlock;	default:        		dprintk("NFSD: nfsd4_lock: posix_lock_file() failed! status %d\n",status);		goto out_destroy_new_stateid;	}conflicting_lock:	dprintk("NFSD: nfsd4_lock: conflicting lock found!\n");	status = nfserr_denied;	/* XXX There is a race here. Future patch needed to provide 	 * an atomic posix_lock_and_test_file	 */	if (!(conflock = posix_test_lock(filp, &file_lock))) {		status = nfserr_serverfault;		goto out;	}	nfs4_set_lock_denied(conflock, &lock->lk_denied);out_destroy_new_stateid:	if (lock->lk_is_new) {		dprintk("NFSD: nfsd4_lock: destroy new stateid!\n");	/*	* An error encountered after instantiation of the new	* stateid has forced us to destroy it.	*/		if (!seqid_mutating_err(status))			open_sop->so_seqid--;		release_state_owner(lock_stp, &lock->lk_stateowner, LOCK_STATE);	}out:	return status;}/* * LOCKT operation */intnfsd4_lockt(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lockt *lockt){	struct inode *inode;	struct file file;	struct file_lock file_lock;	struct file_lock *conflicting_lock;	unsigned int strhashval;	int status;	if (nfs4_in_grace())		return nfserr_grace;	if (check_lock_length(lockt->lt_offset, lockt->lt_length))		 return nfserr_inval;	lockt->lt_stateowner = NULL;	nfs4_lock_state();	status = nfserr_stale_clientid;	if (STALE_CLIENTID(&lockt->lt_clientid)) {		printk("NFSD: nfsd4_lockt: clientid is stale!\n");		goto out;	}	if ((status = fh_verify(rqstp, current_fh, S_IFREG, 0))) {		printk("NFSD: nfsd4_lockt: fh_verify() failed!\n");		if (status == nfserr_symlink)			status = nfserr_inval;		goto out;	}	inode = current_fh->fh_dentry->d_inode;	locks_init_lock(&file_lock);	switch (lockt->lt_type) {		case NFS4_READ_LT:		case NFS4_READW_LT:			file_lock.fl_type = F_RDLCK;		break;		case NFS4_WRITE_LT:		case NFS4_WRITEW_LT:			file_lock.fl_type = F_WRLCK;		break;		default:			printk("NFSD: nfs4_lockt: bad lock type!\n");			status = nfserr_inval;		goto out;	}	strhashval = lock_ownerstr_hashval(inode, 			lockt->lt_clientid.cl_id, lockt->lt_owner);	find_lockstateowner_str(strhashval, &lockt->lt_owner,					&lockt->lt_clientid, 					&lockt->lt_stateowner);	if (lockt->lt_stateowner)		file_lock.fl_owner = (fl_owner_t)lockt->lt_stateowner;	file_lock.fl_pid = current->tgid;	file_lock.fl_flags = FL_POSIX;	file_lock.fl_start = lockt->lt_offset;	if ((lockt->lt_length == ~(u64)0) || LOFF_OVERFLOW(lockt->lt_offset, lockt->lt_length))		file_lock.fl_end = ~(u64)0;	else		file_lock.fl_end = lockt->lt_offset + lockt->lt_length - 1;	nfs4_transform_lock_offset(&file_lock);	/* posix_test_lock uses the struct file _only_ to resolve the inode.	 * since LOCKT doesn't require an OPEN, and therefore a struct	 * file may not exist, pass posix_test_lock a struct file with	 * only the dentry:inode set.	 */	memset(&file, 0, sizeof (struct file));	file.f_dentry = current_fh->fh_dentry;	status = nfs_ok;	conflicting_lock = posix_test_lock(&file, &file_lock);	if (conflicting_lock) {		status = nfserr_denied;		nfs4_set_lock_denied(conflicting_lock, &lockt->lt_denied);	}out:	nfs4_unlock_state();	return status;}intnfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_locku *locku){	struct nfs4_stateid *stp;	struct file *filp = NULL;	struct file_lock file_lock;	int status;						        	dprintk("NFSD: nfsd4_locku: start=%Ld length=%Ld\n",		(long long) locku->lu_offset,		(long long) locku->lu_length);	if (check_lock_length(locku->lu_offset, locku->lu_length))		 return nfserr_inval;	locku->lu_stateowner = NULL;	nfs4_lock_state();									        	if ((status = nfs4_preprocess_seqid_op(current_fh, 					locku->lu_seqid, 					&locku->lu_stateid, 					CHECK_FH | LOCK_STATE, 					&locku->lu_stateowner, &stp, NULL)))		goto out;	filp = stp->st_vfs_file;	BUG_ON(!filp);	locks_init_lock(&file_lock);	file_lock.fl_type = F_UNLCK;	file_lock.fl_owner = (fl_owner_t) locku->lu_stateowner;	file_lock.fl_pid = current->tgid;	file_lock.fl_file = filp;	file_lock.fl_flags = FL_POSIX; 	file_lock.fl_start = locku->lu_offset;	if ((locku->lu_length == ~(u64)0) || LOFF_OVERFLOW(locku->lu_offset, locku->lu_length))		file_lock.fl_end = ~(u64)0;	else		file_lock.fl_end = locku->lu_offset + locku->lu_length - 1;	nfs4_transform_lock_offset(&file_lock);	/*	*  Try to unlock the file in the VFS.	*/	status = posix_lock_file(filp, &file_lock); 	if (file_lock.fl_ops && file_lock.fl_ops->fl_release_private)		file_lock.fl_ops->fl_release_private(&file_lock);	if (status) {		printk("NFSD: nfs4_locku: posix_lock_file failed!\n");		goto out_nfserr;	}	/*	* OK, unlock succeeded; the only thing left to do is update the stateid.	*/	update_stateid(&stp->st_stateid);	memcpy(&locku->lu_stateid, &stp->st_stateid, sizeof(stateid_t));out:	return status;out_nfserr:	status = nfserrno(status);	goto out;}/* * returns * 	1: locks held by lockowner * 	0: no locks held by lockowner */static intcheck_for

⌨️ 快捷键说明

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