diff mbox series

[1/3] afs: Handle len being extending over page end in write_begin/write_end

Message ID 162367681795.460125.11729955608839747375.stgit@warthog.procyon.org.uk (mailing list archive)
State New, archived
Headers show
Series [1/3] afs: Handle len being extending over page end in write_begin/write_end | expand

Commit Message

David Howells June 14, 2021, 1:20 p.m. UTC
With transparent huge pages, in the future, write_begin() and write_end()
may be passed a length parameter that, in combination with the offset into
the page, exceeds the length of that page.  This allows
grab_cache_page_write_begin() to better choose the size of THP to allocate.

Fix afs's functions to handle this by trimming the length as needed after
the page has been allocated.

Fixes: e1b1240c1ff5 ("netfs: Add write_begin helper")
Reported-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Signed-off-by: David Howells <dhowells@redhat.com>
cc: linux-afs@lists.infradead.org
---

 fs/afs/write.c |   11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

Comments

kernel test robot June 17, 2021, 7:43 a.m. UTC | #1
Hi David,

I love your patch! Perhaps something to improve:

[auto build test WARNING on linus/master]
[also build test WARNING on v5.13-rc6 next-20210616]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/David-Howells/afs-Handle-len-being-extending-over-page-end-in-write_begin-write_end/20210617-091000
base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 70585216fe7730d9fb5453d3e2804e149d0fe201
config: arc-allyesconfig (attached as .config)
compiler: arceb-elf-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/d5cb85d0ca85764a811baaf4baca5f1890476434
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review David-Howells/afs-Handle-len-being-extending-over-page-end-in-write_begin-write_end/20210617-091000
        git checkout d5cb85d0ca85764a811baaf4baca5f1890476434
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=arc 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   fs/afs/write.c: In function 'afs_write_begin':
>> fs/afs/write.c:40:10: warning: variable 'index' set but not used [-Wunused-but-set-variable]
      40 |  pgoff_t index;
         |          ^~~~~


vim +/index +40 fs/afs/write.c

