diff options
Diffstat (limited to 'fs/btrfs/transaction.c')
-rw-r--r-- | fs/btrfs/transaction.c | 64 |
1 files changed, 39 insertions, 25 deletions
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 3d73c8d93bbb..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 | } |
@@ -57,16 +55,17 @@ static noinline int join_transaction(struct btrfs_root *root) | |||
57 | if (!cur_trans) { | 55 | if (!cur_trans) { |
58 | cur_trans = kmem_cache_alloc(btrfs_transaction_cachep, | 56 | cur_trans = kmem_cache_alloc(btrfs_transaction_cachep, |
59 | GFP_NOFS); | 57 | GFP_NOFS); |
60 | BUG_ON(!cur_trans); | 58 | if (!cur_trans) |
59 | return -ENOMEM; | ||
61 | root->fs_info->generation++; | 60 | root->fs_info->generation++; |
62 | cur_trans->num_writers = 1; | 61 | atomic_set(&cur_trans->num_writers, 1); |
63 | cur_trans->num_joined = 0; | 62 | cur_trans->num_joined = 0; |
64 | cur_trans->transid = root->fs_info->generation; | 63 | cur_trans->transid = root->fs_info->generation; |
65 | init_waitqueue_head(&cur_trans->writer_wait); | 64 | init_waitqueue_head(&cur_trans->writer_wait); |
66 | init_waitqueue_head(&cur_trans->commit_wait); | 65 | init_waitqueue_head(&cur_trans->commit_wait); |
67 | cur_trans->in_commit = 0; | 66 | cur_trans->in_commit = 0; |
68 | cur_trans->blocked = 0; | 67 | cur_trans->blocked = 0; |
69 | cur_trans->use_count = 1; | 68 | atomic_set(&cur_trans->use_count, 1); |
70 | cur_trans->commit_done = 0; | 69 | cur_trans->commit_done = 0; |
71 | cur_trans->start_time = get_seconds(); | 70 | cur_trans->start_time = get_seconds(); |
72 | 71 | ||
@@ -87,7 +86,7 @@ static noinline int join_transaction(struct btrfs_root *root) | |||
87 | root->fs_info->running_transaction = cur_trans; | 86 | root->fs_info->running_transaction = cur_trans; |
88 | spin_unlock(&root->fs_info->new_trans_lock); | 87 | spin_unlock(&root->fs_info->new_trans_lock); |
89 | } else { | 88 | } else { |
90 | cur_trans->num_writers++; | 89 | atomic_inc(&cur_trans->num_writers); |
91 | cur_trans->num_joined++; | 90 | cur_trans->num_joined++; |
92 | } | 91 | } |
93 | 92 | ||
@@ -144,7 +143,7 @@ static void wait_current_trans(struct btrfs_root *root) | |||
144 | cur_trans = root->fs_info->running_transaction; | 143 | cur_trans = root->fs_info->running_transaction; |
145 | if (cur_trans && cur_trans->blocked) { | 144 | if (cur_trans && cur_trans->blocked) { |
146 | DEFINE_WAIT(wait); | 145 | DEFINE_WAIT(wait); |
147 | cur_trans->use_count++; | 146 | atomic_inc(&cur_trans->use_count); |
148 | while (1) { | 147 | while (1) { |
149 | prepare_to_wait(&root->fs_info->transaction_wait, &wait, | 148 | prepare_to_wait(&root->fs_info->transaction_wait, &wait, |
150 | TASK_UNINTERRUPTIBLE); | 149 | TASK_UNINTERRUPTIBLE); |
@@ -180,6 +179,7 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root, | |||
180 | { | 179 | { |
181 | struct btrfs_trans_handle *h; | 180 | struct btrfs_trans_handle *h; |
182 | struct btrfs_transaction *cur_trans; | 181 | struct btrfs_transaction *cur_trans; |
182 | int retries = 0; | ||
183 | int ret; | 183 | int ret; |
184 | 184 | ||
185 | if (root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) | 185 | if (root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) |
@@ -195,10 +195,15 @@ again: | |||
195 | wait_current_trans(root); | 195 | wait_current_trans(root); |
196 | 196 | ||
197 | ret = join_transaction(root); | 197 | ret = join_transaction(root); |
198 | BUG_ON(ret); | 198 | if (ret < 0) { |
199 | kmem_cache_free(btrfs_trans_handle_cachep, h); | ||
200 | if (type != TRANS_JOIN_NOLOCK) | ||
201 | mutex_unlock(&root->fs_info->trans_mutex); | ||
202 | return ERR_PTR(ret); | ||
203 | } | ||
199 | 204 | ||
200 | cur_trans = root->fs_info->running_transaction; | 205 | cur_trans = root->fs_info->running_transaction; |
201 | cur_trans->use_count++; | 206 | atomic_inc(&cur_trans->use_count); |
202 | if (type != TRANS_JOIN_NOLOCK) | 207 | if (type != TRANS_JOIN_NOLOCK) |
203 | mutex_unlock(&root->fs_info->trans_mutex); | 208 | mutex_unlock(&root->fs_info->trans_mutex); |
204 | 209 | ||
@@ -218,10 +223,18 @@ again: | |||
218 | 223 | ||
219 | if (num_items > 0) { | 224 | if (num_items > 0) { |
220 | ret = btrfs_trans_reserve_metadata(h, root, num_items); | 225 | ret = btrfs_trans_reserve_metadata(h, root, num_items); |
221 | if (ret == -EAGAIN) { | 226 | if (ret == -EAGAIN && !retries) { |
227 | retries++; | ||
222 | btrfs_commit_transaction(h, root); | 228 | btrfs_commit_transaction(h, root); |
223 | 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; | ||
224 | } | 236 | } |
237 | |||
225 | if (ret < 0) { | 238 | if (ret < 0) { |
226 | btrfs_end_transaction(h, root); | 239 | btrfs_end_transaction(h, root); |
227 | return ERR_PTR(ret); | 240 | return ERR_PTR(ret); |
@@ -321,7 +334,7 @@ int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid) | |||
321 | goto out_unlock; /* nothing committing|committed */ | 334 | goto out_unlock; /* nothing committing|committed */ |
322 | } | 335 | } |
323 | 336 | ||
324 | cur_trans->use_count++; | 337 | atomic_inc(&cur_trans->use_count); |
325 | mutex_unlock(&root->fs_info->trans_mutex); | 338 | mutex_unlock(&root->fs_info->trans_mutex); |
326 | 339 | ||
327 | wait_for_commit(root, cur_trans); | 340 | wait_for_commit(root, cur_trans); |
@@ -451,18 +464,14 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, | |||
451 | wake_up_process(info->transaction_kthread); | 464 | wake_up_process(info->transaction_kthread); |
452 | } | 465 | } |
453 | 466 | ||
454 | if (lock) | ||
455 | mutex_lock(&info->trans_mutex); | ||
456 | WARN_ON(cur_trans != info->running_transaction); | 467 | WARN_ON(cur_trans != info->running_transaction); |
457 | WARN_ON(cur_trans->num_writers < 1); | 468 | WARN_ON(atomic_read(&cur_trans->num_writers) < 1); |
458 | cur_trans->num_writers--; | 469 | atomic_dec(&cur_trans->num_writers); |
459 | 470 | ||
460 | smp_mb(); | 471 | smp_mb(); |
461 | if (waitqueue_active(&cur_trans->writer_wait)) | 472 | if (waitqueue_active(&cur_trans->writer_wait)) |
462 | wake_up(&cur_trans->writer_wait); | 473 | wake_up(&cur_trans->writer_wait); |
463 | put_transaction(cur_trans); | 474 | put_transaction(cur_trans); |
464 | if (lock) | ||
465 | mutex_unlock(&info->trans_mutex); | ||
466 | 475 | ||
467 | if (current->journal_info == trans) | 476 | if (current->journal_info == trans) |
468 | current->journal_info = NULL; | 477 | current->journal_info = NULL; |
@@ -970,6 +979,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
970 | record_root_in_trans(trans, root); | 979 | record_root_in_trans(trans, root); |
971 | btrfs_set_root_last_snapshot(&root->root_item, trans->transid); | 980 | btrfs_set_root_last_snapshot(&root->root_item, trans->transid); |
972 | 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); | ||
973 | 983 | ||
974 | root_flags = btrfs_root_flags(new_root_item); | 984 | root_flags = btrfs_root_flags(new_root_item); |
975 | if (pending->readonly) | 985 | if (pending->readonly) |
@@ -1156,7 +1166,8 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans, | |||
1156 | struct btrfs_transaction *cur_trans; | 1166 | struct btrfs_transaction *cur_trans; |
1157 | 1167 | ||
1158 | ac = kmalloc(sizeof(*ac), GFP_NOFS); | 1168 | ac = kmalloc(sizeof(*ac), GFP_NOFS); |
1159 | BUG_ON(!ac); | 1169 | if (!ac) |
1170 | return -ENOMEM; | ||
1160 | 1171 | ||
1161 | INIT_DELAYED_WORK(&ac->work, do_async_commit); | 1172 | INIT_DELAYED_WORK(&ac->work, do_async_commit); |
1162 | ac->root = root; | 1173 | ac->root = root; |
@@ -1170,7 +1181,7 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans, | |||
1170 | /* take transaction reference */ | 1181 | /* take transaction reference */ |
1171 | mutex_lock(&root->fs_info->trans_mutex); | 1182 | mutex_lock(&root->fs_info->trans_mutex); |
1172 | cur_trans = trans->transaction; | 1183 | cur_trans = trans->transaction; |
1173 | cur_trans->use_count++; | 1184 | atomic_inc(&cur_trans->use_count); |
1174 | mutex_unlock(&root->fs_info->trans_mutex); | 1185 | mutex_unlock(&root->fs_info->trans_mutex); |
1175 | 1186 | ||
1176 | btrfs_end_transaction(trans, root); | 1187 | btrfs_end_transaction(trans, root); |
@@ -1229,7 +1240,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
1229 | 1240 | ||
1230 | mutex_lock(&root->fs_info->trans_mutex); | 1241 | mutex_lock(&root->fs_info->trans_mutex); |
1231 | if (cur_trans->in_commit) { | 1242 | if (cur_trans->in_commit) { |
1232 | cur_trans->use_count++; | 1243 | atomic_inc(&cur_trans->use_count); |
1233 | mutex_unlock(&root->fs_info->trans_mutex); | 1244 | mutex_unlock(&root->fs_info->trans_mutex); |
1234 | btrfs_end_transaction(trans, root); | 1245 | btrfs_end_transaction(trans, root); |
1235 | 1246 | ||
@@ -1251,7 +1262,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
1251 | prev_trans = list_entry(cur_trans->list.prev, | 1262 | prev_trans = list_entry(cur_trans->list.prev, |
1252 | struct btrfs_transaction, list); | 1263 | struct btrfs_transaction, list); |
1253 | if (!prev_trans->commit_done) { | 1264 | if (!prev_trans->commit_done) { |
1254 | prev_trans->use_count++; | 1265 | atomic_inc(&prev_trans->use_count); |
1255 | mutex_unlock(&root->fs_info->trans_mutex); | 1266 | mutex_unlock(&root->fs_info->trans_mutex); |
1256 | 1267 | ||
1257 | wait_for_commit(root, prev_trans); | 1268 | wait_for_commit(root, prev_trans); |
@@ -1292,14 +1303,14 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
1292 | TASK_UNINTERRUPTIBLE); | 1303 | TASK_UNINTERRUPTIBLE); |
1293 | 1304 | ||
1294 | smp_mb(); | 1305 | smp_mb(); |
1295 | if (cur_trans->num_writers > 1) | 1306 | if (atomic_read(&cur_trans->num_writers) > 1) |
1296 | schedule_timeout(MAX_SCHEDULE_TIMEOUT); | 1307 | schedule_timeout(MAX_SCHEDULE_TIMEOUT); |
1297 | else if (should_grow) | 1308 | else if (should_grow) |
1298 | schedule_timeout(1); | 1309 | schedule_timeout(1); |
1299 | 1310 | ||
1300 | mutex_lock(&root->fs_info->trans_mutex); | 1311 | mutex_lock(&root->fs_info->trans_mutex); |
1301 | finish_wait(&cur_trans->writer_wait, &wait); | 1312 | finish_wait(&cur_trans->writer_wait, &wait); |
1302 | } while (cur_trans->num_writers > 1 || | 1313 | } while (atomic_read(&cur_trans->num_writers) > 1 || |
1303 | (should_grow && cur_trans->num_joined != joined)); | 1314 | (should_grow && cur_trans->num_joined != joined)); |
1304 | 1315 | ||
1305 | ret = create_pending_snapshots(trans, root->fs_info); | 1316 | ret = create_pending_snapshots(trans, root->fs_info); |
@@ -1386,9 +1397,12 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
1386 | 1397 | ||
1387 | wake_up(&cur_trans->commit_wait); | 1398 | wake_up(&cur_trans->commit_wait); |
1388 | 1399 | ||
1400 | list_del_init(&cur_trans->list); | ||
1389 | put_transaction(cur_trans); | 1401 | put_transaction(cur_trans); |
1390 | put_transaction(cur_trans); | 1402 | put_transaction(cur_trans); |
1391 | 1403 | ||
1404 | trace_btrfs_transaction_commit(root); | ||
1405 | |||
1392 | mutex_unlock(&root->fs_info->trans_mutex); | 1406 | mutex_unlock(&root->fs_info->trans_mutex); |
1393 | 1407 | ||
1394 | if (current->journal_info == trans) | 1408 | if (current->journal_info == trans) |