Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'netfs-fixes-20210621' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs

Pull netfs fixes from David Howells:
"This contains patches to fix netfs_write_begin() and afs_write_end()
in the following ways:

(1) In netfs_write_begin(), extract the decision about whether to skip
a page out to its own helper and have that clear around the region
to be written, but not clear that region. This requires the
filesystem to patch it up afterwards if the hole doesn't get
completely filled.

(2) Use offset_in_thp() in (1) rather than manually calculating the
offset into the page.

(3) Due to (1), afs_write_end() now needs to handle short data write
into the page by generic_perform_write(). I've adopted an
analogous approach to ceph of just returning 0 in this case and
letting the caller go round again.

It also adds a note that (in the future) the len parameter may extend
beyond the page allocated. This is because the page allocation is
deferred to write_begin() and that gets to decide what size of THP to
allocate."

Jeff Layton points out:
"The netfs fix in particular fixes a data corruption bug in cephfs"

* tag 'netfs-fixes-20210621' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs:
netfs: fix test for whether we can skip read when writing beyond EOF
afs: Fix afs_write_end() to handle short writes

+45 -15
+9 -2
fs/afs/write.c
··· 118 118 _enter("{%llx:%llu},{%lx}", 119 119 vnode->fid.vid, vnode->fid.vnode, page->index); 120 120 121 + if (!PageUptodate(page)) { 122 + if (copied < len) { 123 + copied = 0; 124 + goto out; 125 + } 126 + 127 + SetPageUptodate(page); 128 + } 129 + 121 130 if (copied == 0) 122 131 goto out; 123 132 ··· 140 131 i_size_write(&vnode->vfs_inode, maybe_i_size); 141 132 write_sequnlock(&vnode->cb_lock); 142 133 } 143 - 144 - ASSERT(PageUptodate(page)); 145 134 146 135 if (PagePrivate(page)) { 147 136 priv = page_private(page);
+36 -13
fs/netfs/read_helper.c
··· 1011 1011 } 1012 1012 EXPORT_SYMBOL(netfs_readpage); 1013 1013 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) 1015 1029 { 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); 1017 1033 1018 - for (i = 0; i < thp_nr_pages(page); i++) 1019 - clear_highpage(page + i); 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; 1045 + 1046 + return false; 1047 + zero_out: 1048 + zero_user_segments(page, 0, offset, offset + len, thp_size(page)); 1049 + return true; 1020 1050 } 1021 1051 1022 1052 /** ··· 1054 1024 * @file: The file to read from 1055 1025 * @mapping: The mapping to read from 1056 1026 * @pos: File position at which the write will begin 1057 - * @len: The length of the write in this page 1027 + * @len: The length of the write (may extend beyond the end of the page chosen) 1058 1028 * @flags: AOP_* flags 1059 1029 * @_page: Where to put the resultant page 1060 1030 * @_fsdata: Place for the netfs to store a cookie ··· 1091 1061 struct inode *inode = file_inode(file); 1092 1062 unsigned int debug_index = 0; 1093 1063 pgoff_t index = pos >> PAGE_SHIFT; 1094 - int pos_in_page = pos & ~PAGE_MASK; 1095 - loff_t size; 1096 1064 int ret; 1097 1065 1098 1066 DEFINE_READAHEAD(ractl, file, NULL, mapping, index); ··· 1118 1090 * within the cache granule containing the EOF, in which case we need 1119 1091 * to preload the granule. 1120 1092 */ 1121 - size = i_size_read(inode); 1122 1093 if (!ops->is_cache_enabled(inode) && 1123 - ((pos_in_page == 0 && len == thp_size(page)) || 1124 - (pos >= size) || 1125 - (pos_in_page == 0 && (pos + len) >= size))) { 1126 - netfs_clear_thp(page); 1127 - SetPageUptodate(page); 1094 + netfs_skip_page_read(page, pos, len)) { 1128 1095 netfs_stat(&netfs_n_rh_write_zskip); 1129 1096 goto have_page_no_wait; 1130 1097 }