Skip to content

Commit 5f8fe0e

Browse files
Abhi DasLinuxMinion
authored andcommitted
fs: __generic_file_splice_read retry lookup on AOP_TRUNCATED_PAGE
Orabug: 26797298 During testing, I discovered that __generic_file_splice_read() returns 0 (EOF) when aops->readpage fails with AOP_TRUNCATED_PAGE on the first page of a single/multi-page splice read operation. This EOF return code causes the userspace test to (correctly) report a zero-length read error when it was expecting otherwise. The current strategy of returning a partial non-zero read when ->readpage returns AOP_TRUNCATED_PAGE works only when the failed page is not the first of the lot being processed. This patch attempts to retry lookup and call ->readpage again on pages that had previously failed with AOP_TRUNCATED_PAGE. With this patch, my tests pass and I haven't noticed any unwanted side effects. This version removes the thrice-retry loop and instead indefinitely retries lookups on AOP_TRUNCATED_PAGE errors from ->readpage. This behavior is now similar to do_generic_file_read(). Signed-off-by: Abhi Das <[email protected]> Reviewed-by: Jan Kara <[email protected]> Cc: Bob Peterson <[email protected]> Cc: Al Viro <[email protected]> Signed-off-by: Al Viro <[email protected]> AOP_TRUNCATED_PAGE is not used much in the kernel now, but ocfs2 uses it to avoid deadlocks. Specifically, ocfs2_readpage() fails the read and returns AOP_TRUNCATED_PAGE in order to avoid deadlock on page lock with the downconvert thread, if it fails to get the inode cluster lock. It also uses this return value to avoid livelock on the ip_alloc_sem semaphore. This is done with the expectation that the VFS will check for this return value and retry the read on the page and do_generic_file_read() does exactly this. However, in case of splice read, __generic_file_splice_read() fails the read and returns a partial/zero-length read back. This causes upper layers that use splice read (such as nfs) to return EIO or other failures to userspace. Saar ran into this issue while testing database workloads over knfs with ocfs2 as the backend fs on the nfs server. This issue is fixed with this patch in place. (cherrypicked from commit 90330e6) Tested-by: Saar Maoz <[email protected]> Signed-off-by: Ashish Samant <[email protected]> Reviewed-by: Junxiao Bi <[email protected]>
1 parent 42d45fe commit 5f8fe0e

File tree

1 file changed

+3
-5
lines changed

1 file changed

+3
-5
lines changed

fs/splice.c

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,7 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
417417
*/
418418
if (!page->mapping) {
419419
unlock_page(page);
420+
retry_lookup:
420421
page = find_or_create_page(mapping, index,
421422
mapping_gfp_mask(mapping));
422423

@@ -441,13 +442,10 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
441442
error = mapping->a_ops->readpage(in, page);
442443
if (unlikely(error)) {
443444
/*
444-
* We really should re-lookup the page here,
445-
* but it complicates things a lot. Instead
446-
* lets just do what we already stored, and
447-
* we'll get it the next time we are called.
445+
* Re-lookup the page
448446
*/
449447
if (error == AOP_TRUNCATED_PAGE)
450-
error = 0;
448+
goto retry_lookup;
451449

452450
break;
453451
}

0 commit comments

Comments
 (0)