Skip to content

Commit 2c58c39

Browse files
fdmananakdave
authored andcommitted
btrfs: remove BUG() after failure to insert delayed dir index item
Instead of calling BUG() when we fail to insert a delayed dir index item into the delayed node's tree, we can just release all the resources we have allocated/acquired before and return the error to the caller. This is fine because all existing call chains undo anything they have done before calling btrfs_insert_delayed_dir_index() or BUG_ON (when creating pending snapshots in the transaction commit path). So remove the BUG() call and do proper error handling. This relates to a syzbot report linked below, but does not fix it because it only prevents hitting a BUG(), it does not fix the issue where somehow we attempt to use twice the same index number for different index items. Link: https://lore.kernel.org/linux-btrfs/[email protected]/ CC: [email protected] # 5.4+ Reviewed-by: Qu Wenruo <[email protected]> Signed-off-by: Filipe Manana <[email protected]> Reviewed-by: David Sterba <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent 91bfe31 commit 2c58c39

File tree

1 file changed

+47
-27
lines changed

1 file changed

+47
-27
lines changed

fs/btrfs/delayed-inode.c

Lines changed: 47 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1426,7 +1426,29 @@ void btrfs_balance_delayed_items(struct btrfs_fs_info *fs_info)
14261426
btrfs_wq_run_delayed_node(delayed_root, fs_info, BTRFS_DELAYED_BATCH);
14271427
}
14281428

1429-
/* Will return 0 or -ENOMEM */
1429+
static void btrfs_release_dir_index_item_space(struct btrfs_trans_handle *trans)
1430+
{
1431+
struct btrfs_fs_info *fs_info = trans->fs_info;
1432+
const u64 bytes = btrfs_calc_insert_metadata_size(fs_info, 1);
1433+
1434+
if (test_bit(BTRFS_FS_LOG_RECOVERING, &fs_info->flags))
1435+
return;
1436+
1437+
/*
1438+
* Adding the new dir index item does not require touching another
1439+
* leaf, so we can release 1 unit of metadata that was previously
1440+
* reserved when starting the transaction. This applies only to
1441+
* the case where we had a transaction start and excludes the
1442+
* transaction join case (when replaying log trees).
1443+
*/
1444+
trace_btrfs_space_reservation(fs_info, "transaction",
1445+
trans->transid, bytes, 0);
1446+
btrfs_block_rsv_release(fs_info, trans->block_rsv, bytes, NULL);
1447+
ASSERT(trans->bytes_reserved >= bytes);
1448+
trans->bytes_reserved -= bytes;
1449+
}
1450+
1451+
/* Will return 0, -ENOMEM or -EEXIST (index number collision, unexpected). */
14301452
int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans,
14311453
const char *name, int name_len,
14321454
struct btrfs_inode *dir,
@@ -1468,6 +1490,27 @@ int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans,
14681490

14691491
mutex_lock(&delayed_node->mutex);
14701492

1493+
/*
1494+
* First attempt to insert the delayed item. This is to make the error
1495+
* handling path simpler in case we fail (-EEXIST). There's no risk of
1496+
* any other task coming in and running the delayed item before we do
1497+
* the metadata space reservation below, because we are holding the
1498+
* delayed node's mutex and that mutex must also be locked before the
1499+
* node's delayed items can be run.
1500+
*/
1501+
ret = __btrfs_add_delayed_item(delayed_node, delayed_item);
1502+
if (unlikely(ret)) {
1503+
btrfs_err(trans->fs_info,
1504+
"error adding delayed dir index item, name: %.*s, index: %llu, root: %llu, dir: %llu, dir->index_cnt: %llu, delayed_node->index_cnt: %llu, error: %d",
1505+
name_len, name, index, btrfs_root_id(delayed_node->root),
1506+
delayed_node->inode_id, dir->index_cnt,
1507+
delayed_node->index_cnt, ret);
1508+
btrfs_release_delayed_item(delayed_item);
1509+
btrfs_release_dir_index_item_space(trans);
1510+
mutex_unlock(&delayed_node->mutex);
1511+
goto release_node;
1512+
}
1513+
14711514
if (delayed_node->index_item_leaves == 0 ||
14721515
delayed_node->curr_index_batch_size + data_len > leaf_data_size) {
14731516
delayed_node->curr_index_batch_size = data_len;
@@ -1485,37 +1528,14 @@ int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans,
14851528
* impossible.
14861529
*/
14871530
if (WARN_ON(ret)) {
1488-
mutex_unlock(&delayed_node->mutex);
14891531
btrfs_release_delayed_item(delayed_item);
1532+
mutex_unlock(&delayed_node->mutex);
14901533
goto release_node;
14911534
}
14921535

14931536
delayed_node->index_item_leaves++;
1494-
} else if (!test_bit(BTRFS_FS_LOG_RECOVERING, &fs_info->flags)) {
1495-
const u64 bytes = btrfs_calc_insert_metadata_size(fs_info, 1);
1496-
1497-
/*
1498-
* Adding the new dir index item does not require touching another
1499-
* leaf, so we can release 1 unit of metadata that was previously
1500-
* reserved when starting the transaction. This applies only to
1501-
* the case where we had a transaction start and excludes the
1502-
* transaction join case (when replaying log trees).
1503-
*/
1504-
trace_btrfs_space_reservation(fs_info, "transaction",
1505-
trans->transid, bytes, 0);
1506-
btrfs_block_rsv_release(fs_info, trans->block_rsv, bytes, NULL);
1507-
ASSERT(trans->bytes_reserved >= bytes);
1508-
trans->bytes_reserved -= bytes;
1509-
}
1510-
1511-
ret = __btrfs_add_delayed_item(delayed_node, delayed_item);
1512-
if (unlikely(ret)) {
1513-
btrfs_err(trans->fs_info,
1514-
"error adding delayed dir index item, name: %.*s, index: %llu, root: %llu, dir: %llu, dir->index_cnt: %llu, delayed_node->index_cnt: %llu, error: %d",
1515-
name_len, name, index, btrfs_root_id(delayed_node->root),
1516-
delayed_node->inode_id, dir->index_cnt,
1517-
delayed_node->index_cnt, ret);
1518-
BUG();
1537+
} else {
1538+
btrfs_release_dir_index_item_space(trans);
15191539
}
15201540
mutex_unlock(&delayed_node->mutex);
15211541

0 commit comments

Comments
 (0)