Skip to content

Commit c7944eb

Browse files
author
Trond Myklebust
committed
NFSv4: Fix lookup revalidate of regular files
If we're revalidating an existing dentry in order to open a file, we need to ensure that we check the directory has not changed before we optimise away the lookup. Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
1 parent 5ceb9d7 commit c7944eb

File tree

1 file changed

+39
-40
lines changed

1 file changed

+39
-40
lines changed

fs/nfs/dir.c

Lines changed: 39 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1231,7 +1231,8 @@ nfs_do_lookup_revalidate(struct inode *dir, struct dentry *dentry,
12311231
}
12321232

12331233
static int
1234-
nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
1234+
__nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags,
1235+
int (*reval)(struct inode *, struct dentry *, unsigned int))
12351236
{
12361237
struct dentry *parent;
12371238
struct inode *dir;
@@ -1242,17 +1243,22 @@ nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
12421243
dir = d_inode_rcu(parent);
12431244
if (!dir)
12441245
return -ECHILD;
1245-
ret = nfs_do_lookup_revalidate(dir, dentry, flags);
1246+
ret = reval(dir, dentry, flags);
12461247
if (parent != READ_ONCE(dentry->d_parent))
12471248
return -ECHILD;
12481249
} else {
12491250
parent = dget_parent(dentry);
1250-
ret = nfs_do_lookup_revalidate(d_inode(parent), dentry, flags);
1251+
ret = reval(d_inode(parent), dentry, flags);
12511252
dput(parent);
12521253
}
12531254
return ret;
12541255
}
12551256

1257+
static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
1258+
{
1259+
return __nfs_lookup_revalidate(dentry, flags, nfs_do_lookup_revalidate);
1260+
}
1261+
12561262
/*
12571263
* A weaker form of d_revalidate for revalidating just the d_inode(dentry)
12581264
* when we don't really care about the dentry name. This is called when a
@@ -1609,62 +1615,55 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
16091615
}
16101616
EXPORT_SYMBOL_GPL(nfs_atomic_open);
16111617

1612-
static int nfs4_lookup_revalidate(struct dentry *dentry, unsigned int flags)
1618+
static int
1619+
nfs4_do_lookup_revalidate(struct inode *dir, struct dentry *dentry,
1620+
unsigned int flags)
16131621
{
16141622
struct inode *inode;
1615-
int ret = 0;
16161623

16171624
if (!(flags & LOOKUP_OPEN) || (flags & LOOKUP_DIRECTORY))
1618-
goto no_open;
1625+
goto full_reval;
16191626
if (d_mountpoint(dentry))
1620-
goto no_open;
1621-
if (NFS_SB(dentry->d_sb)->caps & NFS_CAP_ATOMIC_OPEN_V1)
1622-
goto no_open;
1627+
goto full_reval;
16231628

16241629
inode = d_inode(dentry);
16251630

16261631
/* We can't create new files in nfs_open_revalidate(), so we
16271632
* optimize away revalidation of negative dentries.
16281633
*/
1629-
if (inode == NULL) {
1630-
struct dentry *parent;
1631-
struct inode *dir;
1632-
1633-
if (flags & LOOKUP_RCU) {
1634-
parent = READ_ONCE(dentry->d_parent);
1635-
dir = d_inode_rcu(parent);
1636-
if (!dir)
1637-
return -ECHILD;
1638-
} else {
1639-
parent = dget_parent(dentry);
1640-
dir = d_inode(parent);
1641-
}
1642-
if (!nfs_neg_need_reval(dir, dentry, flags))
1643-
ret = 1;
1644-
else if (flags & LOOKUP_RCU)
1645-
ret = -ECHILD;
1646-
if (!(flags & LOOKUP_RCU))
1647-
dput(parent);
1648-
else if (parent != READ_ONCE(dentry->d_parent))
1649-
return -ECHILD;
1650-
goto out;
1651-
}
1634+
if (inode == NULL)
1635+
goto full_reval;
1636+
1637+
if (NFS_PROTO(dir)->have_delegation(inode, FMODE_READ))
1638+
return nfs_lookup_revalidate_delegated(dir, dentry, inode);
16521639

16531640
/* NFS only supports OPEN on regular files */
16541641
if (!S_ISREG(inode->i_mode))
1655-
goto no_open;
1642+
goto full_reval;
1643+
16561644
/* We cannot do exclusive creation on a positive dentry */
1657-
if (flags & LOOKUP_EXCL)
1658-
goto no_open;
1645+
if (flags & (LOOKUP_EXCL | LOOKUP_REVAL))
1646+
goto reval_dentry;
1647+
1648+
/* Check if the directory changed */
1649+
if (!nfs_check_verifier(dir, dentry, flags & LOOKUP_RCU))
1650+
goto reval_dentry;
16591651

16601652
/* Let f_op->open() actually open (and revalidate) the file */
1661-
ret = 1;
1653+
return 1;
1654+
reval_dentry:
1655+
if (flags & LOOKUP_RCU)
1656+
return -ECHILD;
1657+
return nfs_lookup_revalidate_dentry(dir, dentry, inode);;
16621658

1663-
out:
1664-
return ret;
1659+
full_reval:
1660+
return nfs_do_lookup_revalidate(dir, dentry, flags);
1661+
}
16651662

1666-
no_open:
1667-
return nfs_lookup_revalidate(dentry, flags);
1663+
static int nfs4_lookup_revalidate(struct dentry *dentry, unsigned int flags)
1664+
{
1665+
return __nfs_lookup_revalidate(dentry, flags,
1666+
nfs4_do_lookup_revalidate);
16681667
}
16691668

16701669
#endif /* CONFIG_NFSV4 */

0 commit comments

Comments
 (0)