Commit 47059d93 authored by Wang Shilong's avatar Wang Shilong Committed by Chris Mason

Btrfs: make defragment work with nodatacow option

Btrfs defragment will utilize COW feature, which means this
did not work for nodatacow option, this problem was detected
by xfstests generic/018 with nodatacow mount option.

Fix this problem by forcing cow for a extent with state
@EXTETN_DEFRAG setting.
Signed-off-by: default avatarWang Shilong <wangsl.fnst@cn.fujitsu.com>
Signed-off-by: default avatarMiao Xie <miaox@cn.fujitsu.com>
Signed-off-by: default avatarChris Mason <clm@fb.com>
parent 48fcc3ff
...@@ -120,6 +120,12 @@ struct btrfs_inode { ...@@ -120,6 +120,12 @@ struct btrfs_inode {
*/ */
u64 delalloc_bytes; u64 delalloc_bytes;
/*
* total number of bytes pending defrag, used by stat to check whether
* it needs COW.
*/
u64 defrag_bytes;
/* /*
* the size of the file stored in the metadata on disk. data=ordered * the size of the file stored in the metadata on disk. data=ordered
* means the in-memory i_size might be larger than the size on disk * means the in-memory i_size might be larger than the size on disk
......
...@@ -1445,6 +1445,26 @@ static noinline int run_delalloc_nocow(struct inode *inode, ...@@ -1445,6 +1445,26 @@ static noinline int run_delalloc_nocow(struct inode *inode,
return ret; return ret;
} }
static inline int need_force_cow(struct inode *inode, u64 start, u64 end)
{
if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATACOW) &&
!(BTRFS_I(inode)->flags & BTRFS_INODE_PREALLOC))
return 0;
/*
* @defrag_bytes is a hint value, no spinlock held here,
* if is not zero, it means the file is defragging.
* Force cow if given extent needs to be defragged.
*/
if (BTRFS_I(inode)->defrag_bytes &&
test_range_bit(&BTRFS_I(inode)->io_tree, start, end,
EXTENT_DEFRAG, 0, NULL))
return 1;
return 0;
}
/* /*
* extent_io.c call back to do delayed allocation processing * extent_io.c call back to do delayed allocation processing
*/ */
...@@ -1454,11 +1474,12 @@ static int run_delalloc_range(struct inode *inode, struct page *locked_page, ...@@ -1454,11 +1474,12 @@ static int run_delalloc_range(struct inode *inode, struct page *locked_page,
{ {
int ret; int ret;
struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_root *root = BTRFS_I(inode)->root;
int force_cow = need_force_cow(inode, start, end);
if (BTRFS_I(inode)->flags & BTRFS_INODE_NODATACOW) { if (BTRFS_I(inode)->flags & BTRFS_INODE_NODATACOW && !force_cow) {
ret = run_delalloc_nocow(inode, locked_page, start, end, ret = run_delalloc_nocow(inode, locked_page, start, end,
page_started, 1, nr_written); page_started, 1, nr_written);
} else if (BTRFS_I(inode)->flags & BTRFS_INODE_PREALLOC) { } else if (BTRFS_I(inode)->flags & BTRFS_INODE_PREALLOC && !force_cow) {
ret = run_delalloc_nocow(inode, locked_page, start, end, ret = run_delalloc_nocow(inode, locked_page, start, end,
page_started, 0, nr_written); page_started, 0, nr_written);
} else if (!btrfs_test_opt(root, COMPRESS) && } else if (!btrfs_test_opt(root, COMPRESS) &&
...@@ -1555,6 +1576,8 @@ static void btrfs_set_bit_hook(struct inode *inode, ...@@ -1555,6 +1576,8 @@ static void btrfs_set_bit_hook(struct inode *inode,
struct extent_state *state, unsigned long *bits) struct extent_state *state, unsigned long *bits)
{ {
if ((*bits & EXTENT_DEFRAG) && !(*bits & EXTENT_DELALLOC))
WARN_ON(1);
/* /*
* set_bit and clear bit hooks normally require _irqsave/restore * set_bit and clear bit hooks normally require _irqsave/restore
* but in this case, we are only testing for the DELALLOC * but in this case, we are only testing for the DELALLOC
...@@ -1577,6 +1600,8 @@ static void btrfs_set_bit_hook(struct inode *inode, ...@@ -1577,6 +1600,8 @@ static void btrfs_set_bit_hook(struct inode *inode,
root->fs_info->delalloc_batch); root->fs_info->delalloc_batch);
spin_lock(&BTRFS_I(inode)->lock); spin_lock(&BTRFS_I(inode)->lock);
BTRFS_I(inode)->delalloc_bytes += len; BTRFS_I(inode)->delalloc_bytes += len;
if (*bits & EXTENT_DEFRAG)
BTRFS_I(inode)->defrag_bytes += len;
if (do_list && !test_bit(BTRFS_INODE_IN_DELALLOC_LIST, if (do_list && !test_bit(BTRFS_INODE_IN_DELALLOC_LIST,
&BTRFS_I(inode)->runtime_flags)) &BTRFS_I(inode)->runtime_flags))
btrfs_add_delalloc_inodes(root, inode); btrfs_add_delalloc_inodes(root, inode);
...@@ -1591,6 +1616,13 @@ static void btrfs_clear_bit_hook(struct inode *inode, ...@@ -1591,6 +1616,13 @@ static void btrfs_clear_bit_hook(struct inode *inode,
struct extent_state *state, struct extent_state *state,
unsigned long *bits) unsigned long *bits)
{ {
u64 len = state->end + 1 - state->start;
spin_lock(&BTRFS_I(inode)->lock);
if ((state->state & EXTENT_DEFRAG) && (*bits & EXTENT_DEFRAG))
BTRFS_I(inode)->defrag_bytes -= len;
spin_unlock(&BTRFS_I(inode)->lock);
/* /*
* set_bit and clear bit hooks normally require _irqsave/restore * set_bit and clear bit hooks normally require _irqsave/restore
* but in this case, we are only testing for the DELALLOC * but in this case, we are only testing for the DELALLOC
...@@ -1598,7 +1630,6 @@ static void btrfs_clear_bit_hook(struct inode *inode, ...@@ -1598,7 +1630,6 @@ static void btrfs_clear_bit_hook(struct inode *inode,
*/ */
if ((state->state & EXTENT_DELALLOC) && (*bits & EXTENT_DELALLOC)) { if ((state->state & EXTENT_DELALLOC) && (*bits & EXTENT_DELALLOC)) {
struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_root *root = BTRFS_I(inode)->root;
u64 len = state->end + 1 - state->start;
bool do_list = !btrfs_is_free_space_inode(inode); bool do_list = !btrfs_is_free_space_inode(inode);
if (*bits & EXTENT_FIRST_DELALLOC) { if (*bits & EXTENT_FIRST_DELALLOC) {
...@@ -8173,6 +8204,7 @@ struct inode *btrfs_alloc_inode(struct super_block *sb) ...@@ -8173,6 +8204,7 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)
ei->last_sub_trans = 0; ei->last_sub_trans = 0;
ei->logged_trans = 0; ei->logged_trans = 0;
ei->delalloc_bytes = 0; ei->delalloc_bytes = 0;
ei->defrag_bytes = 0;
ei->disk_i_size = 0; ei->disk_i_size = 0;
ei->flags = 0; ei->flags = 0;
ei->csum_bytes = 0; ei->csum_bytes = 0;
...@@ -8231,6 +8263,7 @@ void btrfs_destroy_inode(struct inode *inode) ...@@ -8231,6 +8263,7 @@ void btrfs_destroy_inode(struct inode *inode)
WARN_ON(BTRFS_I(inode)->reserved_extents); WARN_ON(BTRFS_I(inode)->reserved_extents);
WARN_ON(BTRFS_I(inode)->delalloc_bytes); WARN_ON(BTRFS_I(inode)->delalloc_bytes);
WARN_ON(BTRFS_I(inode)->csum_bytes); WARN_ON(BTRFS_I(inode)->csum_bytes);
WARN_ON(BTRFS_I(inode)->defrag_bytes);
/* /*
* This can happen where we create an inode, but somebody else also * This can happen where we create an inode, but somebody else also
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment