Commit 4a9d8bde authored by Miao Xie's avatar Miao Xie Committed by Josef Bacik

Btrfs: make the state of the transaction more readable

We used 3 variants to track the state of the transaction, it was complex
and wasted the memory space. Besides that, it was hard to understand that
which types of the transaction handles should be blocked in each transaction
state, so the developers often made mistakes.

This patch improved the above problem. In this patch, we define 6 states
for the transaction,
  enum btrfs_trans_state {
	TRANS_STATE_RUNNING		= 0,
	TRANS_STATE_BLOCKED		= 1,
	TRANS_STATE_COMMIT_START	= 2,
	TRANS_STATE_COMMIT_DOING	= 3,
	TRANS_STATE_UNBLOCKED		= 4,
	TRANS_STATE_COMPLETED		= 5,
	TRANS_STATE_MAX			= 6,
  }
and just use 1 variant to track those state.

In order to make the blocked handle types for each state more clear,
we introduce a array:
  unsigned int btrfs_blocked_trans_types[TRANS_STATE_MAX] = {
	[TRANS_STATE_RUNNING]		= 0U,
	[TRANS_STATE_BLOCKED]		= (__TRANS_USERSPACE |
					   __TRANS_START),
	[TRANS_STATE_COMMIT_START]	= (__TRANS_USERSPACE |
					   __TRANS_START |
					   __TRANS_ATTACH),
	[TRANS_STATE_COMMIT_DOING]	= (__TRANS_USERSPACE |
					   __TRANS_START |
					   __TRANS_ATTACH |
					   __TRANS_JOIN),
	[TRANS_STATE_UNBLOCKED]		= (__TRANS_USERSPACE |
					   __TRANS_START |
					   __TRANS_ATTACH |
					   __TRANS_JOIN |
					   __TRANS_JOIN_NOLOCK),
	[TRANS_STATE_COMPLETED]		= (__TRANS_USERSPACE |
					   __TRANS_START |
					   __TRANS_ATTACH |
					   __TRANS_JOIN |
					   __TRANS_JOIN_NOLOCK),
  }
it is very intuitionistic.

