summaryrefslogtreecommitdiffstats
path: root/fs/nfs/dir.c
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@hammerspace.com>2018-09-28 12:42:51 -0400
committerTrond Myklebust <trond.myklebust@hammerspace.com>2018-09-30 15:35:18 -0400
commitc7944ebb9ce9461079659e9e6ec5baaf73724b3b (patch)
tree2f519efaf6144cb3f34952fce4c1f21d95259269 /fs/nfs/dir.c
parent5ceb9d7fdaaf6d8ced6cd7861cf1deb9cd93fa47 (diff)
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>
Diffstat (limited to 'fs/nfs/dir.c')
-rw-r--r--fs/nfs/dir.c79
1 files changed, 39 insertions, 40 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 2e6a253e4104..71b2e390becf 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -1231,7 +1231,8 @@ out_bad:
1231} 1231}
1232 1232
1233static int 1233static int
1234nfs_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))
1235{ 1236{
1236 struct dentry *parent; 1237 struct dentry *parent;
1237 struct inode *dir; 1238 struct inode *dir;
@@ -1242,17 +1243,22 @@ nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
1242 dir = d_inode_rcu(parent); 1243 dir = d_inode_rcu(parent);
1243 if (!dir) 1244 if (!dir)
1244 return -ECHILD; 1245 return -ECHILD;
1245 ret = nfs_do_lookup_revalidate(dir, dentry, flags); 1246 ret = reval(dir, dentry, flags);
1246 if (parent != READ_ONCE(dentry->d_parent)) 1247 if (parent != READ_ONCE(dentry->d_parent))
1247 return -ECHILD; 1248 return -ECHILD;
1248 } else { 1249 } else {
1249 parent = dget_parent(dentry); 1250 parent = dget_parent(dentry);
1250 ret = nfs_do_lookup_revalidate(d_inode(parent), dentry, flags); 1251 ret = reval(d_inode(parent), dentry, flags);
1251 dput(parent); 1252 dput(parent);
1252 } 1253 }
1253 return ret; 1254 return ret;
1254} 1255}
1255 1256
1257static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
1258{
1259 return __nfs_lookup_revalidate(dentry, flags, nfs_do_lookup_revalidate);
1260}
1261
1256/* 1262/*
1257 * A weaker form of d_revalidate for revalidating just the d_inode(dentry) 1263 * A weaker form of d_revalidate for revalidating just the d_inode(dentry)
1258 * when we don't really care about the dentry name. This is called when a 1264 * when we don't really care about the dentry name. This is called when a
@@ -1609,62 +1615,55 @@ no_open:
1609} 1615}
1610EXPORT_SYMBOL_GPL(nfs_atomic_open); 1616EXPORT_SYMBOL_GPL(nfs_atomic_open);
1611 1617
1612static int nfs4_lookup_revalidate(struct dentry *dentry, unsigned int flags) 1618static int
1619nfs4_do_lookup_revalidate(struct inode *dir, struct dentry *dentry,
1620 unsigned int flags)
1613{ 1621{
1614 struct inode *inode; 1622 struct inode *inode;
1615 int ret = 0;
1616 1623
1617 if (!(flags & LOOKUP_OPEN) || (flags & LOOKUP_DIRECTORY)) 1624 if (!(flags & LOOKUP_OPEN) || (flags & LOOKUP_DIRECTORY))
1618 goto no_open; 1625 goto full_reval;
1619 if (d_mountpoint(dentry)) 1626 if (d_mountpoint(dentry))
1620 goto no_open; 1627 goto full_reval;
1621 if (NFS_SB(dentry->d_sb)->caps & NFS_CAP_ATOMIC_OPEN_V1)
1622 goto no_open;
1623 1628
1624 inode = d_inode(dentry); 1629 inode = d_inode(dentry);
1625 1630
1626 /* We can't create new files in nfs_open_revalidate(), so we 1631 /* We can't create new files in nfs_open_revalidate(), so we
1627 * optimize away revalidation of negative dentries. 1632 * optimize away revalidation of negative dentries.
1628 */ 1633 */
1629 if (inode == NULL) { 1634 if (inode == NULL)
1630 struct dentry *parent; 1635 goto full_reval;
1631 struct inode *dir; 1636
1632 1637 if (NFS_PROTO(dir)->have_delegation(inode, FMODE_READ))
1633 if (flags & LOOKUP_RCU) { 1638 return nfs_lookup_revalidate_delegated(dir, dentry, inode);
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 }
1652 1639
1653 /* NFS only supports OPEN on regular files */ 1640 /* NFS only supports OPEN on regular files */
1654 if (!S_ISREG(inode->i_mode)) 1641 if (!S_ISREG(inode->i_mode))
1655 goto no_open; 1642 goto full_reval;
1643
1656 /* We cannot do exclusive creation on a positive dentry */ 1644 /* We cannot do exclusive creation on a positive dentry */
1657 if (flags & LOOKUP_EXCL) 1645 if (flags & (LOOKUP_EXCL | LOOKUP_REVAL))
1658 goto no_open; 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;
1659 1651
1660 /* Let f_op->open() actually open (and revalidate) the file */ 1652 /* Let f_op->open() actually open (and revalidate) the file */
1661 ret = 1; 1653 return 1;
1654reval_dentry:
1655 if (flags & LOOKUP_RCU)
1656 return -ECHILD;
1657 return nfs_lookup_revalidate_dentry(dir, dentry, inode);;
1662 1658
1663out: 1659full_reval:
1664 return ret; 1660 return nfs_do_lookup_revalidate(dir, dentry, flags);
1661}
1665 1662
1666no_open: 1663static int nfs4_lookup_revalidate(struct dentry *dentry, unsigned int flags)
1667 return nfs_lookup_revalidate(dentry, flags); 1664{
1665 return __nfs_lookup_revalidate(dentry, flags,
1666 nfs4_do_lookup_revalidate);
1668} 1667}
1669 1668
1670#endif /* CONFIG_NFSV4 */ 1669#endif /* CONFIG_NFSV4 */