All of lore.kernel.org
 help / color / mirror / Atom feed
From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
To: linux-kernel@vger.kernel.org
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	stable@vger.kernel.org, Filipe Manana <fdmanana@suse.com>,
	David Sterba <dsterba@suse.com>,
	Anand Jain <anand.jain@oracle.com>
Subject: [PATCH 5.16 120/121] btrfs: make send work with concurrent block group relocation
Date: Mon, 14 Mar 2022 12:55:03 +0100	[thread overview]
Message-ID: <20220314112747.461313246@linuxfoundation.org> (raw)
In-Reply-To: <20220314112744.120491875@linuxfoundation.org>

From: Filipe Manana <fdmanana@suse.com>

commit d96b34248c2f4ea8cd09286090f2f6f77102eaab upstream.

We don't allow send and balance/relocation to run in parallel in order
to prevent send failing or silently producing some bad stream. This is
because while send is using an extent (specially metadata) or about to
read a metadata extent and expecting it belongs to a specific parent
node, relocation can run, the transaction used for the relocation is
committed and the extent gets reallocated while send is still using the
extent, so it ends up with a different content than expected. This can
result in just failing to read a metadata extent due to failure of the
validation checks (parent transid, level, etc), failure to find a
backreference for a data extent, and other unexpected failures. Besides
reallocation, there's also a similar problem of an extent getting
discarded when it's unpinned after the transaction used for block group
relocation is committed.

The restriction between balance and send was added in commit 9e967495e0e0
("Btrfs: prevent send failures and crashes due to concurrent relocation"),
kernel 5.3, while the more general restriction between send and relocation
was added in commit 1cea5cf0e664 ("btrfs: ensure relocation never runs
while we have send operations running"), kernel 5.14.

Both send and relocation can be very long running operations. Relocation
because it has to do a lot of IO and expensive backreference lookups in
case there are many snapshots, and send due to read IO when operating on
very large trees. This makes it inconvenient for users and tools to deal
with scheduling both operations.

For zoned filesystem we also have automatic block group relocation, so
send can fail with -EAGAIN when users least expect it or send can end up
delaying the block group relocation for too long. In the future we might
also get the automatic block group relocation for non zoned filesystems.

This change makes it possible for send and relocation to run in parallel.
This is achieved the following way:

1) For all tree searches, send acquires a read lock on the commit root
   semaphore;

2) After each tree search, and before releasing the commit root semaphore,
   the leaf is cloned and placed in the search path (struct btrfs_path);

3) After releasing the commit root semaphore, the changed_cb() callback
   is invoked, which operates on the leaf and writes commands to the pipe
   (or file in case send/receive is not used with a pipe). It's important
   here to not hold a lock on the commit root semaphore, because if we did
   we could deadlock when sending and receiving to the same filesystem
   using a pipe - the send task blocks on the pipe because it's full, the
   receive task, which is the only consumer of the pipe, triggers a
   transaction commit when attempting to create a subvolume or reserve
   space for a write operation for example, but the transaction commit
   blocks trying to write lock the commit root semaphore, resulting in a
   deadlock;

4) Before moving to the next key, or advancing to the next change in case
   of an incremental send, check if a transaction used for relocation was
   committed (or is about to finish its commit). If so, release the search
   path(s) and restart the search, to where we were before, so that we
   don't operate on stale extent buffers. The search restarts are always
   possible because both the send and parent roots are RO, and no one can
   add, remove of update keys (change their offset) in RO trees - the
   only exception is deduplication, but that is still not allowed to run
   in parallel with send;

5) Periodically check if there is contention on the commit root semaphore,
   which means there is a transaction commit trying to write lock it, and
   release the semaphore and reschedule if there is contention, so as to
   avoid causing any significant delays to transaction commits.

This leaves some room for optimizations for send to have less path
releases and re searching the trees when there's relocation running, but
for now it's kept simple as it performs quite well (on very large trees
with resulting send streams in the order of a few hundred gigabytes).

Test case btrfs/187, from fstests, stresses relocation, send and
deduplication attempting to run in parallel, but without verifying if send
succeeds and if it produces correct streams. A new test case will be added
that exercises relocation happening in parallel with send and then checks
that send succeeds and the resulting streams are correct.

A final note is that for now this still leaves the mutual exclusion
between send operations and deduplication on files belonging to a root
used by send operations. A solution for that will be slightly more complex
but it will eventually be built on top of this change.

Signed-off-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Anand Jain <anand.jain@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 fs/btrfs/block-group.c |    9 -
 fs/btrfs/ctree.c       |   98 ++++++++++---
 fs/btrfs/ctree.h       |   14 -
 fs/btrfs/disk-io.c     |    4 
 fs/btrfs/relocation.c  |   13 -
 fs/btrfs/send.c        |  357 ++++++++++++++++++++++++++++++++++++++++++-------
 fs/btrfs/transaction.c |    4 
 7 files changed, 395 insertions(+), 104 deletions(-)

--- a/fs/btrfs/block-group.c
+++ b/fs/btrfs/block-group.c
@@ -1508,7 +1508,6 @@ void btrfs_reclaim_bgs_work(struct work_
 		container_of(work, struct btrfs_fs_info, reclaim_bgs_work);
 	struct btrfs_block_group *bg;
 	struct btrfs_space_info *space_info;
-	LIST_HEAD(again_list);
 
 	if (!test_bit(BTRFS_FS_OPEN, &fs_info->flags))
 		return;
@@ -1585,18 +1584,14 @@ void btrfs_reclaim_bgs_work(struct work_
 				div64_u64(zone_unusable * 100, bg->length));
 		trace_btrfs_reclaim_block_group(bg);
 		ret = btrfs_relocate_chunk(fs_info, bg->start);
-		if (ret && ret != -EAGAIN)
+		if (ret)
 			btrfs_err(fs_info, "error relocating chunk %llu",
 				  bg->start);
 
 next:
+		btrfs_put_block_group(bg);
 		spin_lock(&fs_info->unused_bgs_lock);
-		if (ret == -EAGAIN && list_empty(&bg->bg_list))
-			list_add_tail(&bg->bg_list, &again_list);
-		else
-			btrfs_put_block_group(bg);
 	}
