Btrfs: fix data space leak fix
authorJosef Bacik <josef@redhat.com>
Thu, 1 Oct 2009 21:10:23 +0000 (17:10 -0400)
committerChris Mason <chris.mason@oracle.com>
Thu, 1 Oct 2009 21:10:23 +0000 (17:10 -0400)
There is a problem where page_mkwrite can be called on a dirtied page that
already has a delalloc range associated with it.  The fix is to clear any
delalloc bits for the range we are dirtying so the space accounting gets
handled properly.  This is the same thing we do in the normal write case, so we
are consistent across the board.  With this patch we no longer leak reserved
space.

Signed-off-by: Josef Bacik <jbacik@redhat.com>
Signed-off-by: Chris Mason <chris.mason@oracle.com>
fs/btrfs/inode.c

index 3cc5677f544029fab14bc3c8f26f913c297f63a1..3a6f953337b51eb7068ae7e0f1489a582b9b054e 100644 (file)
@@ -4909,10 +4909,21 @@ again:
                goto again;
        }
 
                goto again;
        }
 
+       /*
+        * 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
+        * clear any delalloc bits for the range we are fixing to save.  There
+        * is probably a better way to do this, but for now keep consistent with
+        * prepare_pages in the normal write path.
+        */
+       clear_extent_bits(&BTRFS_I(inode)->io_tree, page_start, page_end,
+                         EXTENT_DIRTY | EXTENT_DELALLOC, GFP_NOFS);
+
        ret = btrfs_set_extent_delalloc(inode, page_start, page_end);
        if (ret) {
                unlock_extent(io_tree, page_start, page_end, GFP_NOFS);
                ret = VM_FAULT_SIGBUS;
        ret = btrfs_set_extent_delalloc(inode, page_start, page_end);
        if (ret) {
                unlock_extent(io_tree, page_start, page_end, GFP_NOFS);
                ret = VM_FAULT_SIGBUS;
+               btrfs_free_reserved_data_space(root, inode, PAGE_CACHE_SIZE);
                goto out_unlock;
        }
        ret = 0;
                goto out_unlock;
        }
        ret = 0;