All of lore.kernel.org
 help / color / mirror / Atom feed
From: Josef Bacik <josef@toxicpanda.com>
To: linux-btrfs@vger.kernel.org, kernel-team@fb.com,
	linux-fsdevel@vger.kernel.org
Subject: [PATCH v4 08/46] btrfs: add infrastructure for safe em freeing
Date: Fri,  1 Dec 2023 17:11:05 -0500	[thread overview]
Message-ID: <d376f64ca9a67c6b73d2cffb3558d0c72f6f78c1.1701468306.git.josef@toxicpanda.com> (raw)
In-Reply-To: <cover.1701468305.git.josef@toxicpanda.com>

When we add fscrypt support we're going to have fscrypt objects hanging
off of extent_maps.  This includes a block key, which if we're the last
one freeing the key we may have to unregister it from the block layer.
This requires taking a semaphore in the block layer, which means we
can't free em's under the extent map tree lock.

Thankfully we only do this in two places, one where we're dropping a
range of extent maps, and when we're freeing logged extents.  Add a
free_extent_map_safe() which will add the em to a list in the em_tree if
we free'd the object.  Currently this is unconditional but will be
changed to conditional on the fscrypt object we will add in a later
patch.

To process these delayed objects add a free_pending_extent_maps() that
is called after the lock has been dropped on the em_tree.  This will
process the extent maps on the freed list and do the appropriate freeing
work in a safe manner.

Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
 fs/btrfs/extent_map.c | 69 +++++++++++++++++++++++++++++++++++++++++--
 fs/btrfs/extent_map.h | 10 +++++++
 fs/btrfs/tree-log.c   |  6 ++--
 3 files changed, 81 insertions(+), 4 deletions(-)

diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c
index c956b1ced69f..20d347fa6f8a 100644
--- a/fs/btrfs/extent_map.c
+++ b/fs/btrfs/extent_map.c
@@ -35,7 +35,9 @@ void __cold extent_map_exit(void)
 void extent_map_tree_init(struct extent_map_tree *tree)
 {
 	tree->map = RB_ROOT_CACHED;
+	tree->flags = 0;
 	INIT_LIST_HEAD(&tree->modified_extents);
+	INIT_LIST_HEAD(&tree->freed_extents);
 	rwlock_init(&tree->lock);
 }
 
@@ -53,6 +55,7 @@ struct extent_map *alloc_extent_map(void)
 	em->compress_type = BTRFS_COMPRESS_NONE;
 	refcount_set(&em->refs, 1);
 	INIT_LIST_HEAD(&em->list);
+	INIT_LIST_HEAD(&em->free_list);
 	return em;
 }
 
@@ -71,6 +74,65 @@ void free_extent_map(struct extent_map *em)
 	}
 }
 
