Skip to content

Commit 7f98ab9

Browse files
committed
Merge tag 'for-6.19-rc4-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux
Pull btrfs fixes from David Sterba: - fix potential deadlock due to mismatching transaction states when waiting for the current transaction - fix squota accounting with nested snapshots - fix quota inheritance of qgroups with multiple parent qgroups - fix NULL inode pointer in evict tracepoint - fix writes beyond end of file on systems with 64K page size and 4K block size - fix logging of inodes after exchange rename - fix use after free when using ref_tracker feature - space reservation fixes * tag 'for-6.19-rc4-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: btrfs: fix reservation leak in some error paths when inserting inline extent btrfs: do not free data reservation in fallback from inline due to -ENOSPC btrfs: fix use-after-free warning in btrfs_get_or_create_delayed_node() btrfs: always detect conflicting inodes when logging inode refs btrfs: fix beyond-EOF write handling btrfs: fix deadlock in wait_current_trans() due to ignored transaction type btrfs: fix NULL dereference on root when tracing inode eviction btrfs: qgroup: update all parent qgroups when doing quick inherit btrfs: fix qgroup_snapshot_quick_inherit() squota bug
2 parents 3609fa9 + c1c050f commit 7f98ab9

7 files changed

Lines changed: 65 additions & 38 deletions

File tree

fs/btrfs/delayed-inode.c

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -152,37 +152,39 @@ static struct btrfs_delayed_node *btrfs_get_or_create_delayed_node(
152152
return ERR_PTR(-ENOMEM);
153153
btrfs_init_delayed_node(node, root, ino);
154154

155+
/* Cached in the inode and can be accessed. */
156+
refcount_set(&node->refs, 2);
157+
btrfs_delayed_node_ref_tracker_alloc(node, tracker, GFP_NOFS);
158+
btrfs_delayed_node_ref_tracker_alloc(node, &node->inode_cache_tracker, GFP_NOFS);
159+
155160
/* Allocate and reserve the slot, from now it can return a NULL from xa_load(). */
156161
ret = xa_reserve(&root->delayed_nodes, ino, GFP_NOFS);
157-
if (ret == -ENOMEM) {
158-
btrfs_delayed_node_ref_tracker_dir_exit(node);
159-
kmem_cache_free(delayed_node_cache, node);
160-
return ERR_PTR(-ENOMEM);
161-
}
162+
if (ret == -ENOMEM)
163+
goto cleanup;
164+
162165
xa_lock(&root->delayed_nodes);
163166
ptr = xa_load(&root->delayed_nodes, ino);
164167
if (ptr) {
165168
/* Somebody inserted it, go back and read it. */
166169
xa_unlock(&root->delayed_nodes);
167-
btrfs_delayed_node_ref_tracker_dir_exit(node);
168-
kmem_cache_free(delayed_node_cache, node);
169-
node = NULL;
170-
goto again;
170+
goto cleanup;
171171
}
172172
ptr = __xa_store(&root->delayed_nodes, ino, node, GFP_ATOMIC);
173173
ASSERT(xa_err(ptr) != -EINVAL);
174174
ASSERT(xa_err(ptr) != -ENOMEM);
175175
ASSERT(ptr == NULL);
176-
177-
/* Cached in the inode and can be accessed. */
178-
refcount_set(&node->refs, 2);
179-
btrfs_delayed_node_ref_tracker_alloc(node, tracker, GFP_ATOMIC);
180-
btrfs_delayed_node_ref_tracker_alloc(node, &node->inode_cache_tracker, GFP_ATOMIC);
181-
182176
btrfs_inode->delayed_node = node;
183177
xa_unlock(&root->delayed_nodes);
184178

185179
return node;
180+
cleanup:
181+
btrfs_delayed_node_ref_tracker_free(node, tracker);
182+
btrfs_delayed_node_ref_tracker_free(node, &node->inode_cache_tracker);
183+
btrfs_delayed_node_ref_tracker_dir_exit(node);
184+
kmem_cache_free(delayed_node_cache, node);
185+
if (ret)
186+
return ERR_PTR(ret);
187+
goto again;
186188
}
187189

