diff options
author | Josef Bacik <josef@redhat.com> | 2011-04-11 15:45:29 -0400 |
---|---|---|
committer | Josef Bacik <josef@redhat.com> | 2011-04-11 20:43:52 -0400 |
commit | 13c5a93e7005d7dae0b6d070d25203593e692d13 (patch) | |
tree | ecbc7205618940bbba3f0d9ad000462a5364f763 /fs | |
parent | 93a54bc4c28a125978cddbe2db9e347391e3522d (diff) |
Btrfs: avoid taking the trans_mutex in btrfs_end_transaction
I've been working on making our O_DIRECT latency not suck and I noticed we were
taking the trans_mutex in btrfs_end_transaction. So to do this we convert
num_writers and use_count to atomic_t's and just decrement them in
btrfs_end_transaction. Instead of deleting the transaction from the trans list
in put_transaction we do that in btrfs_commit_transaction() since that's the
only time it actually needs to be removed from the list. Thanks,
Signed-off-by: Josef Bacik <josef@redhat.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/disk-io.c | 2 | ||||
-rw-r--r-- | fs/btrfs/transaction.c | 37 | ||||
-rw-r--r-- | fs/btrfs/transaction.h | 4 |
3 files changed, 19 insertions, 24 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index a272bfd74ea0..ef6865c17cd6 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -3136,7 +3136,7 @@ static int btrfs_cleanup_transaction(struct btrfs_root *root) | |||
3136 | btrfs_destroy_pinned_extent(root, | 3136 | btrfs_destroy_pinned_extent(root, |
3137 | root->fs_info->pinned_extents); | 3137 | root->fs_info->pinned_extents); |
3138 | 3138 | ||
3139 | t->use_count = 0; | 3139 | atomic_set(&t->use_count, 0); |
3140 | list_del_init(&t->list); | 3140 | list_del_init(&t->list); |
3141 | memset(t, 0, sizeof(*t)); | 3141 | memset(t, 0, sizeof(*t)); |
3142 | kmem_cache_free(btrfs_transaction_cachep, t); | 3142 | kmem_cache_free(btrfs_transaction_cachep, t); |
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 4583008217e6..c571734d5e5a 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -32,10 +32,8 @@ | |||
32 | 32 | ||
33 | static noinline void put_transaction(struct btrfs_transaction *transaction) | 33 | static noinline void put_transaction(struct btrfs_transaction *transaction) |
34 | { | 34 | { |
35 | WARN_ON(transaction->use_count == 0); | 35 | WARN_ON(atomic_read(&transaction->use_count) == 0); |
36 | transaction->use_count--; | 36 | if (atomic_dec_and_test(&transaction->use_count)) { |
37 | if (transaction->use_count == 0) { | ||
38 | list_del_init(&transaction->list); | ||
39 | memset(transaction, 0, sizeof(*transaction)); | 37 | memset(transaction, 0, sizeof(*transaction)); |
40 | kmem_cache_free(btrfs_transaction_cachep, transaction); | 38 | kmem_cache_free(btrfs_transaction_cachep, transaction); |
41 | } | 39 | } |
@@ -60,14 +58,14 @@ static noinline int join_transaction(struct btrfs_root *root) | |||
60 | if (!cur_trans) | 58 | if (!cur_trans) |
61 | return -ENOMEM; | 59 | return -ENOMEM; |
62 | root->fs_info->generation++; | 60 | root->fs_info->generation++; |
63 | cur_trans->num_writers = 1; | 61 | atomic_set(&cur_trans->num_writers, 1); |
64 | cur_trans->num_joined = 0; | 62 | cur_trans->num_joined = 0; |
65 | cur_trans->transid = root->fs_info->generation; | 63 | cur_trans->transid = root->fs_info->generation; |
66 | init_waitqueue_head(&cur_trans->writer_wait); | 64 | init_waitqueue_head(&cur_trans->writer_wait); |
67 | init_waitqueue_head(&cur_trans->commit_wait); | 65 | init_waitqueue_head(&cur_trans->commit_wait); |
68 | cur_trans->in_commit = 0; | 66 | cur_trans->in_commit = 0; |
69 | cur_trans->blocked = 0; | 67 | cur_trans->blocked = 0; |
70 | cur_trans->use_count = 1; | 68 | atomic_set(&cur_trans->use_count, 1); |
71 | cur_trans->commit_done = 0; | 69 | cur_trans->commit_done = 0; |
72 | cur_trans->start_time = get_seconds(); | 70 | cur_trans->start_time = get_seconds(); |
73 | 71 | ||
@@ -88,7 +86,7 @@ static noinline int join_transaction(struct btrfs_root *root) | |||
88 | root->fs_info->running_transaction = cur_trans; | 86 | root->fs_info->running_transaction = cur_trans; |
89 | spin_unlock(&root->fs_info->new_trans_lock); | 87 | spin_unlock(&root->fs_info->new_trans_lock); |
90 | } else { | 88 | } else { |
91 | cur_trans->num_writers++; | 89 | atomic_inc(&cur_trans->num_writers); |
92 | cur_trans->num_joined++; | 90 | cur_trans->num_joined++; |
93 | } | 91 | } |
94 | 92 | ||
@@ -145,7 +143,7 @@ static void wait_current_trans(struct btrfs_root *root) | |||
145 | cur_trans = root->fs_info->running_transaction; | 143 | cur_trans = root->fs_info->running_transaction; |
146 | if (cur_trans && cur_trans->blocked) { | 144 | if (cur_trans && cur_trans->blocked) { |
147 | DEFINE_WAIT(wait); | 145 | DEFINE_WAIT(wait); |
148 | cur_trans->use_count++; | 146 | atomic_inc(&cur_trans->use_count); |
149 | while (1) { | 147 | while (1) { |
150 | prepare_to_wait(&root->fs_info->transaction_wait, &wait, | 148 | prepare_to_wait(&root->fs_info->transaction_wait, &wait, |
151 | TASK_UNINTERRUPTIBLE); | 149 | TASK_UNINTERRUPTIBLE); |
@@ -205,7 +203,7 @@ again: | |||
205 | } | 203 | } |
206 | 204 | ||
207 | cur_trans = root->fs_info->running_transaction; | 205 | cur_trans = root->fs_info->running_transaction; |
208 | cur_trans->use_count++; | 206 | atomic_inc(&cur_trans->use_count); |
209 | if (type != TRANS_JOIN_NOLOCK) | 207 | if (type != TRANS_JOIN_NOLOCK) |
210 | mutex_unlock(&root->fs_info->trans_mutex); | 208 | mutex_unlock(&root->fs_info->trans_mutex); |
211 | 209 | ||
@@ -336,7 +334,7 @@ int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid) | |||
336 | goto out_unlock; /* nothing committing|committed */ | 334 | goto out_unlock; /* nothing committing|committed */ |
337 | } | 335 | } |
338 | 336 | ||
339 | cur_trans->use_count++; | 337 | atomic_inc(&cur_trans->use_count); |
340 | mutex_unlock(&root->fs_info->trans_mutex); | 338 | mutex_unlock(&root->fs_info->trans_mutex); |
341 | 339 | ||
342 | wait_for_commit(root, cur_trans); | 340 | wait_for_commit(root, cur_trans); |
@@ -466,18 +464,14 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, | |||
466 | wake_up_process(info->transaction_kthread); | 464 | wake_up_process(info->transaction_kthread); |
467 | } | 465 | } |
468 | 466 | ||
469 | if (lock) | ||
470 | mutex_lock(&info->trans_mutex); | ||
471 | WARN_ON(cur_trans != info->running_transaction); | 467 | WARN_ON(cur_trans != info->running_transaction); |
472 | WARN_ON(cur_trans->num_writers < 1); | 468 | WARN_ON(atomic_read(&cur_trans->num_writers) < 1); |
473 | cur_trans->num_writers--; | 469 | atomic_dec(&cur_trans->num_writers); |
474 | 470 | ||
475 | smp_mb(); | 471 | smp_mb(); |
476 | if (waitqueue_active(&cur_trans->writer_wait)) | 472 | if (waitqueue_active(&cur_trans->writer_wait)) |
477 | wake_up(&cur_trans->writer_wait); | 473 | wake_up(&cur_trans->writer_wait); |
478 | put_transaction(cur_trans); | 474 | put_transaction(cur_trans); |
479 | if (lock) | ||
480 | mutex_unlock(&info->trans_mutex); | ||
481 | 475 | ||
482 | if (current->journal_info == trans) | 476 | if (current->journal_info == trans) |
483 | current->journal_info = NULL; | 477 | current->journal_info = NULL; |
@@ -1187,7 +1181,7 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans, | |||
1187 | /* take transaction reference */ | 1181 | /* take transaction reference */ |
1188 | mutex_lock(&root->fs_info->trans_mutex); | 1182 | mutex_lock(&root->fs_info->trans_mutex); |
1189 | cur_trans = trans->transaction; | 1183 | cur_trans = trans->transaction; |
1190 | cur_trans->use_count++; | 1184 | atomic_inc(&cur_trans->use_count); |
1191 | mutex_unlock(&root->fs_info->trans_mutex); | 1185 | mutex_unlock(&root->fs_info->trans_mutex); |
1192 | 1186 | ||
1193 | btrfs_end_transaction(trans, root); | 1187 | btrfs_end_transaction(trans, root); |
@@ -1246,7 +1240,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
1246 | 1240 | ||
1247 | mutex_lock(&root->fs_info->trans_mutex); | 1241 | mutex_lock(&root->fs_info->trans_mutex); |
1248 | if (cur_trans->in_commit) { | 1242 | if (cur_trans->in_commit) { |
1249 | cur_trans->use_count++; | 1243 | atomic_inc(&cur_trans->use_count); |
1250 | mutex_unlock(&root->fs_info->trans_mutex); | 1244 | mutex_unlock(&root->fs_info->trans_mutex); |
1251 | btrfs_end_transaction(trans, root); | 1245 | btrfs_end_transaction(trans, root); |
1252 | 1246 | ||
@@ -1268,7 +1262,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
1268 | prev_trans = list_entry(cur_trans->list.prev, | 1262 | prev_trans = list_entry(cur_trans->list.prev, |
1269 | struct btrfs_transaction, list); | 1263 | struct btrfs_transaction, list); |
1270 | if (!prev_trans->commit_done) { | 1264 | if (!prev_trans->commit_done) { |
1271 | prev_trans->use_count++; | 1265 | atomic_inc(&prev_trans->use_count); |
1272 | mutex_unlock(&root->fs_info->trans_mutex); | 1266 | mutex_unlock(&root->fs_info->trans_mutex); |
1273 | 1267 | ||
1274 | wait_for_commit(root, prev_trans); | 1268 | wait_for_commit(root, prev_trans); |
@@ -1309,14 +1303,14 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
1309 | TASK_UNINTERRUPTIBLE); | 1303 | TASK_UNINTERRUPTIBLE); |
1310 | 1304 | ||
1311 | smp_mb(); | 1305 | smp_mb(); |
1312 | if (cur_trans->num_writers > 1) | 1306 | if (atomic_read(&cur_trans->num_writers) > 1) |
1313 | schedule_timeout(MAX_SCHEDULE_TIMEOUT); | 1307 | schedule_timeout(MAX_SCHEDULE_TIMEOUT); |
1314 | else if (should_grow) | 1308 | else if (should_grow) |
1315 | schedule_timeout(1); | 1309 | schedule_timeout(1); |
1316 | 1310 | ||
1317 | mutex_lock(&root->fs_info->trans_mutex); | 1311 | mutex_lock(&root->fs_info->trans_mutex); |
1318 | finish_wait(&cur_trans->writer_wait, &wait); | 1312 | finish_wait(&cur_trans->writer_wait, &wait); |
1319 | } while (cur_trans->num_writers > 1 || | 1313 | } while (atomic_read(&cur_trans->num_writers) > 1 || |
1320 | (should_grow && cur_trans->num_joined != joined)); | 1314 | (should_grow && cur_trans->num_joined != joined)); |
1321 | 1315 | ||
1322 | ret = create_pending_snapshots(trans, root->fs_info); | 1316 | ret = create_pending_snapshots(trans, root->fs_info); |
@@ -1403,6 +1397,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
1403 | 1397 | ||
1404 | wake_up(&cur_trans->commit_wait); | 1398 | wake_up(&cur_trans->commit_wait); |
1405 | 1399 | ||
1400 | list_del_init(&cur_trans->list); | ||
1406 | put_transaction(cur_trans); | 1401 | put_transaction(cur_trans); |
1407 | put_transaction(cur_trans); | 1402 | put_transaction(cur_trans); |
1408 | 1403 | ||
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h index 229a594cacd5..e441acc6c584 100644 --- a/fs/btrfs/transaction.h +++ b/fs/btrfs/transaction.h | |||
@@ -27,11 +27,11 @@ struct btrfs_transaction { | |||
27 | * total writers in this transaction, it must be zero before the | 27 | * total writers in this transaction, it must be zero before the |
28 | * transaction can end | 28 | * transaction can end |
29 | */ | 29 | */ |
30 | unsigned long num_writers; | 30 | atomic_t num_writers; |
31 | 31 | ||
32 | unsigned long num_joined; | 32 | unsigned long num_joined; |
33 | int in_commit; | 33 | int in_commit; |
34 | int use_count; | 34 | atomic_t use_count; |
35 | int commit_done; | 35 | int commit_done; |
36 | int blocked; | 36 | int blocked; |
37 | struct list_head list; | 37 | struct list_head list; |