[PATCH v3 23/33] afs: Use netfslib for directories
David Howells
dhowells at redhat.com
Sat Nov 9 04:23:10 AEDT 2024
The attached fix needs folding in across this patch (23), patch 24, patch
29 and patch 31.
David
---
commit 9d4429bc7bb3f2b518d6decd1ca0e99e4d80d58e
Author: David Howells <dhowells at redhat.com>
Date: Thu Nov 7 23:46:48 2024 +0000
afs: Fix handling of signals during readdir
When a directory is being read, whether or not the dvnode->directory buffer
pointer is NULL is used to track whether we've checked fscache yet.
However, if a signal occurs after the buffer being allocated but whilst
we're doing the read, we may end up in an invalid state with ->directory
set but no data in the buffer.
In this state, afs_readdir(), afs_lookup() and afs_d_revalidate() see
corrupt directory contents leading to a variety of malfunctions.
Fix this by providing a specific flag to record whether or not we've
performed a read yet - and, incidentally, sampled fscache - rather than
using the value in ->directory instead.
Signed-off-by: David Howells <dhowells at redhat.com>
cc: Marc Dionne <marc.dionne at auristor.com>
cc: linux-afs at lists.infradead.org
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index 663a212964d8..b6a202fd9926 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -323,7 +323,7 @@ ssize_t afs_read_dir(struct afs_vnode *dvnode, struct file *file)
* haven't read it yet.
*/
if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags) &&
- dvnode->directory) {
+ test_bit(AFS_VNODE_DIR_READ, &dvnode->flags)) {
ret = i_size;
goto valid;
}
@@ -336,7 +336,7 @@ ssize_t afs_read_dir(struct afs_vnode *dvnode, struct file *file)
afs_invalidate_cache(dvnode, 0);
if (!test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags) ||
- !dvnode->directory) {
+ !test_bit(AFS_VNODE_DIR_READ, &dvnode->flags)) {
trace_afs_reload_dir(dvnode);
ret = afs_read_single(dvnode, file);
if (ret < 0)
@@ -345,6 +345,7 @@ ssize_t afs_read_dir(struct afs_vnode *dvnode, struct file *file)
// TODO: Trim excess pages
set_bit(AFS_VNODE_DIR_VALID, &dvnode->flags);
+ set_bit(AFS_VNODE_DIR_READ, &dvnode->flags);
} else {
ret = i_size;
}
diff --git a/fs/afs/dir_edit.c b/fs/afs/dir_edit.c
index f6f4b1adc8dc..60a549f1d9c5 100644
--- a/fs/afs/dir_edit.c
+++ b/fs/afs/dir_edit.c
@@ -644,4 +644,5 @@ void afs_mkdir_init_dir(struct afs_vnode *dvnode, struct afs_vnode *parent_dvnod
netfs_single_mark_inode_dirty(&dvnode->netfs.inode);
set_bit(AFS_VNODE_DIR_VALID, &dvnode->flags);
+ set_bit(AFS_VNODE_DIR_READ, &dvnode->flags);
}
diff --git a/fs/afs/inode.c b/fs/afs/inode.c
index f5618564b3fc..e9538e91f848 100644
--- a/fs/afs/inode.c
+++ b/fs/afs/inode.c
@@ -39,6 +39,7 @@ void afs_init_new_symlink(struct afs_vnode *vnode, struct afs_operation *op)
p = kmap_local_folio(folioq_folio(vnode->directory, 0), 0);
memcpy(p, op->create.symlink, size);
kunmap_local(p);
+ set_bit(AFS_VNODE_DIR_READ, &vnode->flags);
netfs_single_mark_inode_dirty(&vnode->netfs.inode);
}
@@ -60,12 +61,12 @@ const char *afs_get_link(struct dentry *dentry, struct inode *inode,
if (!dentry) {
/* RCU pathwalk. */
- if (!vnode->directory || !afs_check_validity(vnode))
+ if (!test_bit(AFS_VNODE_DIR_READ, &vnode->flags) || !afs_check_validity(vnode))
return ERR_PTR(-ECHILD);
goto good;
}
- if (!vnode->directory)
+ if (test_bit(AFS_VNODE_DIR_READ, &vnode->flags))
goto fetch;
ret = afs_validate(vnode, NULL);
@@ -73,13 +74,14 @@ const char *afs_get_link(struct dentry *dentry, struct inode *inode,
return ERR_PTR(ret);
if (!test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags) &&
- vnode->directory)
+ test_bit(AFS_VNODE_DIR_READ, &vnode->flags))
goto good;
fetch:
ret = afs_read_single(vnode, NULL);
if (ret < 0)
return ERR_PTR(ret);
+ set_bit(AFS_VNODE_DIR_READ, &vnode->flags);
good:
folio = folioq_folio(vnode->directory, 0);
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index a5da0dd8e9cc..90f407774a9a 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -705,6 +705,7 @@ struct afs_vnode {
#define AFS_VNODE_NEW_CONTENT 8 /* Set if file has new content (create/trunc-0) */
#define AFS_VNODE_SILLY_DELETED 9 /* Set if file has been silly-deleted */
#define AFS_VNODE_MODIFYING 10 /* Set if we're performing a modification op */
+#define AFS_VNODE_DIR_READ 11 /* Set if we've read a dir's contents */
struct folio_queue *directory; /* Directory contents */
struct list_head wb_keys; /* List of keys available for writeback */
More information about the Linux-erofs
mailing list