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

📄 nfs4state.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		clp = sop->so_client;		release_stateowner(sop);		open->op_stateowner = NULL;		goto renew;	}	if (open->op_seqid == sop->so_seqid - 1) {		if (sop->so_replay.rp_buflen)			return nfserr_replay_me;		/* The original OPEN failed 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");		goto renew;	}	if (open->op_seqid != sop->so_seqid)		return nfserr_bad_seqid;renew:	if (open->op_stateowner == NULL) {		sop = alloc_init_open_stateowner(strhashval, clp, open);		if (sop == NULL)			return nfserr_resource;		open->op_stateowner = sop;	}	list_del_init(&sop->so_close_lru);	renew_client(sop->so_client);	return nfs_ok;}static inline __be32nfs4_check_delegmode(struct nfs4_delegation *dp, int flags){	if ((flags & WR_STATE) && (dp->dl_type == NFS4_OPEN_DELEGATE_READ))		return nfserr_openmode;	else		return nfs_ok;}static struct nfs4_delegation *find_delegation_file(struct nfs4_file *fp, stateid_t *stid){	struct nfs4_delegation *dp;	list_for_each_entry(dp, &fp->fi_delegations, dl_perfile) {		if (dp->dl_stateid.si_stateownerid == stid->si_stateownerid)			return dp;	}	return NULL;}static __be32nfs4_check_deleg(struct nfs4_file *fp, struct nfsd4_open *open,		struct nfs4_delegation **dp){	int flags;	__be32 status = nfserr_bad_stateid;	*dp = find_delegation_file(fp, &open->op_delegate_stateid);	if (*dp == NULL)		goto out;	flags = open->op_share_access == NFS4_SHARE_ACCESS_READ ?						RD_STATE : WR_STATE;	status = nfs4_check_delegmode(*dp, flags);	if (status)		*dp = NULL;out:	if (open->op_claim_type != NFS4_OPEN_CLAIM_DELEGATE_CUR)		return nfs_ok;	if (status)		return status;	open->op_stateowner->so_confirmed = 1;	return nfs_ok;}static __be32nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_stateid **stpp){	struct nfs4_stateid *local;	__be32 status = nfserr_share_denied;	struct nfs4_stateowner *sop = open->op_stateowner;	list_for_each_entry(local, &fp->fi_stateids, st_perfile) {		/* ignore lock owners */		if (local->st_stateowner->so_is_open_owner == 0)			continue;		/* remember if we have seen this open owner */		if (local->st_stateowner == sop)			*stpp = local;		/* check for conflicting share reservations */		if (!test_share(local, open))			goto out;	}	status = 0;out:	return status;}static inline struct nfs4_stateid *nfs4_alloc_stateid(void){	return kmem_cache_alloc(stateid_slab, GFP_KERNEL);}static __be32nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp,		struct nfs4_delegation *dp,		struct svc_fh *cur_fh, int flags){	struct nfs4_stateid *stp;	stp = nfs4_alloc_stateid();	if (stp == NULL)		return nfserr_resource;	if (dp) {		get_file(dp->dl_vfs_file);		stp->st_vfs_file = dp->dl_vfs_file;	} else {		__be32 status;		status = nfsd_open(rqstp, cur_fh, S_IFREG, flags,				&stp->st_vfs_file);		if (status) {			if (status == nfserr_dropit)				status = nfserr_jukebox;			kmem_cache_free(stateid_slab, stp);			return status;		}	}	*stpp = stp;	return 0;}static inline __be32nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh,		struct nfsd4_open *open){	struct iattr iattr = {		.ia_valid = ATTR_SIZE,		.ia_size = 0,	};	if (!open->op_truncate)		return 0;	if (!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE))		return nfserr_inval;	return nfsd_setattr(rqstp, fh, &iattr, 0, (time_t)0);}static __be32nfs4_upgrade_open(struct svc_rqst *rqstp, struct svc_fh *cur_fh, struct nfs4_stateid *stp, struct nfsd4_open *open){	struct file *filp = stp->st_vfs_file;	struct inode *inode = filp->f_path.dentry->d_inode;	unsigned int share_access, new_writer;	__be32 status;	set_access(&share_access, stp->st_access_bmap);	new_writer = (~share_access) & open->op_share_access			& NFS4_SHARE_ACCESS_WRITE;	if (new_writer) {		int err = get_write_access(inode);		if (err)			return nfserrno(err);	}	status = nfsd4_truncate(rqstp, cur_fh, open);	if (status) {		if (new_writer)			put_write_access(inode);		return status;	}	/* remember the open */	filp->f_mode |= open->op_share_access;	set_bit(open->op_share_access, &stp->st_access_bmap);	set_bit(open->op_share_deny, &stp->st_deny_bmap);	return nfs_ok;}static voidnfs4_set_claim_prev(struct nfsd4_open *open){	open->op_stateowner->so_confirmed = 1;	open->op_stateowner->so_client->cl_firststate = 1;}/* * Attempt to hand out a delegation. */static voidnfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_stateid *stp){	struct nfs4_delegation *dp;	struct nfs4_stateowner *sop = stp->st_stateowner;	struct nfs4_callback *cb = &sop->so_client->cl_callback;	struct file_lock fl, *flp = &fl;	int status, flag = 0;	flag = NFS4_OPEN_DELEGATE_NONE;	open->op_recall = 0;	switch (open->op_claim_type) {		case NFS4_OPEN_CLAIM_PREVIOUS:			if (!atomic_read(&cb->cb_set))				open->op_recall = 1;			flag = open->op_delegate_type;			if (flag == NFS4_OPEN_DELEGATE_NONE)				goto out;			break;		case NFS4_OPEN_CLAIM_NULL:			/* Let's not give out any delegations till everyone's			 * had the chance to reclaim theirs.... */			if (nfs4_in_grace())				goto out;			if (!atomic_read(&cb->cb_set) || !sop->so_confirmed)				goto out;			if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)				flag = NFS4_OPEN_DELEGATE_WRITE;			else				flag = NFS4_OPEN_DELEGATE_READ;			break;		default:			goto out;	}	dp = alloc_init_deleg(sop->so_client, stp, fh, flag);	if (dp == NULL) {		flag = NFS4_OPEN_DELEGATE_NONE;		goto out;	}	locks_init_lock(&fl);	fl.fl_lmops = &nfsd_lease_mng_ops;	fl.fl_flags = FL_LEASE;	fl.fl_end = OFFSET_MAX;	fl.fl_owner =  (fl_owner_t)dp;	fl.fl_file = stp->st_vfs_file;	fl.fl_pid = current->tgid;	/* vfs_setlease checks to see if delegation should be handed out.	 * the lock_manager callbacks fl_mylease and fl_change are used	 */	if ((status = vfs_setlease(stp->st_vfs_file,		flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK, &flp))) {		dprintk("NFSD: setlease failed [%d], no delegation\n", status);		unhash_delegation(dp);		flag = NFS4_OPEN_DELEGATE_NONE;		goto out;	}	memcpy(&open->op_delegate_stateid, &dp->dl_stateid, sizeof(dp->dl_stateid));	dprintk("NFSD: delegation stateid=(%08x/%08x/%08x/%08x)\n\n",	             dp->dl_stateid.si_boot,	             dp->dl_stateid.si_stateownerid,	             dp->dl_stateid.si_fileid,	             dp->dl_stateid.si_generation);out:	if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS			&& flag == NFS4_OPEN_DELEGATE_NONE			&& open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE)		dprintk("NFSD: WARNING: refusing delegation reclaim\n");	open->op_delegate_type = flag;}/* * called with nfs4_lock_state() held. */__be32nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open){	struct nfs4_file *fp = NULL;	struct inode *ino = current_fh->fh_dentry->d_inode;	struct nfs4_stateid *stp = NULL;	struct nfs4_delegation *dp = NULL;	__be32 status;	status = nfserr_inval;	if (!access_valid(open->op_share_access)			|| !deny_valid(open->op_share_deny))		goto out;	/*	 * Lookup file; if found, lookup stateid and check open request,	 * and check for delegations in the process of being recalled.	 * If not found, create the nfs4_file struct	 */	fp = find_file(ino);	if (fp) {		if ((status = nfs4_check_open(fp, open, &stp)))			goto out;		status = nfs4_check_deleg(fp, open, &dp);		if (status)			goto out;	} else {		status = nfserr_bad_stateid;		if (open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR)			goto out;		status = nfserr_resource;		fp = alloc_init_file(ino);		if (fp == NULL)			goto out;	}	/*	 * OPEN the file, or upgrade an existing OPEN.	 * If truncate fails, the OPEN fails.	 */	if (stp) {		/* Stateid was found, this is an OPEN upgrade */		status = nfs4_upgrade_open(rqstp, current_fh, stp, open);		if (status)			goto out;		update_stateid(&stp->st_stateid);	} else {		/* Stateid was not found, this is a new OPEN */		int flags = 0;		if (open->op_share_access & NFS4_SHARE_ACCESS_READ)			flags |= MAY_READ;		if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)			flags |= MAY_WRITE;		status = nfs4_new_open(rqstp, &stp, dp, current_fh, flags);		if (status)			goto out;		init_stateid(stp, fp, open);		status = nfsd4_truncate(rqstp, current_fh, open);		if (status) {			release_stateid(stp, OPEN_STATE);			goto out;		}	}	memcpy(&open->op_stateid, &stp->st_stateid, sizeof(stateid_t));	/*	* Attempt to hand out a delegation. No error return, because the	* OPEN succeeds even if we fail.	*/	nfs4_open_delegation(current_fh, open, stp);	status = nfs_ok;	dprintk("nfs4_process_open2: stateid=(%08x/%08x/%08x/%08x)\n",	            stp->st_stateid.si_boot, stp->st_stateid.si_stateownerid,	            stp->st_stateid.si_fileid, stp->st_stateid.si_generation);out:	if (fp)		put_nfs4_file(fp);	if (status == 0 && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)		nfs4_set_claim_prev(open);	/*	* To finish the open response, we just need to set the rflags.	*/	open->op_rflags = NFS4_OPEN_RESULT_LOCKTYPE_POSIX;	if (!open->op_stateowner->so_confirmed)		open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM;	return status;}static struct workqueue_struct *laundry_wq;static void laundromat_main(struct work_struct *);static DECLARE_DELAYED_WORK(laundromat_work, laundromat_main);__be32nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,	    clientid_t *clid){	struct nfs4_client *clp;	__be32 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;	clp = find_confirmed_client(clid);	status = nfserr_expired;	if (clp == NULL) {		/* We assume the client took too long to RENEW. */		dprintk("nfsd4_renew: clientid not found!\n");		goto out;	}	renew_client(clp);	status = nfserr_cb_path_down;	if (!list_empty(&clp->cl_delegations)			&& !atomic_read(&clp->cl_callback.cb_set))		goto out;	status = nfs_ok;out:	nfs4_unlock_state();	return status;}static voidend_grace(void){	dprintk("NFSD: end of grace period\n");	nfsd4_recdir_purge_old();	in_grace = 0;}static time_tnfs4_laundromat(void){	struct nfs4_client *clp;	struct nfs4_stateowner *sop;	struct nfs4_delegation *dp;	struct list_head *pos, *next, reaplist;	time_t cutoff = get_seconds() - NFSD_LEASE_TIME;	time_t t, clientid_val = NFSD_LEASE_TIME;	time_t u, test_val = NFSD_LEASE_TIME;	nfs4_lock_state();	dprintk("NFSD: laundromat service - starting\n");	if (in_grace)		end_grace();	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);		nfsd4_remove_clid_dir(clp);		expire_client(clp);	}	INIT_LIST_HEAD(&reaplist);	spin_lock(&recall_lock);	list_for_each_safe(pos, next, &del_recall_lru) {		dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);		if (time_after((unsigned long)dp->dl_time, (unsigned long)cutoff)) {			u = dp->dl_time - cutoff;			if (test_val > u)				test_val = u;			break;		}		dprintk("NFSD: purging unused delegation dp %p, fp %p\n",			            dp, dp->dl_flock);		list_move(&dp->dl_recall_lru, &reaplist);	}	spin_unlock(&recall_lock);	list_for_each_safe(pos, next, &reaplist) {		dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);		list_del_init(&dp->dl_recall_lru);		unhash_delegation(dp);	}	test_val = NFSD_LEASE_TIME;	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;			if (test_val > u)				test_val = u;			break;		}		dprintk("NFSD: purging unused open stateowner (so_id %d)\n",			sop->so_id);		release_stateowner(sop);	}	if (clientid_val < NFSD_LAUNDROMAT_MINTIMEOUT)		clientid_val = NFSD_LAUNDROMAT_MINTIMEOUT;	nfs4_unlock_state();	return clientid_val;}voidlaundromat_main(struct work_struct *not_used){	time_t t;	t = nfs4_laundromat();	dprintk("NFSD: laundromat_main - sleeping for %ld seconds\n", t);	queue_delayed_work(laundry_wq, &laundromat_work, t*HZ);}static struct nfs4_stateowner *search_close_lru(u32 st_id, int flags){	struct nfs4_stateowner *local = NULL;	if (flags & CLOSE_STATE) {		list_for_each_entry(local, &close_lru, so_close_lru) {			if (local->so_id == st_id)				return local;		}	}

⌨️ 快捷键说明

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