+/*
+ * Drop a ref for the extent map in the given tree.
+ *
+ * @tree:	tree that the em is a part of.
+ * @em:		the em to drop the reference to.
+ *
+ * Drop the reference count on @em by one, if the reference count hits 0 and
+ * there is an object on the em that can't be safely freed in the current
+ * context (if we are holding the extent_map_tree->lock for example), then add
+ * it to the freed_extents list on the extent_map_tree for later processing.
+ *
+ * This must be followed by a free_pending_extent_maps() to clear the pending
+ * frees.
+ */
+void free_extent_map_safe(struct extent_map_tree *tree,
+			  struct extent_map *em)
+{
+	lockdep_assert_held_write(&tree->lock);
+
+	if (!em)
+		return;
+
+	if (refcount_dec_and_test(&em->refs)) {
+		WARN_ON(extent_map_in_tree(em));
+		WARN_ON(!list_empty(&em->list));
+		list_add_tail(&em->free_list, &tree->freed_extents);
+		set_bit(EXTENT_MAP_TREE_PENDING_FREES, &tree->flags);
+	}
+}
+
+/*
+ * Free the em objects that exist on the em tree
+ *
+ * @tree:	the tree to free the objects from.
+ *
+ * If there are any objects on the em->freed_extents list go ahead and free them
+ * here in a safe way.  This is to be coupled with any uses of
+ * free_extent_map_safe().
+ */
+void free_pending_extent_maps(struct extent_map_tree *tree)
+{
+	struct extent_map *em;
+
+	/* Avoid taking the write lock if we don't have any pending frees. */
+	if (!test_and_clear_bit(EXTENT_MAP_TREE_PENDING_FREES, &tree->flags))
+		return;
+
+	write_lock(&tree->lock);
+	while ((em = list_first_entry_or_null(&tree->freed_extents,
+					      struct extent_map, free_list))) {
+		list_del_init(&em->free_list);
+		write_unlock(&tree->lock);
+		__free_extent_map(em);
+		cond_resched();
+		write_lock(&tree->lock);
+	}
+	write_unlock(&tree->lock);
+}
+
 /* Do the math around the end of an extent, handling wrapping. */
 static u64 range_end(u64 start, u64 len)
 {
@@ -645,10 +707,12 @@ static void drop_all_extent_maps_fast(struct extent_map_tree *tree)
 		clear_bit(EXTENT_FLAG_PINNED, &em->flags);
 		clear_bit(EXTENT_FLAG_LOGGING, &em->flags);
 		remove_extent_mapping(tree, em);
-		free_extent_map(em);
+		free_extent_map_safe(tree, em);
 		cond_resched_rwlock_write(&tree->lock);
 	}
 	write_unlock(&tree->lock);
+
+	free_pending_extent_maps(tree);
 }
 
 /*
@@ -869,13 +933,14 @@ void btrfs_drop_extent_map_range(struct btrfs_inode *inode, u64 start, u64 end,
 		free_extent_map(em);
 next:
 		/* Once for us (for our lookup reference). */
-		free_extent_map(em);
+		free_extent_map_safe(em_tree, em);
 
 		em = next_em;
 	}
 
 	write_unlock(&em_tree->lock);
 
+	free_pending_extent_maps(em_tree);
 	free_extent_map(split);
 	free_extent_map(split2);
 }
diff --git a/fs/btrfs/extent_map.h b/fs/btrfs/extent_map.h
index bae14af197ef..fb8905f88f7c 100644
--- a/fs/btrfs/extent_map.h
+++ b/fs/btrfs/extent_map.h
@@ -51,11 +51,18 @@ struct extent_map {
 	refcount_t refs;
 	unsigned int compress_type;
 	struct list_head list;
+	struct list_head free_list;
+};
+
+enum extent_map_flags {
+	EXTENT_MAP_TREE_PENDING_FREES,
 };
 
 struct extent_map_tree {
 	struct rb_root_cached map;
+	unsigned long flags;
 	struct list_head modified_extents;
+	struct list_head freed_extents;
 	rwlock_t lock;
 };
 
@@ -84,6 +91,9 @@ int split_extent_map(struct btrfs_inode *inode, u64 start, u64 len, u64 pre,
 
 struct extent_map *alloc_extent_map(void);
 void free_extent_map(struct extent_map *em);
+void free_extent_map_safe(struct extent_map_tree *tree,
+			  struct extent_map *em);
+void free_pending_extent_maps(struct extent_map_tree *tree);
 int __init extent_map_init(void);
 void __cold extent_map_exit(void);
 int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len, u64 gen);
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 7d6729d9fd2f..00b6f0c71e1d 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -4883,7 +4883,7 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans,
 		 */
 		if (ret) {
 			clear_em_logging(tree, em);
-			free_extent_map(em);
+			free_extent_map_safe(tree, em);
 			continue;
 		}
 
@@ -4892,11 +4892,13 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans,
 		ret = log_one_extent(trans, inode, em, path, ctx);
 		write_lock(&tree->lock);
 		clear_em_logging(tree, em);
-		free_extent_map(em);
+		free_extent_map_safe(tree, em);
 	}
 	WARN_ON(!list_empty(&extents));
 	write_unlock(&tree->lock);
 
