Commit a0ce4837 authored by J. Bruce Fields's avatar J. Bruce Fields Committed by Chuck Lever
Browse files

nfsd: track filehandle aliasing in nfs4_files



It's unusual but possible for multiple filehandles to point to the same
file.  In that case, we may end up with multiple nfs4_files referencing
the same inode.

For delegation purposes it will turn out to be useful to flag those
cases.

Signed-off-by: default avatarJ. Bruce Fields <bfields@redhat.com>
Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
parent f9b60e22
Loading
Loading
Loading
Loading
+28 −9
Original line number Diff line number Diff line
@@ -4086,6 +4086,8 @@ static void nfsd4_init_file(struct svc_fh *fh, unsigned int hashval,
	fp->fi_share_deny = 0;
	memset(fp->fi_fds, 0, sizeof(fp->fi_fds));
	memset(fp->fi_access, 0, sizeof(fp->fi_access));
	fp->fi_aliased = false;
	fp->fi_inode = d_inode(fh->fh_dentry);
#ifdef CONFIG_NFSD_PNFS
	INIT_LIST_HEAD(&fp->fi_lo_states);
	atomic_set(&fp->fi_lo_recalls, 0);
@@ -4438,6 +4440,31 @@ find_file_locked(struct svc_fh *fh, unsigned int hashval)
	return NULL;
}

static struct nfs4_file *insert_file(struct nfs4_file *new, struct svc_fh *fh,
				     unsigned int hashval)
{
	struct nfs4_file *fp;
	struct nfs4_file *ret = NULL;
	bool alias_found = false;

	spin_lock(&state_lock);
	hlist_for_each_entry_rcu(fp, &file_hashtbl[hashval], fi_hash,
				 lockdep_is_held(&state_lock)) {
		if (fh_match(&fp->fi_fhandle, &fh->fh_handle)) {
			if (refcount_inc_not_zero(&fp->fi_ref))
				ret = fp;
		} else if (d_inode(fh->fh_dentry) == fp->fi_inode)
			fp->fi_aliased = alias_found = true;
	}
	if (likely(ret == NULL)) {
		nfsd4_init_file(fh, hashval, new);
		new->fi_aliased = alias_found;
		ret = new;
	}
	spin_unlock(&state_lock);
	return ret;
}

static struct nfs4_file * find_file(struct svc_fh *fh)
{
	struct nfs4_file *fp;
@@ -4461,15 +4488,7 @@ find_or_add_file(struct nfs4_file *new, struct svc_fh *fh)
	if (fp)
		return fp;

	spin_lock(&state_lock);
	fp = find_file_locked(fh, hashval);
	if (likely(fp == NULL)) {
		nfsd4_init_file(fh, hashval, new);
		fp = new;
	}
	spin_unlock(&state_lock);

	return fp;
	return insert_file(new, fh, hashval);
}

/*
+2 −0
Original line number Diff line number Diff line
@@ -516,6 +516,8 @@ struct nfs4_clnt_odstate {
 */
struct nfs4_file {
	refcount_t		fi_ref;
	struct inode *		fi_inode;
	bool			fi_aliased;
	spinlock_t		fi_lock;
	struct hlist_node       fi_hash;	/* hash on fi_fhandle */
	struct list_head        fi_stateids;