[V5,13/13] Btrfs: Return valid delalloc range when the page does not have PG_Dirty flag set or has been invalidated
diff mbox

Message ID 1443608912-31667-14-git-send-email-chandan@linux.vnet.ibm.com
State New
Headers show

Commit Message

Chandan Rajendra Sept. 30, 2015, 10:28 a.m. UTC
The following issue was observed when running generic/095 test on
subpagesize-blocksize patchset.

Assume that we are trying to write a dirty page that is mapping file offset
range [159744, 163839].

writepage_delalloc()
  find_lock_delalloc_range(*start = 159744, *end = 0)
    find_delalloc_range()
      Returns range [X, Y] where (X > 163839)
    lock_delalloc_pages()
      One of the pages in range [X, Y] has dirty flag cleared;
      Loop once more restricting the delalloc range to span only
      PAGE_CACHE_SIZE bytes;
    find_delalloc_range()
      Returns range [356352, 360447];
    lock_delalloc_pages()
      The page [356352, 360447] has dirty flag cleared;
    Returns with *start = 159744 and *end = 0;
  *start = *end + 1;
  find_lock_delalloc_range(*start = 1, *end = 0)
    Finds and returns delalloc range [1, 12288];
  cow_file_range()
    Clears delalloc range [1, 12288]
    Create ordered extent for range [1, 12288]

The ordered extent thus created above breaks the rule that extents have to be
aligned to the filesystem's block size.

In cases where lock_delalloc_pages() fails (either due to PG_dirty flag being
cleared or the page no longer being a member of the inode's page cache), this
patch sets and returns the delalloc range that was found by
find_delalloc_range().

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

Comments

Josef Bacik Oct. 1, 2015, 2:48 p.m. UTC | #1
On 09/30/2015 06:28 AM, Chandan Rajendra wrote:
> The following issue was observed when running generic/095 test on
> subpagesize-blocksize patchset.
>
> Assume that we are trying to write a dirty page that is mapping file offset
> range [159744, 163839].
>
> writepage_delalloc()
>    find_lock_delalloc_range(*start = 159744, *end = 0)
>      find_delalloc_range()
>        Returns range [X, Y] where (X > 163839)
>      lock_delalloc_pages()
>        One of the pages in range [X, Y] has dirty flag cleared;
>        Loop once more restricting the delalloc range to span only
>        PAGE_CACHE_SIZE bytes;
>      find_delalloc_range()
>        Returns range [356352, 360447];
>      lock_delalloc_pages()
>        The page [356352, 360447] has dirty flag cleared;
>      Returns with *start = 159744 and *end = 0;
>    *start = *end + 1;
>    find_lock_delalloc_range(*start = 1, *end = 0)
>      Finds and returns delalloc range [1, 12288];
>    cow_file_range()
>      Clears delalloc range [1, 12288]
>      Create ordered extent for range [1, 12288]
>
> The ordered extent thus created above breaks the rule that extents have to be
> aligned to the filesystem's block size.
>
> In cases where lock_delalloc_pages() fails (either due to PG_dirty flag being
> cleared or the page no longer being a member of the inode's page cache), this
> patch sets and returns the delalloc range that was found by
> find_delalloc_range().
>
> Signed-off-by: Chandan Rajendra <chandan@linux.vnet.ibm.com>

Reviewed-by: Josef Bacik <jbacik@fb.com>

Thanks,

Josef
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Patch
diff mbox

diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index 0ee486a..3912d1f 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -1731,6 +1731,8 @@  again:
 			goto again;
 		} else {
 			found = 0;
+			*start = delalloc_start;
+			*end = delalloc_end;
 			goto out_failed;
 		}
 	}