summary refs log tree commit diff
path: root/fs/afs/file.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2017-03-16 16:27:44 +0000
committerDavid Howells <dhowells@redhat.com>2017-03-16 16:27:44 +0000
commit6db3ac3c4bc552837d232ec794559a2fae2815a0 (patch)
tree3d6a01c735e66fd6e597eba738321b91c2160ef1 /fs/afs/file.c
parentbcd89270d93b7edebb5de5e5e7dca1a77a33496e (diff)
downloadlinux-6db3ac3c4bc552837d232ec794559a2fae2815a0.tar.gz
afs: Handle better the server returning excess or short data
When an AFS server is given an FS.FetchData{,64} request to read data from
a file, it is permitted by the protocol to return more or less than was
requested.  kafs currently relies on the latter behaviour in readpage{,s}
to handle a partial page at the end of the file (we just ask for a whole
page and clear space beyond the short read).

However, we don't handle all cases.  Add:

 (1) Handle excess data by discarding it rather than aborting.  Note that
     we use a common static buffer to discard into so that the decryption
     algorithm advances the PCBC state.

 (2) Handle a short read that affects more than just the last page.

Note that if a read comes up unexpectedly short of long, it's possible that
the server's copy of the file changed - in which case the data version
number will have been incremented and the callback will have been broken -
in which case all the pages currently attached to the inode will be zapped
anyway at some point.

Signed-off-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'fs/afs/file.c')
-rw-r--r--fs/afs/file.c7
1 files changed, 5 insertions, 2 deletions
diff --git a/fs/afs/file.c b/fs/afs/file.c
index ba7b71fba34b..a38e1c30d110 100644
--- a/fs/afs/file.c
+++ b/fs/afs/file.c
@@ -184,10 +184,13 @@ int afs_page_filler(void *data, struct page *page)
 		if (!req)
 			goto enomem;
 
+		/* We request a full page.  If the page is a partial one at the
+		 * end of the file, the server will return a short read and the
+		 * unmarshalling code will clear the unfilled space.
+		 */
 		atomic_set(&req->usage, 1);
 		req->pos = (loff_t)page->index << PAGE_SHIFT;
-		req->len = min_t(size_t, i_size_read(inode) - req->pos,
-				 PAGE_SIZE);
+		req->len = PAGE_SIZE;
 		req->nr_pages = 1;
 		req->pages[0] = page;
 		get_page(page);