@@ -1627,7 +1627,16 @@ nfs_lookup_revalidate_done(struct inode *dir, struct dentry *dentry,
16271627 switch (error ) {
16281628 case 1 :
16291629 break ;
1630- case 0 :
1630+ case - ETIMEDOUT :
1631+ if (inode && (IS_ROOT (dentry ) ||
1632+ NFS_SERVER (inode )-> flags & NFS_MOUNT_SOFTREVAL ))
1633+ error = 1 ;
1634+ break ;
1635+ case - ESTALE :
1636+ case - ENOENT :
1637+ error = 0 ;
1638+ fallthrough ;
1639+ default :
16311640 /*
16321641 * We can't d_drop the root of a disconnected tree:
16331642 * its d_hash is on the s_anon list and d_drop() would hide
@@ -1682,18 +1691,8 @@ static int nfs_lookup_revalidate_dentry(struct inode *dir,
16821691
16831692 dir_verifier = nfs_save_change_attribute (dir );
16841693 ret = NFS_PROTO (dir )-> lookup (dir , dentry , fhandle , fattr );
1685- if (ret < 0 ) {
1686- switch (ret ) {
1687- case - ESTALE :
1688- case - ENOENT :
1689- ret = 0 ;
1690- break ;
1691- case - ETIMEDOUT :
1692- if (NFS_SERVER (inode )-> flags & NFS_MOUNT_SOFTREVAL )
1693- ret = 1 ;
1694- }
1694+ if (ret < 0 )
16951695 goto out ;
1696- }
16971696
16981697 /* Request help from readdirplus */
16991698 nfs_lookup_advise_force_readdirplus (dir , flags );
@@ -1737,7 +1736,7 @@ nfs_do_lookup_revalidate(struct inode *dir, struct dentry *dentry,
17371736 unsigned int flags )
17381737{
17391738 struct inode * inode ;
1740- int error ;
1739+ int error = 0 ;
17411740
17421741 nfs_inc_stats (dir , NFSIOS_DENTRYREVALIDATE );
17431742 inode = d_inode (dentry );
@@ -1782,7 +1781,7 @@ nfs_do_lookup_revalidate(struct inode *dir, struct dentry *dentry,
17821781out_bad :
17831782 if (flags & LOOKUP_RCU )
17841783 return - ECHILD ;
1785- return nfs_lookup_revalidate_done (dir , dentry , inode , 0 );
1784+ return nfs_lookup_revalidate_done (dir , dentry , inode , error );
17861785}
17871786
17881787static int
@@ -1804,9 +1803,10 @@ __nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags,
18041803 if (parent != READ_ONCE (dentry -> d_parent ))
18051804 return - ECHILD ;
18061805 } else {
1807- /* Wait for unlink to complete */
1806+ /* Wait for unlink to complete - see unblock_revalidate() */
18081807 wait_var_event (& dentry -> d_fsdata ,
1809- dentry -> d_fsdata != NFS_FSDATA_BLOCKED );
1808+ smp_load_acquire (& dentry -> d_fsdata )
1809+ != NFS_FSDATA_BLOCKED );
18101810 parent = dget_parent (dentry );
18111811 ret = reval (d_inode (parent ), dentry , flags );
18121812 dput (parent );
@@ -1819,6 +1819,29 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
18191819 return __nfs_lookup_revalidate (dentry , flags , nfs_do_lookup_revalidate );
18201820}
18211821
1822+ static void block_revalidate (struct dentry * dentry )
1823+ {
1824+ /* old devname - just in case */
1825+ kfree (dentry -> d_fsdata );
1826+
1827+ /* Any new reference that could lead to an open
1828+ * will take ->d_lock in lookup_open() -> d_lookup().
1829+ * Holding this lock ensures we cannot race with
1830+ * __nfs_lookup_revalidate() and removes and need
1831+ * for further barriers.
1832+ */
1833+ lockdep_assert_held (& dentry -> d_lock );
1834+
1835+ dentry -> d_fsdata = NFS_FSDATA_BLOCKED ;
1836+ }
1837+
1838+ static void unblock_revalidate (struct dentry * dentry )
1839+ {
1840+ /* store_release ensures wait_var_event() sees the update */
1841+ smp_store_release (& dentry -> d_fsdata , NULL );
1842+ wake_up_var (& dentry -> d_fsdata );
1843+ }
1844+
18221845/*
18231846 * A weaker form of d_revalidate for revalidating just the d_inode(dentry)
18241847 * when we don't really care about the dentry name. This is called when a
@@ -2255,6 +2278,9 @@ int nfs_atomic_open_v23(struct inode *dir, struct dentry *dentry,
22552278 */
22562279 int error = 0 ;
22572280
2281+ if (dentry -> d_name .len > NFS_SERVER (dir )-> namelen )
2282+ return - ENAMETOOLONG ;
2283+
22582284 if (open_flags & O_CREAT ) {
22592285 file -> f_mode |= FMODE_CREATED ;
22602286 error = nfs_do_create (dir , dentry , mode , open_flags );
@@ -2549,15 +2575,12 @@ int nfs_unlink(struct inode *dir, struct dentry *dentry)
25492575 spin_unlock (& dentry -> d_lock );
25502576 goto out ;
25512577 }
2552- /* old devname */
2553- kfree (dentry -> d_fsdata );
2554- dentry -> d_fsdata = NFS_FSDATA_BLOCKED ;
2578+ block_revalidate (dentry );
25552579
25562580 spin_unlock (& dentry -> d_lock );
25572581 error = nfs_safe_remove (dentry );
25582582 nfs_dentry_remove_handle_error (dir , dentry , error );
2559- dentry -> d_fsdata = NULL ;
2560- wake_up_var (& dentry -> d_fsdata );
2583+ unblock_revalidate (dentry );
25612584out :
25622585 trace_nfs_unlink_exit (dir , dentry , error );
25632586 return error ;
@@ -2664,8 +2687,7 @@ nfs_unblock_rename(struct rpc_task *task, struct nfs_renamedata *data)
26642687{
26652688 struct dentry * new_dentry = data -> new_dentry ;
26662689
2667- new_dentry -> d_fsdata = NULL ;
2668- wake_up_var (& new_dentry -> d_fsdata );
2690+ unblock_revalidate (new_dentry );
26692691}
26702692
26712693/*
@@ -2727,11 +2749,6 @@ int nfs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
27272749 if (WARN_ON (new_dentry -> d_flags & DCACHE_NFSFS_RENAMED ) ||
27282750 WARN_ON (new_dentry -> d_fsdata == NFS_FSDATA_BLOCKED ))
27292751 goto out ;
2730- if (new_dentry -> d_fsdata ) {
2731- /* old devname */
2732- kfree (new_dentry -> d_fsdata );
2733- new_dentry -> d_fsdata = NULL ;
2734- }
27352752
27362753 spin_lock (& new_dentry -> d_lock );
27372754 if (d_count (new_dentry ) > 2 ) {
@@ -2753,7 +2770,7 @@ int nfs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
27532770 new_dentry = dentry ;
27542771 new_inode = NULL ;
27552772 } else {
2756- new_dentry -> d_fsdata = NFS_FSDATA_BLOCKED ;
2773+ block_revalidate ( new_dentry ) ;
27572774 must_unblock = true;
27582775 spin_unlock (& new_dentry -> d_lock );
27592776 }
@@ -2765,6 +2782,8 @@ int nfs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
27652782 task = nfs_async_rename (old_dir , new_dir , old_dentry , new_dentry ,
27662783 must_unblock ? nfs_unblock_rename : NULL );
27672784 if (IS_ERR (task )) {
2785+ if (must_unblock )
2786+ unblock_revalidate (new_dentry );
27682787 error = PTR_ERR (task );
27692788 goto out ;
27702789 }
0 commit comments