+	free_pending_extent_maps(tree);
+
 	if (!ret)
 		ret = btrfs_log_prealloc_extents(trans, inode, path);
 	if (ret)
-- 
2.41.0


  parent reply	other threads:[~2023-12-01 22:12 UTC|newest]

Thread overview: 70+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-12-01 22:10 [PATCH v4 00/46] btrfs: add fscrypt support Josef Bacik
2023-12-01 22:10 ` [PATCH v4 01/46] fs: move fscrypt keyring destruction to after ->put_super Josef Bacik
2023-12-05  1:58   ` Eric Biggers
2023-12-05 22:48     ` Josef Bacik
2023-12-06  0:01       ` Eric Biggers
2023-12-01 22:10 ` [PATCH v4 02/46] fscrypt: add per-extent encryption support Josef Bacik
2023-12-05  3:58   ` Eric Biggers
2023-12-05 22:48     ` Josef Bacik
2023-12-05 23:57       ` Eric Biggers
2023-12-13  4:16     ` Eric Biggers
2023-12-01 22:11 ` [PATCH v4 03/46] fscrypt: add a fscrypt_inode_open helper Josef Bacik
2023-12-05  4:14   ` Eric Biggers
2023-12-01 22:11 ` [PATCH v4 04/46] fscrypt: conditionally don't wipe mk secret until the last active user is done Josef Bacik
2023-12-01 22:11 ` [PATCH v4 05/46] blk-crypto: add a process bio callback Josef Bacik
2023-12-05  4:54   ` Eric Biggers
2023-12-01 22:11 ` [PATCH v4 06/46] fscrypt: expose fscrypt_nokey_name Josef Bacik
2023-12-05  5:03   ` Eric Biggers
2023-12-01 22:11 ` [PATCH v4 07/46] fscrypt: add documentation about extent encryption Josef Bacik
2023-12-01 22:11 ` Josef Bacik [this message]
2023-12-01 22:11 ` [PATCH v4 09/46] btrfs: disable various operations on encrypted inodes Josef Bacik
2023-12-01 22:11 ` [PATCH v4 10/46] btrfs: disable verity " Josef Bacik
2023-12-05  5:07   ` Eric Biggers
2023-12-01 22:11 ` [PATCH v4 11/46] btrfs: start using fscrypt hooks Josef Bacik
2023-12-01 22:11 ` [PATCH v4 12/46] btrfs: add inode encryption contexts Josef Bacik
2023-12-05  5:22   ` Eric Biggers
2023-12-01 22:11 ` [PATCH v4 13/46] btrfs: add new FEATURE_INCOMPAT_ENCRYPT flag Josef Bacik
2023-12-01 22:11 ` [PATCH v4 14/46] btrfs: adapt readdir for encrypted and nokey names Josef Bacik
2023-12-01 22:11 ` [PATCH v4 15/46] btrfs: handle " Josef Bacik
2023-12-05  5:29   ` Eric Biggers
2023-12-01 22:11 ` [PATCH v4 16/46] btrfs: implement fscrypt ioctls Josef Bacik
2023-12-01 22:11 ` [PATCH v4 17/46] btrfs: add encryption to CONFIG_BTRFS_DEBUG Josef Bacik
2023-12-05  5:11   ` Eric Biggers
2023-12-01 22:11 ` [PATCH v4 18/46] btrfs: add get_devices hook for fscrypt Josef Bacik
2023-12-01 22:11 ` [PATCH v4 19/46] btrfs: turn on inlinecrypt mount option for encrypt Josef Bacik
2023-12-05  5:41   ` Eric Biggers
2023-12-01 22:11 ` [PATCH v4 20/46] btrfs: set file extent encryption excplicitly Josef Bacik
2023-12-01 22:11 ` [PATCH v4 21/46] btrfs: add fscrypt_info and encryption_type to extent_map Josef Bacik
2023-12-01 22:11 ` [PATCH v4 22/46] btrfs: add fscrypt_info and encryption_type to ordered_extent Josef Bacik
2023-12-01 22:11 ` [PATCH v4 23/46] btrfs: plumb through setting the fscrypt_info for ordered extents Josef Bacik
2023-12-01 22:11 ` [PATCH v4 24/46] btrfs: plumb the fscrypt extent context through create_io_em Josef Bacik
2023-12-01 22:11 ` [PATCH v4 25/46] btrfs: populate the ordered_extent with the fscrypt context Josef Bacik
2023-12-01 22:11 ` [PATCH v4 26/46] btrfs: keep track of fscrypt info and orig_start for dio reads Josef Bacik
2023-12-05  5:44   ` Eric Biggers
2023-12-01 22:11 ` [PATCH v4 27/46] btrfs: add an optional encryption context to the end of file extents Josef Bacik
2023-12-01 22:11 ` [PATCH v4 28/46] btrfs: explicitly track file extent length for replace and drop Josef Bacik
2023-12-01 22:11 ` [PATCH v4 29/46] btrfs: pass through fscrypt_extent_info to the file extent helpers Josef Bacik
2023-12-01 22:11 ` [PATCH v4 30/46] btrfs: pass the fscrypt_info through the replace extent infrastructure Josef Bacik
2023-12-01 22:11 ` [PATCH v4 31/46] btrfs: implement the fscrypt extent encryption hooks Josef Bacik
2023-12-01 22:11 ` [PATCH v4 32/46] btrfs: setup fscrypt_extent_info for new extents Josef Bacik
2023-12-01 22:11 ` [PATCH v4 33/46] btrfs: populate ordered_extent with the orig offset Josef Bacik
2023-12-01 22:11 ` [PATCH v4 34/46] btrfs: set the bio fscrypt context when applicable Josef Bacik
2023-12-01 22:11 ` [PATCH v4 35/46] btrfs: add a bio argument to btrfs_csum_one_bio Josef Bacik
2023-12-01 22:11 ` [PATCH v4 36/46] btrfs: add orig_logical to btrfs_bio Josef Bacik
2023-12-01 22:11 ` [PATCH v4 37/46] btrfs: limit encrypted writes to 256 segments Josef Bacik
2023-12-01 22:11 ` [PATCH v4 38/46] btrfs: implement process_bio cb for fscrypt Josef Bacik
2023-12-01 22:11 ` [PATCH v4 39/46] btrfs: add test_dummy_encryption support Josef Bacik
2023-12-01 22:11 ` [PATCH v4 40/46] btrfs: don't rewrite ret from inode_permission Josef Bacik
2023-12-01 22:11 ` [PATCH v4 41/46] btrfs: move inode_to_path higher in backref.c Josef Bacik
2023-12-01 22:11 ` [PATCH v4 42/46] btrfs: make btrfs_ref_to_path handle encrypted filenames Josef Bacik
2023-12-01 22:11 ` [PATCH v4 43/46] btrfs: don't search back for dir inode item in INO_LOOKUP_USER Josef Bacik
2023-12-01 22:11 ` [PATCH v4 44/46] btrfs: deal with encrypted symlinks in send Josef Bacik
2023-12-01 22:11 ` [PATCH v4 45/46] btrfs: decrypt file names for send Josef Bacik
2023-12-01 22:11 ` [PATCH v4 46/46] btrfs: load the inode context before sending writes Josef Bacik
2023-12-05  5:54   ` Eric Biggers
2023-12-01 22:15 ` [PATCH v4 00/46] btrfs: add fscrypt support Josef Bacik
2023-12-05  1:49 ` Eric Biggers
2023-12-05 14:16   ` David Sterba
2023-12-05 20:02     ` Eric Biggers
2024-04-09 23:42 ` Eric Biggers
2024-04-11 18:45   ` Josef Bacik

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=d376f64ca9a67c6b73d2cffb3558d0c72f6f78c1.1701468306.git.josef@toxicpanda.com \
    --to=josef@toxicpanda.com \
    --cc=kernel-team@fb.com \
    --cc=linux-btrfs@vger.kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.