[V17,10/18] Btrfs: subpage-blocksize: btrfs_punch_hole: Fix uptodate blocks check
diff mbox

Message ID 1460641107-13834-11-git-send-email-chandan@linux.vnet.ibm.com
State New
Headers show

Commit Message

Chandan Rajendra April 14, 2016, 1:38 p.m. UTC
In case of subpage-blocksize, the file blocks to be punched may map only
part of a page. For file blocks inside such pages, we need to check for
the presence of BLK_STATE_UPTODATE flag.

Signed-off-by: Chandan Rajendra <chandan@linux.vnet.ibm.com>
---
 fs/btrfs/file.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 65 insertions(+), 1 deletion(-)

Comments

kbuild test robot April 14, 2016, 4:04 p.m. UTC | #1
Hi Chandan,

[auto build test ERROR on tip/perf/core]
[also build test ERROR on v4.6-rc3 next-20160414]
[cannot apply to btrfs/next]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]

url:    https://github.com/0day-ci/linux/commits/Chandan-Rajendra/Allow-I-O-on-blocks-whose-size-is-less-than-page-size/20160414-214339
config: arm-allyesconfig (attached as .config)
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=arm 

Note: the linux-review/Chandan-Rajendra/Allow-I-O-on-blocks-whose-size-is-less-than-page-size/20160414-214339 HEAD cb75f40d8b4d47c9133c24f3cc01b3eef831bf19 builds fine.
      It only hurts bisectibility.

All error/warnings (new ones prefixed by >>):

   fs/btrfs/file.c: In function 'btrfs_punch_hole':
>> fs/btrfs/file.c:2435:29: error: 'PAGE_CACHE_SHIFT' undeclared (first use in this function)
     start_index = lockstart >> PAGE_CACHE_SHIFT;
                                ^
   fs/btrfs/file.c:2435:29: note: each undeclared identifier is reported only once for each function it appears in
>> fs/btrfs/file.c:2449:20: error: 'PAGE_CACHE_SIZE' undeclared (first use in this function)
      if (lockstart & (PAGE_CACHE_SIZE - 1)) {
                       ^
>> fs/btrfs/file.c:2464:6: error: implicit declaration of function 'page_cache_release' [-Werror=implicit-function-declaration]
         page_cache_release(start_page);
         ^
   In file included from include/linux/list.h:8:0,
                    from include/linux/wait.h:6,
                    from include/linux/fs.h:5,
                    from fs/btrfs/file.c:19:
   include/linux/kernel.h:735:17: warning: comparison of distinct pointer types lacks a cast
     (void) (&_min1 == &_min2);  \
                    ^
>> fs/btrfs/file.c:2491:5: note: in expansion of macro 'min'
        min(lockstart + PAGE_CACHE_SIZE - 1, lockend), 0)) &&
        ^
   cc1: some warnings being treated as errors

vim +/PAGE_CACHE_SHIFT +2435 fs/btrfs/file.c

  2429	
  2430		if (lockend < lockstart) {
  2431			ret = 0;
  2432			goto out_only_mutex;
  2433		}
  2434	
> 2435		start_index = lockstart >> PAGE_CACHE_SHIFT;
  2436		end_index = lockend >> PAGE_CACHE_SHIFT;
  2437	
  2438		same_page = lockstart >> PAGE_CACHE_SHIFT
  2439			== lockend >> PAGE_CACHE_SHIFT;
  2440	
  2441		while (1) {
  2442			struct btrfs_ordered_extent *ordered;
  2443			struct page *start_page = NULL;
  2444			struct page *end_page = NULL;
  2445			u64 nr_pages;
  2446	
  2447			truncate_pagecache_range(inode, lockstart, lockend);
  2448	
> 2449			if (lockstart & (PAGE_CACHE_SIZE - 1)) {
  2450				start_page = find_or_create_page(mapping, start_index,
  2451								GFP_NOFS);
  2452				if (!start_page) {
  2453					mutex_unlock(&inode->i_mutex);
  2454					return -ENOMEM;
  2455				}
  2456			}
  2457	
  2458			if (!same_page && ((lockend + 1) & (PAGE_CACHE_SIZE - 1))) {
  2459				end_page = find_or_create_page(mapping, end_index,
  2460							GFP_NOFS);
  2461				if (!end_page) {
  2462					if (start_page) {
  2463						unlock_page(start_page);
> 2464						page_cache_release(start_page);
  2465					}
  2466					mutex_unlock(&inode->i_mutex);
  2467					return -ENOMEM;
  2468				}
  2469			}
  2470	
  2471	
  2472			lock_extent_bits(&BTRFS_I(inode)->io_tree, lockstart, lockend,
  2473					 &cached_state);
  2474			ordered = btrfs_lookup_first_ordered_extent(inode, lockend);
  2475	
  2476			/*
  2477			 * We need to make sure we have no ordered extents in this range
  2478			 * and nobody raced in and read a page in this range, if we did
  2479			 * we need to try again.
  2480			 */
  2481			nr_pages = round_up(lockend, PAGE_CACHE_SIZE)
  2482				- round_down(lockstart, PAGE_CACHE_SIZE);
  2483			nr_pages >>= PAGE_CACHE_SHIFT;
  2484	
  2485			if ((!ordered ||
  2486			    (ordered->file_offset + ordered->len <= lockstart ||
  2487			     ordered->file_offset > lockend)) &&
  2488			     (!(start_page && PagePrivate(start_page) &&
  2489				test_page_blks_state(start_page, 1 << BLK_STATE_UPTODATE,
  2490				 lockstart,
> 2491				 min(lockstart + PAGE_CACHE_SIZE - 1, lockend), 0)) &&
  2492			      !(end_page && PagePrivate(end_page) &&
  2493				test_page_blks_state(end_page, 1 << BLK_STATE_UPTODATE,
  2494				 page_offset(end_page), lockend, 0)) &&

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

Patch
diff mbox

diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index e2f0968..a17bcab 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -2321,6 +2321,8 @@  static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
 	struct btrfs_path *path;
 	struct btrfs_block_rsv *rsv;
 	struct btrfs_trans_handle *trans;
+	struct address_space *mapping = inode->i_mapping;
+	pgoff_t start_index, end_index;
 	u64 lockstart;
 	u64 lockend;
 	u64 tail_start;
@@ -2333,6 +2335,7 @@  static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
 	int err = 0;
 	unsigned int rsv_count;
 	bool same_block;
+	bool same_page;
 	bool no_holes = btrfs_fs_incompat(root->fs_info, NO_HOLES);
 	u64 ino_size;
 	bool truncated_block = false;
@@ -2429,11 +2432,43 @@  static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
 		goto out_only_mutex;
 	}
 
+	start_index = lockstart >> PAGE_CACHE_SHIFT;
+	end_index = lockend >> PAGE_CACHE_SHIFT;
+
+	same_page = lockstart >> PAGE_CACHE_SHIFT
+		== lockend >> PAGE_CACHE_SHIFT;
+
 	while (1) {
 		struct btrfs_ordered_extent *ordered;
+		struct page *start_page = NULL;
+		struct page *end_page = NULL;
+		u64 nr_pages;
 
 		truncate_pagecache_range(inode, lockstart, lockend);
 
+		if (lockstart & (PAGE_CACHE_SIZE - 1)) {
+			start_page = find_or_create_page(mapping, start_index,
+							GFP_NOFS);
+			if (!start_page) {
+				mutex_unlock(&inode->i_mutex);
+				return -ENOMEM;
+			}
+		}
+
+		if (!same_page && ((lockend + 1) & (PAGE_CACHE_SIZE - 1))) {
+			end_page = find_or_create_page(mapping, end_index,
+						GFP_NOFS);
+			if (!end_page) {
+				if (start_page) {
+					unlock_page(start_page);
+					page_cache_release(start_page);
+				}
+				mutex_unlock(&inode->i_mutex);
+				return -ENOMEM;
+			}
+		}
+
+
 		lock_extent_bits(&BTRFS_I(inode)->io_tree, lockstart, lockend,
 				 &cached_state);
 		ordered = btrfs_lookup_first_ordered_extent(inode, lockend);
@@ -2443,18 +2478,47 @@  static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
 		 * and nobody raced in and read a page in this range, if we did
 		 * we need to try again.
 		 */
+		nr_pages = round_up(lockend, PAGE_CACHE_SIZE)
+			- round_down(lockstart, PAGE_CACHE_SIZE);
+		nr_pages >>= PAGE_CACHE_SHIFT;
+
 		if ((!ordered ||
 		    (ordered->file_offset + ordered->len <= lockstart ||
 		     ordered->file_offset > lockend)) &&
-		     !btrfs_page_exists_in_range(inode, lockstart, lockend)) {
+		     (!(start_page && PagePrivate(start_page) &&
+			test_page_blks_state(start_page, 1 << BLK_STATE_UPTODATE,
+			 lockstart,
+			 min(lockstart + PAGE_CACHE_SIZE - 1, lockend), 0)) &&
+		      !(end_page && PagePrivate(end_page) &&
+			test_page_blks_state(end_page, 1 << BLK_STATE_UPTODATE,
+			 page_offset(end_page), lockend, 0)) &&
+		      !(nr_pages > 2 && btrfs_page_exists_in_range(inode,
+					 round_up(lockstart, PAGE_CACHE_SIZE),
+					 round_down(lockend, PAGE_CACHE_SIZE) - 1)))) {
 			if (ordered)
 				btrfs_put_ordered_extent(ordered);
+			if (end_page) {
+				unlock_page(end_page);
+				page_cache_release(end_page);
+			}
+			if (start_page) {
+				unlock_page(start_page);
+				page_cache_release(start_page);
+			}
 			break;
 		}
 		if (ordered)
 			btrfs_put_ordered_extent(ordered);
 		unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart,
 				     lockend, &cached_state, GFP_NOFS);
+		if (end_page) {
+			unlock_page(end_page);
+			page_cache_release(end_page);
+		}
+		if (start_page) {
+			unlock_page(start_page);
+			page_cache_release(start_page);
+		}
 		ret = btrfs_wait_ordered_range(inode, lockstart,
 					       lockend - lockstart + 1);
 		if (ret) {