-	list_splice_tail(&again_list, &fs_info->reclaim_bgs);
 	spin_unlock(&fs_info->unused_bgs_lock);
 	mutex_unlock(&fs_info->reclaim_bgs_lock);
 	btrfs_exclop_finish(fs_info);
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -1568,32 +1568,13 @@ static struct extent_buffer *btrfs_searc
 							struct btrfs_path *p,
 							int write_lock_level)
 {
-	struct btrfs_fs_info *fs_info = root->fs_info;
 	struct extent_buffer *b;
 	int root_lock = 0;
 	int level = 0;
 
 	if (p->search_commit_root) {
-		/*
-		 * The commit roots are read only so we always do read locks,
-		 * and we always must hold the commit_root_sem when doing
-		 * searches on them, the only exception is send where we don't
-		 * want to block transaction commits for a long time, so
-		 * we need to clone the commit root in order to avoid races
-		 * with transaction commits that create a snapshot of one of
-		 * the roots used by a send operation.
-		 */
-		if (p->need_commit_sem) {
-			down_read(&fs_info->commit_root_sem);
-			b = btrfs_clone_extent_buffer(root->commit_root);
-			up_read(&fs_info->commit_root_sem);
-			if (!b)
-				return ERR_PTR(-ENOMEM);
-
-		} else {
-			b = root->commit_root;
-			atomic_inc(&b->refs);
-		}
+		b = root->commit_root;
+		atomic_inc(&b->refs);
 		level = btrfs_header_level(b);
 		/*
 		 * Ensure that all callers have set skip_locking when
@@ -1659,6 +1640,42 @@ out:
 	return b;
 }
 
+/*
+ * Replace the extent buffer at the lowest level of the path with a cloned
+ * version. The purpose is to be able to use it safely, after releasing the
+ * commit root semaphore, even if relocation is happening in parallel, the
+ * transaction used for relocation is committed and the extent buffer is
+ * reallocated in the next transaction.
+ *
+ * This is used in a context where the caller does not prevent transaction
+ * commits from happening, either by holding a transaction handle or holding
+ * some lock, while it's doing searches through a commit root.
+ * At the moment it's only used for send operations.
+ */
+static int finish_need_commit_sem_search(struct btrfs_path *path)
+{
+	const int i = path->lowest_level;
+	const int slot = path->slots[i];
+	struct extent_buffer *lowest = path->nodes[i];
+	struct extent_buffer *clone;
+
+	ASSERT(path->need_commit_sem);
+
+	if (!lowest)
+		return 0;
+
+	lockdep_assert_held_read(&lowest->fs_info->commit_root_sem);
+
+	clone = btrfs_clone_extent_buffer(lowest);
+	if (!clone)
+		return -ENOMEM;
+
+	btrfs_release_path(path);
+	path->nodes[i] = clone;
+	path->slots[i] = slot;
+
+	return 0;
+}
 
 /*
  * btrfs_search_slot - look for a key in a tree and perform necessary
@@ -1695,6 +1712,7 @@ int btrfs_search_slot(struct btrfs_trans
 		      const struct btrfs_key *key, struct btrfs_path *p,
 		      int ins_len, int cow)
 {
+	struct btrfs_fs_info *fs_info = root->fs_info;
 	struct extent_buffer *b;
 	int slot;
 	int ret;
@@ -1736,6 +1754,11 @@ int btrfs_search_slot(struct btrfs_trans
 
 	min_write_lock_level = write_lock_level;
 
+	if (p->need_commit_sem) {
+		ASSERT(p->search_commit_root);
+		down_read(&fs_info->commit_root_sem);
+	}
+
 again:
 	prev_cmp = -1;
 	b = btrfs_search_slot_get_root(root, p, write_lock_level);
@@ -1930,6 +1953,16 @@ cow_done:
 done:
 	if (ret < 0 && !p->skip_release_on_error)
 		btrfs_release_path(p);
+
+	if (p->need_commit_sem) {
+		int ret2;
+
+		ret2 = finish_need_commit_sem_search(p);
+		up_read(&fs_info->commit_root_sem);
+		if (ret2)
+			ret = ret2;
+	}
+
 	return ret;
 }
 ALLOW_ERROR_INJECTION(btrfs_search_slot, ERRNO);
@@ -4414,7 +4447,9 @@ int btrfs_next_old_leaf(struct btrfs_roo
 	int level;
 	struct extent_buffer *c;
 	struct extent_buffer *next;
+	struct btrfs_fs_info *fs_info = root->fs_info;
 	struct btrfs_key key;
+	bool need_commit_sem = false;
 	u32 nritems;
 	int ret;
 	int i;
@@ -4431,14 +4466,20 @@ again:
 
 	path->keep_locks = 1;
 
-	if (time_seq)
+	if (time_seq) {
 		ret = btrfs_search_old_slot(root, &key, path, time_seq);
-	else
+	} else {
+		if (path->need_commit_sem) {
+			path->need_commit_sem = 0;
+			need_commit_sem = true;
+			down_read(&fs_info->commit_root_sem);
+		}
 		ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
+	}
 	path->keep_locks = 0;
 
 	if (ret < 0)
-		return ret;
+		goto done;
 
 	nritems = btrfs_header_nritems(path->nodes[0]);
 	/*
@@ -4561,6 +4602,15 @@ again:
 	ret = 0;
 done:
 	unlock_up(path, 0, 1, 0, NULL);
+	if (need_commit_sem) {
+		int ret2;
+
+		path->need_commit_sem = 1;
+		ret2 = finish_need_commit_sem_search(path);
+		up_read(&fs_info->commit_root_sem);
+		if (ret2)
+			ret = ret2;
+	}
 
 	return ret;
 }
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -576,7 +576,6 @@ enum {
 	/*
 	 * Indicate that relocation of a chunk has started, it's set per chunk
 	 * and is toggled between chunks.
-	 * Set, tested and cleared while holding fs_info::send_reloc_lock.
 	 */
 	BTRFS_FS_RELOC_RUNNING,
 
@@ -676,6 +675,12 @@ struct btrfs_fs_info {
 
 	u64 generation;
 	u64 last_trans_committed;
+	/*
+	 * Generation of the last transaction used for block group relocation
+	 * since the filesystem was last mounted (or 0 if none happened yet).
+	 * Must be written and read while holding btrfs_fs_info::commit_root_sem.
+	 */
+	u64 last_reloc_trans;
 	u64 avg_delayed_ref_runtime;
 
 	/*
@@ -1006,13 +1011,6 @@ struct btrfs_fs_info {
 
 	struct crypto_shash *csum_shash;
 
-	spinlock_t send_reloc_lock;
-	/*
-	 * Number of send operations in progress.
-	 * Updated while holding fs_info::send_reloc_lock.
-	 */
-	int send_in_progress;
-
 	/* Type of exclusive operation running, protected by super_lock */
 	enum btrfs_exclusive_operation exclusive_operation;
 
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -2858,6 +2858,7 @@ static int __cold init_tree_roots(struct
 		/* All successful */
 		fs_info->generation = generation;
 		fs_info->last_trans_committed = generation;
+		fs_info->last_reloc_trans = 0;
 
 		/* Always begin writing backup roots after the one being used */
 		if (backup_index < 0) {
@@ -2993,9 +2994,6 @@ void btrfs_init_fs_info(struct btrfs_fs_
 	spin_lock_init(&fs_info->swapfile_pins_lock);
 	fs_info->swapfile_pins = RB_ROOT;
 
-	spin_lock_init(&fs_info->send_reloc_lock);
-	fs_info->send_in_progress = 0;
-
 	fs_info->bg_reclaim_threshold = BTRFS_DEFAULT_RECLAIM_THRESH;
 	INIT_WORK(&fs_info->reclaim_bgs_work, btrfs_reclaim_bgs_work);
 }
--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -3858,25 +3858,14 @@ out:
  *   0             success
  *   -EINPROGRESS  operation is already in progress, that's probably a bug
  *   -ECANCELED    cancellation request was set before the operation started
- *   -EAGAIN       can not start because there are ongoing send operations
  */
 static int reloc_chunk_start(struct btrfs_fs_info *fs_info)
 {
-	spin_lock(&fs_info->send_reloc_lock);
-	if (fs_info->send_in_progress) {
-		btrfs_warn_rl(fs_info,
-"cannot run relocation while send operations are in progress (%d in progress)",
-			      fs_info->send_in_progress);
-		spin_unlock(&fs_info->send_reloc_lock);
-		return -EAGAIN;
-	}
 	if (test_and_set_bit(BTRFS_FS_RELOC_RUNNING, &fs_info->flags)) {
 		/* This should not happen */
-		spin_unlock(&fs_info->send_reloc_lock);
 		btrfs_err(fs_info, "reloc already running, cannot start");
 		return -EINPROGRESS;
 	}
-	spin_unlock(&fs_info->send_reloc_lock);
 
 	if (atomic_read(&fs_info->reloc_cancel_req) > 0) {
 		btrfs_info(fs_info, "chunk relocation canceled on start");
@@ -3898,9 +3887,7 @@ static void reloc_chunk_end(struct btrfs
 	/* Requested after start, clear bit first so any waiters can continue */
 	if (atomic_read(&fs_info->reloc_cancel_req) > 0)
 		btrfs_info(fs_info, "chunk relocation canceled during operation");
-	spin_lock(&fs_info->send_reloc_lock);
 	clear_and_wake_up_bit(BTRFS_FS_RELOC_RUNNING, &fs_info->flags);
-	spin_unlock(&fs_info->send_reloc_lock);
 	atomic_set(&fs_info->reloc_cancel_req, 0);
 }
 
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -24,6 +24,7 @@
 #include "transaction.h"
 #include "compression.h"
 #include "xattr.h"
+#include "print-tree.h"
 
 /*
  * Maximum number of references an extent can have in order for us to attempt to
@@ -98,6 +99,15 @@ struct send_ctx {
 	struct btrfs_key *cmp_key;
 
 	/*
+	 * Keep track of the generation of the last transaction that was used
+	 * for relocating a block group. This is periodically checked in order
+	 * to detect if a relocation happened since the last check, so that we
+	 * don't operate on stale extent buffers for nodes (level >= 1) or on
+	 * stale disk_bytenr values of file extent items.
+	 */
+	u64 last_reloc_trans;
+
+	/*
 	 * infos of the currently processed inode. In case of deleted inodes,
 	 * these are the values from the deleted inode.
 	 */
@@ -1427,6 +1437,26 @@ static int find_extent_clone(struct send
 	if (ret < 0)
 		goto out;
 
+	down_read(&fs_info->commit_root_sem);
+	if (fs_info->last_reloc_trans > sctx->last_reloc_trans) {
+		/*
+		 * A transaction commit for a transaction in which block group
+		 * relocation was done just happened.
+		 * The disk_bytenr of the file extent item we processed is
+		 * possibly stale, referring to the extent's location before
+		 * relocation. So act as if we haven't found any clone sources
+		 * and fallback to write commands, which will read the correct
+		 * data from the new extent location. Otherwise we will fail
+		 * below because we haven't found our own back reference or we
+		 * could be getting incorrect sources in case the old extent
+		 * was already reallocated after the relocation.
+		 */
+		up_read(&fs_info->commit_root_sem);
+		ret = -ENOENT;
+		goto out;
+	}
+	up_read(&fs_info->commit_root_sem);
+
 	if (!backref_ctx.found_itself) {
 		/* found a bug in backref code? */
 		ret = -EIO;
@@ -6601,6 +6631,50 @@ static int changed_cb(struct btrfs_path
 {
 	int ret = 0;
 
+	/*
+	 * We can not hold the commit root semaphore here. This is because in
+	 * the case of sending and receiving to the same filesystem, using a
+	 * pipe, could result in a deadlock:
+	 *
+	 * 1) The task running send blocks on the pipe because it's full;
+	 *
+	 * 2) The task running receive, which is the only consumer of the pipe,
+	 *    is waiting for a transaction commit (for example due to a space
+	 *    reservation when doing a write or triggering a transaction commit
+	 *    when creating a subvolume);
+	 *
+	 * 3) The transaction is waiting to write lock the commit root semaphore,
+	 *    but can not acquire it since it's being held at 1).
+	 *
+	 * Down this call chain we write to the pipe through kernel_write().
+	 * The same type of problem can also happen when sending to a file that
+	 * is stored in the same filesystem - when reserving space for a write
+	 * into the file, we can trigger a transaction commit.
+	 *
+	 * Our caller has supplied us with clones of leaves from the send and
+	 * parent roots, so we're safe here from a concurrent relocation and
+	 * further reallocation of metadata extents while we are here. Below we
+	 * also assert that the leaves are clones.
+	 */
+	lockdep_assert_not_held(&sctx->send_root->fs_info->commit_root_sem);
+
+	/*
+	 * We always have a send root, so left_path is never NULL. We will not
+	 * have a leaf when we have reached the end of the send root but have
+	 * not yet reached the end of the parent root.
+	 */
+	if (left_path->nodes[0])
+		ASSERT(test_bit(EXTENT_BUFFER_UNMAPPED,
+				&left_path->nodes[0]->bflags));
+	/*
+	 * When doing a full send we don't have a parent root, so right_path is
+	 * NULL. When doing an incremental send, we may have reached the end of
+	 * the parent root already, so we don't have a leaf at right_path.
+	 */
+	if (right_path && right_path->nodes[0])
+		ASSERT(test_bit(EXTENT_BUFFER_UNMAPPED,
+				&right_path->nodes[0]->bflags));
+
 	if (result == BTRFS_COMPARE_TREE_SAME) {
 		if (key->type == BTRFS_INODE_REF_KEY ||
 		    key->type == BTRFS_INODE_EXTREF_KEY) {
@@ -6647,14 +6721,46 @@ out:
 	return ret;
 }
 
+static int search_key_again(const struct send_ctx *sctx,
+			    struct btrfs_root *root,
+			    struct btrfs_path *path,
+			    const struct btrfs_key *key)
+{
+	int ret;
+
+	if (!path->need_commit_sem)
+		lockdep_assert_held_read(&root->fs_info->commit_root_sem);
+
+	/*
+	 * Roots used for send operations are readonly and no one can add,
+	 * update or remove keys from them, so we should be able to find our
+	 * key again. The only exception is deduplication, which can operate on
+	 * readonly roots and add, update or remove keys to/from them - but at
+	 * the moment we don't allow it to run in parallel with send.
+	 */
+	ret = btrfs_search_slot(NULL, root, key, path, 0, 0);
+	ASSERT(ret <= 0);
+	if (ret > 0) {
+		btrfs_print_tree(path->nodes[path->lowest_level], false);
+		btrfs_err(root->fs_info,
+"send: key (%llu %u %llu) not found in %s root %llu, lowest_level %d, slot %d",
+			  key->objectid, key->type, key->offset,
+			  (root == sctx->parent_root ? "parent" : "send"),
+			  root->root_key.objectid, path->lowest_level,
+			  path->slots[path->lowest_level]);
+		return -EUCLEAN;
+	}
+
+	return ret;
+}
+
 static int full_send_tree(struct send_ctx *sctx)
 {
 	int ret;
 	struct btrfs_root *send_root = sctx->send_root;
 	struct btrfs_key key;
+	struct btrfs_fs_info *fs_info = send_root->fs_info;
 	struct btrfs_path *path;
-	struct extent_buffer *eb;
-	int slot;
 
 	path = alloc_path_for_send();
 	if (!path)
@@ -6665,6 +6771,10 @@ static int full_send_tree(struct send_ct
 	key.type = BTRFS_INODE_ITEM_KEY;
 	key.offset = 0;
 
+	down_read(&fs_info->commit_root_sem);
+	sctx->last_reloc_trans = fs_info->last_reloc_trans;
+	up_read(&fs_info->commit_root_sem);
+
 	ret = btrfs_search_slot_for_read(send_root, &key, path, 1, 0);
 	if (ret < 0)
 		goto out;
@@ -6672,15 +6782,35 @@ static int full_send_tree(struct send_ct
 		goto out_finish;
 
 	while (1) {
-		eb = path->nodes[0];
-		slot = path->slots[0];
-		btrfs_item_key_to_cpu(eb, &key, slot);
+		btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
 
 		ret = changed_cb(path, NULL, &key,
 				 BTRFS_COMPARE_TREE_NEW, sctx);
 		if (ret < 0)
 			goto out;
 
+		down_read(&fs_info->commit_root_sem);
+		if (fs_info->last_reloc_trans > sctx->last_reloc_trans) {
+			sctx->last_reloc_trans = fs_info->last_reloc_trans;
+			up_read(&fs_info->commit_root_sem);
+			/*
+			 * A transaction used for relocating a block group was
+			 * committed or is about to finish its commit. Release
+			 * our path (leaf) and restart the search, so that we
+			 * avoid operating on any file extent items that are
+			 * stale, with a disk_bytenr that reflects a pre
+			 * relocation value. This way we avoid as much as
+			 * possible to fallback to regular writes when checking
+			 * if we can clone file ranges.
+			 */
+			btrfs_release_path(path);
+			ret = search_key_again(sctx, send_root, path, &key);
+			if (ret < 0)
+				goto out;
+		} else {
+			up_read(&fs_info->commit_root_sem);
+		}
+
 		ret = btrfs_next_item(send_root, path);
 		if (ret < 0)
 			goto out;
@@ -6698,6 +6828,20 @@ out:
 	return ret;
 }
 
+static int replace_node_with_clone(struct btrfs_path *path, int level)
+{
+	struct extent_buffer *clone;
+
+	clone = btrfs_clone_extent_buffer(path->nodes[level]);
+	if (!clone)
+		return -ENOMEM;
+
+	free_extent_buffer(path->nodes[level]);
+	path->nodes[level] = clone;
+
+	return 0;
+}
+
 static int tree_move_down(struct btrfs_path *path, int *level, u64 reada_min_gen)
 {
 	struct extent_buffer *eb;
@@ -6707,6 +6851,8 @@ static int tree_move_down(struct btrfs_p
 	u64 reada_max;
 	u64 reada_done = 0;
 
+	lockdep_assert_held_read(&parent->fs_info->commit_root_sem);
+
 	BUG_ON(*level == 0);
 	eb = btrfs_read_node_slot(parent, slot);
 	if (IS_ERR(eb))
@@ -6730,6 +6876,10 @@ static int tree_move_down(struct btrfs_p
 	path->nodes[*level - 1] = eb;
 	path->slots[*level - 1] = 0;
 	(*level)--;
+
+	if (*level == 0)
+		return replace_node_with_clone(path, 0);
+
 	return 0;
 }
 
@@ -6743,8 +6893,10 @@ static int tree_move_next_or_upnext(stru
 	path->slots[*level]++;
 
 	while (path->slots[*level] >= nritems) {
-		if (*level == root_level)
+		if (*level == root_level) {
+			path->slots[*level] = nritems - 1;
 			return -1;
+		}
 
 		/* move upnext */
 		path->slots[*level] = 0;
@@ -6776,14 +6928,20 @@ static int tree_advance(struct btrfs_pat
 	} else {
 		ret = tree_move_down(path, level, reada_min_gen);
 	}
-	if (ret >= 0) {
-		if (*level == 0)
-			btrfs_item_key_to_cpu(path->nodes[*level], key,
-					path->slots[*level]);
-		else
-			btrfs_node_key_to_cpu(path->nodes[*level], key,
-					path->slots[*level]);
-	}
+
+	/*
+	 * Even if we have reached the end of a tree, ret is -1, update the key
+	 * anyway, so that in case we need to restart due to a block group
+	 * relocation, we can assert that the last key of the root node still
+	 * exists in the tree.
+	 */
+	if (*level == 0)
+		btrfs_item_key_to_cpu(path->nodes[*level], key,
+				      path->slots[*level]);
+	else
+		btrfs_node_key_to_cpu(path->nodes[*level], key,
+				      path->slots[*level]);
+
 	return ret;
 }
 
@@ -6813,6 +6971,97 @@ static int tree_compare_item(struct btrf
 }
 
 /*
+ * A transaction used for relocating a block group was committed or is about to
+ * finish its commit. Release our paths and restart the search, so that we are
+ * not using stale extent buffers:
+ *
+ * 1) For levels > 0, we are only holding references of extent buffers, without
+ *    any locks on them, which does not prevent them from having been relocated
+ *    and reallocated after the last time we released the commit root semaphore.
+ *    The exception are the root nodes, for which we always have a clone, see
+ *    the comment at btrfs_compare_trees();
+ *
+ * 2) For leaves, level 0, we are holding copies (clones) of extent buffers, so
+ *    we are safe from the concurrent relocation and reallocation. However they
+ *    can have file extent items with a pre relocation disk_bytenr value, so we
+ *    restart the start from the current commit roots and clone the new leaves so
+ *    that we get the post relocation disk_bytenr values. Not doing so, could
+ *    make us clone the wrong data in case there are new extents using the old
+ *    disk_bytenr that happen to be shared.
+ */
+static int restart_after_relocation(struct btrfs_path *left_path,
+				    struct btrfs_path *right_path,
+				    const struct btrfs_key *left_key,
+				    const struct btrfs_key *right_key,
+				    int left_level,
+				    int right_level,
+				    const struct send_ctx *sctx)
+{
+	int root_level;
+	int ret;
+
+	lockdep_assert_held_read(&sctx->send_root->fs_info->commit_root_sem);
+
+	btrfs_release_path(left_path);
+	btrfs_release_path(right_path);
+
+	/*
+	 * Since keys can not be added or removed to/from our roots because they
+	 * are readonly and we do not allow deduplication to run in parallel
+	 * (which can add, remove or change keys), the layout of the trees should
+	 * not change.
+	 */
+	left_path->lowest_level = left_level;
+	ret = search_key_again(sctx, sctx->send_root, left_path, left_key);
+	if (ret < 0)
+		return ret;
+
+	right_path->lowest_level = right_level;
+	ret = search_key_again(sctx, sctx->parent_root, right_path, right_key);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * If the lowest level nodes are leaves, clone them so that they can be
+	 * safely used by changed_cb() while not under the protection of the
+	 * commit root semaphore, even if relocation and reallocation happens in
+	 * parallel.
+	 */
+	if (left_level == 0) {
+		ret = replace_node_with_clone(left_path, 0);
+		if (ret < 0)
+			return ret;
+	}
+
+	if (right_level == 0) {
+		ret = replace_node_with_clone(right_path, 0);
+		if (ret < 0)
+			return ret;
+	}
+
+	/*
+	 * Now clone the root nodes (unless they happen to be the leaves we have
+	 * already cloned). This is to protect against concurrent snapshotting of
+	 * the send and parent roots (see the comment at btrfs_compare_trees()).
+	 */
+	root_level = btrfs_header_level(sctx->send_root->commit_root);
+	if (root_level > 0) {
+		ret = replace_node_with_clone(left_path, root_level);
+		if (ret < 0)
+			return ret;
+	}
+
+	root_level = btrfs_header_level(sctx->parent_root->commit_root);
+	if (root_level > 0) {
+		ret = replace_node_with_clone(right_path, root_level);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+/*
  * This function compares two trees and calls the provided callback for
  * every changed/new/deleted item it finds.
  * If shared tree blocks are encountered, whole subtrees are skipped, making
@@ -6840,10 +7089,10 @@ static int btrfs_compare_trees(struct bt
 	int right_root_level;
 	int left_level;
 	int right_level;
-	int left_end_reached;
-	int right_end_reached;
-	int advance_left;
-	int advance_right;
+	int left_end_reached = 0;
+	int right_end_reached = 0;
+	int advance_left = 0;
+	int advance_right = 0;
 	u64 left_blockptr;
 	u64 right_blockptr;
 	u64 left_gen;
@@ -6911,12 +7160,18 @@ static int btrfs_compare_trees(struct bt
 	down_read(&fs_info->commit_root_sem);
 	left_level = btrfs_header_level(left_root->commit_root);
 	left_root_level = left_level;
+	/*
+	 * We clone the root node of the send and parent roots to prevent races
+	 * with snapshot creation of these roots. Snapshot creation COWs the
+	 * root node of a tree, so after the transaction is committed the old
+	 * extent can be reallocated while this send operation is still ongoing.
+	 * So we clone them, under the commit root semaphore, to be race free.
+	 */
 	left_path->nodes[left_level] =
 			btrfs_clone_extent_buffer(left_root->commit_root);
 	if (!left_path->nodes[left_level]) {
-		up_read(&fs_info->commit_root_sem);
 		ret = -ENOMEM;
-		goto out;
+		goto out_unlock;
 	}
 
 	right_level = btrfs_header_level(right_root->commit_root);
@@ -6924,9 +7179,8 @@ static int btrfs_compare_trees(struct bt
 	right_path->nodes[right_level] =
 			btrfs_clone_extent_buffer(right_root->commit_root);
 	if (!right_path->nodes[right_level]) {
-		up_read(&fs_info->commit_root_sem);
 		ret = -ENOMEM;
-		goto out;
+		goto out_unlock;
 	}
 	/*
 	 * Our right root is the parent root, while the left root is the "send"
@@ -6936,7 +7190,6 @@ static int btrfs_compare_trees(struct bt
 	 * will need to read them at some point.
 	 */
 	reada_min_gen = btrfs_header_generation(right_root->commit_root);
-	up_read(&fs_info->commit_root_sem);
 
 	if (left_level == 0)
 		btrfs_item_key_to_cpu(left_path->nodes[left_level],
@@ -6951,11 +7204,26 @@ static int btrfs_compare_trees(struct bt
 		btrfs_node_key_to_cpu(right_path->nodes[right_level],
 				&right_key, right_path->slots[right_level]);
 
-	left_end_reached = right_end_reached = 0;
-	advance_left = advance_right = 0;
+	sctx->last_reloc_trans = fs_info->last_reloc_trans;
 
 	while (1) {
-		cond_resched();
+		if (need_resched() ||
+		    rwsem_is_contended(&fs_info->commit_root_sem)) {
+			up_read(&fs_info->commit_root_sem);
+			cond_resched();
+			down_read(&fs_info->commit_root_sem);
+		}
+
+		if (fs_info->last_reloc_trans > sctx->last_reloc_trans) {
+			ret = restart_after_relocation(left_path, right_path,
+						       &left_key, &right_key,
+						       left_level, right_level,
+						       sctx);
+			if (ret < 0)
+				goto out_unlock;
+			sctx->last_reloc_trans = fs_info->last_reloc_trans;
+		}
+
 		if (advance_left && !left_end_reached) {
 			ret = tree_advance(left_path, &left_level,
 					left_root_level,
@@ -6964,7 +7232,7 @@ static int btrfs_compare_trees(struct bt
 			if (ret == -1)
 				left_end_reached = ADVANCE;
 			else if (ret < 0)
-				goto out;
+				goto out_unlock;
 			advance_left = 0;
 		}
 		if (advance_right && !right_end_reached) {
@@ -6975,54 +7243,55 @@ static int btrfs_compare_trees(struct bt
 			if (ret == -1)
 				right_end_reached = ADVANCE;
 			else if (ret < 0)
-				goto out;
+				goto out_unlock;
 			advance_right = 0;
 		}
 
 		if (left_end_reached && right_end_reached) {
 			ret = 0;
-			goto out;
+			goto out_unlock;
 		} else if (left_end_reached) {
 			if (right_level == 0) {
+				up_read(&fs_info->commit_root_sem);
 				ret = changed_cb(left_path, right_path,
 						&right_key,
 						BTRFS_COMPARE_TREE_DELETED,
 						sctx);
 				if (ret < 0)
 					goto out;
+				down_read(&fs_info->commit_root_sem);
 			}
 			advance_right = ADVANCE;
 			continue;
 		} else if (right_end_reached) {
 			if (left_level == 0) {
+				up_read(&fs_info->commit_root_sem);
 				ret = changed_cb(left_path, right_path,
 						&left_key,
 						BTRFS_COMPARE_TREE_NEW,
 						sctx);
 				if (ret < 0)
 					goto out;
+				down_read(&fs_info->commit_root_sem);
 			}
 			advance_left = ADVANCE;
 			continue;
 		}
 
 		if (left_level == 0 && right_level == 0) {
+			up_read(&fs_info->commit_root_sem);
 			cmp = btrfs_comp_cpu_keys(&left_key, &right_key);
 			if (cmp < 0) {
 				ret = changed_cb(left_path, right_path,
 						&left_key,
 						BTRFS_COMPARE_TREE_NEW,
 						sctx);
-				if (ret < 0)
-					goto out;
 				advance_left = ADVANCE;
 			} else if (cmp > 0) {
 				ret = changed_cb(left_path, right_path,
 						&right_key,
 						BTRFS_COMPARE_TREE_DELETED,
 						sctx);
-				if (ret < 0)
-					goto out;
 				advance_right = ADVANCE;
 			} else {
 				enum btrfs_compare_tree_result result;
@@ -7036,11 +7305,13 @@ static int btrfs_compare_trees(struct bt
 					result = BTRFS_COMPARE_TREE_SAME;
 				ret = changed_cb(left_path, right_path,
 						 &left_key, result, sctx);
-				if (ret < 0)
-					goto out;
 				advance_left = ADVANCE;
 				advance_right = ADVANCE;
 			}
+
+			if (ret < 0)
+				goto out;
+			down_read(&fs_info->commit_root_sem);
 		} else if (left_level == right_level) {
 			cmp = btrfs_comp_cpu_keys(&left_key, &right_key);
 			if (cmp < 0) {
@@ -7080,6 +7351,8 @@ static int btrfs_compare_trees(struct bt
 		}
 	}
 
+out_unlock:
+	up_read(&fs_info->commit_root_sem);
 out:
 	btrfs_free_path(left_path);
 	btrfs_free_path(right_path);
@@ -7429,21 +7702,7 @@ long btrfs_ioctl_send(struct file *mnt_f
 	if (ret)
 		goto out;
 
-	spin_lock(&fs_info->send_reloc_lock);
-	if (test_bit(BTRFS_FS_RELOC_RUNNING, &fs_info->flags)) {
-		spin_unlock(&fs_info->send_reloc_lock);
-		btrfs_warn_rl(fs_info,
-		"cannot run send because a relocation operation is in progress");
-		ret = -EAGAIN;
-		goto out;
-	}
-	fs_info->send_in_progress++;
-	spin_unlock(&fs_info->send_reloc_lock);
-
 	ret = send_subvol(sctx);
-	spin_lock(&fs_info->send_reloc_lock);
-	fs_info->send_in_progress--;
-	spin_unlock(&fs_info->send_reloc_lock);
 	if (ret < 0)
 		goto out;
 
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -163,6 +163,10 @@ static noinline void switch_commit_roots
 	struct btrfs_caching_control *caching_ctl, *next;
 
 	down_write(&fs_info->commit_root_sem);
+
+	if (test_bit(BTRFS_FS_RELOC_RUNNING, &fs_info->flags))
+		fs_info->last_reloc_trans = trans->transid;
+
 	list_for_each_entry_safe(root, tmp, &cur_trans->switch_commits,
 				 dirty_list) {
 		list_del_init(&root->dirty_list);



  parent reply	other threads:[~2022-03-14 12:33 UTC|newest]

Thread overview: 134+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-03-14 11:53 [PATCH 5.16 000/121] 5.16.15-rc1 review Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 001/121] arm64: dts: qcom: sm8350: Describe GCC dependency clocks Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 002/121] arm64: dts: qcom: sm8350: Correct UFS symbol clocks Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 003/121] HID: elo: Revert USB reference counting Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 004/121] HID: hid-thrustmaster: fix OOB read in thrustmaster_interrupts Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 005/121] ARM: boot: dts: bcm2711: Fix HVS register range Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 006/121] clk: qcom: gdsc: Add support to update GDSC transition delay Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 007/121] clk: qcom: dispcc: Update the transition delay for MDSS GDSC Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 008/121] soc: mediatek: mt8192-mmsys: Fix dither to dsi0 paths input sel Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 009/121] HID: vivaldi: fix sysfs attributes leak Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 010/121] HID: nintendo: check the return value of alloc_workqueue() Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 011/121] arm64: dts: armada-3720-turris-mox: Add missing ethernet0 alias Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 012/121] tipc: fix kernel panic when enabling bearer Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 013/121] vdpa/mlx5: add validation for VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET command Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 014/121] vduse: Fix returning wrong type in vduse_domain_alloc_iova() Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 015/121] net: phy: meson-gxl: fix interrupt handling in forced mode Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 016/121] mISDN: Fix memory leak in dsp_pipeline_build() Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 017/121] vhost: fix hung thread due to erroneous iotlb entries Greg Kroah-Hartman
2022-03-14 16:20   ` Anirudh Rayabharam
2022-03-14 11:53 ` [PATCH 5.16 018/121] virtio-blk: Dont use MAX_DISCARD_SEGMENTS if max_discard_seg is zero Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 019/121] virtio-blk: Remove BUG_ON() in virtio_queue_rq() Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 020/121] vdpa: fix use-after-free on vp_vdpa_remove Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 021/121] isdn: hfcpci: check the return value of dma_set_mask() in setup_hw() Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 022/121] net: qlogic: check the return value of dma_alloc_coherent() in qed_vf_hw_prepare() Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 023/121] esp: Fix possible buffer overflow in ESP transformation Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 024/121] esp: Fix BEET mode inter address family tunneling on GSO Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 025/121] net: gro: move skb_gro_receive_list to udp_offload.c Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 026/121] qed: return status of qed_iov_get_link Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 027/121] smsc95xx: Ignore -ENODEV errors when device is unplugged Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 028/121] gpiolib: acpi: Convert ACPI value of debounce to microseconds Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 029/121] drm/i915/psr: Set "SF Partial Frame Enable" also on full update Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 030/121] drm/sun4i: mixer: Fix P010 and P210 format numbers Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 031/121] net: dsa: mt7530: fix incorrect test in mt753x_phylink_validate() Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 032/121] ARM: dts: aspeed: Fix AST2600 quad spi group Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 033/121] iavf: Fix handling of vlan strip virtual channel messages Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 034/121] i40e: stop disabling VFs due to PF error responses Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 035/121] ice: " Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 036/121] ice: Fix error with handling of bonding MTU Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 037/121] ice: Dont use GFP_KERNEL in atomic context Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 038/121] ice: Fix curr_link_speed advertised speed Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 039/121] ethernet: Fix error handling in xemaclite_of_probe Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 040/121] tipc: fix incorrect order of state message data sanity check Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 041/121] net: ethernet: ti: cpts: Handle error for clk_enable Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 042/121] net: ethernet: lpc_eth: " Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 043/121] net: marvell: prestera: Add missing of_node_put() in prestera_switch_set_base_mac_addr Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 044/121] ax25: Fix NULL pointer dereference in ax25_kill_by_device Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 045/121] net/mlx5: Fix size field in bufferx_reg struct Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 046/121] net/mlx5: Fix a race on command flush flow Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 047/121] net/mlx5e: Lag, Only handle events from highest priority multipath entry Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 048/121] net/mlx5e: SHAMPO, reduce TIR indication Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 049/121] NFC: port100: fix use-after-free in port100_send_complete Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 050/121] selftests: pmtu.sh: Kill tcpdump processes launched by subshell Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 051/121] selftests: pmtu.sh: Kill nettest processes launched in subshell Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 052/121] gpio: ts4900: Do not set DAT and OE together Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 053/121] mm: gup: make fault_in_safe_writeable() use fixup_user_fault() Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 054/121] gianfar: ethtool: Fix refcount leak in gfar_get_ts_info Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 055/121] net: phy: DP83822: clear MISR2 register to disable interrupts Greg Kroah-Hartman
2022-03-14 11:53 ` [PATCH 5.16 056/121] sctp: fix kernel-infoleak for SCTP sockets Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 057/121] net: arc_emac: Fix use after free in arc_mdio_probe() Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 058/121] net: bcmgenet: Dont claim WOL when its not available Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 059/121] net: phy: meson-gxl: improve link-up behavior Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 060/121] selftests/bpf: Add test for bpf_timer overwriting crash Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 061/121] swiotlb: fix info leak with DMA_FROM_DEVICE Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 062/121] usb: dwc3: pci: add support for the Intel Raptor Lake-S Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 063/121] pinctrl: tigerlake: Revert "Add Alder Lake-M ACPI ID" Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 064/121] KVM: Fix lockdep false negative during host resume Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 065/121] kvm: x86: Disable KVM_HC_CLOCK_PAIRING if tsc is in always catchup mode Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 066/121] spi: rockchip: Fix error in getting num-cs property Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 067/121] spi: rockchip: terminate dma transmission when slave abort Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 068/121] drm/vc4: hdmi: Unregister codec device on unbind Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 069/121] of/fdt: move elfcorehdr reservation early for crash dump kernel Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 070/121] x86/kvm: Dont use pv tlb/ipi/sched_yield if on 1 vCPU Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 071/121] drivers: hamradio: 6pack: fix UAF bug caused by mod_timer() Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 072/121] net-sysfs: add check for netdevice being present to speed_show Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 073/121] hwmon: (pmbus) Clear pmbus fault/warning bits after read Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 074/121] nvme-tcp: send H2CData PDUs based on MAXH2CDATA Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 075/121] PCI: Mark all AMD Navi10 and Navi14 GPU ATS as broken Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 076/121] gpio: Return EPROBE_DEFER if gc->to_irq is NULL Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 077/121] drm/amdgpu: bypass tiling flag check in virtual display case (v2) Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 078/121] Revert "xen-netback: remove hotplug-status once it has served its purpose" Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 079/121] Revert "xen-netback: Check for hotplug-status existence before watching" Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 080/121] ipv6: prevent a possible race condition with lifetimes Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 081/121] tracing: Ensure trace buffer is at least 4096 bytes large Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 082/121] tracing/osnoise: Make osnoise_main to sleep for microseconds Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 083/121] tracing: Fix selftest config check for function graph start up test Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 084/121] selftest/vm: fix map_fixed_noreplace test failure Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 085/121] selftests/memfd: clean up mapping in mfd_fail_write Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 086/121] ARM: Spectre-BHB: provide empty stub for non-config Greg Kroah-Hartman
2022-03-14 11:54   ` Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 087/121] fuse: fix fileattr op failure Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 088/121] fuse: fix pipe buffer lifetime for direct_io Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 089/121] staging: rtl8723bs: Fix access-point mode deadlock Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 090/121] staging: gdm724x: fix use after free in gdm_lte_rx() Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 091/121] net: macb: Fix lost RX packet wakeup race in NAPI receive Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 092/121] riscv: alternative only works on !XIP_KERNEL Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 093/121] mmc: meson: Fix usage of meson_mmc_post_req() Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 094/121] riscv: Fix auipc+jalr relocation range checks Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 095/121] tracing/osnoise: Force quiescent states while tracing Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 096/121] tracing/osnoise: Do not unregister events twice Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 097/121] arm64: dts: marvell: armada-37xx: Remap IO space to bus address 0x0 Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 098/121] arm64: Ensure execute-only permissions are not allowed without EPAN Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 099/121] arm64: kasan: fix include error in MTE functions Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 100/121] swiotlb: rework "fix info leak with DMA_FROM_DEVICE" Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 101/121] virtio: unexport virtio_finalize_features Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 102/121] virtio: acknowledge all features before access Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 103/121] net/mlx5: Fix offloading with ESWITCH_IPV4_TTL_MODIFY_ENABLE Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 104/121] ARM: fix Thumb2 regression with Spectre BHB Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 105/121] watch_queue: Fix filter limit check Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 106/121] watch_queue, pipe: Free watchqueue state after clearing pipe ring Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 107/121] watch_queue: Fix to release page in ->release() Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 108/121] watch_queue: Fix to always request a pow-of-2 pipe ring size Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 109/121] watch_queue: Fix the alloc bitmap size to reflect notes allocated Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 110/121] watch_queue: Free the alloc bitmap when the watch_queue is torn down Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 111/121] watch_queue: Fix lack of barrier/sync/lock between post and read Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 112/121] watch_queue: Make comment about setting ->defunct more accurate Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 113/121] x86/boot: Fix memremap of setup_indirect structures Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 114/121] x86/boot: Add setup_indirect support in early_memremap_is_setup_data() Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 115/121] x86/module: Fix the paravirt vs alternative order Greg Kroah-Hartman
2022-03-14 11:54 ` [PATCH 5.16 116/121] x86/sgx: Free backing memory after faulting the enclave page Greg Kroah-Hartman
2022-03-14 11:55 ` [PATCH 5.16 117/121] x86/traps: Mark do_int3() NOKPROBE_SYMBOL Greg Kroah-Hartman
2022-03-14 11:55 ` [PATCH 5.16 118/121] drm/panel: Select DRM_DP_HELPER for DRM_PANEL_EDP Greg Kroah-Hartman
2022-03-14 11:55   ` Greg Kroah-Hartman
2022-03-14 11:55 ` [PATCH 5.16 119/121] perf parse: Fix event parser error for hybrid systems Greg Kroah-Hartman
2022-03-14 11:55 ` Greg Kroah-Hartman [this message]
2022-03-14 11:55 ` [PATCH 5.16 121/121] riscv: dts: k210: fix broken IRQs on hart1 Greg Kroah-Hartman
2022-03-14 20:05 ` [PATCH 5.16 000/121] 5.16.15-rc1 review Justin Forbes
2022-03-14 22:55 ` Florian Fainelli
2022-03-15  0:54 ` Guenter Roeck
2022-03-15  2:42 ` Fox Chen
2022-03-15  4:06 ` Rudi Heitbaum
2022-03-15  5:10 ` Naresh Kamboju
2022-03-15  7:28 ` Ron Economos
2022-03-15  9:42 ` Jon Hunter
2022-03-15 11:16 ` Bagas Sanjaya

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=20220314112747.461313246@linuxfoundation.org \
    --to=gregkh@linuxfoundation.org \
    --cc=anand.jain@oracle.com \
    --cc=dsterba@suse.com \
    --cc=fdmanana@suse.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=stable@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.