Skip to content

Commit 364ecf3

Browse files
Qu Wenruokdave
authored andcommitted
btrfs: qgroup: Introduce extent changeset for qgroup reserve functions
Introduce a new parameter, struct extent_changeset for btrfs_qgroup_reserved_data() and its callers. Such extent_changeset was used in btrfs_qgroup_reserve_data() to record which range it reserved in current reserve, so it can free it in error paths. The reason we need to export it to callers is, at buffered write error path, without knowing what exactly which range we reserved in current allocation, we can free space which is not reserved by us. This will lead to qgroup reserved space underflow. Reviewed-by: Chandan Rajendra <[email protected]> Signed-off-by: Qu Wenruo <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent a12b877 commit 364ecf3

File tree

10 files changed

+119
-41
lines changed

10 files changed

+119
-41
lines changed

fs/btrfs/ctree.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2708,8 +2708,9 @@ enum btrfs_flush_state {
27082708
COMMIT_TRANS = 6,
27092709
};
27102710

2711-
int btrfs_check_data_free_space(struct inode *inode, u64 start, u64 len);
27122711
int btrfs_alloc_data_chunk_ondemand(struct btrfs_inode *inode, u64 bytes);
2712+
int btrfs_check_data_free_space(struct inode *inode,
2713+
struct extent_changeset **reserved, u64 start, u64 len);
27132714
void btrfs_free_reserved_data_space(struct inode *inode, u64 start, u64 len);
27142715
void btrfs_free_reserved_data_space_noquota(struct inode *inode, u64 start,
27152716
u64 len);
@@ -2727,7 +2728,8 @@ void btrfs_subvolume_release_metadata(struct btrfs_fs_info *fs_info,
27272728
struct btrfs_block_rsv *rsv);
27282729
int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes);
27292730
void btrfs_delalloc_release_metadata(struct btrfs_inode *inode, u64 num_bytes);
2730-
int btrfs_delalloc_reserve_space(struct inode *inode, u64 start, u64 len);
2731+
int btrfs_delalloc_reserve_space(struct inode *inode,
2732+
struct extent_changeset **reserved, u64 start, u64 len);
27312733
void btrfs_delalloc_release_space(struct inode *inode, u64 start, u64 len);
27322734
void btrfs_init_block_rsv(struct btrfs_block_rsv *rsv, unsigned short type);
27332735
struct btrfs_block_rsv *btrfs_alloc_block_rsv(struct btrfs_fs_info *fs_info,

fs/btrfs/extent-tree.c

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3402,6 +3402,7 @@ static int cache_save_setup(struct btrfs_block_group_cache *block_group,
34023402
struct btrfs_fs_info *fs_info = block_group->fs_info;
34033403
struct btrfs_root *root = fs_info->tree_root;
34043404
struct inode *inode = NULL;
3405+
struct extent_changeset *data_reserved = NULL;
34053406
u64 alloc_hint = 0;
34063407
int dcs = BTRFS_DC_ERROR;
34073408
u64 num_pages = 0;
@@ -3521,7 +3522,7 @@ static int cache_save_setup(struct btrfs_block_group_cache *block_group,
35213522
num_pages *= 16;
35223523
num_pages *= PAGE_SIZE;
35233524

3524-
ret = btrfs_check_data_free_space(inode, 0, num_pages);
3525+
ret = btrfs_check_data_free_space(inode, &data_reserved, 0, num_pages);
35253526
if (ret)
35263527
goto out_put;
35273528

@@ -3552,6 +3553,7 @@ static int cache_save_setup(struct btrfs_block_group_cache *block_group,
35523553
block_group->disk_cache_state = dcs;
35533554
spin_unlock(&block_group->lock);
35543555

3556+
extent_changeset_free(data_reserved);
35553557
return ret;
35563558
}
35573559

@@ -4326,12 +4328,8 @@ int btrfs_alloc_data_chunk_ondemand(struct btrfs_inode *inode, u64 bytes)
43264328
return ret;
43274329
}
43284330

4329-
/*
4330-
* New check_data_free_space() with ability for precious data reservation
4331-
* Will replace old btrfs_check_data_free_space(), but for patch split,
4332-
* add a new function first and then replace it.
4333-
*/
4334-
int btrfs_check_data_free_space(struct inode *inode, u64 start, u64 len)
4331+
int btrfs_check_data_free_space(struct inode *inode,
4332+
struct extent_changeset **reserved, u64 start, u64 len)
43354333
{
43364334
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
43374335
int ret;
@@ -4346,9 +4344,11 @@ int btrfs_check_data_free_space(struct inode *inode, u64 start, u64 len)
43464344
return ret;
43474345

43484346
/* Use new btrfs_qgroup_reserve_data to reserve precious data space. */
4349-
ret = btrfs_qgroup_reserve_data(inode, start, len);
4347+
ret = btrfs_qgroup_reserve_data(inode, reserved, start, len);
43504348
if (ret < 0)
43514349
btrfs_free_reserved_data_space_noquota(inode, start, len);
4350+
else
4351+
ret = 0;
43524352
return ret;
43534353
}
43544354

@@ -6175,6 +6175,8 @@ void btrfs_delalloc_release_metadata(struct btrfs_inode *inode, u64 num_bytes)
61756175
* @inode: inode we're writing to
61766176
* @start: start range we are writing to
61776177
* @len: how long the range we are writing to
6178+
* @reserved: mandatory parameter, record actually reserved qgroup ranges of
6179+
* current reservation.
61786180
*
61796181
* This will do the following things
61806182
*
@@ -6192,11 +6194,12 @@ void btrfs_delalloc_release_metadata(struct btrfs_inode *inode, u64 num_bytes)
61926194
* Return 0 for success
61936195
* Return <0 for error(-ENOSPC or -EQUOT)
61946196
*/
6195-
int btrfs_delalloc_reserve_space(struct inode *inode, u64 start, u64 len)
6197+
int btrfs_delalloc_reserve_space(struct inode *inode,
6198+
struct extent_changeset **reserved, u64 start, u64 len)
61966199
{
61976200
int ret;
61986201

6199-
ret = btrfs_check_data_free_space(inode, start, len);
6202+
ret = btrfs_check_data_free_space(inode, reserved, start, len);
62006203
if (ret < 0)
62016204
return ret;
62026205
ret = btrfs_delalloc_reserve_metadata(BTRFS_I(inode), len);

fs/btrfs/extent_io.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,40 @@ struct extent_changeset {
215215
struct ulist range_changed;
216216
};
217217

218+
static inline void extent_changeset_init(struct extent_changeset *changeset)
219+
{
220+
changeset->bytes_changed = 0;
221+
ulist_init(&changeset->range_changed);
222+
}
223+
224+
static inline struct extent_changeset *extent_changeset_alloc(void)
225+
{
226+
struct extent_changeset *ret;
227+
228+
ret = kmalloc(sizeof(*ret), GFP_KERNEL);
229+
if (!ret)
230+
return NULL;
231+
232+
extent_changeset_init(ret);
233+
return ret;
234+
}
235+
236+
static inline void extent_changeset_release(struct extent_changeset *changeset)
237+
{
238+
if (!changeset)
239+
return;
240+
changeset->bytes_changed = 0;
241+
ulist_release(&changeset->range_changed);
242+
}
243+
244+
static inline void extent_changeset_free(struct extent_changeset *changeset)
245+
{
246+
if (!changeset)
247+
return;
248+
extent_changeset_release(changeset);
249+
kfree(changeset);
250+
}
251+
218252
static inline void extent_set_compress_type(unsigned long *bio_flags,
219253
int compress_type)
220254
{

fs/btrfs/file.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1581,6 +1581,7 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
15811581
struct btrfs_root *root = BTRFS_I(inode)->root;
15821582
struct page **pages = NULL;
15831583
struct extent_state *cached_state = NULL;
1584+
struct extent_changeset *data_reserved = NULL;
15841585
u64 release_bytes = 0;
15851586
u64 lockstart;
15861587
u64 lockend;
@@ -1628,7 +1629,9 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
16281629
reserve_bytes = round_up(write_bytes + sector_offset,
16291630
fs_info->sectorsize);
16301631

1631-
ret = btrfs_check_data_free_space(inode, pos, write_bytes);
1632+
extent_changeset_release(data_reserved);
1633+
ret = btrfs_check_data_free_space(inode, &data_reserved, pos,
1634+
write_bytes);
16321635
if (ret < 0) {
16331636
if ((BTRFS_I(inode)->flags & (BTRFS_INODE_NODATACOW |
16341637
BTRFS_INODE_PREALLOC)) &&
@@ -1802,6 +1805,7 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
18021805
}
18031806
}
18041807

1808+
extent_changeset_free(data_reserved);
18051809
return num_written ? num_written : ret;
18061810
}
18071811

@@ -2772,6 +2776,7 @@ static long btrfs_fallocate(struct file *file, int mode,
27722776
{
27732777
struct inode *inode = file_inode(file);
27742778
struct extent_state *cached_state = NULL;
2779+
struct extent_changeset *data_reserved = NULL;
27752780
struct falloc_range *range;
27762781
struct falloc_range *tmp;
27772782
struct list_head reserve_list;
@@ -2901,8 +2906,8 @@ static long btrfs_fallocate(struct file *file, int mode,
29012906
free_extent_map(em);
29022907
break;
29032908
}
2904-
ret = btrfs_qgroup_reserve_data(inode, cur_offset,
2905-
last_byte - cur_offset);
2909+
ret = btrfs_qgroup_reserve_data(inode, &data_reserved,
2910+
cur_offset, last_byte - cur_offset);
29062911
if (ret < 0) {
29072912
free_extent_map(em);
29082913
break;
@@ -2974,6 +2979,7 @@ static long btrfs_fallocate(struct file *file, int mode,
29742979
if (ret != 0)
29752980
btrfs_free_reserved_data_space(inode, alloc_start,
29762981
alloc_end - cur_offset);
2982+
extent_changeset_free(data_reserved);
29772983
return ret;
29782984
}
29792985

fs/btrfs/inode-map.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,7 @@ int btrfs_save_ino_cache(struct btrfs_root *root,
400400
struct btrfs_path *path;
401401
struct inode *inode;
402402
struct btrfs_block_rsv *rsv;
403+
struct extent_changeset *data_reserved = NULL;
403404
u64 num_bytes;
404405
u64 alloc_hint = 0;
405406
int ret;
@@ -492,7 +493,7 @@ int btrfs_save_ino_cache(struct btrfs_root *root,
492493
/* Just to make sure we have enough space */
493494
prealloc += 8 * PAGE_SIZE;
494495

495-
ret = btrfs_delalloc_reserve_space(inode, 0, prealloc);
496+
ret = btrfs_delalloc_reserve_space(inode, &data_reserved, 0, prealloc);
496497
if (ret)
497498
goto out_put;
498499

@@ -516,6 +517,7 @@ int btrfs_save_ino_cache(struct btrfs_root *root,
516517
trans->bytes_reserved = num_bytes;
517518

518519
btrfs_free_path(path);
520+
extent_changeset_free(data_reserved);
519521
return ret;
520522
}
521523

fs/btrfs/inode.c

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2037,6 +2037,7 @@ static void btrfs_writepage_fixup_worker(struct btrfs_work *work)
20372037
struct btrfs_writepage_fixup *fixup;
20382038
struct btrfs_ordered_extent *ordered;
20392039
struct extent_state *cached_state = NULL;
2040+
struct extent_changeset *data_reserved = NULL;
20402041
struct page *page;
20412042
struct inode *inode;
20422043
u64 page_start;
@@ -2074,7 +2075,7 @@ static void btrfs_writepage_fixup_worker(struct btrfs_work *work)
20742075
goto again;
20752076
}
20762077

2077-
ret = btrfs_delalloc_reserve_space(inode, page_start,
2078+
ret = btrfs_delalloc_reserve_space(inode, &data_reserved, page_start,
20782079
PAGE_SIZE);
20792080
if (ret) {
20802081
mapping_set_error(page->mapping, ret);
@@ -2094,6 +2095,7 @@ static void btrfs_writepage_fixup_worker(struct btrfs_work *work)
20942095
unlock_page(page);
20952096
put_page(page);
20962097
kfree(fixup);
2098+
extent_changeset_free(data_reserved);
20972099
}
20982100

20992101
/*
@@ -4769,6 +4771,7 @@ int btrfs_truncate_block(struct inode *inode, loff_t from, loff_t len,
47694771
struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
47704772
struct btrfs_ordered_extent *ordered;
47714773
struct extent_state *cached_state = NULL;
4774+
struct extent_changeset *data_reserved = NULL;
47724775
char *kaddr;
47734776
u32 blocksize = fs_info->sectorsize;
47744777
pgoff_t index = from >> PAGE_SHIFT;
@@ -4783,7 +4786,7 @@ int btrfs_truncate_block(struct inode *inode, loff_t from, loff_t len,
47834786
(!len || ((len & (blocksize - 1)) == 0)))
47844787
goto out;
47854788

4786-
ret = btrfs_delalloc_reserve_space(inode,
4789+
ret = btrfs_delalloc_reserve_space(inode, &data_reserved,
47874790
round_down(from, blocksize), blocksize);
47884791
if (ret)
47894792
goto out;
@@ -4868,6 +4871,7 @@ int btrfs_truncate_block(struct inode *inode, loff_t from, loff_t len,
48684871
unlock_page(page);
48694872
put_page(page);
48704873
out:
4874+
extent_changeset_free(data_reserved);
48714875
return ret;
48724876
}
48734877

@@ -8718,6 +8722,7 @@ static ssize_t btrfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
87188722
struct inode *inode = file->f_mapping->host;
87198723
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
87208724
struct btrfs_dio_data dio_data = { 0 };
8725+
struct extent_changeset *data_reserved = NULL;
87218726
loff_t offset = iocb->ki_pos;
87228727
size_t count = 0;
87238728
int flags = 0;
@@ -8754,7 +8759,8 @@ static ssize_t btrfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
87548759
inode_unlock(inode);
87558760
relock = true;
87568761
}
8757-
ret = btrfs_delalloc_reserve_space(inode, offset, count);
8762+
ret = btrfs_delalloc_reserve_space(inode, &data_reserved,
8763+
offset, count);
87588764
if (ret)
87598765
goto out;
87608766
dio_data.outstanding_extents = count_max_extents(count);
@@ -8811,6 +8817,7 @@ static ssize_t btrfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
88118817
if (relock)
88128818
inode_lock(inode);
88138819

8820+
extent_changeset_free(data_reserved);
88148821
return ret;
88158822
}
88168823

@@ -9043,6 +9050,7 @@ int btrfs_page_mkwrite(struct vm_fault *vmf)
90439050
struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
90449051
struct btrfs_ordered_extent *ordered;
90459052
struct extent_state *cached_state = NULL;
9053+
struct extent_changeset *data_reserved = NULL;
90469054
char *kaddr;
90479055
unsigned long zero_start;
90489056
loff_t size;
@@ -9068,7 +9076,7 @@ int btrfs_page_mkwrite(struct vm_fault *vmf)
90689076
* end up waiting indefinitely to get a lock on the page currently
90699077
* being processed by btrfs_page_mkwrite() function.
90709078
*/
9071-
ret = btrfs_delalloc_reserve_space(inode, page_start,
9079+
ret = btrfs_delalloc_reserve_space(inode, &data_reserved, page_start,
90729080
reserved_space);
90739081
if (!ret) {
90749082
ret = file_update_time(vmf->vma->vm_file);
@@ -9174,13 +9182,15 @@ int btrfs_page_mkwrite(struct vm_fault *vmf)
91749182
out_unlock:
91759183
if (!ret) {
91769184
sb_end_pagefault(inode->i_sb);
9185+
extent_changeset_free(data_reserved);
91779186
return VM_FAULT_LOCKED;
91789187
}
91799188
unlock_page(page);
91809189
out:
91819190
btrfs_delalloc_release_space(inode, page_start, reserved_space);
91829191
out_noreserve:
91839192
sb_end_pagefault(inode->i_sb);
9193+
extent_changeset_free(data_reserved);
91849194
return ret;
91859195
}
91869196

fs/btrfs/ioctl.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1127,6 +1127,7 @@ static int cluster_pages_for_defrag(struct inode *inode,
11271127
struct btrfs_ordered_extent *ordered;
11281128
struct extent_state *cached_state = NULL;
11291129
struct extent_io_tree *tree;
1130+
struct extent_changeset *data_reserved = NULL;
11301131
gfp_t mask = btrfs_alloc_write_mask(inode->i_mapping);
11311132

11321133
file_end = (isize - 1) >> PAGE_SHIFT;
@@ -1135,7 +1136,7 @@ static int cluster_pages_for_defrag(struct inode *inode,
11351136

11361137
page_cnt = min_t(u64, (u64)num_pages, (u64)file_end - start_index + 1);
11371138

1138-
ret = btrfs_delalloc_reserve_space(inode,
1139+
ret = btrfs_delalloc_reserve_space(inode, &data_reserved,
11391140
start_index << PAGE_SHIFT,
11401141
page_cnt << PAGE_SHIFT);
11411142
if (ret)
@@ -1247,6 +1248,7 @@ static int cluster_pages_for_defrag(struct inode *inode,
12471248
unlock_page(pages[i]);
12481249
put_page(pages[i]);
12491250
}
1251+
extent_changeset_free(data_reserved);
12501252
return i_done;
12511253
out:
12521254
for (i = 0; i < i_done; i++) {
@@ -1256,6 +1258,7 @@ static int cluster_pages_for_defrag(struct inode *inode,
12561258
btrfs_delalloc_release_space(inode,
12571259
start_index << PAGE_SHIFT,
12581260
page_cnt << PAGE_SHIFT);
1261+
extent_changeset_free(data_reserved);
12591262
return ret;
12601263

12611264
}

0 commit comments

Comments
 (0)