mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	NFSD: add support for share reservation conflict to courteous server
This patch allows expired client with open state to be in COURTESY state. Share/access conflict with COURTESY client is resolved by setting COURTESY client to EXPIRABLE state, schedule laundromat to run and returning nfserr_jukebox to the request client. Reviewed-by: J. Bruce Fields <bfields@fieldses.org> Signed-off-by: Dai Ngo <dai.ngo@oracle.com> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
This commit is contained in:
		
							parent
							
								
									66af257999
								
							
						
					
					
						commit
						3d69427151
					
				
					 1 changed files with 101 additions and 8 deletions
				
			
		| 
						 | 
				
			
			@ -694,6 +694,57 @@ static unsigned int file_hashval(struct svc_fh *fh)
 | 
			
		|||
 | 
			
		||||
static struct hlist_head file_hashtbl[FILE_HASH_SIZE];
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Check if courtesy clients have conflicting access and resolve it if possible
 | 
			
		||||
 *
 | 
			
		||||
 * access:  is op_share_access if share_access is true.
 | 
			
		||||
 *	    Check if access mode, op_share_access, would conflict with
 | 
			
		||||
 *	    the current deny mode of the file 'fp'.
 | 
			
		||||
 * access:  is op_share_deny if share_access is false.
 | 
			
		||||
 *	    Check if the deny mode, op_share_deny, would conflict with
 | 
			
		||||
 *	    current access of the file 'fp'.
 | 
			
		||||
 * stp:     skip checking this entry.
 | 
			
		||||
 * new_stp: normal open, not open upgrade.
 | 
			
		||||
 *
 | 
			
		||||
 * Function returns:
 | 
			
		||||
 *	false - access/deny mode conflict with normal client.
 | 
			
		||||
 *	true  - no conflict or conflict with courtesy client(s) is resolved.
 | 
			
		||||
 */
 | 
			
		||||
static bool
 | 
			
		||||
