Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5e7f2337 authored by Anton Blanchard's avatar Anton Blanchard Committed by Al Viro
Browse files

afs: afs_fill_page reads too much, or wrong data



afs_fill_page should read the page that is about to be written but
the current implementation has a number of issues. If we aren't
extending the file we always read PAGE_CACHE_SIZE at offset 0. If we
are extending the file we try to read the entire file.

Change afs_fill_page to read PAGE_CACHE_SIZE at the right offset,
clamped to i_size.

While here, avoid calling afs_fill_page when we are doing a
PAGE_CACHE_SIZE write.

Signed-off-by: default avatarAnton Blanchard <anton@samba.org>
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 8aef1884
Loading
Loading
Loading
Loading
+9 −12
Original line number Diff line number Diff line
@@ -84,23 +84,21 @@ void afs_put_writeback(struct afs_writeback *wb)
 * partly or wholly fill a page that's under preparation for writing
 */
static int afs_fill_page(struct afs_vnode *vnode, struct key *key,
			 loff_t pos, unsigned len, struct page *page)
			 loff_t pos, struct page *page)
{
	loff_t i_size;
	unsigned eof;
	int ret;
	int len;

	_enter(",,%llu,%u", (unsigned long long)pos, len);

	ASSERTCMP(len, <=, PAGE_CACHE_SIZE);
	_enter(",,%llu", (unsigned long long)pos);

	i_size = i_size_read(&vnode->vfs_inode);
	if (pos + len > i_size)
		eof = i_size;
	if (pos + PAGE_CACHE_SIZE > i_size)
		len = i_size - pos;
	else
		eof = PAGE_CACHE_SIZE;
		len = PAGE_CACHE_SIZE;

	ret = afs_vnode_fetch_data(vnode, key, 0, eof, page);
	ret = afs_vnode_fetch_data(vnode, key, pos, len, page);
	if (ret < 0) {
		if (ret == -ENOENT) {
			_debug("got NOENT from server"
@@ -153,9 +151,8 @@ int afs_write_begin(struct file *file, struct address_space *mapping,
	*pagep = page;
	/* page won't leak in error case: it eventually gets cleaned off LRU */

	if (!PageUptodate(page)) {
		_debug("not up to date");
		ret = afs_fill_page(vnode, key, pos, len, page);
	if (!PageUptodate(page) && len != PAGE_CACHE_SIZE) {
		ret = afs_fill_page(vnode, key, index << PAGE_CACHE_SHIFT, page);
		if (ret < 0) {
			kfree(candidate);
			_leave(" = %d [prep]", ret);