@@ -1804,9 +1804,10 @@ __nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags,
18041804 if (parent != READ_ONCE (dentry -> d_parent ))
18051805 return - ECHILD ;
18061806 } else {
1807- /* Wait for unlink to complete */
1807+ /* Wait for unlink to complete - see unblock_revalidate() */
18081808 wait_var_event (& dentry -> d_fsdata ,
1809- dentry -> d_fsdata != NFS_FSDATA_BLOCKED );
1809+ smp_load_acquire (& dentry -> d_fsdata )
1810+ != NFS_FSDATA_BLOCKED );
18101811 parent = dget_parent (dentry );
18111812 ret = reval (d_inode (parent ), dentry , flags );
18121813 dput (parent );
@@ -1819,6 +1820,29 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
18191820 return __nfs_lookup_revalidate (dentry , flags , nfs_do_lookup_revalidate );
18201821}
18211822
1823+ static void block_revalidate (struct dentry * dentry )
1824+ {
1825+ /* old devname - just in case */
1826+ kfree (dentry -> d_fsdata );
1827+
1828+ /* Any new reference that could lead to an open
1829+ * will take ->d_lock in lookup_open() -> d_lookup().
1830+ * Holding this lock ensures we cannot race with
1831+ * __nfs_lookup_revalidate() and removes and need
1832+ * for further barriers.
1833+ */
1834+ lockdep_assert_held (& dentry -> d_lock );
1835+
1836+ dentry -> d_fsdata = NFS_FSDATA_BLOCKED ;
1837+ }
1838+
1839+ static void unblock_revalidate (struct dentry * dentry )
1840+ {
1841+ /* store_release ensures wait_var_event() sees the update */
1842+ smp_store_release (& dentry -> d_fsdata , NULL );
1843+ wake_up_var (& dentry -> d_fsdata );
1844+ }
1845+
18221846/*
18231847 * A weaker form of d_revalidate for revalidating just the d_inode(dentry)
18241848 * when we don't really care about the dentry name. This is called when a
@@ -2503,15 +2527,12 @@ int nfs_unlink(struct inode *dir, struct dentry *dentry)
25032527 spin_unlock (& dentry -> d_lock );
25042528 goto out ;
25052529 }
2506- /* old devname */
2507- kfree (dentry -> d_fsdata );
2508- dentry -> d_fsdata = NFS_FSDATA_BLOCKED ;
2530+ block_revalidate (dentry );
25092531
25102532 spin_unlock (& dentry -> d_lock );
25112533 error = nfs_safe_remove (dentry );
25122534 nfs_dentry_remove_handle_error (dir , dentry , error );
2513- dentry -> d_fsdata = NULL ;
2514- wake_up_var (& dentry -> d_fsdata );
2535+ unblock_revalidate (dentry );
25152536out :
25162537 trace_nfs_unlink_exit (dir , dentry , error );
25172538 return error ;
@@ -2618,8 +2639,7 @@ nfs_unblock_rename(struct rpc_task *task, struct nfs_renamedata *data)
26182639{
26192640 struct dentry * new_dentry = data -> new_dentry ;
26202641
2621- new_dentry -> d_fsdata = NULL ;
2622- wake_up_var (& new_dentry -> d_fsdata );
2642+ unblock_revalidate (new_dentry );
26232643}
26242644
26252645/*
@@ -2681,11 +2701,6 @@ int nfs_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
26812701 if (WARN_ON (new_dentry -> d_flags & DCACHE_NFSFS_RENAMED ) ||
26822702 WARN_ON (new_dentry -> d_fsdata == NFS_FSDATA_BLOCKED ))
26832703 goto out ;
2684- if (new_dentry -> d_fsdata ) {
2685- /* old devname */
2686- kfree (new_dentry -> d_fsdata );
2687- new_dentry -> d_fsdata = NULL ;
2688- }
26892704
26902705 spin_lock (& new_dentry -> d_lock );
26912706 if (d_count (new_dentry ) > 2 ) {
@@ -2707,7 +2722,7 @@ int nfs_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
27072722 new_dentry = dentry ;
27082723 new_inode = NULL ;
27092724 } else {
2710- new_dentry -> d_fsdata = NFS_FSDATA_BLOCKED ;
2725+ block_revalidate ( new_dentry ) ;
27112726 must_unblock = true;
27122727 spin_unlock (& new_dentry -> d_lock );
27132728 }
@@ -2719,6 +2734,8 @@ int nfs_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
27192734 task = nfs_async_rename (old_dir , new_dir , old_dentry , new_dentry ,
27202735 must_unblock ? nfs_unblock_rename : NULL );
27212736 if (IS_ERR (task )) {
2737+ if (must_unblock )
2738+ unblock_revalidate (new_dentry );
27222739 error = PTR_ERR (task );
27232740 goto out ;
27242741 }
0 commit comments