Hi,
Thanks for your patch.
Please subscribe the kernel@openeuler.org mailing list first before sending patch, or your patch would be pending by the mailing list service. Other people can not receive your email.
Follow the tips to subscribe kernel@openeuler.org and kernel-discuss@openeuler.org list. https://openeuler.org/zh/community/mailing-list/
--- Xie XiuQi
On 2021/6/15 11:10, Gou Hao wrote:
From: gouhao gouhao@uniontech.com
make btrfs_truncate_block check NOCOW attribute
mainline inclusion from https://patchwork.kernel.org/project/linux-btrfs/patch/20200130052822.11765-... category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I39MZM CVE: NA
ltp fallocate06 testcase failed
Signed-off-by: gouhao gouhao@uniontech.com
fs/btrfs/ctree.h | 3 ++- fs/btrfs/file.c | 8 ++++---- fs/btrfs/inode.c | 39 +++++++++++++++++++++++++++++++++------ 3 files changed, 39 insertions(+), 11 deletions(-)
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 4d1c12faada8..4f5c58d40a79 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -3271,7 +3271,8 @@ int btrfs_dirty_pages(struct inode *inode, struct page **pages, int btrfs_fdatawrite_range(struct inode *inode, loff_t start, loff_t end); int btrfs_clone_file_range(struct file *file_in, loff_t pos_in, struct file *file_out, loff_t pos_out, u64 len);
+int btrfs_check_can_nocow(struct btrfs_inode *inode, loff_t pos,
size_t *write_bytes);
/* tree-defrag.c */ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, struct btrfs_root *root); diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index a202f2f12b1c..c204fbe512b7 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -1536,8 +1536,8 @@ lock_and_cleanup_extent_if_need(struct btrfs_inode *inode, struct page **pages, return ret; }
-static noinline int check_can_nocow(struct btrfs_inode *inode, loff_t pos,
size_t *write_bytes)
+int btrfs_check_can_nocow(struct btrfs_inode *inode, loff_t pos,
size_t *write_bytes)
{ struct btrfs_fs_info *fs_info = inode->root->fs_info; struct btrfs_root *root = inode->root; @@ -1647,7 +1647,7 @@ static noinline ssize_t btrfs_buffered_write(struct kiocb *iocb, if (ret < 0) { if ((BTRFS_I(inode)->flags & (BTRFS_INODE_NODATACOW | BTRFS_INODE_PREALLOC)) &&
check_can_nocow(BTRFS_I(inode), pos,
btrfs_check_can_nocow(BTRFS_I(inode), pos, &write_bytes) > 0) { /* * For nodata cow case, no need to reserve
@@ -1925,7 +1925,7 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb, */ if (!(BTRFS_I(inode)->flags & (BTRFS_INODE_NODATACOW | BTRFS_INODE_PREALLOC)) ||
check_can_nocow(BTRFS_I(inode), pos, &count) <= 0) {
}btrfs_check_can_nocow(BTRFS_I(inode), pos, &count) <= 0) { inode_unlock(inode); return -EAGAIN;
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 8c6f619c9ee6..6641fa77d4f9 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -4946,11 +4946,13 @@ int btrfs_truncate_block(struct inode *inode, loff_t from, loff_t len, struct extent_state *cached_state = NULL; struct extent_changeset *data_reserved = NULL; char *kaddr;
- bool only_release_metadata = false; u32 blocksize = fs_info->sectorsize; pgoff_t index = from >> PAGE_SHIFT; unsigned offset = from & (blocksize - 1); struct page *page; gfp_t mask = btrfs_alloc_write_mask(mapping);
- size_t write_bytes = blocksize; int ret = 0; u64 block_start; u64 block_end;
@@ -4962,10 +4964,26 @@ int btrfs_truncate_block(struct inode *inode, loff_t from, loff_t len, block_start = round_down(from, blocksize); block_end = block_start + blocksize - 1;
- ret = btrfs_delalloc_reserve_space(inode, &data_reserved,
block_start, blocksize);
- if (ret)
- ret = btrfs_check_data_free_space(inode, &data_reserved,
block_start, blocksize);
- if (ret < 0) {
if ((BTRFS_I(inode)->flags & (BTRFS_INODE_NODATACOW |
BTRFS_INODE_PREALLOC)) &&
btrfs_check_can_nocow(BTRFS_I(inode), block_start,
&write_bytes) > 0) {
/* For nocow case, no need to reserve data space */
only_release_metadata = true;
} else {
goto out;
}
- }
- ret = btrfs_delalloc_reserve_metadata(BTRFS_I(inode), blocksize);
- if (ret < 0) {
if (!only_release_metadata)
btrfs_free_reserved_data_space(inode, data_reserved,
goto out;block_start, blocksize);
- }
again: page = find_or_create_page(mapping, index, mask); @@ -5036,10 +5054,19 @@ int btrfs_truncate_block(struct inode *inode, loff_t from, loff_t len, set_page_dirty(page); unlock_extent_cached(io_tree, block_start, block_end, &cached_state);
- if (only_release_metadata)
set_extent_bit(&BTRFS_I(inode)->io_tree, block_start,
block_end, EXTENT_NORESERVE, NULL, NULL,
GFP_NOFS);
out_unlock:
- if (ret)
btrfs_delalloc_release_space(inode, data_reserved, block_start,
blocksize, true);
- if (ret) {
if (only_release_metadata)
btrfs_delalloc_release_metadata(BTRFS_I(inode),
blocksize, true);
else
btrfs_delalloc_release_space(inode, data_reserved,
block_start, blocksize, true);
- } btrfs_delalloc_release_extents(BTRFS_I(inode), blocksize); unlock_page(page); put_page(page);