Commit 21d2be64 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
parents d7b3ffe2 9ea4eff4
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -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 @@ static struct afs_read *afs_read_dir(struct afs_vnode *dvnode, struct key *key)
			 * buffer.
			 */
			up_write(&dvnode->validate_lock);
			remote_size = req->file_size;
			goto expand;
		}

+9 −1
Original line number Diff line number Diff line
@@ -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);