mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-03-30 11:04:25 +00:00
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: Wang Shilong <wangsl.fnst@cn.fujitsu.com> Signed-off-by: Miao Xie <miaox@cn.fujitsu.com> Signed-off-by: Chris Mason <clm@fb.com>
This commit is contained in:
parent
48fcc3ff7d
commit
47059d930f
2 changed files with 42 additions and 3 deletions
|
@ -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 @@ error:
|
||||||
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,
|
||||||
{
|
{
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
*/
|
*/
|
||||||
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)
|
||||||
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)
|
||||||
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
|
||||||
|
|
Loading…
Add table
Reference in a new issue