Skip to content

Commit 67b07bd

Browse files
nefelim4agkdave
authored andcommitted
Btrfs: reuse cmp workspace in EXTENT_SAME ioctl
We support big dedup requests by splitting range to smaller parts, and call dedupe logic on each of them. Instead of repeated allocation and deallocation, allocate once at the beginning and reuse in the iteration. Signed-off-by: Timofey Titovets <[email protected]> Reviewed-by: David Sterba <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent b672876 commit 67b07bd

File tree

1 file changed

+40
-39
lines changed

1 file changed

+40
-39
lines changed

fs/btrfs/ioctl.c

Lines changed: 40 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2914,8 +2914,6 @@ static void btrfs_cmp_data_free(struct cmp_pages *cmp)
29142914
put_page(pg);
29152915
}
29162916
}
2917-
kfree(cmp->src_pages);
2918-
kfree(cmp->dst_pages);
29192917
}
29202918

29212919
static int btrfs_cmp_data_prepare(struct inode *src, u64 loff,
@@ -2924,40 +2922,14 @@ static int btrfs_cmp_data_prepare(struct inode *src, u64 loff,
29242922
{
29252923
int ret;
29262924
int num_pages = PAGE_ALIGN(len) >> PAGE_SHIFT;
2927-
struct page **src_pgarr, **dst_pgarr;
29282925

2929-
/*
2930-
* We must gather up all the pages before we initiate our
2931-
* extent locking. We use an array for the page pointers. Size
2932-
* of the array is bounded by len, which is in turn bounded by
2933-
* BTRFS_MAX_DEDUPE_LEN.
2934-
*/
2935-
src_pgarr = kcalloc(num_pages, sizeof(struct page *), GFP_KERNEL);
2936-
dst_pgarr = kcalloc(num_pages, sizeof(struct page *), GFP_KERNEL);
2937-
if (!src_pgarr || !dst_pgarr) {
2938-
kfree(src_pgarr);
2939-
kfree(dst_pgarr);
2940-
return -ENOMEM;
2941-
}
29422926
cmp->num_pages = num_pages;
2943-
cmp->src_pages = src_pgarr;
2944-
cmp->dst_pages = dst_pgarr;
2945-
2946-
/*
2947-
* If deduping ranges in the same inode, locking rules make it mandatory
2948-
* to always lock pages in ascending order to avoid deadlocks with
2949-
* concurrent tasks (such as starting writeback/delalloc).
2950-
*/
2951-
if (src == dst && dst_loff < loff) {
2952-
swap(src_pgarr, dst_pgarr);
2953-
swap(loff, dst_loff);
2954-
}
29552927

2956-
ret = gather_extent_pages(src, src_pgarr, cmp->num_pages, loff);
2928+
ret = gather_extent_pages(src, cmp->src_pages, num_pages, loff);
29572929
if (ret)
29582930
goto out;
29592931

2960-
ret = gather_extent_pages(dst, dst_pgarr, cmp->num_pages, dst_loff);
2932+
ret = gather_extent_pages(dst, cmp->dst_pages, num_pages, dst_loff);
29612933

29622934
out:
29632935
if (ret)
@@ -3028,11 +3000,11 @@ static int extent_same_check_offsets(struct inode *inode, u64 off, u64 *plen,
30283000
}
30293001

30303002
static int btrfs_extent_same_range(struct inode *src, u64 loff, u64 olen,
3031-
struct inode *dst, u64 dst_loff)
3003+
struct inode *dst, u64 dst_loff,
3004+
struct cmp_pages *cmp)
30323005
{
30333006
int ret;
30343007
u64 len = olen;
3035-
struct cmp_pages cmp;
30363008
bool same_inode = (src == dst);
30373009
u64 same_lock_start = 0;
30383010
u64 same_lock_len = 0;
@@ -3072,7 +3044,7 @@ static int btrfs_extent_same_range(struct inode *src, u64 loff, u64 olen,
30723044
}
30733045

30743046
again:
3075-
ret = btrfs_cmp_data_prepare(src, loff, dst, dst_loff, olen, &cmp);
3047+
ret = btrfs_cmp_data_prepare(src, loff, dst, dst_loff, olen, cmp);
30763048
if (ret)
30773049
return ret;
30783050

@@ -3095,7 +3067,7 @@ static int btrfs_extent_same_range(struct inode *src, u64 loff, u64 olen,
30953067
* Ranges in the io trees already unlocked. Now unlock all
30963068
* pages before waiting for all IO to complete.
30973069
*/
3098-
btrfs_cmp_data_free(&cmp);
3070+
btrfs_cmp_data_free(cmp);
30993071
if (same_inode) {
31003072
btrfs_wait_ordered_range(src, same_lock_start,
31013073
same_lock_len);
@@ -3108,12 +3080,12 @@ static int btrfs_extent_same_range(struct inode *src, u64 loff, u64 olen,
31083080
ASSERT(ret == 0);
31093081
if (WARN_ON(ret)) {
31103082
/* ranges in the io trees already unlocked */
3111-
btrfs_cmp_data_free(&cmp);
3083+
btrfs_cmp_data_free(cmp);
31123084
return ret;
31133085
}
31143086

31153087
/* pass original length for comparison so we stay within i_size */
3116-
ret = btrfs_cmp_data(olen, &cmp);
3088+
ret = btrfs_cmp_data(olen, cmp);
31173089
if (ret == 0)
31183090
ret = btrfs_clone(src, dst, loff, olen, len, dst_loff, 1);
31193091

@@ -3123,7 +3095,7 @@ static int btrfs_extent_same_range(struct inode *src, u64 loff, u64 olen,
31233095
else
31243096
btrfs_double_extent_unlock(src, loff, dst, dst_loff, len);
31253097

3126-
btrfs_cmp_data_free(&cmp);
3098+
btrfs_cmp_data_free(cmp);
31273099

31283100
return ret;
31293101
}
@@ -3134,6 +3106,8 @@ static int btrfs_extent_same(struct inode *src, u64 loff, u64 olen,
31343106
struct inode *dst, u64 dst_loff)
31353107
{
31363108
int ret;
3109+
struct cmp_pages cmp;
3110+
int num_pages = PAGE_ALIGN(BTRFS_MAX_DEDUPE_LEN) >> PAGE_SHIFT;
31373111
bool same_inode = (src == dst);
31383112
u64 i, tail_len, chunk_count;
31393113

@@ -3154,10 +3128,33 @@ static int btrfs_extent_same(struct inode *src, u64 loff, u64 olen,
31543128

31553129
tail_len = olen % BTRFS_MAX_DEDUPE_LEN;
31563130
chunk_count = div_u64(olen, BTRFS_MAX_DEDUPE_LEN);
3131+
if (chunk_count == 0)
3132+
num_pages = PAGE_ALIGN(tail_len) >> PAGE_SHIFT;
3133+
3134+
/*
3135+
* If deduping ranges in the same inode, locking rules make it
3136+
* mandatory to always lock pages in ascending order to avoid deadlocks
3137+
* with concurrent tasks (such as starting writeback/delalloc).
3138+
*/
3139+
if (same_inode && dst_loff < loff)
3140+
swap(loff, dst_loff);
3141+
3142+
/*
3143+
* We must gather up all the pages before we initiate our extent
3144+
* locking. We use an array for the page pointers. Size of the array is
3145+
* bounded by len, which is in turn bounded by BTRFS_MAX_DEDUPE_LEN.
3146+
*/
3147+
cmp.src_pages = kcalloc(num_pages, sizeof(struct page *), GFP_KERNEL);
3148+
cmp.dst_pages = kcalloc(num_pages, sizeof(struct page *), GFP_KERNEL);
3149+
if (!cmp.src_pages || !cmp.dst_pages) {
3150+
kfree(cmp.src_pages);
3151+
kfree(cmp.dst_pages);
3152+
return -ENOMEM;
3153+
}
31573154

31583155
for (i = 0; i < chunk_count; i++) {
31593156
ret = btrfs_extent_same_range(src, loff, BTRFS_MAX_DEDUPE_LEN,
3160-
dst, dst_loff);
3157+
dst, dst_loff, &cmp);
31613158
if (ret)
31623159
goto out_unlock;
31633160

@@ -3166,14 +3163,18 @@ static int btrfs_extent_same(struct inode *src, u64 loff, u64 olen,
31663163
}
31673164

31683165
if (tail_len > 0)
3169-
ret = btrfs_extent_same_range(src, loff, tail_len, dst, dst_loff);
3166+
ret = btrfs_extent_same_range(src, loff, tail_len, dst,
3167+
dst_loff, &cmp);
31703168

31713169
out_unlock:
31723170
if (same_inode)
31733171
inode_unlock(src);
31743172
else
31753173
btrfs_double_inode_unlock(src, dst);
31763174

3175+
kfree(cmp.src_pages);
3176+
kfree(cmp.dst_pages);
3177+
31773178
return ret;
31783179
}
31793180

0 commit comments

Comments
 (0)