Merge tag 'afs-fixes-20230502' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs
Pull AFS updates from David Howells:
"Three fixes to AFS directory handling:
- Make sure that afs_read_dir() sees any increase in file size if the
file unexpectedly changed on the server (e.g. due to another client
making a change).
- Make afs_getattr() always return the server's dir file size, not
the locally edited one, so that pagecache eviction doesn't cause
the dir file size to change unexpectedly.
- Prevent afs_read_dir() from getting into an endless loop if the
server indicates that the directory file size is larger than
expected"
* tag 'afs-fixes-20230502' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs:
afs: Avoid endless loop if file is larger than expected
afs: Fix getattr to report server i_size on dirs, not local size
afs: Fix updating of i_size with dv jump from server
This commit is contained in:
@@ -275,6 +275,7 @@ static struct afs_read *afs_read_dir(struct afs_vnode *dvnode, struct key *key)
|
||||
loff_t i_size;
|
||||
int nr_pages, i;
|
||||
int ret;
|
||||
loff_t remote_size = 0;
|
||||
|
||||
_enter("");
|
||||
|
||||
@@ -289,6 +290,8 @@ static struct afs_read *afs_read_dir(struct afs_vnode *dvnode, struct key *key)
|
||||
|
||||
expand:
|
||||
i_size = i_size_read(&dvnode->netfs.inode);
|
||||
if (i_size < remote_size)
|
||||
i_size = remote_size;
|
||||
if (i_size < 2048) {
|
||||
ret = afs_bad(dvnode, afs_file_error_dir_small);
|
||||
goto error;
|
||||
@@ -364,6 +367,7 @@ expand:
|
||||
* buffer.
|
||||
*/
|
||||
up_write(&dvnode->validate_lock);
|
||||
remote_size = req->file_size;
|
||||
goto expand;
|
||||
}
|
||||
|
||||
|
||||
+9
-1
@@ -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
|
||||
@@ -449,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
|
||||
}
|
||||
|
||||
@@ -776,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);
|
||||
|
||||
Reference in New Issue
Block a user