188190
/*

fs/btrfs/extent_io.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1728,7 +1728,7 @@ static noinline_for_stack int extent_writepage_io(struct btrfs_inode *inode,
17281728
struct btrfs_ordered_extent *ordered;
17291729

17301730
ordered = btrfs_lookup_first_ordered_range(inode, cur,
1731-
folio_end - cur);
1731+
fs_info->sectorsize);
17321732
/*
17331733
* We have just run delalloc before getting here, so
17341734
* there must be an ordered extent.
@@ -1742,7 +1742,7 @@ static noinline_for_stack int extent_writepage_io(struct btrfs_inode *inode,
17421742
btrfs_put_ordered_extent(ordered);
17431743

17441744
btrfs_mark_ordered_io_finished(inode, folio, cur,
1745-
end - cur, true);
1745+
fs_info->sectorsize, true);
17461746
/*
17471747
* This range is beyond i_size, thus we don't need to
17481748
* bother writing back.
@@ -1751,8 +1751,8 @@ static noinline_for_stack int extent_writepage_io(struct btrfs_inode *inode,
17511751
* writeback the sectors with subpage dirty bits,
17521752
* causing writeback without ordered extent.
17531753
*/
1754-
btrfs_folio_clear_dirty(fs_info, folio, cur, end - cur);
1755-
break;
1754+
btrfs_folio_clear_dirty(fs_info, folio, cur, fs_info->sectorsize);
1755+
continue;
17561756
}
17571757
ret = submit_one_sector(inode, folio, cur, bio_ctrl, i_size);
17581758
if (unlikely(ret < 0)) {

fs/btrfs/inode.c

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -618,19 +618,22 @@ static noinline int __cow_file_range_inline(struct btrfs_inode *inode,
618618
struct btrfs_drop_extents_args drop_args = { 0 };
619619
struct btrfs_root *root = inode->root;
620620
struct btrfs_fs_info *fs_info = root->fs_info;
621-
struct btrfs_trans_handle *trans;
621+
struct btrfs_trans_handle *trans = NULL;
622622
u64 data_len = (compressed_size ?: size);
623623
int ret;
624624
struct btrfs_path *path;
625625

626626
path = btrfs_alloc_path();
627-
if (!path)
628-
return -ENOMEM;
627+
if (!path) {
628+
ret = -ENOMEM;
629+
goto out;
630+
}
629631

630632
trans = btrfs_join_transaction(root);
631633
if (IS_ERR(trans)) {
632-
btrfs_free_path(path);
633-
return PTR_ERR(trans);
634+
ret = PTR_ERR(trans);
635+
trans = NULL;
636+
goto out;
634637
}
635638
trans->block_rsv = &inode->block_rsv;
636639

@@ -674,10 +677,15 @@ static noinline int __cow_file_range_inline(struct btrfs_inode *inode,
674677
* it won't count as data extent, free them directly here.
675678
* And at reserve time, it's always aligned to page size, so
676679
* just free one page here.
680+
*
681+
* If we fallback to non-inline (ret == 1) due to -ENOSPC, then we need
682+
* to keep the data reservation.
677683
*/
678-
btrfs_qgroup_free_data(inode, NULL, 0, fs_info->sectorsize, NULL);
684+
if (ret <= 0)
685+
btrfs_qgroup_free_data(inode, NULL, 0, fs_info->sectorsize, NULL);
679686
btrfs_free_path(path);
680-
btrfs_end_transaction(trans);
687+
if (trans)
688+
btrfs_end_transaction(trans);
681689
return ret;
682690
}
683691

fs/btrfs/qgroup.c

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3208,9 +3208,15 @@ static int qgroup_snapshot_quick_inherit(struct btrfs_fs_info *fs_info,
32083208
{
32093209
struct btrfs_qgroup *src;
32103210
struct btrfs_qgroup *parent;
3211+
struct btrfs_qgroup *qgroup;
32113212
struct btrfs_qgroup_list *list;
3213+
LIST_HEAD(qgroup_list);
3214+
const u32 nodesize = fs_info->nodesize;
32123215
int nr_parents = 0;
32133216

3217+
if (btrfs_qgroup_mode(fs_info) != BTRFS_QGROUP_MODE_FULL)
3218+
return 0;
3219+
32143220
src = find_qgroup_rb(fs_info, srcid);
32153221
if (!src)
32163222
return -ENOENT;
@@ -3245,8 +3251,19 @@ static int qgroup_snapshot_quick_inherit(struct btrfs_fs_info *fs_info,
32453251
if (parent->excl != parent->rfer)
32463252
return 1;
32473253

3248-
parent->excl += fs_info->nodesize;
3249-
parent->rfer += fs_info->nodesize;
3254+
qgroup_iterator_add(&qgroup_list, parent);
3255+
list_for_each_entry(qgroup, &qgroup_list, iterator) {
3256+
qgroup->rfer += nodesize;
3257+
qgroup->rfer_cmpr += nodesize;
3258+
qgroup->excl += nodesize;
3259+
qgroup->excl_cmpr += nodesize;
3260+
qgroup_dirty(fs_info, qgroup);
3261+
3262+
/* Append parent qgroups to @qgroup_list. */
3263+
list_for_each_entry(list, &qgroup->groups, next_group)
3264+
qgroup_iterator_add(&qgroup_list, list->group);
3265+
}
3266+
qgroup_iterator_clean(&qgroup_list);
32503267
return 0;
32513268
}
32523269

fs/btrfs/transaction.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -520,13 +520,14 @@ static inline int is_transaction_blocked(struct btrfs_transaction *trans)
520520
* when this is done, it is safe to start a new transaction, but the current
521521
* transaction might not be fully on disk.
522522
*/
523-
static void wait_current_trans(struct btrfs_fs_info *fs_info)
523+
static void wait_current_trans(struct btrfs_fs_info *fs_info, unsigned int type)
524524
{
525525
struct btrfs_transaction *cur_trans;
526526

527527
spin_lock(&fs_info->trans_lock);
528528
cur_trans = fs_info->running_transaction;
529-
if (cur_trans && is_transaction_blocked(cur_trans)) {
529+
if (cur_trans && is_transaction_blocked(cur_trans) &&
530+
(btrfs_blocked_trans_types[cur_trans->state] & type)) {
530531
refcount_inc(&cur_trans->use_count);
531532
spin_unlock(&fs_info->trans_lock);
532533

@@ -701,12 +702,12 @@ start_transaction(struct btrfs_root *root, unsigned int num_items,
701702
sb_start_intwrite(fs_info->sb);
702703

703704
if (may_wait_transaction(fs_info, type))
704-
wait_current_trans(fs_info);
705+
wait_current_trans(fs_info, type);
705706

706707
do {
707708
ret = join_transaction(fs_info, type);
708709
if (ret == -EBUSY) {
709-
wait_current_trans(fs_info);
710+
wait_current_trans(fs_info, type);
710711
if (unlikely(type == TRANS_ATTACH ||
711712
type == TRANS_JOIN_NOSTART))
712713
ret = -ENOENT;
@@ -1003,7 +1004,7 @@ int btrfs_wait_for_commit(struct btrfs_fs_info *fs_info, u64 transid)
10031004

10041005
void btrfs_throttle(struct btrfs_fs_info *fs_info)
10051006
{
1006-
wait_current_trans(fs_info);
1007+
wait_current_trans(fs_info, TRANS_START);
10071008
}
10081009

10091010
bool btrfs_should_end_transaction(struct btrfs_trans_handle *trans)

fs/btrfs/tree-log.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6341,10 +6341,8 @@ static int copy_inode_items_to_log(struct btrfs_trans_handle *trans,
63416341
* and no keys greater than that, so bail out.
63426342
*/
63436343
break;
6344-
} else if ((min_key->type == BTRFS_INODE_REF_KEY ||
6345-
min_key->type == BTRFS_INODE_EXTREF_KEY) &&
6346-
(inode->generation == trans->transid ||
6347-
ctx->logging_conflict_inodes)) {
6344+
} else if (min_key->type == BTRFS_INODE_REF_KEY ||
6345+
min_key->type == BTRFS_INODE_EXTREF_KEY) {
63486346
u64 other_ino = 0;
63496347
u64 other_parent = 0;
63506348

include/trace/events/btrfs.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,8 @@ DECLARE_EVENT_CLASS(btrfs__inode,
224224
__entry->generation = BTRFS_I(inode)->generation;
225225
__entry->last_trans = BTRFS_I(inode)->last_trans;
226226
__entry->logged_trans = BTRFS_I(inode)->logged_trans;
227-
__entry->root_objectid = btrfs_root_id(BTRFS_I(inode)->root);
227+
__entry->root_objectid = BTRFS_I(inode)->root ?
228+
btrfs_root_id(BTRFS_I(inode)->root) : 0;
228229
),
229230

230231
TP_printk_btrfs("root=%llu(%s) gen=%llu ino=%llu blocks=%llu "

0 commit comments

Comments
 (0)