@@ -155,6 +155,7 @@ typedef struct {
155
155
loff_t current_index ;
156
156
decode_dirent_t decode ;
157
157
158
+ unsigned long dir_verifier ;
158
159
unsigned long timestamp ;
159
160
unsigned long gencount ;
160
161
unsigned int cache_entry_index ;
@@ -353,6 +354,7 @@ int nfs_readdir_xdr_filler(struct page **pages, nfs_readdir_descriptor_t *desc,
353
354
again :
354
355
timestamp = jiffies ;
355
356
gencount = nfs_inc_attr_generation_counter ();
357
+ desc -> dir_verifier = nfs_save_change_attribute (inode );
356
358
error = NFS_PROTO (inode )-> readdir (file_dentry (file ), cred , entry -> cookie , pages ,
357
359
NFS_SERVER (inode )-> dtsize , desc -> plus );
358
360
if (error < 0 ) {
@@ -455,13 +457,13 @@ void nfs_force_use_readdirplus(struct inode *dir)
455
457
}
456
458
457
459
static
458
- void nfs_prime_dcache (struct dentry * parent , struct nfs_entry * entry )
460
+ void nfs_prime_dcache (struct dentry * parent , struct nfs_entry * entry ,
461
+ unsigned long dir_verifier )
459
462
{
460
463
struct qstr filename = QSTR_INIT (entry -> name , entry -> len );
461
464
DECLARE_WAIT_QUEUE_HEAD_ONSTACK (wq );
462
465
struct dentry * dentry ;
463
466
struct dentry * alias ;
464
- struct inode * dir = d_inode (parent );
465
467
struct inode * inode ;
466
468
int status ;
467
469
@@ -500,7 +502,7 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
500
502
if (nfs_same_file (dentry , entry )) {
501
503
if (!entry -> fh -> size )
502
504
goto out ;
503
- nfs_set_verifier (dentry , nfs_save_change_attribute ( dir ) );
505
+ nfs_set_verifier (dentry , dir_verifier );
504
506
status = nfs_refresh_inode (d_inode (dentry ), entry -> fattr );
505
507
if (!status )
506
508
nfs_setsecurity (d_inode (dentry ), entry -> fattr , entry -> label );
@@ -526,7 +528,7 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
526
528
dput (dentry );
527
529
dentry = alias ;
528
530
}
529
- nfs_set_verifier (dentry , nfs_save_change_attribute ( dir ) );
531
+ nfs_set_verifier (dentry , dir_verifier );
530
532
out :
531
533
dput (dentry );
532
534
}
@@ -564,7 +566,8 @@ int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *en
564
566
count ++ ;
565
567
566
568
if (desc -> plus )
567
- nfs_prime_dcache (file_dentry (desc -> file ), entry );
569
+ nfs_prime_dcache (file_dentry (desc -> file ), entry ,
570
+ desc -> dir_verifier );
568
571
569
572
status = nfs_readdir_add_to_array (entry , page );
570
573
if (status != 0 )
@@ -983,14 +986,113 @@ static int nfs_fsync_dir(struct file *filp, loff_t start, loff_t end,
983
986
* full lookup on all child dentries of 'dir' whenever a change occurs
984
987
* on the server that might have invalidated our dcache.
985
988
*
989
+ * Note that we reserve bit '0' as a tag to let us know when a dentry
990
+ * was revalidated while holding a delegation on its inode.
991
+ *
986
992
* The caller should be holding dir->i_lock
987
993
*/
988
994
void nfs_force_lookup_revalidate (struct inode * dir )
989
995
{
990
- NFS_I (dir )-> cache_change_attribute ++ ;
996
+ NFS_I (dir )-> cache_change_attribute += 2 ;
991
997
}
992
998
EXPORT_SYMBOL_GPL (nfs_force_lookup_revalidate );
993
999
1000
+ /**
1001
+ * nfs_verify_change_attribute - Detects NFS remote directory changes
1002
+ * @dir: pointer to parent directory inode
1003
+ * @verf: previously saved change attribute
1004
+ *
1005
+ * Return "false" if the verifiers doesn't match the change attribute.
1006
+ * This would usually indicate that the directory contents have changed on
1007
+ * the server, and that any dentries need revalidating.
1008
+ */
1009
+ static bool nfs_verify_change_attribute (struct inode * dir , unsigned long verf )
1010
+ {
1011
+ return (verf & ~1UL ) == nfs_save_change_attribute (dir );
1012
+ }
1013
+
1014
+ static void nfs_set_verifier_delegated (unsigned long * verf )
1015
+ {
1016
+ * verf |= 1UL ;
1017
+ }
1018
+
1019
+ #if IS_ENABLED (CONFIG_NFS_V4 )
1020
+ static void nfs_unset_verifier_delegated (unsigned long * verf )
1021
+ {
1022
+ * verf &= ~1UL ;
1023
+ }
1024
+ #endif /* IS_ENABLED(CONFIG_NFS_V4) */
1025
+
1026
+ static bool nfs_test_verifier_delegated (unsigned long verf )
1027
+ {
1028
+ return verf & 1 ;
1029
+ }
1030
+
1031
+ static bool nfs_verifier_is_delegated (struct dentry * dentry )
1032
+ {
1033
+ return nfs_test_verifier_delegated (dentry -> d_time );
1034
+ }
1035
+
1036
+ static void nfs_set_verifier_locked (struct dentry * dentry , unsigned long verf )
1037
+ {
1038
+ struct inode * inode = d_inode (dentry );
1039
+
1040
+ if (!nfs_verifier_is_delegated (dentry ) &&
1041
+ !nfs_verify_change_attribute (d_inode (dentry -> d_parent ), verf ))
1042
+ goto out ;
1043
+ if (inode && NFS_PROTO (inode )-> have_delegation (inode , FMODE_READ ))
1044
+ nfs_set_verifier_delegated (& verf );
1045
+ out :
1046
+ dentry -> d_time = verf ;
1047
+ }
1048
+
1049
+ /**
1050
+ * nfs_set_verifier - save a parent directory verifier in the dentry
1051
+ * @dentry: pointer to dentry
1052
+ * @verf: verifier to save
1053
+ *
1054
+ * Saves the parent directory verifier in @dentry. If the inode has
1055
+ * a delegation, we also tag the dentry as having been revalidated
1056
+ * while holding a delegation so that we know we don't have to
1057
+ * look it up again after a directory change.
1058
+ */
1059
+ void nfs_set_verifier (struct dentry * dentry , unsigned long verf )
1060
+ {
1061
+
1062
+ spin_lock (& dentry -> d_lock );
1063
+ nfs_set_verifier_locked (dentry , verf );
1064
+ spin_unlock (& dentry -> d_lock );
1065
+ }
1066
+ EXPORT_SYMBOL_GPL (nfs_set_verifier );
1067
+
1068
+ #if IS_ENABLED (CONFIG_NFS_V4 )
1069
+ /**
1070
+ * nfs_clear_verifier_delegated - clear the dir verifier delegation tag
1071
+ * @inode: pointer to inode
1072
+ *
1073
+ * Iterates through the dentries in the inode alias list and clears
1074
+ * the tag used to indicate that the dentry has been revalidated
1075
+ * while holding a delegation.
1076
+ * This function is intended for use when the delegation is being
1077
+ * returned or revoked.
1078
+ */
1079
+ void nfs_clear_verifier_delegated (struct inode * inode )
1080
+ {
1081
+ struct dentry * alias ;
1082
+
1083
+ if (!inode )
1084
+ return ;
1085
+ spin_lock (& inode -> i_lock );
1086
+ hlist_for_each_entry (alias , & inode -> i_dentry , d_u .d_alias ) {
1087
+ spin_lock (& alias -> d_lock );
1088
+ nfs_unset_verifier_delegated (& alias -> d_time );
1089
+ spin_unlock (& alias -> d_lock );
1090
+ }
1091
+ spin_unlock (& inode -> i_lock );
1092
+ }
1093
+ EXPORT_SYMBOL_GPL (nfs_clear_verifier_delegated );
1094
+ #endif /* IS_ENABLED(CONFIG_NFS_V4) */
1095
+
994
1096
/*
995
1097
* A check for whether or not the parent directory has changed.
996
1098
* In the case it has, we assume that the dentries are untrustworthy
@@ -1159,6 +1261,7 @@ nfs_lookup_revalidate_dentry(struct inode *dir, struct dentry *dentry,
1159
1261
struct nfs_fh * fhandle ;
1160
1262
struct nfs_fattr * fattr ;
1161
1263
struct nfs4_label * label ;
1264
+ unsigned long dir_verifier ;
1162
1265
int ret ;
1163
1266
1164
1267
ret = - ENOMEM ;
@@ -1168,6 +1271,7 @@ nfs_lookup_revalidate_dentry(struct inode *dir, struct dentry *dentry,
1168
1271
if (fhandle == NULL || fattr == NULL || IS_ERR (label ))
1169
1272
goto out ;
1170
1273
1274
+ dir_verifier = nfs_save_change_attribute (dir );
1171
1275
ret = NFS_PROTO (dir )-> lookup (dir , dentry , fhandle , fattr , label );
1172
1276
if (ret < 0 ) {
1173
1277
switch (ret ) {
@@ -1188,7 +1292,7 @@ nfs_lookup_revalidate_dentry(struct inode *dir, struct dentry *dentry,
1188
1292
goto out ;
1189
1293
1190
1294
nfs_setsecurity (inode , fattr , label );
1191
- nfs_set_verifier (dentry , nfs_save_change_attribute ( dir ) );
1295
+ nfs_set_verifier (dentry , dir_verifier );
1192
1296
1193
1297
/* set a readdirplus hint that we had a cache miss */
1194
1298
nfs_force_use_readdirplus (dir );
@@ -1230,7 +1334,7 @@ nfs_do_lookup_revalidate(struct inode *dir, struct dentry *dentry,
1230
1334
goto out_bad ;
1231
1335
}
1232
1336
1233
- if (NFS_PROTO ( dir ) -> have_delegation ( inode , FMODE_READ ))
1337
+ if (nfs_verifier_is_delegated ( dentry ))
1234
1338
return nfs_lookup_revalidate_delegated (dir , dentry , inode );
1235
1339
1236
1340
/* Force a full look up iff the parent directory has changed */
@@ -1415,6 +1519,7 @@ struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned in
1415
1519
struct nfs_fh * fhandle = NULL ;
1416
1520
struct nfs_fattr * fattr = NULL ;
1417
1521
struct nfs4_label * label = NULL ;
1522
+ unsigned long dir_verifier ;
1418
1523
int error ;
1419
1524
1420
1525
dfprintk (VFS , "NFS: lookup(%pd2)\n" , dentry );
@@ -1440,6 +1545,7 @@ struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned in
1440
1545
if (IS_ERR (label ))
1441
1546
goto out ;
1442
1547
1548
+ dir_verifier = nfs_save_change_attribute (dir );
1443
1549
trace_nfs_lookup_enter (dir , dentry , flags );
1444
1550
error = NFS_PROTO (dir )-> lookup (dir , dentry , fhandle , fattr , label );
1445
1551
if (error == - ENOENT )
@@ -1463,7 +1569,7 @@ struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned in
1463
1569
goto out_label ;
1464
1570
dentry = res ;
1465
1571
}
1466
- nfs_set_verifier (dentry , nfs_save_change_attribute ( dir ) );
1572
+ nfs_set_verifier (dentry , dir_verifier );
1467
1573
out_label :
1468
1574
trace_nfs_lookup_exit (dir , dentry , flags , error );
1469
1575
nfs4_label_free (label );
@@ -1668,7 +1774,7 @@ nfs4_do_lookup_revalidate(struct inode *dir, struct dentry *dentry,
1668
1774
if (inode == NULL )
1669
1775
goto full_reval ;
1670
1776
1671
- if (NFS_PROTO ( dir ) -> have_delegation ( inode , FMODE_READ ))
1777
+ if (nfs_verifier_is_delegated ( dentry ))
1672
1778
return nfs_lookup_revalidate_delegated (dir , dentry , inode );
1673
1779
1674
1780
/* NFS only supports OPEN on regular files */
0 commit comments