diff options
Diffstat (limited to 'fs/btrfs/transaction.c')
| -rw-r--r-- | fs/btrfs/transaction.c | 50 |
1 files changed, 28 insertions, 22 deletions
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index ce48eb59d615..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); |
| @@ -181,6 +179,7 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root, | |||
| 181 | { | 179 | { |
| 182 | struct btrfs_trans_handle *h; | 180 | struct btrfs_trans_handle *h; |
| 183 | struct btrfs_transaction *cur_trans; | 181 | struct btrfs_transaction *cur_trans; |
| 182 | int retries = 0; | ||
| 184 | int ret; | 183 | int ret; |
| 185 | 184 | ||
| 186 | if (root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) | 185 | if (root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) |
| @@ -197,13 +196,14 @@ again: | |||
| 197 | 196 | ||
| 198 | ret = join_transaction(root); | 197 | ret = join_transaction(root); |
| 199 | if (ret < 0) { | 198 | if (ret < 0) { |
| 199 | kmem_cache_free(btrfs_trans_handle_cachep, h); | ||
| 200 | if (type != TRANS_JOIN_NOLOCK) | 200 | if (type != TRANS_JOIN_NOLOCK) |
| 201 | mutex_unlock(&root->fs_info->trans_mutex); | 201 | mutex_unlock(&root->fs_info->trans_mutex); |
| 202 | return ERR_PTR(ret); | 202 | return ERR_PTR(ret); |
| 203 | } | 203 | } |
| 204 | 204 | ||
| 205 | cur_trans = root->fs_info->running_transaction; | 205 | cur_trans = root->fs_info->running_transaction; |
| 206 | cur_trans->use_count++; | 206 | atomic_inc(&cur_trans->use_count); |
| 207 | if (type != TRANS_JOIN_NOLOCK) | 207 | if (type != TRANS_JOIN_NOLOCK) |
| 208 | mutex_unlock(&root->fs_info->trans_mutex); | 208 | mutex_unlock(&root->fs_info->trans_mutex); |
| 209 | 209 | ||
| @@ -223,10 +223,18 @@ again: | |||
| 223 | 223 | ||
| 224 | if (num_items > 0) { | 224 | if (num_items > 0) { |
| 225 | ret = btrfs_trans_reserve_metadata(h, root, num_items); | 225 | ret = btrfs_trans_reserve_metadata(h, root, num_items); |
| 226 | if (ret == -EAGAIN) { | 226 | if (ret == -EAGAIN && !retries) { |
| 227 | retries++; | ||
| 227 | btrfs_commit_transaction(h, root); | 228 | btrfs_commit_transaction(h, root); |
| 228 | goto again; | 229 | goto again; |
| 230 | } else if (ret == -EAGAIN) { | ||
| 231 | /* | ||
| 232 | * We have already retried and got EAGAIN, so really we | ||
| 233 | * don't have space, so set ret to -ENOSPC. | ||
| 234 | */ | ||
| 235 | ret = -ENOSPC; | ||
| 229 | } | 236 | } |
| 237 | |||
| 230 | if (ret < 0) { | 238 | if (ret < 0) { |
| 231 | btrfs_end_transaction(h, root); | 239 | btrfs_end_transaction(h, root); |
| 232 | return ERR_PTR(ret); | 240 | return ERR_PTR(ret); |
| @@ -326,7 +334,7 @@ int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid) | |||
| 326 | goto out_unlock; /* nothing committing|committed */ | 334 | goto out_unlock; /* nothing committing|committed */ |
| 327 | } | 335 | } |
| 328 | 336 | ||
| 329 | cur_trans->use_count++; | 337 | atomic_inc(&cur_trans->use_count); |
| 330 | mutex_unlock(&root->fs_info->trans_mutex); | 338 | mutex_unlock(&root->fs_info->trans_mutex); |
| 331 | 339 | ||
| 332 | wait_for_commit(root, cur_trans); | 340 | wait_for_commit(root, cur_trans); |
| @@ -456,18 +464,14 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, | |||
| 456 | wake_up_process(info->transaction_kthread); | 464 | wake_up_process(info->transaction_kthread); |
| 457 | } | 465 | } |
| 458 | 466 | ||
| 459 | if (lock) | ||
| 460 | mutex_lock(&info->trans_mutex); | ||
| 461 | WARN_ON(cur_trans != info->running_transaction); | 467 | WARN_ON(cur_trans != info->running_transaction); |
| 462 | WARN_ON(cur_trans->num_writers < 1); | 468 | WARN_ON(atomic_read(&cur_trans->num_writers) < 1); |
| 463 | cur_trans->num_writers--; | 469 | atomic_dec(&cur_trans->num_writers); |
| 464 | 470 | ||
| 465 | smp_mb(); | 471 | smp_mb(); |
| 466 | if (waitqueue_active(&cur_trans->writer_wait)) | 472 | if (waitqueue_active(&cur_trans->writer_wait)) |
| 467 | wake_up(&cur_trans->writer_wait); | 473 | wake_up(&cur_trans->writer_wait); |
| 468 | put_transaction(cur_trans); | 474 | put_transaction(cur_trans); |
| 469 | if (lock) | ||
| 470 | mutex_unlock(&info->trans_mutex); | ||
| 471 | 475 | ||
| 472 | if (current->journal_info == trans) | 476 | if (current->journal_info == trans) |
| 473 | current->journal_info = NULL; | 477 | current->journal_info = NULL; |
| @@ -975,6 +979,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
| 975 | record_root_in_trans(trans, root); | 979 | record_root_in_trans(trans, root); |
| 976 | btrfs_set_root_last_snapshot(&root->root_item, trans->transid); | 980 | btrfs_set_root_last_snapshot(&root->root_item, trans->transid); |
| 977 | memcpy(new_root_item, &root->root_item, sizeof(*new_root_item)); | 981 | memcpy(new_root_item, &root->root_item, sizeof(*new_root_item)); |
| 982 | btrfs_check_and_init_root_item(new_root_item); | ||
| 978 | 983 | ||
| 979 | root_flags = btrfs_root_flags(new_root_item); | 984 | root_flags = btrfs_root_flags(new_root_item); |
| 980 | if (pending->readonly) | 985 | if (pending->readonly) |
| @@ -1176,7 +1181,7 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans, | |||
| 1176 | /* take transaction reference */ | 1181 | /* take transaction reference */ |
| 1177 | mutex_lock(&root->fs_info->trans_mutex); | 1182 | mutex_lock(&root->fs_info->trans_mutex); |
| 1178 | cur_trans = trans->transaction; | 1183 | cur_trans = trans->transaction; |
| 1179 | cur_trans->use_count++; | 1184 | atomic_inc(&cur_trans->use_count); |
| 1180 | mutex_unlock(&root->fs_info->trans_mutex); | 1185 | mutex_unlock(&root->fs_info->trans_mutex); |
| 1181 | 1186 | ||
| 1182 | btrfs_end_transaction(trans, root); | 1187 | btrfs_end_transaction(trans, root); |
| @@ -1235,7 +1240,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
| 1235 | 1240 | ||
| 1236 | mutex_lock(&root->fs_info->trans_mutex); | 1241 | mutex_lock(&root->fs_info->trans_mutex); |
| 1237 | if (cur_trans->in_commit) { | 1242 | if (cur_trans->in_commit) { |
| 1238 | cur_trans->use_count++; | 1243 | atomic_inc(&cur_trans->use_count); |
| 1239 | mutex_unlock(&root->fs_info->trans_mutex); | 1244 | mutex_unlock(&root->fs_info->trans_mutex); |
| 1240 | btrfs_end_transaction(trans, root); | 1245 | btrfs_end_transaction(trans, root); |
| 1241 | 1246 | ||
| @@ -1257,7 +1262,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
| 1257 | prev_trans = list_entry(cur_trans->list.prev, | 1262 | prev_trans = list_entry(cur_trans->list.prev, |
| 1258 | struct btrfs_transaction, list); | 1263 | struct btrfs_transaction, list); |
| 1259 | if (!prev_trans->commit_done) { | 1264 | if (!prev_trans->commit_done) { |
| 1260 | prev_trans->use_count++; | 1265 | atomic_inc(&prev_trans->use_count); |
| 1261 | mutex_unlock(&root->fs_info->trans_mutex); | 1266 | mutex_unlock(&root->fs_info->trans_mutex); |
| 1262 | 1267 | ||
| 1263 | wait_for_commit(root, prev_trans); | 1268 | wait_for_commit(root, prev_trans); |
| @@ -1298,14 +1303,14 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
| 1298 | TASK_UNINTERRUPTIBLE); | 1303 | TASK_UNINTERRUPTIBLE); |
| 1299 | 1304 | ||
| 1300 | smp_mb(); | 1305 | smp_mb(); |
| 1301 | if (cur_trans->num_writers > 1) | 1306 | if (atomic_read(&cur_trans->num_writers) > 1) |
| 1302 | schedule_timeout(MAX_SCHEDULE_TIMEOUT); | 1307 | schedule_timeout(MAX_SCHEDULE_TIMEOUT); |
| 1303 | else if (should_grow) | 1308 | else if (should_grow) |
| 1304 | schedule_timeout(1); | 1309 | schedule_timeout(1); |
| 1305 | 1310 | ||
| 1306 | mutex_lock(&root->fs_info->trans_mutex); | 1311 | mutex_lock(&root->fs_info->trans_mutex); |
| 1307 | finish_wait(&cur_trans->writer_wait, &wait); | 1312 | finish_wait(&cur_trans->writer_wait, &wait); |
| 1308 | } while (cur_trans->num_writers > 1 || | 1313 | } while (atomic_read(&cur_trans->num_writers) > 1 || |
| 1309 | (should_grow && cur_trans->num_joined != joined)); | 1314 | (should_grow && cur_trans->num_joined != joined)); |
| 1310 | 1315 | ||
| 1311 | ret = create_pending_snapshots(trans, root->fs_info); | 1316 | ret = create_pending_snapshots(trans, root->fs_info); |
| @@ -1392,6 +1397,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
| 1392 | 1397 | ||
| 1393 | wake_up(&cur_trans->commit_wait); | 1398 | wake_up(&cur_trans->commit_wait); |
| 1394 | 1399 | ||
| 1400 | list_del_init(&cur_trans->list); | ||
| 1395 | put_transaction(cur_trans); | 1401 | put_transaction(cur_trans); |
| 1396 | put_transaction(cur_trans); | 1402 | put_transaction(cur_trans); |
| 1397 | 1403 | ||
