@@ -3148,6 +3148,8 @@ int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, int delay_iput,
int nr);
int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end,
struct extent_state **cached_state, int dedupe);
+int btrfs_set_extent_defrag(struct inode *inode, u64 start, u64 end,
+ struct extent_state **cached_state);
int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
struct btrfs_root *new_root,
struct btrfs_root *parent_root,
@@ -1521,6 +1521,9 @@ static void btrfs_split_extent_hook(struct inode *inode,
if (!(orig->state & EXTENT_DELALLOC))
return;
+ if (btrfs_is_free_space_inode(BTRFS_I(inode)))
+ return;
+
size = orig->end - orig->start + 1;
if (size > BTRFS_MAX_EXTENT_SIZE) {
u32 num_extents;
@@ -1560,6 +1563,9 @@ static void btrfs_merge_extent_hook(struct inode *inode,
if (!(other->state & EXTENT_DELALLOC))
return;
+ if (btrfs_is_free_space_inode(BTRFS_I(inode)))
+ return;
+
if (new->start > other->start)
new_size = new->end - other->start + 1;
else
@@ -1655,7 +1661,6 @@ static void btrfs_del_delalloc_inode(struct btrfs_root *root,
static void btrfs_set_bit_hook(struct inode *inode,
struct extent_state *state, unsigned *bits)
{
-
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
if ((*bits & EXTENT_DEFRAG) && !(*bits & EXTENT_DELALLOC))
@@ -1668,13 +1673,16 @@ static void btrfs_set_bit_hook(struct inode *inode,
if (!(state->state & EXTENT_DELALLOC) && (*bits & EXTENT_DELALLOC)) {
struct btrfs_root *root = BTRFS_I(inode)->root;
u64 len = state->end + 1 - state->start;
+ u64 num_extents = div64_u64(len + BTRFS_MAX_EXTENT_SIZE - 1,
+ BTRFS_MAX_EXTENT_SIZE);
bool do_list = !btrfs_is_free_space_inode(BTRFS_I(inode));
- if (*bits & EXTENT_FIRST_DELALLOC) {
+ if (*bits & EXTENT_FIRST_DELALLOC)
*bits &= ~EXTENT_FIRST_DELALLOC;
- } else {
+
+ if (do_list) {
spin_lock(&BTRFS_I(inode)->lock);
- BTRFS_I(inode)->outstanding_extents++;
+ BTRFS_I(inode)->outstanding_extents += num_extents;
spin_unlock(&BTRFS_I(inode)->lock);
}
@@ -1920,9 +1928,52 @@ static noinline int add_pending_csums(struct btrfs_trans_handle *trans,
int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end,
struct extent_state **cached_state, int dedupe)
{
+ int ret;
+ u64 num_extents = div64_u64(end - start + BTRFS_MAX_EXTENT_SIZE,
+ BTRFS_MAX_EXTENT_SIZE);
+
+ WARN_ON((end & (PAGE_SIZE - 1)) == 0);
+ ret = set_extent_delalloc(&BTRFS_I(inode)->io_tree, start, end,
+ cached_state);
+
+ /*
+ * btrfs_delalloc_reserve_metadata() will first add number of
+ * outstanding extents according to data length, which is inaccurate
+ * for case like dirtying already dirty pages.
+ * so here we will decrease such inaccurate numbers, to make
+ * outstanding_extents only rely on the correct values added by
+ * set_bit_hook()
+ *
+ * Also, we skipped the metadata space reserve for space cache inodes,
+ * so don't modify the outstanding_extents value.
+ */
+ if (ret == 0 && !btrfs_is_free_space_inode(BTRFS_I(inode))) {
+ spin_lock(&BTRFS_I(inode)->lock);
+ BTRFS_I(inode)->outstanding_extents -= num_extents;
+ spin_unlock(&BTRFS_I(inode)->lock);
+ }
+
+ return ret;
+}
+
+int btrfs_set_extent_defrag(struct inode *inode, u64 start, u64 end,
+ struct extent_state **cached_state)
+{
+ int ret;
+ u64 num_extents = div64_u64(end - start + BTRFS_MAX_EXTENT_SIZE,
+ BTRFS_MAX_EXTENT_SIZE);
+
WARN_ON((end & (PAGE_SIZE - 1)) == 0);
- return set_extent_delalloc(&BTRFS_I(inode)->io_tree, start, end,
- cached_state);
+ ret = set_extent_defrag(&BTRFS_I(inode)->io_tree, start, end,
+ cached_state);
+
+ if (ret == 0 && !btrfs_is_free_space_inode(BTRFS_I(inode))) {
+ spin_lock(&BTRFS_I(inode)->lock);
+ BTRFS_I(inode)->outstanding_extents -= num_extents;
+ spin_unlock(&BTRFS_I(inode)->lock);
+ }
+
+ return ret;
}
/* see btrfs_writepage_start_hook for details on why this is required */
@@ -1231,10 +1231,8 @@ static int cluster_pages_for_defrag(struct inode *inode,
(page_cnt - i_done) << PAGE_SHIFT);
}
-
- set_extent_defrag(&BTRFS_I(inode)->io_tree, page_start, page_end - 1,
- &cached_state);
-
+ btrfs_set_extent_defrag(inode, page_start,
+ page_end - 1, &cached_state);
unlock_extent_cached(&BTRFS_I(inode)->io_tree,
page_start, page_end - 1, &cached_state,
GFP_NOFS);