Besides that, because we remove ->in_commit in transaction structure, so
the lock ->commit_lock which was used to protect it is unnecessary, remove
->commit_lock.
Signed-off-by: default avatarMiao Xie <miaox@cn.fujitsu.com>
Signed-off-by: default avatarJosef Bacik <jbacik@fusionio.com>
parent 581227d0
...@@ -1496,7 +1496,6 @@ struct btrfs_fs_info { ...@@ -1496,7 +1496,6 @@ struct btrfs_fs_info {
int closing; int closing;
int log_root_recovering; int log_root_recovering;
int enospc_unlink; int enospc_unlink;
int trans_no_join;
u64 total_pinned; u64 total_pinned;
......
...@@ -1747,7 +1747,7 @@ static int transaction_kthread(void *arg) ...@@ -1747,7 +1747,7 @@ static int transaction_kthread(void *arg)
} }
now = get_seconds(); now = get_seconds();
if (!cur->blocked && if (cur->state < TRANS_STATE_BLOCKED &&
(now < cur->start_time || now - cur->start_time < 30)) { (now < cur->start_time || now - cur->start_time < 30)) {
spin_unlock(&root->fs_info->trans_lock); spin_unlock(&root->fs_info->trans_lock);
delay = HZ * 5; delay = HZ * 5;
...@@ -2186,7 +2186,6 @@ int open_ctree(struct super_block *sb, ...@@ -2186,7 +2186,6 @@ int open_ctree(struct super_block *sb,
fs_info->max_inline = 8192 * 1024; fs_info->max_inline = 8192 * 1024;
fs_info->metadata_ratio = 0; fs_info->metadata_ratio = 0;
fs_info->defrag_inodes = RB_ROOT; fs_info->defrag_inodes = RB_ROOT;
fs_info->trans_no_join = 0;
fs_info->free_chunk_space = 0; fs_info->free_chunk_space = 0;
fs_info->tree_mod_log = RB_ROOT; fs_info->tree_mod_log = RB_ROOT;
...@@ -3958,19 +3957,14 @@ void btrfs_cleanup_one_transaction(struct btrfs_transaction *cur_trans, ...@@ -3958,19 +3957,14 @@ void btrfs_cleanup_one_transaction(struct btrfs_transaction *cur_trans,
btrfs_block_rsv_release(root, &root->fs_info->trans_block_rsv, btrfs_block_rsv_release(root, &root->fs_info->trans_block_rsv,
cur_trans->dirty_pages.dirty_bytes); cur_trans->dirty_pages.dirty_bytes);
/* FIXME: cleanup wait for commit */ cur_trans->state = TRANS_STATE_COMMIT_START;
cur_trans->in_commit = 1;
cur_trans->blocked = 1;
wake_up(&root->fs_info->transaction_blocked_wait); wake_up(&root->fs_info->transaction_blocked_wait);
btrfs_evict_pending_snapshots(cur_trans); btrfs_evict_pending_snapshots(cur_trans);
cur_trans->blocked = 0; cur_trans->state = TRANS_STATE_UNBLOCKED;
wake_up(&root->fs_info->transaction_wait); wake_up(&root->fs_info->transaction_wait);
cur_trans->commit_done = 1;
wake_up(&cur_trans->commit_wait);
btrfs_destroy_delayed_inodes(root); btrfs_destroy_delayed_inodes(root);
btrfs_assert_delayed_root_empty(root); btrfs_assert_delayed_root_empty(root);
...@@ -3979,6 +3973,9 @@ void btrfs_cleanup_one_transaction(struct btrfs_transaction *cur_trans, ...@@ -3979,6 +3973,9 @@ void btrfs_cleanup_one_transaction(struct btrfs_transaction *cur_trans,
btrfs_destroy_pinned_extent(root, btrfs_destroy_pinned_extent(root,
root->fs_info->pinned_extents); root->fs_info->pinned_extents);
cur_trans->state =TRANS_STATE_COMPLETED;
wake_up(&cur_trans->commit_wait);
/* /*
memset(cur_trans, 0, sizeof(*cur_trans)); memset(cur_trans, 0, sizeof(*cur_trans));
kmem_cache_free(btrfs_transaction_cachep, cur_trans); kmem_cache_free(btrfs_transaction_cachep, cur_trans);
...@@ -4006,25 +4003,23 @@ static int btrfs_cleanup_transaction(struct btrfs_root *root) ...@@ -4006,25 +4003,23 @@ static int btrfs_cleanup_transaction(struct btrfs_root *root)
btrfs_destroy_delayed_refs(t, root); btrfs_destroy_delayed_refs(t, root);
/* FIXME: cleanup wait for commit */ /*
t->in_commit = 1; * FIXME: cleanup wait for commit
t->blocked = 1; * We needn't acquire the lock here, because we are during
* the umount, there is no other task which will change it.
*/
t->state = TRANS_STATE_COMMIT_START;
smp_mb(); smp_mb();
if (waitqueue_active(&root->fs_info->transaction_blocked_wait)) if (waitqueue_active(&root->fs_info->transaction_blocked_wait))
wake_up(&root->fs_info->transaction_blocked_wait); wake_up(&root->fs_info->transaction_blocked_wait);
btrfs_evict_pending_snapshots(t); btrfs_evict_pending_snapshots(t);
t->blocked = 0; t->state = TRANS_STATE_UNBLOCKED;
smp_mb(); smp_mb();
if (waitqueue_active(&root->fs_info->transaction_wait)) if (waitqueue_active(&root->fs_info->transaction_wait))
wake_up(&root->fs_info->transaction_wait); wake_up(&root->fs_info->transaction_wait);
t->commit_done = 1;
smp_mb();
if (waitqueue_active(&t->commit_wait))
wake_up(&t->commit_wait);
btrfs_destroy_delayed_inodes(root); btrfs_destroy_delayed_inodes(root);
btrfs_assert_delayed_root_empty(root); btrfs_assert_delayed_root_empty(root);
...@@ -4036,6 +4031,11 @@ static int btrfs_cleanup_transaction(struct btrfs_root *root) ...@@ -4036,6 +4031,11 @@ static int btrfs_cleanup_transaction(struct btrfs_root *root)
btrfs_destroy_pinned_extent(root, btrfs_destroy_pinned_extent(root,
root->fs_info->pinned_extents); root->fs_info->pinned_extents);
t->state = TRANS_STATE_COMPLETED;
smp_mb();
if (waitqueue_active(&t->commit_wait))
wake_up(&t->commit_wait);
atomic_set(&t->use_count, 0); atomic_set(&t->use_count, 0);
list_del_init(&t->list); list_del_init(&t->list);
memset(t, 0, sizeof(*t)); memset(t, 0, sizeof(*t));
......
This diff is collapsed.
...@@ -22,6 +22,16 @@ ...@@ -22,6 +22,16 @@
#include "delayed-ref.h" #include "delayed-ref.h"
#include "ctree.h" #include "ctree.h"
enum btrfs_trans_state {
TRANS_STATE_RUNNING = 0,
TRANS_STATE_BLOCKED = 1,
TRANS_STATE_COMMIT_START = 2,
TRANS_STATE_COMMIT_DOING = 3,
TRANS_STATE_UNBLOCKED = 4,
TRANS_STATE_COMPLETED = 5,
TRANS_STATE_MAX = 6,
};
struct btrfs_transaction { struct btrfs_transaction {
u64 transid; u64 transid;
/* /*
...@@ -37,10 +47,8 @@ struct btrfs_transaction { ...@@ -37,10 +47,8 @@ struct btrfs_transaction {
atomic_t num_writers; atomic_t num_writers;
atomic_t use_count; atomic_t use_count;
spinlock_t commit_lock; /* Be protected by fs_info->trans_lock when we want to change it. */
int in_commit; enum btrfs_trans_state state;
int commit_done;
int blocked;
struct list_head list; struct list_head list;
struct extent_io_tree dirty_pages; struct extent_io_tree dirty_pages;
unsigned long start_time; unsigned long start_time;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment