Patch "btrfs: prevent transaction block reserve underflow when starting transaction" has been added to the 6.5-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    btrfs: prevent transaction block reserve underflow when starting transaction

to the 6.5-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     btrfs-prevent-transaction-block-reserve-underflow-wh.patch
and it can be found in the queue-6.5 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit 12b0f13348c1f95959887bc74f88e36f5b53e837
Author: Filipe Manana <fdmanana@xxxxxxxx>
Date:   Fri Sep 8 18:20:19 2023 +0100

    btrfs: prevent transaction block reserve underflow when starting transaction
    
    [ Upstream commit a7ddeeb079505961355cf0106154da0110f1fdff ]
    
    When starting a transaction, with a non-zero number of items, we reserve
    metadata space for that number of items and for delayed refs by doing a
    call to btrfs_block_rsv_add(), with the transaction block reserve passed
    as the block reserve argument. This reserves metadata space and adds it
    to the transaction block reserve. Later we migrate the space we reserved
    for delayed references from the transaction block reserve into the delayed
    refs block reserve, by calling btrfs_migrate_to_delayed_refs_rsv().
    
    btrfs_migrate_to_delayed_refs_rsv() decrements the number of bytes to
    migrate from the source block reserve, and this however may result in an
    underflow in case the space added to the transaction block reserve ended
    up being used by another task that has not reserved enough space for its
    own use - examples are tasks doing reflinks or hole punching because they
    end up calling btrfs_replace_file_extents() -> btrfs_drop_extents() and
    may need to modify/COW a variable number of leaves/paths, so they keep
    trying to use space from the transaction block reserve when they need to
    COW an extent buffer, and may end up trying to use more space then they
    have reserved (1 unit/path only for removing file extent items).
    
    This can be avoided by simply reserving space first without adding it to
    the transaction block reserve, then add the space for delayed refs to the
    delayed refs block reserve and finally add the remaining reserved space
    to the transaction block reserve. This also makes the code a bit shorter
    and simpler. So just do that.
    
    Reviewed-by: Josef Bacik <josef@xxxxxxxxxxxxxx>
    Signed-off-by: Filipe Manana <fdmanana@xxxxxxxx>
    Signed-off-by: David Sterba <dsterba@xxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/fs/btrfs/delayed-ref.c b/fs/btrfs/delayed-ref.c
index 1043f66cc130d..9fe4ccca50a06 100644
--- a/fs/btrfs/delayed-ref.c
+++ b/fs/btrfs/delayed-ref.c
@@ -103,24 +103,17 @@ void btrfs_update_delayed_refs_rsv(struct btrfs_trans_handle *trans)
  * Transfer bytes to our delayed refs rsv.
  *
  * @fs_info:   the filesystem
- * @src:       source block rsv to transfer from
  * @num_bytes: number of bytes to transfer
  *
- * This transfers up to the num_bytes amount from the src rsv to the
+ * This transfers up to the num_bytes amount, previously reserved, to the
  * delayed_refs_rsv.  Any extra bytes are returned to the space info.
  */
 void btrfs_migrate_to_delayed_refs_rsv(struct btrfs_fs_info *fs_info,
-				       struct btrfs_block_rsv *src,
 				       u64 num_bytes)
 {
 	struct btrfs_block_rsv *delayed_refs_rsv = &fs_info->delayed_refs_rsv;
 	u64 to_free = 0;
 
-	spin_lock(&src->lock);
-	src->reserved -= num_bytes;
-	src->size -= num_bytes;
-	spin_unlock(&src->lock);
-
 	spin_lock(&delayed_refs_rsv->lock);
 	if (delayed_refs_rsv->size > delayed_refs_rsv->reserved) {
 		u64 delta = delayed_refs_rsv->size -
diff --git a/fs/btrfs/delayed-ref.h b/fs/btrfs/delayed-ref.h
index b8e14b0ba5f16..fd9bf2b709c0e 100644
--- a/fs/btrfs/delayed-ref.h
+++ b/fs/btrfs/delayed-ref.h
@@ -407,7 +407,6 @@ void btrfs_update_delayed_refs_rsv(struct btrfs_trans_handle *trans);
 int btrfs_delayed_refs_rsv_refill(struct btrfs_fs_info *fs_info,
 				  enum btrfs_reserve_flush_enum flush);
 void btrfs_migrate_to_delayed_refs_rsv(struct btrfs_fs_info *fs_info,
-				       struct btrfs_block_rsv *src,
 				       u64 num_bytes);
 bool btrfs_check_space_for_delayed_refs(struct btrfs_fs_info *fs_info);
 
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 5bbd288b9cb54..0554ca2a8e3ba 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -625,14 +625,14 @@ start_transaction(struct btrfs_root *root, unsigned int num_items,
 			reloc_reserved = true;
 		}
 
-		ret = btrfs_block_rsv_add(fs_info, rsv, num_bytes, flush);
+		ret = btrfs_reserve_metadata_bytes(fs_info, rsv, num_bytes, flush);
 		if (ret)
 			goto reserve_fail;
 		if (delayed_refs_bytes) {
-			btrfs_migrate_to_delayed_refs_rsv(fs_info, rsv,
-							  delayed_refs_bytes);
+			btrfs_migrate_to_delayed_refs_rsv(fs_info, delayed_refs_bytes);
 			num_bytes -= delayed_refs_bytes;
 		}
+		btrfs_block_rsv_add_bytes(rsv, num_bytes, true);
 
 		if (rsv->space_info->force_alloc)
 			do_chunk_alloc = true;



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux