Btrfs: subpage-blocksize: btrfs_punch_hole: Fix uptodate blocks check
diff mbox

Message ID 1460895884-3524-1-git-send-email-chandan@linux.vnet.ibm.com
State New
Headers show

Commit Message

Chandan Rajendra April 17, 2016, 12:24 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 17, 2016, 12:38 p.m. UTC | #1
Hi Chandan,

[auto build test ERROR on btrfs/next]
[also build test ERROR on v4.6-rc3 next-20160415]
[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/Btrfs-subpage-blocksize-btrfs_punch_hole-Fix-uptodate-blocks-check/20160417-201821
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs.git next
config: i386-randconfig-x008-04171808 (attached as .config)
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All errors (new ones prefixed by >>):

   fs/btrfs/file.c: In function 'btrfs_punch_hole':
>> fs/btrfs/file.c:2473:4: error: implicit declaration of function 'test_page_blks_state' [-Werror=implicit-function-declaration]
       test_page_blks_state(start_page, 1 << BLK_STATE_UPTODATE,
       ^
>> fs/btrfs/file.c:2473:42: error: 'BLK_STATE_UPTODATE' undeclared (first use in this function)
       test_page_blks_state(start_page, 1 << BLK_STATE_UPTODATE,
                                             ^
   fs/btrfs/file.c:2473:42: note: each undeclared identifier is reported only once for each function it appears in
   cc1: some warnings being treated as errors

vim +/test_page_blks_state +2473 fs/btrfs/file.c

  2467			nr_pages >>= PAGE_SHIFT;
  2468	
  2469			if ((!ordered ||
  2470			    (ordered->file_offset + ordered->len <= lockstart ||
  2471			     ordered->file_offset > lockend)) &&
  2472			     (!(start_page && PagePrivate(start_page) &&
> 2473				test_page_blks_state(start_page, 1 << BLK_STATE_UPTODATE,
  2474				 lockstart,
  2475				 min(lockstart + PAGE_SIZE - 1, lockend), 0)) &&
  2476			      !(end_page && PagePrivate(end_page) &&

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
kbuild test robot April 18, 2016, 8:35 a.m. UTC | #2
Hi Chandan,

[auto build test ERROR on btrfs/next]
[also build test ERROR on v4.6-rc4 next-20160418]
[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/Btrfs-subpage-blocksize-btrfs_punch_hole-Fix-uptodate-blocks-check/20160417-202629
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs.git next
config: x86_64-lkp (attached as .config)
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

All errors (new ones prefixed by >>):

   fs/btrfs/file.c: In function 'btrfs_punch_hole':
>> fs/btrfs/file.c:2473:4: error: implicit declaration of function 'test_page_blks_state' [-Werror=implicit-function-declaration]
       test_page_blks_state(start_page, 1 << BLK_STATE_UPTODATE,
       ^
>> fs/btrfs/file.c:2473:42: error: 'BLK_STATE_UPTODATE' undeclared (first use in this function)
       test_page_blks_state(start_page, 1 << BLK_STATE_UPTODATE,
                                             ^
   fs/btrfs/file.c:2473:42: note: each undeclared identifier is reported only once for each function it appears in
   cc1: some warnings being treated as errors

vim +/test_page_blks_state +2473 fs/btrfs/file.c

  2467			nr_pages >>= PAGE_SHIFT;
  2468	
  2469			if ((!ordered ||
  2470			    (ordered->file_offset + ordered->len <= lockstart ||
  2471			     ordered->file_offset > lockend)) &&
  2472			     (!(start_page && PagePrivate(start_page) &&
> 2473				test_page_blks_state(start_page, 1 << BLK_STATE_UPTODATE,
  2474				 lockstart,
  2475				 min(lockstart + PAGE_SIZE - 1, lockend), 0)) &&
  2476			      !(end_page && PagePrivate(end_page) &&

---
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..8d35c47 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_SHIFT;
+	end_index = lockend >> PAGE_SHIFT;
+
+	same_page = lockstart >> PAGE_SHIFT
+		== lockend >> PAGE_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_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_SIZE - 1))) {
+			end_page = find_or_create_page(mapping, end_index,
+						GFP_NOFS);
+			if (!end_page) {
+				if (start_page) {
+					unlock_page(start_page);
+					put_page(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_SIZE)
+			- round_down(lockstart, PAGE_SIZE);
+		nr_pages >>= PAGE_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_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_SIZE),
+					 round_down(lockend, PAGE_SIZE) - 1)))) {
 			if (ordered)
 				btrfs_put_ordered_extent(ordered);
+			if (end_page) {
+				unlock_page(end_page);
+				put_page(end_page);
+			}
+			if (start_page) {
+				unlock_page(start_page);
+				put_page(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);
+			put_page(end_page);
+		}
+		if (start_page) {
+			unlock_page(start_page);
+			put_page(start_page);
+		}
 		ret = btrfs_wait_ordered_range(inode, lockstart,
 					       lockend - lockstart + 1);
 		if (ret) {