diff options
author | Josef Bacik <josef@redhat.com> | 2011-07-15 11:16:44 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2011-07-27 12:46:44 -0400 |
commit | 9e0baf60dea69f31ac3b1adeb35b03b02a53e8e1 (patch) | |
tree | 0fb899e1fa78b599d22389ca3befc8ab51ff5049 /fs/btrfs/ioctl.c | |
parent | a5991428064e98c7367fe1c1686ea6a23fb6a4b3 (diff) |
Btrfs: fix enospc problems with delalloc
So I had this brilliant idea to use atomic counters for outstanding and reserved
extents, but this turned out to be a bad idea. Consider this where we have 1
outstanding extent and 1 reserved extent
Reserver Releaser
atomic_dec(outstanding) now 0
atomic_read(outstanding)+1 get 1
atomic_read(reserved) get 1
don't actually reserve anything because
they are the same
atomic_cmpxchg(reserved, 1, 0)
atomic_inc(outstanding)
atomic_add(0, reserved)
free reserved space for 1 extent
Then the reserver now has no actual space reserved for it, and when it goes to
finish the ordered IO it won't have enough space to do it's allocation and you
get those lovely warnings.
Signed-off-by: Josef Bacik <josef@redhat.com>
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r-- | fs/btrfs/ioctl.c | 4 |
1 files changed, 3 insertions, 1 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 09c9a8d26ee9..fd252fff4c66 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -938,7 +938,9 @@ again: | |||
938 | GFP_NOFS); | 938 | GFP_NOFS); |
939 | 939 | ||
940 | if (i_done != num_pages) { | 940 | if (i_done != num_pages) { |
941 | atomic_inc(&BTRFS_I(inode)->outstanding_extents); | 941 | spin_lock(&BTRFS_I(inode)->lock); |
942 | BTRFS_I(inode)->outstanding_extents++; | ||
943 | spin_unlock(&BTRFS_I(inode)->lock); | ||
942 | btrfs_delalloc_release_space(inode, | 944 | btrfs_delalloc_release_space(inode, |
943 | (num_pages - i_done) << PAGE_CACHE_SHIFT); | 945 | (num_pages - i_done) << PAGE_CACHE_SHIFT); |
944 | } | 946 | } |