@@ -1627,7 +1627,16 @@ nfs_lookup_revalidate_done(struct inode *dir, struct dentry *dentry,
1627
1627
switch (error ) {
1628
1628
case 1 :
1629
1629
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 :
1631
1640
/*
1632
1641
* We can't d_drop the root of a disconnected tree:
1633
1642
* 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,
1682
1691
1683
1692
dir_verifier = nfs_save_change_attribute (dir );
1684
1693
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 )
1695
1695
goto out ;
1696
- }
1697
1696
1698
1697
/* Request help from readdirplus */
1699
1698
nfs_lookup_advise_force_readdirplus (dir , flags );
@@ -1737,7 +1736,7 @@ nfs_do_lookup_revalidate(struct inode *dir, struct dentry *dentry,
1737
1736
unsigned int flags )
1738
1737
{
1739
1738
struct inode * inode ;
1740
- int error ;
1739
+ int error = 0 ;
1741
1740
1742
1741
nfs_inc_stats (dir , NFSIOS_DENTRYREVALIDATE );
1743
1742
inode = d_inode (dentry );
@@ -1782,7 +1781,7 @@ nfs_do_lookup_revalidate(struct inode *dir, struct dentry *dentry,
1782
1781
out_bad :
1783
1782
if (flags & LOOKUP_RCU )
1784
1783
return - ECHILD ;
1785
- return nfs_lookup_revalidate_done (dir , dentry , inode , 0 );
1784
+ return nfs_lookup_revalidate_done (dir , dentry , inode , error );
1786
1785
}
1787
1786
1788
1787
static int
@@ -1804,9 +1803,10 @@ __nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags,
1804
1803
if (parent != READ_ONCE (dentry -> d_parent ))
1805
1804
return - ECHILD ;
1806
1805
} else {
1807
- /* Wait for unlink to complete */
1806
+ /* Wait for unlink to complete - see unblock_revalidate() */
1808
1807
wait_var_event (& dentry -> d_fsdata ,
1809
- dentry -> d_fsdata != NFS_FSDATA_BLOCKED );
1808
+ smp_load_acquire (& dentry -> d_fsdata )
1809
+ != NFS_FSDATA_BLOCKED );
1810
1810
parent = dget_parent (dentry );
1811
1811
ret = reval (d_inode (parent ), dentry , flags );
1812
1812
dput (parent );
@@ -1819,6 +1819,29 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
1819
1819
return __nfs_lookup_revalidate (dentry , flags , nfs_do_lookup_revalidate );
1820
1820
}
1821
1821
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
+
1822
1845
/*
1823
1846
* A weaker form of d_revalidate for revalidating just the d_inode(dentry)
1824
1847
* 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,
2255
2278
*/
2256
2279
int error = 0 ;
2257
2280
2281
+ if (dentry -> d_name .len > NFS_SERVER (dir )-> namelen )
2282
+ return - ENAMETOOLONG ;
2283
+
2258
2284
if (open_flags & O_CREAT ) {
2259
2285
file -> f_mode |= FMODE_CREATED ;
2260
2286
error = nfs_do_create (dir , dentry , mode , open_flags );
@@ -2549,15 +2575,12 @@ int nfs_unlink(struct inode *dir, struct dentry *dentry)
2549
2575
spin_unlock (& dentry -> d_lock );
2550
2576
goto out ;
2551
2577
}
2552
- /* old devname */
2553
- kfree (dentry -> d_fsdata );
2554
- dentry -> d_fsdata = NFS_FSDATA_BLOCKED ;
2578
+ block_revalidate (dentry );
2555
2579
2556
2580
spin_unlock (& dentry -> d_lock );
2557
2581
error = nfs_safe_remove (dentry );
2558
2582
nfs_dentry_remove_handle_error (dir , dentry , error );
2559
- dentry -> d_fsdata = NULL ;
2560
- wake_up_var (& dentry -> d_fsdata );
2583
+ unblock_revalidate (dentry );
2561
2584
out :
2562
2585
trace_nfs_unlink_exit (dir , dentry , error );
2563
2586
return error ;
@@ -2664,8 +2687,7 @@ nfs_unblock_rename(struct rpc_task *task, struct nfs_renamedata *data)
2664
2687
{
2665
2688
struct dentry * new_dentry = data -> new_dentry ;
2666
2689
2667
- new_dentry -> d_fsdata = NULL ;
2668
- wake_up_var (& new_dentry -> d_fsdata );
2690
+ unblock_revalidate (new_dentry );
2669
2691
}
2670
2692
2671
2693
/*
@@ -2727,11 +2749,6 @@ int nfs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
2727
2749
if (WARN_ON (new_dentry -> d_flags & DCACHE_NFSFS_RENAMED ) ||
2728
2750
WARN_ON (new_dentry -> d_fsdata == NFS_FSDATA_BLOCKED ))
2729
2751
goto out ;
2730
- if (new_dentry -> d_fsdata ) {
2731
- /* old devname */
2732
- kfree (new_dentry -> d_fsdata );
2733
- new_dentry -> d_fsdata = NULL ;
2734
- }
2735
2752
2736
2753
spin_lock (& new_dentry -> d_lock );
2737
2754
if (d_count (new_dentry ) > 2 ) {
@@ -2753,7 +2770,7 @@ int nfs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
2753
2770
new_dentry = dentry ;
2754
2771
new_inode = NULL ;
2755
2772
} else {
2756
- new_dentry -> d_fsdata = NFS_FSDATA_BLOCKED ;
2773
+ block_revalidate ( new_dentry ) ;
2757
2774
must_unblock = true;
2758
2775
spin_unlock (& new_dentry -> d_lock );
2759
2776
}
@@ -2765,6 +2782,8 @@ int nfs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
2765
2782
task = nfs_async_rename (old_dir , new_dir , old_dentry , new_dentry ,
2766
2783
must_unblock ? nfs_unblock_rename : NULL );
2767
2784
if (IS_ERR (task )) {
2785
+ if (must_unblock )
2786
+ unblock_revalidate (new_dentry );
2768
2787
error = PTR_ERR (task );
2769
2788
goto out ;
2770
2789
}
0 commit comments