From 0050d7f5ee532f92e8ab1efcec6547bfac527973 Mon Sep 17 00:00:00 2001 From: "Matthew Wilcox (Oracle)" Date: Mon, 27 Mar 2023 18:45:14 +0100 Subject: afs: split afs_pagecache_valid() out of afs_validate() For the map_pages() method, we need a test that does not sleep. The page fault handler will continue to call the fault() method where we can sleep and do the full revalidation there. Link: https://lkml.kernel.org/r/20230327174515.1811532-3-willy@infradead.org Signed-off-by: Matthew Wilcox (Oracle) Acked-by: David Howells Tested-by: David Howells Cc: Darrick J. Wong Cc: Dave Chinner Signed-off-by: Andrew Morton --- fs/afs/inode.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) (limited to 'fs/afs/inode.c') diff --git a/fs/afs/inode.c b/fs/afs/inode.c index 0167e96e5198..b1bdffd5e888 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c @@ -667,6 +667,24 @@ bool afs_check_validity(struct afs_vnode *vnode) return false; } +/* + * Returns true if the pagecache is still valid. Does not sleep. + */ +bool afs_pagecache_valid(struct afs_vnode *vnode) +{ + if (unlikely(test_bit(AFS_VNODE_DELETED, &vnode->flags))) { + if (vnode->netfs.inode.i_nlink) + clear_nlink(&vnode->netfs.inode); + return true; + } + + if (test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags) && + afs_check_validity(vnode)) + return true; + + return false; +} + /* * validate a vnode/inode * - there are several things we need to check @@ -684,14 +702,7 @@ int afs_validate(struct afs_vnode *vnode, struct key *key) vnode->fid.vid, vnode->fid.vnode, vnode->flags, key_serial(key)); - if (unlikely(test_bit(AFS_VNODE_DELETED, &vnode->flags))) { - if (vnode->netfs.inode.i_nlink) - clear_nlink(&vnode->netfs.inode); - goto valid; - } - - if (test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags) && - afs_check_validity(vnode)) + if (afs_pagecache_valid(vnode)) goto valid; down_write(&vnode->validate_lock); -- cgit v1.2.3 From d7f74e9a917503ee78f2b603a456d7227cf38919 Mon Sep 17 00:00:00 2001 From: Marc Dionne Date: Fri, 2 Dec 2022 10:07:01 -0400 Subject: afs: Fix updating of i_size with dv jump from server If the data version returned from the server is larger than expected, the local data is invalidated, but we may still want to note the remote file size. Since we're setting change_size, we have to also set data_changed for the i_size to get updated. Fixes: 3f4aa9818163 ("afs: Fix EOF corruption") Signed-off-by: Marc Dionne Signed-off-by: David Howells cc: linux-afs@lists.infradead.org --- fs/afs/inode.c | 1 + 1 file changed, 1 insertion(+) (limited to 'fs/afs/inode.c') diff --git a/fs/afs/inode.c b/fs/afs/inode.c index b1bdffd5e888..82edd3351734 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c @@ -230,6 +230,7 @@ static void afs_apply_status(struct afs_operation *op, set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags); } change_size = true; + data_changed = true; } else if (vnode->status.type == AFS_FTYPE_DIR) { /* Expected directory change is handled elsewhere so * that we can locally edit the directory and save on a -- cgit v1.2.3 From 45f66fa03ba9943cca5af88d691399332b8bde08 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 6 Dec 2022 13:49:42 +0000 Subject: afs: Fix getattr to report server i_size on dirs, not local size Fix afs_getattr() to report the server's idea of the file size of a directory rather than the local size. The local size may differ as we edit the local copy to avoid having to redownload it and we may end up with a differently structured blob of a different size. However, if the directory is discarded from the pagecache we then download it again and the user may see the directory file size apparently change. Fixes: 63a4681ff39c ("afs: Locally edit directory data for mkdir/create/unlink/...") Signed-off-by: David Howells cc: Marc Dionne cc: linux-afs@lists.infradead.org --- fs/afs/inode.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'fs/afs/inode.c') diff --git a/fs/afs/inode.c b/fs/afs/inode.c index 82edd3351734..866bab860a88 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c @@ -450,7 +450,7 @@ static void afs_get_inode_cache(struct afs_vnode *vnode) 0 : FSCACHE_ADV_SINGLE_CHUNK, &key, sizeof(key), &aux, sizeof(aux), - vnode->status.size)); + i_size_read(&vnode->netfs.inode))); #endif } @@ -777,6 +777,13 @@ int afs_getattr(struct mnt_idmap *idmap, const struct path *path, if (test_bit(AFS_VNODE_SILLY_DELETED, &vnode->flags) && stat->nlink > 0) stat->nlink -= 1; + + /* Lie about the size of directories. We maintain a locally + * edited copy and may make different allocation decisions on + * it, but we need to give userspace the server's size. + */ + if (S_ISDIR(inode->i_mode)) + stat->size = vnode->netfs.remote_i_size; } while (need_seqretry(&vnode->cb_lock, seq)); done_seqretry(&vnode->cb_lock, seq); -- cgit v1.2.3