31143d5d515ece David Howells   2007-05-09   26  
31143d5d515ece David Howells   2007-05-09   27  /*
d5cb85d0ca8576 David Howells   2021-06-14   28   * Prepare to perform part of a write to a page.  Note that len may extend
d5cb85d0ca8576 David Howells   2021-06-14   29   * beyond the end of the page.
31143d5d515ece David Howells   2007-05-09   30   */
15b4650e55e06d Nicholas Piggin 2008-10-15   31  int afs_write_begin(struct file *file, struct address_space *mapping,
15b4650e55e06d Nicholas Piggin 2008-10-15   32  		    loff_t pos, unsigned len, unsigned flags,
21db2cdc667f74 David Howells   2020-10-22   33  		    struct page **_page, void **fsdata)
31143d5d515ece David Howells   2007-05-09   34  {
496ad9aa8ef448 Al Viro         2013-01-23   35  	struct afs_vnode *vnode = AFS_FS_I(file_inode(file));
15b4650e55e06d Nicholas Piggin 2008-10-15   36  	struct page *page;
4343d00872e1de David Howells   2017-11-02   37  	unsigned long priv;
e87b03f5830ecd David Howells   2020-10-20   38  	unsigned f, from;
e87b03f5830ecd David Howells   2020-10-20   39  	unsigned t, to;
e87b03f5830ecd David Howells   2020-10-20  @40  	pgoff_t index;
31143d5d515ece David Howells   2007-05-09   41  	int ret;
31143d5d515ece David Howells   2007-05-09   42  
e87b03f5830ecd David Howells   2020-10-20   43  	_enter("{%llx:%llu},%llx,%x",
e87b03f5830ecd David Howells   2020-10-20   44  	       vnode->fid.vid, vnode->fid.vnode, pos, len);
31143d5d515ece David Howells   2007-05-09   45  
3003bbd0697b65 David Howells   2020-02-06   46  	/* Prefetch area to be written into the cache if we're caching this
3003bbd0697b65 David Howells   2020-02-06   47  	 * file.  We need to do this before we get a lock on the page in case
3003bbd0697b65 David Howells   2020-02-06   48  	 * there's more than one writer competing for the same cache block.
3003bbd0697b65 David Howells   2020-02-06   49  	 */
3003bbd0697b65 David Howells   2020-02-06   50  	ret = netfs_write_begin(file, mapping, pos, len, flags, &page, fsdata,
3003bbd0697b65 David Howells   2020-02-06   51  				&afs_req_ops, NULL);
3003bbd0697b65 David Howells   2020-02-06   52  	if (ret < 0)
31143d5d515ece David Howells   2007-05-09   53  		return ret;
630f5dda8442ca David Howells   2020-02-06   54  
e87b03f5830ecd David Howells   2020-10-20   55  	index = page->index;
d5cb85d0ca8576 David Howells   2021-06-14   56  	from = offset_in_thp(page, pos);
d5cb85d0ca8576 David Howells   2021-06-14   57  	len = min_t(size_t, len, thp_size(page) - from);
e87b03f5830ecd David Howells   2020-10-20   58  	to = from + len;
e87b03f5830ecd David Howells   2020-10-20   59  
31143d5d515ece David Howells   2007-05-09   60  try_again:
4343d00872e1de David Howells   2017-11-02   61  	/* See if this page is already partially written in a way that we can
4343d00872e1de David Howells   2017-11-02   62  	 * merge the new write with.
4343d00872e1de David Howells   2017-11-02   63  	 */
4343d00872e1de David Howells   2017-11-02   64  	if (PagePrivate(page)) {
4343d00872e1de David Howells   2017-11-02   65  		priv = page_private(page);
67d78a6f6e7b38 David Howells   2020-10-28   66  		f = afs_page_dirty_from(page, priv);
67d78a6f6e7b38 David Howells   2020-10-28   67  		t = afs_page_dirty_to(page, priv);
4343d00872e1de David Howells   2017-11-02   68  		ASSERTCMP(f, <=, t);
4343d00872e1de David Howells   2017-11-02   69  
5a039c32271b9a David Howells   2017-11-18   70  		if (PageWriteback(page)) {
67d78a6f6e7b38 David Howells   2020-10-28   71  			trace_afs_page_dirty(vnode, tracepoint_string("alrdy"), page);
5a039c32271b9a David Howells   2017-11-18   72  			goto flush_conflicting_write;
5a039c32271b9a David Howells   2017-11-18   73  		}
5a8132761609bd David Howells   2018-04-06   74  		/* If the file is being filled locally, allow inter-write
5a8132761609bd David Howells   2018-04-06   75  		 * spaces to be merged into writes.  If it's not, only write
5a8132761609bd David Howells   2018-04-06   76  		 * back what the user gives us.
5a8132761609bd David Howells   2018-04-06   77  		 */
5a8132761609bd David Howells   2018-04-06   78  		if (!test_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags) &&
5a8132761609bd David Howells   2018-04-06   79  		    (to < f || from > t))
4343d00872e1de David Howells   2017-11-02   80  			goto flush_conflicting_write;
31143d5d515ece David Howells   2007-05-09   81  	}
31143d5d515ece David Howells   2007-05-09   82  
21db2cdc667f74 David Howells   2020-10-22   83  	*_page = page;
4343d00872e1de David Howells   2017-11-02   84  	_leave(" = 0");
31143d5d515ece David Howells   2007-05-09   85  	return 0;
31143d5d515ece David Howells   2007-05-09   86  
4343d00872e1de David Howells   2017-11-02   87  	/* The previous write and this write aren't adjacent or overlapping, so
4343d00872e1de David Howells   2017-11-02   88  	 * flush the page out.
4343d00872e1de David Howells   2017-11-02   89  	 */
4343d00872e1de David Howells   2017-11-02   90  flush_conflicting_write:
31143d5d515ece David Howells   2007-05-09   91  	_debug("flush conflict");
4343d00872e1de David Howells   2017-11-02   92  	ret = write_one_page(page);
21db2cdc667f74 David Howells   2020-10-22   93  	if (ret < 0)
21db2cdc667f74 David Howells   2020-10-22   94  		goto error;
31143d5d515ece David Howells   2007-05-09   95  
4343d00872e1de David Howells   2017-11-02   96  	ret = lock_page_killable(page);
21db2cdc667f74 David Howells   2020-10-22   97  	if (ret < 0)
21db2cdc667f74 David Howells   2020-10-22   98  		goto error;
21db2cdc667f74 David Howells   2020-10-22   99  	goto try_again;
21db2cdc667f74 David Howells   2020-10-22  100  
21db2cdc667f74 David Howells   2020-10-22  101  error:
21db2cdc667f74 David Howells   2020-10-22  102  	put_page(page);
4343d00872e1de David Howells   2017-11-02  103  	_leave(" = %d", ret);
4343d00872e1de David Howells   2017-11-02  104  	return ret;
4343d00872e1de David Howells   2017-11-02  105  }
31143d5d515ece David Howells   2007-05-09  106  

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
diff mbox series

Patch

diff --git a/fs/afs/write.c b/fs/afs/write.c
index a523bb86915d..f68274c39f47 100644
--- a/fs/afs/write.c
+++ b/fs/afs/write.c
@@ -25,7 +25,8 @@  int afs_set_page_dirty(struct page *page)
 }
 
 /*
- * prepare to perform part of a write to a page
+ * Prepare to perform part of a write to a page.  Note that len may extend
+ * beyond the end of the page.
  */
 int afs_write_begin(struct file *file, struct address_space *mapping,
 		    loff_t pos, unsigned len, unsigned flags,
@@ -52,7 +53,8 @@  int afs_write_begin(struct file *file, struct address_space *mapping,
 		return ret;
 
 	index = page->index;
-	from = pos - index * PAGE_SIZE;
+	from = offset_in_thp(page, pos);
+	len = min_t(size_t, len, thp_size(page) - from);
 	to = from + len;
 
 try_again:
@@ -103,7 +105,8 @@  int afs_write_begin(struct file *file, struct address_space *mapping,
 }
 
 /*
- * finalise part of a write to a page
+ * Finalise part of a write to a page.  Note that len may extend beyond the end
+ * of the page.
  */
 int afs_write_end(struct file *file, struct address_space *mapping,
 		  loff_t pos, unsigned len, unsigned copied,
@@ -111,7 +114,7 @@  int afs_write_end(struct file *file, struct address_space *mapping,
 {
 	struct afs_vnode *vnode = AFS_FS_I(file_inode(file));
 	unsigned long priv;
-	unsigned int f, from = pos & (thp_size(page) - 1);
+	unsigned int f, from = offset_in_thp(page, pos);
 	unsigned int t, to = from + copied;
 	loff_t i_size, maybe_i_size;