From: Ioannis Angelakopoulos <iangelak@fb.com>
To: <linux-btrfs@vger.kernel.org>, <kernel-team@fb.com>
Subject: [PATCH v2 3/5] btrfs: Add lockdep models for the transaction states wait events
Date: Mon, 18 Jul 2022 21:09:56 -0700 [thread overview]
Message-ID: <20220719040954.3964407-4-iangelak@fb.com> (raw)
In-Reply-To: <20220719040954.3964407-1-iangelak@fb.com>
Add a lockdep annotation for the transaction states that have wait
events; 1) TRANS_STATE_COMMIT_START, 2) TRANS_STATE_UNBLOCKED, 3)
TRANS_STATE_SUPER_COMMITTED, and 4) TRANS_STATE_COMPLETED in
fs/btrfs/transaction.c.
With the exception of the lockdep annotation for TRANS_STATE_COMMIT_START
the transaction thread has to acquire the lockdep maps for the transaction
states as reader after the lockdep map for num_writers is released so that
lockdep does not complain.
Signed-off-by: Ioannis Angelakopoulos <iangelak@fb.com>
---
fs/btrfs/ctree.h | 20 +++++++++++++++
fs/btrfs/disk-io.c | 17 +++++++++++++
fs/btrfs/transaction.c | 57 +++++++++++++++++++++++++++++++++++++-----
3 files changed, 88 insertions(+), 6 deletions(-)
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 586756f831e5..e6c7cafcd296 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -1097,6 +1097,7 @@ struct btrfs_fs_info {
struct lockdep_map btrfs_trans_num_writers_map;
struct lockdep_map btrfs_trans_num_extwriters_map;
+ struct lockdep_map btrfs_state_change_map[4];
#ifdef CONFIG_BTRFS_FS_REF_VERIFY
spinlock_t ref_verify_lock;
@@ -1178,6 +1179,13 @@ enum {
BTRFS_ROOT_UNFINISHED_DROP,
};
+enum btrfs_lockdep_trans_states {
+ BTRFS_LOCKDEP_TRANS_COMMIT_START,
+ BTRFS_LOCKDEP_TRANS_UNBLOCKED,
+ BTRFS_LOCKDEP_TRANS_SUPER_COMMITTED,
+ BTRFS_LOCKDEP_TRANS_COMPLETED,
+};
+
#define btrfs_might_wait_for_event(b, lock) \
do { \
rwsem_acquire(&b->lock##_map, 0, 0, _THIS_IP_); \
@@ -1190,6 +1198,18 @@ enum {
#define btrfs_lockdep_release(b, lock) \
rwsem_release(&b->lock##_map, _THIS_IP_)
+#define btrfs_might_wait_for_state(b, i) \
+ do { \
+ rwsem_acquire(&b->btrfs_state_change_map[i], 0, 0, _THIS_IP_); \
+ rwsem_release(&b->btrfs_state_change_map[i], _THIS_IP_); \
+ } while (0)
+
+#define btrfs_trans_state_lockdep_acquire(b, i) \
+ rwsem_acquire_read(&b->btrfs_state_change_map[i], 0, 0, _THIS_IP_)
+
+#define btrfs_trans_state_lockdep_release(b, i) \
+ rwsem_release(&b->btrfs_state_change_map[i], _THIS_IP_)
+
static inline void btrfs_wake_unfinished_drop(struct btrfs_fs_info *fs_info)
{
clear_and_wake_up_bit(BTRFS_FS_UNFINISHED_DROPS, &fs_info->flags);
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index b1193584ba49..be5cf86fa992 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -3048,6 +3048,10 @@ void btrfs_init_fs_info(struct btrfs_fs_info *fs_info)
{
static struct lock_class_key btrfs_trans_num_writers_key;
static struct lock_class_key btrfs_trans_num_extwriters_key;
+ static struct lock_class_key btrfs_trans_commit_start_key;
+ static struct lock_class_key btrfs_trans_unblocked_key;
+ static struct lock_class_key btrfs_trans_sup_committed_key;
+ static struct lock_class_key btrfs_trans_completed_key;
INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_ATOMIC);
INIT_RADIX_TREE(&fs_info->buffer_radix, GFP_ATOMIC);
@@ -3084,6 +3088,19 @@ void btrfs_init_fs_info(struct btrfs_fs_info *fs_info)
"btrfs_trans_num_extwriters",
&btrfs_trans_num_extwriters_key, 0);
+ lockdep_init_map(&fs_info->btrfs_state_change_map[0],
+ "btrfs_trans_commit_start",
+ &btrfs_trans_commit_start_key, 0);
+ lockdep_init_map(&fs_info->btrfs_state_change_map[1],
+ "btrfs_trans_unblocked",
+ &btrfs_trans_unblocked_key, 0);
+ lockdep_init_map(&fs_info->btrfs_state_change_map[2],
+ "btrfs_trans_sup_commited",
+ &btrfs_trans_sup_committed_key, 0);
+ lockdep_init_map(&fs_info->btrfs_state_change_map[3],
+ "btrfs_trans_completed",
+ &btrfs_trans_completed_key, 0);
+
INIT_LIST_HEAD(&fs_info->dirty_cowonly_roots);
INIT_LIST_HEAD(&fs_info->space_info);
INIT_LIST_HEAD(&fs_info->tree_mod_seq_list);
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index c9751a05c029..e4efaa27ec17 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -550,6 +550,7 @@ static void wait_current_trans(struct btrfs_fs_info *fs_info)
refcount_inc(&cur_trans->use_count);
spin_unlock(&fs_info->trans_lock);
+ btrfs_might_wait_for_state(fs_info, BTRFS_LOCKDEP_TRANS_UNBLOCKED);
wait_event(fs_info->transaction_wait,
cur_trans->state >= TRANS_STATE_UNBLOCKED ||
TRANS_ABORTED(cur_trans));
@@ -949,6 +950,7 @@ int btrfs_wait_for_commit(struct btrfs_fs_info *fs_info, u64 transid)
goto out; /* nothing committing|committed */
}
+ btrfs_might_wait_for_state(fs_info, BTRFS_LOCKDEP_TRANS_COMPLETED);
wait_for_commit(cur_trans, TRANS_STATE_COMPLETED);
btrfs_put_transaction(cur_trans);
out:
@@ -1980,6 +1982,7 @@ void btrfs_commit_transaction_async(struct btrfs_trans_handle *trans)
* Wait for the current transaction commit to start and block
* subsequent transaction joins
*/
+ btrfs_might_wait_for_state(fs_info, BTRFS_LOCKDEP_TRANS_COMMIT_START);
wait_event(fs_info->transaction_blocked_wait,
cur_trans->state >= TRANS_STATE_COMMIT_START ||
TRANS_ABORTED(cur_trans));
@@ -2137,14 +2140,16 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
ktime_t interval;
ASSERT(refcount_read(&trans->use_count) == 1);
+ btrfs_trans_state_lockdep_acquire(fs_info,
+ BTRFS_LOCKDEP_TRANS_COMMIT_START);
/* Stop the commit early if ->aborted is set */
if (TRANS_ABORTED(cur_trans)) {
ret = cur_trans->aborted;
- btrfs_end_transaction(trans);
- return ret;
+ goto lockdep_trans_commit_start_release;
}
+
btrfs_trans_release_metadata(trans);
trans->block_rsv = NULL;
@@ -2160,8 +2165,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
*/
ret = btrfs_run_delayed_refs(trans, 0);
if (ret) {
- btrfs_end_transaction(trans);
- return ret;
+ goto lockdep_trans_commit_start_release;
}
}
@@ -2192,8 +2196,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
if (run_it) {
ret = btrfs_start_dirty_block_groups(trans);
if (ret) {
- btrfs_end_transaction(trans);
- return ret;
+ goto lockdep_trans_commit_start_release;
}
}
}
@@ -2209,7 +2212,17 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
if (trans->in_fsync)
want_state = TRANS_STATE_SUPER_COMMITTED;
+
+ btrfs_trans_state_lockdep_release(fs_info,
+ BTRFS_LOCKDEP_TRANS_COMMIT_START);
ret = btrfs_end_transaction(trans);
+
+ if (want_state == TRANS_STATE_COMPLETED)
+ btrfs_might_wait_for_state(fs_info, BTRFS_LOCKDEP_TRANS_COMPLETED);
+ else
+ btrfs_might_wait_for_state(fs_info,
+ BTRFS_LOCKDEP_TRANS_SUPER_COMMITTED);
+
wait_for_commit(cur_trans, want_state);
if (TRANS_ABORTED(cur_trans))
@@ -2222,6 +2235,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
cur_trans->state = TRANS_STATE_COMMIT_START;
wake_up(&fs_info->transaction_blocked_wait);
+ btrfs_trans_state_lockdep_release(fs_info,
+ BTRFS_LOCKDEP_TRANS_COMMIT_START);
if (cur_trans->list.prev != &fs_info->trans_list) {
enum btrfs_trans_state want_state = TRANS_STATE_COMPLETED;
@@ -2235,6 +2250,12 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
refcount_inc(&prev_trans->use_count);
spin_unlock(&fs_info->trans_lock);
+ if (want_state == TRANS_STATE_COMPLETED)
+ btrfs_might_wait_for_state(fs_info,
+ BTRFS_LOCKDEP_TRANS_COMPLETED);
+ else
+ btrfs_might_wait_for_state(fs_info,
+ BTRFS_LOCKDEP_TRANS_SUPER_COMMITTED);
wait_for_commit(prev_trans, want_state);
ret = READ_ONCE(prev_trans->aborted);
@@ -2323,6 +2344,15 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
wait_event(cur_trans->writer_wait,
atomic_read(&cur_trans->num_writers) == 1);
+ /*
+ * Make lockdep happy by acquiring the state locks after
+ * btrfs_trans_num_writers is released.
+ */
+ btrfs_trans_state_lockdep_acquire(fs_info, BTRFS_LOCKDEP_TRANS_COMPLETED);
+ btrfs_trans_state_lockdep_acquire(fs_info,
+ BTRFS_LOCKDEP_TRANS_SUPER_COMMITTED);
+ btrfs_trans_state_lockdep_acquire(fs_info, BTRFS_LOCKDEP_TRANS_UNBLOCKED);
+
/*
* We've started the commit, clear the flag in case we were triggered to
* do an async commit but somebody else started before the transaction
@@ -2332,6 +2362,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
if (TRANS_ABORTED(cur_trans)) {
ret = cur_trans->aborted;
+ btrfs_trans_state_lockdep_release(fs_info,
+ BTRFS_LOCKDEP_TRANS_UNBLOCKED);
goto scrub_continue;
}
/*
@@ -2466,6 +2498,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
mutex_unlock(&fs_info->reloc_mutex);
wake_up(&fs_info->transaction_wait);
+ btrfs_trans_state_lockdep_release(fs_info, BTRFS_LOCKDEP_TRANS_UNBLOCKED);
ret = btrfs_write_and_wait_transaction(trans);
if (ret) {
@@ -2497,6 +2530,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
*/
cur_trans->state = TRANS_STATE_SUPER_COMMITTED;
wake_up(&cur_trans->commit_wait);
+ btrfs_trans_state_lockdep_release(fs_info,
+ BTRFS_LOCKDEP_TRANS_SUPER_COMMITTED);
btrfs_finish_extent_commit(trans);
@@ -2510,6 +2545,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
*/
cur_trans->state = TRANS_STATE_COMPLETED;
wake_up(&cur_trans->commit_wait);
+ btrfs_trans_state_lockdep_release(fs_info, BTRFS_LOCKDEP_TRANS_COMPLETED);
spin_lock(&fs_info->trans_lock);
list_del_init(&cur_trans->list);
@@ -2538,7 +2574,11 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
unlock_reloc:
mutex_unlock(&fs_info->reloc_mutex);
+ btrfs_trans_state_lockdep_release(fs_info, BTRFS_LOCKDEP_TRANS_UNBLOCKED);
scrub_continue:
+ btrfs_trans_state_lockdep_release(fs_info,
+ BTRFS_LOCKDEP_TRANS_SUPER_COMMITTED);
+ btrfs_trans_state_lockdep_release(fs_info, BTRFS_LOCKDEP_TRANS_COMPLETED);
btrfs_scrub_continue(fs_info);
cleanup_transaction:
btrfs_trans_release_metadata(trans);
@@ -2555,6 +2595,11 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
btrfs_lockdep_release(fs_info, btrfs_trans_num_extwriters);
btrfs_lockdep_release(fs_info, btrfs_trans_num_writers);
goto cleanup_transaction;
+lockdep_trans_commit_start_release:
+ btrfs_trans_state_lockdep_release(fs_info,
+ BTRFS_LOCKDEP_TRANS_COMMIT_START);
+ btrfs_end_transaction(trans);
+ return ret;
}
/*
--
2.30.2
next prev parent reply other threads:[~2022-07-19 4:16 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-07-19 4:09 [PATCH v2 0/5] btrfs: Annotate wait events with lockdep Ioannis Angelakopoulos
2022-07-19 4:09 ` [PATCH v2 1/5] btrfs: Add a lockdep model for the num_writers wait event Ioannis Angelakopoulos
2022-07-20 14:46 ` Josef Bacik
2022-07-20 14:47 ` Sweet Tea Dorminy
2022-07-20 17:12 ` Ioannis Angelakopoulos
2022-07-19 4:09 ` [PATCH v2 2/5] btrfs: Add a lockdep model for the num_extwriters " Ioannis Angelakopoulos
2022-07-20 14:46 ` Josef Bacik
2022-07-19 4:09 ` Ioannis Angelakopoulos [this message]
2022-07-20 14:47 ` [PATCH v2 3/5] btrfs: Add lockdep models for the transaction states wait events Sweet Tea Dorminy
2022-07-20 17:39 ` Ioannis Angelakopoulos
2022-07-20 14:48 ` Josef Bacik
2022-07-20 17:49 ` Ioannis Angelakopoulos
2022-07-19 4:09 ` [PATCH v2 4/5] btrfs: Add a lockdep model for the pending_ordered wait event Ioannis Angelakopoulos
2022-07-20 14:48 ` Josef Bacik
2022-07-19 4:10 ` [PATCH v2 5/5] btrfs: Add a lockdep model for the ordered extents " Ioannis Angelakopoulos
2022-07-20 14:50 ` Josef Bacik
2022-07-20 14:47 ` [PATCH v2 0/5] btrfs: Annotate wait events with lockdep Sweet Tea Dorminy
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=20220719040954.3964407-4-iangelak@fb.com \
--to=iangelak@fb.com \
--cc=kernel-team@fb.com \
--cc=linux-btrfs@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.