nfs4_resolve_deny_conflicts_locked(struct nfs4_file *fp, bool new_stp,
 | 
			
		||||
		struct nfs4_ol_stateid *stp, u32 access, bool share_access)
 | 
			
		||||
{
 | 
			
		||||
	struct nfs4_ol_stateid *st;
 | 
			
		||||
	bool resolvable = true;
 | 
			
		||||
	unsigned char bmap;
 | 
			
		||||
	struct nfsd_net *nn;
 | 
			
		||||
	struct nfs4_client *clp;
 | 
			
		||||
 | 
			
		||||
	lockdep_assert_held(&fp->fi_lock);
 | 
			
		||||
	list_for_each_entry(st, &fp->fi_stateids, st_perfile) {
 | 
			
		||||
		/* ignore lock stateid */
 | 
			
		||||
		if (st->st_openstp)
 | 
			
		||||
			continue;
 | 
			
		||||
		if (st == stp && new_stp)
 | 
			
		||||
			continue;
 | 
			
		||||
		/* check file access against deny mode or vice versa */
 | 
			
		||||
		bmap = share_access ? st->st_deny_bmap : st->st_access_bmap;
 | 
			
		||||
		if (!(access & bmap_to_share_mode(bmap)))
 | 
			
		||||
			continue;
 | 
			
		||||
		clp = st->st_stid.sc_client;
 | 
			
		||||
		if (try_to_expire_client(clp))
 | 
			
		||||
			continue;
 | 
			
		||||
		resolvable = false;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
	if (resolvable) {
 | 
			
		||||
		clp = stp->st_stid.sc_client;
 | 
			
		||||
		nn = net_generic(clp->net, nfsd_net_id);
 | 
			
		||||
		mod_delayed_work(laundry_wq, &nn->laundromat_work, 0);
 | 
			
		||||
	}
 | 
			
		||||
	return resolvable;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
__nfs4_file_get_access(struct nfs4_file *fp, u32 access)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -4968,7 +5019,7 @@ nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh,
 | 
			
		|||
 | 
			
		||||
static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
 | 
			
		||||
		struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp,
 | 
			
		||||
		struct nfsd4_open *open)
 | 
			
		||||
		struct nfsd4_open *open, bool new_stp)
 | 
			
		||||
{
 | 
			
		||||
	struct nfsd_file *nf = NULL;
 | 
			
		||||
	__be32 status;
 | 
			
		||||
| 
						 | 
				
			
			@ -4984,6 +5035,13 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
 | 
			
		|||
	 */
 | 
			
		||||
	status = nfs4_file_check_deny(fp, open->op_share_deny);
 | 
			
		||||
	if (status != nfs_ok) {
 | 
			
		||||
		if (status != nfserr_share_denied) {
 | 
			
		||||
			spin_unlock(&fp->fi_lock);
 | 
			
		||||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
		if (nfs4_resolve_deny_conflicts_locked(fp, new_stp,
 | 
			
		||||
				stp, open->op_share_deny, false))
 | 
			
		||||
			status = nfserr_jukebox;
 | 
			
		||||
		spin_unlock(&fp->fi_lock);
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -4991,6 +5049,13 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
 | 
			
		|||
	/* set access to the file */
 | 
			
		||||
	status = nfs4_file_get_access(fp, open->op_share_access);
 | 
			
		||||
	if (status != nfs_ok) {
 | 
			
		||||
		if (status != nfserr_share_denied) {
 | 
			
		||||
			spin_unlock(&fp->fi_lock);
 | 
			
		||||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
		if (nfs4_resolve_deny_conflicts_locked(fp, new_stp,
 | 
			
		||||
				stp, open->op_share_access, true))
 | 
			
		||||
			status = nfserr_jukebox;
 | 
			
		||||
		spin_unlock(&fp->fi_lock);
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -5037,21 +5102,29 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
static __be32
 | 
			
		||||
nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp, struct nfsd4_open *open)
 | 
			
		||||
nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp,
 | 
			
		||||
		struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp,
 | 
			
		||||
		struct nfsd4_open *open)
 | 
			
		||||
{
 | 
			
		||||
	__be32 status;
 | 
			
		||||
	unsigned char old_deny_bmap = stp->st_deny_bmap;
 | 
			
		||||
 | 
			
		||||
	if (!test_access(open->op_share_access, stp))
 | 
			
		||||
		return nfs4_get_vfs_file(rqstp, fp, cur_fh, stp, open);
 | 
			
		||||
		return nfs4_get_vfs_file(rqstp, fp, cur_fh, stp, open, false);
 | 
			
		||||
 | 
			
		||||
	/* test and set deny mode */
 | 
			
		||||
	spin_lock(&fp->fi_lock);
 | 
			
		||||
	status = nfs4_file_check_deny(fp, open->op_share_deny);
 | 
			
		||||
	if (status == nfs_ok) {
 | 
			
		||||
		set_deny(open->op_share_deny, stp);
 | 
			
		||||
		fp->fi_share_deny |=
 | 
			
		||||
		if (status != nfserr_share_denied) {
 | 
			
		||||
			set_deny(open->op_share_deny, stp);
 | 
			
		||||
			fp->fi_share_deny |=
 | 
			
		||||
				(open->op_share_deny & NFS4_SHARE_DENY_BOTH);
 | 
			
		||||
		} else {
 | 
			
		||||
			if (nfs4_resolve_deny_conflicts_locked(fp, false,
 | 
			
		||||
					stp, open->op_share_deny, false))
 | 
			
		||||
				status = nfserr_jukebox;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	spin_unlock(&fp->fi_lock);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -5392,7 +5465,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
 | 
			
		|||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open);
 | 
			
		||||
		status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open, true);
 | 
			
		||||
		if (status) {
 | 
			
		||||
			stp->st_stid.sc_type = NFS4_CLOSED_STID;
 | 
			
		||||
			release_open_stateid(stp);
 | 
			
		||||
| 
						 | 
				
			
			@ -5626,6 +5699,26 @@ static void nfsd4_ssc_expire_umount(struct nfsd_net *nn)
 | 
			
		|||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static bool
 | 
			
		||||
nfs4_has_any_locks(struct nfs4_client *clp)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	struct nfs4_stateowner *so;
 | 
			
		||||
 | 
			
		||||
	spin_lock(&clp->cl_lock);
 | 
			
		||||
	for (i = 0; i < OWNER_HASH_SIZE; i++) {
 | 
			
		||||
		list_for_each_entry(so, &clp->cl_ownerstr_hashtbl[i],
 | 
			
		||||
				so_strhash) {
 | 
			
		||||
			if (so->so_is_open_owner)
 | 
			
		||||
				continue;
 | 
			
		||||
			spin_unlock(&clp->cl_lock);
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	spin_unlock(&clp->cl_lock);
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * place holder for now, no check for lock blockers yet
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			@ -5633,8 +5726,8 @@ static bool
 | 
			
		|||
nfs4_anylock_blockers(struct nfs4_client *clp)
 | 
			
		||||
{
 | 
			
		||||
	if (atomic_read(&clp->cl_delegs_in_recall) ||
 | 
			
		||||
			client_has_openowners(clp)  ||
 | 
			
		||||
			!list_empty(&clp->async_copies))
 | 
			
		||||
			!list_empty(&clp->async_copies) ||
 | 
			
		||||
			nfs4_has_any_locks(clp))
 | 
			
		||||
		return true;
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue