In subpagesize-blocksize scenario, if i_size occurs in a block which is not
the last block in the page, then the space to be reserved should be calculated
appropriately.

Signed-off-by: Chandan Rajendra <chan...@linux.vnet.ibm.com>
---
 fs/btrfs/inode.c | 33 ++++++++++++++++++++++-----------
 1 file changed, 22 insertions(+), 11 deletions(-)

diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index a9c7bc8..3255568 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -7690,26 +7690,23 @@ int btrfs_page_mkwrite(struct vm_area_struct *vma, 
struct vm_fault *vmf)
        loff_t size;
        int ret;
        int reserved = 0;
+       u64 delalloc_size;
        u64 page_start;
        u64 page_end;
 
        sb_start_pagefault(inode->i_sb);
-       ret  = btrfs_delalloc_reserve_space(inode, PAGE_CACHE_SIZE);
-       if (!ret) {
-               ret = file_update_time(vma->vm_file);
-               reserved = 1;
-       }
+
+       ret = file_update_time(vma->vm_file);
        if (ret) {
                if (ret == -ENOMEM)
                        ret = VM_FAULT_OOM;
                else /* -ENOSPC, -EIO, etc */
                        ret = VM_FAULT_SIGBUS;
-               if (reserved)
-                       goto out;
-               goto out_noreserve;
+               goto out;
        }
 
        ret = VM_FAULT_NOPAGE; /* make the VM retry the fault */
+
 again:
        lock_page(page);
        size = i_size_read(inode);
@@ -7740,6 +7737,19 @@ again:
                goto again;
        }
 
+       if (page->index == ((size - 1) >> PAGE_CACHE_SHIFT))
+               delalloc_size = round_up(size - page_start, root->sectorsize);
+       else
+               delalloc_size = PAGE_CACHE_SIZE;
+
+       ret = btrfs_delalloc_reserve_space(inode, delalloc_size);
+       if (ret) {
+               /* -ENOSPC */
+               ret = VM_FAULT_SIGBUS;
+               goto out_unlock;
+       }
+       reserved = 1;
+
        /*
         * XXX - page_mkwrite gets called every time the page is dirtied, even
         * if it was already dirty, so for space accounting reasons we need to
@@ -7752,7 +7762,8 @@ again:
                          EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG,
                          0, 0, &cached_state, GFP_NOFS);
 
-       ret = btrfs_set_extent_delalloc(inode, page_start, page_end,
+       ret = btrfs_set_extent_delalloc(inode, page_start,
+                                       page_start + delalloc_size - 1,
                                        &cached_state);
        if (ret) {
                unlock_extent_cached(io_tree, page_start, page_end,
@@ -7791,8 +7802,8 @@ out_unlock:
        }
        unlock_page(page);
 out:
-       btrfs_delalloc_release_space(inode, PAGE_CACHE_SIZE);
-out_noreserve:
+       if (reserved)
+               btrfs_delalloc_release_space(inode, delalloc_size);
        sb_end_pagefault(inode->i_sb);
        return ret;
 }
-- 
1.8.3.1

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

Reply via email to