summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2012-01-25 13:47:40 -0500
committerChris Mason <chris.mason@oracle.com>2012-01-27 10:44:44 -0500
commit9998eb703490589c3e8f1bf09b15203156776edb (patch)
tree5d01f0e7efae049b9be80292c93fe30f11eeefd1
parent9b23062840e7c685ef0a0b561285d6e3a3b6811b (diff)
downloadlinux-3.10-9998eb703490589c3e8f1bf09b15203156776edb.tar.gz
linux-3.10-9998eb703490589c3e8f1bf09b15203156776edb.tar.bz2
linux-3.10-9998eb703490589c3e8f1bf09b15203156776edb.zip
Btrfs: fix reservations in btrfs_page_mkwrite
Josef fixed btrfs_page_mkwrite to properly release reserved extents if there was an error. But if we fail to get a reservation and we fail to dirty the inode (for ENOSPC reasons), we'll end up trying to release a reservation we never had. This makes sure we only release if we were able to reserve. Signed-off-by: Chris Mason <chris.mason@oracle.com>
-rw-r--r--fs/btrfs/inode.c10
1 files changed, 8 insertions, 2 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 5977987abdb..7405753ec5d 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -6401,18 +6401,23 @@ int btrfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
unsigned long zero_start;
loff_t size;
int ret;
+ int reserved = 0;
u64 page_start;
u64 page_end;
ret = btrfs_delalloc_reserve_space(inode, PAGE_CACHE_SIZE);
- if (!ret)
+ if (!ret) {
ret = btrfs_update_time(vma->vm_file);
+ reserved = 1;
+ }
if (ret) {
if (ret == -ENOMEM)
ret = VM_FAULT_OOM;
else /* -ENOSPC, -EIO, etc */
ret = VM_FAULT_SIGBUS;
- goto out;
+ if (reserved)
+ goto out;
+ goto out_noreserve;
}
ret = VM_FAULT_NOPAGE; /* make the VM retry the fault */
@@ -6495,6 +6500,7 @@ out_unlock:
unlock_page(page);
out:
btrfs_delalloc_release_space(inode, PAGE_CACHE_SIZE);
+out_noreserve:
return ret;
}