mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-01-11 17:10:13 +00:00
for-6.19-rc4-tag
-----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEE8rQSAMVO+zA4DBdWxWXV+ddtWDsFAmlb99EACgkQxWXV+ddt WDtJfQ//cppHAHSxb3NNDGXDiKx4ccCp9CWiOF7z+BTFfngsNGvbs2FzKFnYI2f3 dT/DlPV8uBgVX3uYL3ZI1na/5MShXvS+sajIRhz3woyKBb2shVqVnFmfA8A3pKf6 3Dfm6FWrJHGCgV28Oi5pbg/UQeTAHAmA2aPLYJKRnNwIq8pSSzDWRCVNFfYrt4o2 7UUW1PzasZ7tuqL55HcwzuXjVTYr/t3puLjq+ydVfGSJSZlmlMd3pnZXz8S7/BC6 jVQGOT6nK9SWCnfXD9plqqr4CY+ThJZJNSdhVTwfVxkxVHmEBWfqfhAToqZaLKX9 co3rXvvZyIQf5KeHMmtbb2P736zaAcKb7G41liRN7EZg/gOsROE+UziYRkTg+Xyg rztTksc913DsuHj19sZhIgcKRcym2h57wyZyt7vYAdsv9uksLUgKUo3U9CiTbEsb 8d/vgt1e3+ELoVcc+xVZSSGRDVzvZnxVmRHQV2dAtIXK34FXzqCDeKnFG0wsjqtF Kw6bV93cXLohfcB7fPPBdAHzVN89kfUXTBT8mrri7HnjSnZTJNeHrGpcRNNQ76BT 8RL6gSP32Mpo9HZOYYhl1Xj2hRonRiJrUQAb6x9CY1MMUP2vwVvVBUVj2NAohWdM vAYwRQDigw92RoKIYvHu+X+E5PXgX2AQ9NV8qiL79od+A7NFLgY= =hmbc -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
7f98ab9da0
@ -152,37 +152,39 @@ again:
|
|||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
btrfs_init_delayed_node(node, root, ino);
|
btrfs_init_delayed_node(node, root, ino);
|
||||||
|
|
||||||
|
/* Cached in the inode and can be accessed. */
|
||||||
|
refcount_set(&node->refs, 2);
|
||||||
|
btrfs_delayed_node_ref_tracker_alloc(node, tracker, GFP_NOFS);
|
||||||
|
btrfs_delayed_node_ref_tracker_alloc(node, &node->inode_cache_tracker, GFP_NOFS);
|
||||||
|
|
||||||
/* Allocate and reserve the slot, from now it can return a NULL from xa_load(). */
|
/* Allocate and reserve the slot, from now it can return a NULL from xa_load(). */
|
||||||
ret = xa_reserve(&root->delayed_nodes, ino, GFP_NOFS);
|
ret = xa_reserve(&root->delayed_nodes, ino, GFP_NOFS);
|
||||||
if (ret == -ENOMEM) {
|
if (ret == -ENOMEM)
|
||||||
btrfs_delayed_node_ref_tracker_dir_exit(node);
|
goto cleanup;
|
||||||
kmem_cache_free(delayed_node_cache, node);
|
|
||||||
return ERR_PTR(-ENOMEM);
|
|
||||||
}
|
|
||||||
xa_lock(&root->delayed_nodes);
|
xa_lock(&root->delayed_nodes);
|
||||||
ptr = xa_load(&root->delayed_nodes, ino);
|
ptr = xa_load(&root->delayed_nodes, ino);
|
||||||
if (ptr) {
|
if (ptr) {
|
||||||
/* Somebody inserted it, go back and read it. */
|
/* Somebody inserted it, go back and read it. */
|
||||||
xa_unlock(&root->delayed_nodes);
|
xa_unlock(&root->delayed_nodes);
|
||||||
btrfs_delayed_node_ref_tracker_dir_exit(node);
|
goto cleanup;
|
||||||
kmem_cache_free(delayed_node_cache, node);
|
|
||||||
node = NULL;
|
|
||||||
goto again;
|
|
||||||
}
|
}
|
||||||
ptr = __xa_store(&root->delayed_nodes, ino, node, GFP_ATOMIC);
|
ptr = __xa_store(&root->delayed_nodes, ino, node, GFP_ATOMIC);
|
||||||
ASSERT(xa_err(ptr) != -EINVAL);
|
ASSERT(xa_err(ptr) != -EINVAL);
|
||||||
ASSERT(xa_err(ptr) != -ENOMEM);
|
ASSERT(xa_err(ptr) != -ENOMEM);
|
||||||
ASSERT(ptr == NULL);
|
ASSERT(ptr == NULL);
|
||||||
|
|
||||||
/* Cached in the inode and can be accessed. */
|
|
||||||
refcount_set(&node->refs, 2);
|
|
||||||
btrfs_delayed_node_ref_tracker_alloc(node, tracker, GFP_ATOMIC);
|
|
||||||
btrfs_delayed_node_ref_tracker_alloc(node, &node->inode_cache_tracker, GFP_ATOMIC);
|
|
||||||
|
|
||||||
btrfs_inode->delayed_node = node;
|
btrfs_inode->delayed_node = node;
|
||||||
xa_unlock(&root->delayed_nodes);
|
xa_unlock(&root->delayed_nodes);
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
|
cleanup:
|
||||||
|
btrfs_delayed_node_ref_tracker_free(node, tracker);
|
||||||
|
btrfs_delayed_node_ref_tracker_free(node, &node->inode_cache_tracker);
|
||||||
|
btrfs_delayed_node_ref_tracker_dir_exit(node);
|
||||||
|
kmem_cache_free(delayed_node_cache, node);
|
||||||
|
if (ret)
|
||||||
|
return ERR_PTR(ret);
|
||||||
|
goto again;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@ -1728,7 +1728,7 @@ static noinline_for_stack int extent_writepage_io(struct btrfs_inode *inode,
|
|||||||
struct btrfs_ordered_extent *ordered;
|
struct btrfs_ordered_extent *ordered;
|
||||||
|
|
||||||
ordered = btrfs_lookup_first_ordered_range(inode, cur,
|
ordered = btrfs_lookup_first_ordered_range(inode, cur,
|
||||||
folio_end - cur);
|
fs_info->sectorsize);
|
||||||
/*
|
/*
|
||||||
* We have just run delalloc before getting here, so
|
* We have just run delalloc before getting here, so
|
||||||
* there must be an ordered extent.
|
* there must be an ordered extent.
|
||||||
@ -1742,7 +1742,7 @@ static noinline_for_stack int extent_writepage_io(struct btrfs_inode *inode,
|
|||||||
btrfs_put_ordered_extent(ordered);
|
btrfs_put_ordered_extent(ordered);
|
||||||
|
|
||||||
btrfs_mark_ordered_io_finished(inode, folio, cur,
|
btrfs_mark_ordered_io_finished(inode, folio, cur,
|
||||||
end - cur, true);
|
fs_info->sectorsize, true);
|
||||||
/*
|
/*
|
||||||
* This range is beyond i_size, thus we don't need to
|
* This range is beyond i_size, thus we don't need to
|
||||||
* bother writing back.
|
* bother writing back.
|
||||||
@ -1751,8 +1751,8 @@ static noinline_for_stack int extent_writepage_io(struct btrfs_inode *inode,
|
|||||||
* writeback the sectors with subpage dirty bits,
|
* writeback the sectors with subpage dirty bits,
|
||||||
* causing writeback without ordered extent.
|
* causing writeback without ordered extent.
|
||||||
*/
|
*/
|
||||||
btrfs_folio_clear_dirty(fs_info, folio, cur, end - cur);
|
btrfs_folio_clear_dirty(fs_info, folio, cur, fs_info->sectorsize);
|
||||||
break;
|
continue;
|
||||||
}
|
}
|
||||||
ret = submit_one_sector(inode, folio, cur, bio_ctrl, i_size);
|
ret = submit_one_sector(inode, folio, cur, bio_ctrl, i_size);
|
||||||
if (unlikely(ret < 0)) {
|
if (unlikely(ret < 0)) {
|
||||||
|
|||||||
@ -618,19 +618,22 @@ static noinline int __cow_file_range_inline(struct btrfs_inode *inode,
|
|||||||
struct btrfs_drop_extents_args drop_args = { 0 };
|
struct btrfs_drop_extents_args drop_args = { 0 };
|
||||||
struct btrfs_root *root = inode->root;
|
struct btrfs_root *root = inode->root;
|
||||||
struct btrfs_fs_info *fs_info = root->fs_info;
|
struct btrfs_fs_info *fs_info = root->fs_info;
|
||||||
struct btrfs_trans_handle *trans;
|
struct btrfs_trans_handle *trans = NULL;
|
||||||
u64 data_len = (compressed_size ?: size);
|
u64 data_len = (compressed_size ?: size);
|
||||||
int ret;
|
int ret;
|
||||||
struct btrfs_path *path;
|
struct btrfs_path *path;
|
||||||
|
|
||||||
path = btrfs_alloc_path();
|
path = btrfs_alloc_path();
|
||||||
if (!path)
|
if (!path) {
|
||||||
return -ENOMEM;
|
ret = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
trans = btrfs_join_transaction(root);
|
trans = btrfs_join_transaction(root);
|
||||||
if (IS_ERR(trans)) {
|
if (IS_ERR(trans)) {
|
||||||
btrfs_free_path(path);
|
ret = PTR_ERR(trans);
|
||||||
return PTR_ERR(trans);
|
trans = NULL;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
trans->block_rsv = &inode->block_rsv;
|
trans->block_rsv = &inode->block_rsv;
|
||||||
|
|
||||||
@ -674,10 +677,15 @@ out:
|
|||||||
* it won't count as data extent, free them directly here.
|
* it won't count as data extent, free them directly here.
|
||||||
* And at reserve time, it's always aligned to page size, so
|
* And at reserve time, it's always aligned to page size, so
|
||||||
* just free one page here.
|
* just free one page here.
|
||||||
|
*
|
||||||
|
* If we fallback to non-inline (ret == 1) due to -ENOSPC, then we need
|
||||||
|
* to keep the data reservation.
|
||||||
*/
|
*/
|
||||||
btrfs_qgroup_free_data(inode, NULL, 0, fs_info->sectorsize, NULL);
|
if (ret <= 0)
|
||||||
|
btrfs_qgroup_free_data(inode, NULL, 0, fs_info->sectorsize, NULL);
|
||||||
btrfs_free_path(path);
|
btrfs_free_path(path);
|
||||||
btrfs_end_transaction(trans);
|
if (trans)
|
||||||
|
btrfs_end_transaction(trans);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3208,9 +3208,15 @@ static int qgroup_snapshot_quick_inherit(struct btrfs_fs_info *fs_info,
|
|||||||
{
|
{
|
||||||
struct btrfs_qgroup *src;
|
struct btrfs_qgroup *src;
|
||||||
struct btrfs_qgroup *parent;
|
struct btrfs_qgroup *parent;
|
||||||
|
struct btrfs_qgroup *qgroup;
|
||||||
struct btrfs_qgroup_list *list;
|
struct btrfs_qgroup_list *list;
|
||||||
|
LIST_HEAD(qgroup_list);
|
||||||
|
const u32 nodesize = fs_info->nodesize;
|
||||||
int nr_parents = 0;
|
int nr_parents = 0;
|
||||||
|
|
||||||
|
if (btrfs_qgroup_mode(fs_info) != BTRFS_QGROUP_MODE_FULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
src = find_qgroup_rb(fs_info, srcid);
|
src = find_qgroup_rb(fs_info, srcid);
|
||||||
if (!src)
|
if (!src)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
@ -3245,8 +3251,19 @@ static int qgroup_snapshot_quick_inherit(struct btrfs_fs_info *fs_info,
|
|||||||
if (parent->excl != parent->rfer)
|
if (parent->excl != parent->rfer)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
parent->excl += fs_info->nodesize;
|
qgroup_iterator_add(&qgroup_list, parent);
|
||||||
parent->rfer += fs_info->nodesize;
|
list_for_each_entry(qgroup, &qgroup_list, iterator) {
|
||||||
|
qgroup->rfer += nodesize;
|
||||||
|
qgroup->rfer_cmpr += nodesize;
|
||||||
|
qgroup->excl += nodesize;
|
||||||
|
qgroup->excl_cmpr += nodesize;
|
||||||
|
qgroup_dirty(fs_info, qgroup);
|
||||||
|
|
||||||
|
/* Append parent qgroups to @qgroup_list. */
|
||||||
|
list_for_each_entry(list, &qgroup->groups, next_group)
|
||||||
|
qgroup_iterator_add(&qgroup_list, list->group);
|
||||||
|
}
|
||||||
|
qgroup_iterator_clean(&qgroup_list);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -520,13 +520,14 @@ static inline int is_transaction_blocked(struct btrfs_transaction *trans)
|
|||||||
* when this is done, it is safe to start a new transaction, but the current
|
* when this is done, it is safe to start a new transaction, but the current
|
||||||
* transaction might not be fully on disk.
|
* transaction might not be fully on disk.
|
||||||
*/
|
*/
|
||||||
static void wait_current_trans(struct btrfs_fs_info *fs_info)
|
static void wait_current_trans(struct btrfs_fs_info *fs_info, unsigned int type)
|
||||||
{
|
{
|
||||||
struct btrfs_transaction *cur_trans;
|
struct btrfs_transaction *cur_trans;
|
||||||
|
|
||||||
spin_lock(&fs_info->trans_lock);
|
spin_lock(&fs_info->trans_lock);
|
||||||
cur_trans = fs_info->running_transaction;
|
cur_trans = fs_info->running_transaction;
|
||||||
if (cur_trans && is_transaction_blocked(cur_trans)) {
|
if (cur_trans && is_transaction_blocked(cur_trans) &&
|
||||||
|
(btrfs_blocked_trans_types[cur_trans->state] & type)) {
|
||||||
refcount_inc(&cur_trans->use_count);
|
refcount_inc(&cur_trans->use_count);
|
||||||
spin_unlock(&fs_info->trans_lock);
|
spin_unlock(&fs_info->trans_lock);
|
||||||
|
|
||||||
@ -701,12 +702,12 @@ again:
|
|||||||
sb_start_intwrite(fs_info->sb);
|
sb_start_intwrite(fs_info->sb);
|
||||||
|
|
||||||
if (may_wait_transaction(fs_info, type))
|
if (may_wait_transaction(fs_info, type))
|
||||||
wait_current_trans(fs_info);
|
wait_current_trans(fs_info, type);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
ret = join_transaction(fs_info, type);
|
ret = join_transaction(fs_info, type);
|
||||||
if (ret == -EBUSY) {
|
if (ret == -EBUSY) {
|
||||||
wait_current_trans(fs_info);
|
wait_current_trans(fs_info, type);
|
||||||
if (unlikely(type == TRANS_ATTACH ||
|
if (unlikely(type == TRANS_ATTACH ||
|
||||||
type == TRANS_JOIN_NOSTART))
|
type == TRANS_JOIN_NOSTART))
|
||||||
ret = -ENOENT;
|
ret = -ENOENT;
|
||||||
@ -1003,7 +1004,7 @@ out:
|
|||||||
|
|
||||||
void btrfs_throttle(struct btrfs_fs_info *fs_info)
|
void btrfs_throttle(struct btrfs_fs_info *fs_info)
|
||||||
{
|
{
|
||||||
wait_current_trans(fs_info);
|
wait_current_trans(fs_info, TRANS_START);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool btrfs_should_end_transaction(struct btrfs_trans_handle *trans)
|
bool btrfs_should_end_transaction(struct btrfs_trans_handle *trans)
|
||||||
|
|||||||
@ -6341,10 +6341,8 @@ again:
|
|||||||
* and no keys greater than that, so bail out.
|
* and no keys greater than that, so bail out.
|
||||||
*/
|
*/
|
||||||
break;
|
break;
|
||||||
} else if ((min_key->type == BTRFS_INODE_REF_KEY ||
|
} else if (min_key->type == BTRFS_INODE_REF_KEY ||
|
||||||
min_key->type == BTRFS_INODE_EXTREF_KEY) &&
|
min_key->type == BTRFS_INODE_EXTREF_KEY) {
|
||||||
(inode->generation == trans->transid ||
|
|
||||||
ctx->logging_conflict_inodes)) {
|
|
||||||
u64 other_ino = 0;
|
u64 other_ino = 0;
|
||||||
u64 other_parent = 0;
|
u64 other_parent = 0;
|
||||||
|
|
||||||
|
|||||||
@ -224,7 +224,8 @@ DECLARE_EVENT_CLASS(btrfs__inode,
|
|||||||
__entry->generation = BTRFS_I(inode)->generation;
|
__entry->generation = BTRFS_I(inode)->generation;
|
||||||
__entry->last_trans = BTRFS_I(inode)->last_trans;
|
__entry->last_trans = BTRFS_I(inode)->last_trans;
|
||||||
__entry->logged_trans = BTRFS_I(inode)->logged_trans;
|
__entry->logged_trans = BTRFS_I(inode)->logged_trans;
|
||||||
__entry->root_objectid = btrfs_root_id(BTRFS_I(inode)->root);
|
__entry->root_objectid = BTRFS_I(inode)->root ?
|
||||||
|
btrfs_root_id(BTRFS_I(inode)->root) : 0;
|
||||||
),
|
),
|
||||||
|
|
||||||
TP_printk_btrfs("root=%llu(%s) gen=%llu ino=%llu blocks=%llu "
|
TP_printk_btrfs("root=%llu(%s) gen=%llu ino=%llu blocks=%llu "
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user