Skip to content

Commit b74c02a

Browse files
dhowellsbrauner
authored andcommitted
afs: Fix occasional rmdir-then-VNOVNODE with generic/011
Sometimes generic/011 causes kafs to follow up an FS.RemoveDir RPC call by spending around a second sending a slew of FS.FetchStatus RPC calls to the directory just deleted that then abort with VNOVNODE, indicating deletion of the target directory. This seems to stem from userspace attempting to stat the directory or something in it: afs_select_fileserver+0x46d/0xaa2 afs_wait_for_operation+0x12/0x17e afs_fetch_status+0x56/0x75 afs_validate+0xfb/0x240 afs_permission+0xef/0x1b0 inode_permission+0x90/0x139 link_path_walk.part.0.constprop.0+0x6f/0x2f0 path_lookupat+0x4c/0xfa filename_lookup+0x63/0xd7 vfs_statx+0x62/0x13f vfs_fstatat+0x72/0x8a The issue appears to be that afs_dir_remove_subdir() marks the callback promise as being cancelled by setting the expiry time to AFS_NO_CB_PROMISE - which then confuses afs_validate() which sends the FetchStatus to try and get a new one before it checks for the AFS_VNODE_DELETED flag which indicates that we know the directory got deleted. Fix this by: (1) Make afs_check_validity() return true if AFS_VNODE_DELETED is set, and then tweak the return from afs_validate() if the DELETED flag is set. (2) Move the AFS_VNODE_DELETED check in afs_validate() up above the expiration check to immediately after we've grabbed the validate_lock. Fixes: 453924d ("afs: Overhaul invalidation handling to better support RO volumes") Signed-off-by: David Howells <dhowells@redhat.com> Link: https://lore.kernel.org/r/20240313081505.3060173-3-dhowells@redhat.com Reviewed-by: Marc Dionne <marc.dionne@auristor.com> cc: Marc Dionne <marc.dionne@auristor.com> cc: linux-afs@lists.infradead.org Signed-off-by: Christian Brauner <brauner@kernel.org>
1 parent 83505bd commit b74c02a

File tree

1 file changed

+9
-7
lines changed

1 file changed

+9
-7
lines changed

fs/afs/validation.c

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,9 @@ bool afs_check_validity(const struct afs_vnode *vnode)
122122
const struct afs_volume *volume = vnode->volume;
123123
time64_t deadline = ktime_get_real_seconds() + 10;
124124

125+
if (test_bit(AFS_VNODE_DELETED, &vnode->flags))
126+
return true;
127+
125128
if (atomic_read(&volume->cb_v_check) != atomic_read(&volume->cb_v_break) ||
126129
atomic64_read(&vnode->cb_expires_at) <= deadline ||
127130
volume->cb_expires_at <= deadline ||
@@ -389,12 +392,17 @@ int afs_validate(struct afs_vnode *vnode, struct key *key)
389392
key_serial(key));
390393

391394
if (afs_check_validity(vnode))
392-
return 0;
395+
return test_bit(AFS_VNODE_DELETED, &vnode->flags) ? -ESTALE : 0;
393396

394397
ret = down_write_killable(&vnode->validate_lock);
395398
if (ret < 0)
396399
goto error;
397400

401+
if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) {
402+
ret = -ESTALE;
403+
goto error_unlock;
404+
}
405+
398406
/* Validate a volume after the v_break has changed or the volume
399407
* callback expired. We only want to do this once per volume per
400408
* v_break change. The actual work will be done when parsing the
@@ -448,12 +456,6 @@ int afs_validate(struct afs_vnode *vnode, struct key *key)
448456
vnode->cb_ro_snapshot = cb_ro_snapshot;
449457
vnode->cb_scrub = cb_scrub;
450458

451-
if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) {
452-
_debug("file already deleted");
453-
ret = -ESTALE;
454-
goto error_unlock;
455-
}
456-
457459
/* if the vnode's data version number changed then its contents are
458460
* different */
459461
zap |= test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags);

0 commit comments

Comments
 (0)