Skip to content

Commit 827a746

Browse files
jtlaytondhowells
authored andcommitted
netfs: fix test for whether we can skip read when writing beyond EOF
It's not sufficient to skip reading when the pos is beyond the EOF. There may be data at the head of the page that we need to fill in before the write. Add a new helper function that corrects and clarifies the logic of when we can skip reads, and have it only zero out the part of the page that won't have data copied in for the write. Finally, don't set the page Uptodate after zeroing. It's not up to date since the write data won't have been copied in yet. [DH made the following changes: - Prefixed the new function with "netfs_". - Don't call zero_user_segments() for a full-page write. - Altered the beyond-last-page check to avoid a DIV instruction and got rid of then-redundant zero-length file check. ] Fixes: e1b1240 ("netfs: Add write_begin helper") Reported-by: Andrew W Elble <[email protected]> Signed-off-by: Jeff Layton <[email protected]> Signed-off-by: David Howells <[email protected]> Reviewed-by: Matthew Wilcox (Oracle) <[email protected]> cc: [email protected] Link: https://lore.kernel.org/r/[email protected]/ Link: https://lore.kernel.org/r/162367683365.460125.4467036947364047314.stgit@warthog.procyon.org.uk/ # v1 Link: https://lore.kernel.org/r/162391826758.1173366.11794946719301590013.stgit@warthog.procyon.org.uk/ # v2
1 parent 66e9c6a commit 827a746

File tree

1 file changed

+36
-13
lines changed

1 file changed

+36
-13
lines changed

fs/netfs/read_helper.c

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1011,20 +1011,50 @@ int netfs_readpage(struct file *file,
10111011
}
10121012
EXPORT_SYMBOL(netfs_readpage);
10131013

1014-
static void netfs_clear_thp(struct page *page)
1014+
/**
1015+
* netfs_skip_page_read - prep a page for writing without reading first
1016+
* @page: page being prepared
1017+
* @pos: starting position for the write
1018+
* @len: length of write
1019+
*
1020+
* In some cases, write_begin doesn't need to read at all:
1021+
* - full page write
1022+
* - write that lies in a page that is completely beyond EOF
1023+
* - write that covers the the page from start to EOF or beyond it
1024+
*
1025+
* If any of these criteria are met, then zero out the unwritten parts
1026+
* of the page and return true. Otherwise, return false.
1027+
*/
1028+
static bool netfs_skip_page_read(struct page *page, loff_t pos, size_t len)
10151029
{
1016-
unsigned int i;
1030+
struct inode *inode = page->mapping->host;
1031+
loff_t i_size = i_size_read(inode);
1032+
size_t offset = offset_in_thp(page, pos);
1033+
1034+
/* Full page write */
1035+
if (offset == 0 && len >= thp_size(page))
1036+
return true;
1037+
1038+
/* pos beyond last page in the file */
1039+
if (pos - offset >= i_size)
1040+
goto zero_out;
1041+
1042+
/* Write that covers from the start of the page to EOF or beyond */
1043+
if (offset == 0 && (pos + len) >= i_size)
1044+
goto zero_out;
10171045

1018-
for (i = 0; i < thp_nr_pages(page); i++)
1019-
clear_highpage(page + i);
1046+
return false;
1047+
zero_out:
1048+
zero_user_segments(page, 0, offset, offset + len, thp_size(page));
1049+
return true;
10201050
}
10211051

10221052
/**
10231053
* netfs_write_begin - Helper to prepare for writing
10241054
* @file: The file to read from
10251055
* @mapping: The mapping to read from
10261056
* @pos: File position at which the write will begin
1027-
* @len: The length of the write in this page
1057+
* @len: The length of the write (may extend beyond the end of the page chosen)
10281058
* @flags: AOP_* flags
10291059
* @_page: Where to put the resultant page
10301060
* @_fsdata: Place for the netfs to store a cookie
@@ -1061,8 +1091,6 @@ int netfs_write_begin(struct file *file, struct address_space *mapping,
10611091
struct inode *inode = file_inode(file);
10621092
unsigned int debug_index = 0;
10631093
pgoff_t index = pos >> PAGE_SHIFT;
1064-
int pos_in_page = pos & ~PAGE_MASK;
1065-
loff_t size;
10661094
int ret;
10671095

10681096
DEFINE_READAHEAD(ractl, file, NULL, mapping, index);
@@ -1090,13 +1118,8 @@ int netfs_write_begin(struct file *file, struct address_space *mapping,
10901118
* within the cache granule containing the EOF, in which case we need
10911119
* to preload the granule.
10921120
*/
1093-
size = i_size_read(inode);
10941121
if (!ops->is_cache_enabled(inode) &&
1095-
((pos_in_page == 0 && len == thp_size(page)) ||
1096-
(pos >= size) ||
1097-
(pos_in_page == 0 && (pos + len) >= size))) {
1098-
netfs_clear_thp(page);
1099-
SetPageUptodate(page);
1122+
netfs_skip_page_read(page, pos, len)) {
11001123
netfs_stat(&netfs_n_rh_write_zskip);
11011124
goto have_page_no_wait;
11021125
}

0 commit comments

Comments
 (0)