nfsd: track filehandle aliasing in nfs4_files
[ Upstream commit a0ce48375a367222989c2618fe68bf34db8c7bb7 ] 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: J. Bruce Fields <bfields@redhat.com> Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
01cc621293
commit
bd25d8b91c
2 changed files with 30 additions and 9 deletions
|
@ -4120,6 +4120,8 @@ static void nfsd4_init_file(struct svc_fh *fh, unsigned int hashval,
|
||||||
fp->fi_share_deny = 0;
|
fp->fi_share_deny = 0;
|
||||||
memset(fp->fi_fds, 0, sizeof(fp->fi_fds));
|
memset(fp->fi_fds, 0, sizeof(fp->fi_fds));
|
||||||
memset(fp->fi_access, 0, sizeof(fp->fi_access));
|
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
|
#ifdef CONFIG_NFSD_PNFS
|
||||||
INIT_LIST_HEAD(&fp->fi_lo_states);
|
INIT_LIST_HEAD(&fp->fi_lo_states);
|
||||||
atomic_set(&fp->fi_lo_recalls, 0);
|
atomic_set(&fp->fi_lo_recalls, 0);
|
||||||
|
@ -4472,6 +4474,31 @@ find_file_locked(struct svc_fh *fh, unsigned int hashval)
|
||||||
return NULL;
|
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)
|
static struct nfs4_file * find_file(struct svc_fh *fh)
|
||||||
{
|
{
|
||||||
struct nfs4_file *fp;
|
struct nfs4_file *fp;
|
||||||
|
@ -4495,15 +4522,7 @@ find_or_add_file(struct nfs4_file *new, struct svc_fh *fh)
|
||||||
if (fp)
|
if (fp)
|
||||||
return fp;
|
return fp;
|
||||||
|
|
||||||
spin_lock(&state_lock);
|
return insert_file(new, fh, hashval);
|
||||||
fp = find_file_locked(fh, hashval);
|
|
||||||
if (likely(fp == NULL)) {
|
|
||||||
nfsd4_init_file(fh, hashval, new);
|
|
||||||
fp = new;
|
|
||||||
}
|
|
||||||
spin_unlock(&state_lock);
|
|
||||||
|
|
||||||
return fp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -516,6 +516,8 @@ struct nfs4_clnt_odstate {
|
||||||
*/
|
*/
|
||||||
struct nfs4_file {
|
struct nfs4_file {
|
||||||
refcount_t fi_ref;
|
refcount_t fi_ref;
|
||||||
|
struct inode * fi_inode;
|
||||||
|
bool fi_aliased;
|
||||||
spinlock_t fi_lock;
|
spinlock_t fi_lock;
|
||||||
struct hlist_node fi_hash; /* hash on fi_fhandle */
|
struct hlist_node fi_hash; /* hash on fi_fhandle */
|
||||||
struct list_head fi_stateids;
|
struct list_head fi_stateids;
|
||||||
|
|
Loading…
Add table
Reference in a new issue