diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-06-28 15:57:36 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-06-28 15:57:36 -0400 |
commit | ccd467d60e81b48cdbecae93532b66bcdedca91d (patch) | |
tree | 7c8c74ca8c6c058fc2e3c90c0082e796b7c1e92e /fs/btrfs/transaction.c | |
parent | f2654de42a759127cb1f1e8a626ec94178732e20 (diff) |
Btrfs: crash recovery fixes
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/transaction.c')
-rw-r--r-- | fs/btrfs/transaction.c | 54 |
1 files changed, 34 insertions, 20 deletions
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 3b2face593e9..bec38ae8aa11 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -85,6 +85,8 @@ struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root, | |||
85 | 85 | ||
86 | if (root != root->fs_info->tree_root && root->last_trans < | 86 | if (root != root->fs_info->tree_root && root->last_trans < |
87 | running_trans_id) { | 87 | running_trans_id) { |
88 | WARN_ON(root == root->fs_info->extent_root); | ||
89 | WARN_ON(root->ref_cows != 1); | ||
88 | if (root->root_item.refs != 0) { | 90 | if (root->root_item.refs != 0) { |
89 | radix_tree_tag_set(&root->fs_info->fs_roots_radix, | 91 | radix_tree_tag_set(&root->fs_info->fs_roots_radix, |
90 | (unsigned long)root->root_key.objectid, | 92 | (unsigned long)root->root_key.objectid, |
@@ -113,10 +115,11 @@ int btrfs_end_transaction(struct btrfs_trans_handle *trans, | |||
113 | 115 | ||
114 | mutex_lock(&root->fs_info->trans_mutex); | 116 | mutex_lock(&root->fs_info->trans_mutex); |
115 | cur_trans = root->fs_info->running_transaction; | 117 | cur_trans = root->fs_info->running_transaction; |
118 | WARN_ON(cur_trans != trans->transaction); | ||
116 | WARN_ON(cur_trans->num_writers < 1); | 119 | WARN_ON(cur_trans->num_writers < 1); |
120 | cur_trans->num_writers--; | ||
117 | if (waitqueue_active(&cur_trans->writer_wait)) | 121 | if (waitqueue_active(&cur_trans->writer_wait)) |
118 | wake_up(&cur_trans->writer_wait); | 122 | wake_up(&cur_trans->writer_wait); |
119 | cur_trans->num_writers--; | ||
120 | put_transaction(cur_trans); | 123 | put_transaction(cur_trans); |
121 | mutex_unlock(&root->fs_info->trans_mutex); | 124 | mutex_unlock(&root->fs_info->trans_mutex); |
122 | memset(trans, 0, sizeof(*trans)); | 125 | memset(trans, 0, sizeof(*trans)); |
@@ -194,6 +197,7 @@ static int wait_for_commit(struct btrfs_root *root, | |||
194 | struct btrfs_transaction *commit) | 197 | struct btrfs_transaction *commit) |
195 | { | 198 | { |
196 | DEFINE_WAIT(wait); | 199 | DEFINE_WAIT(wait); |
200 | mutex_lock(&root->fs_info->trans_mutex); | ||
197 | while(!commit->commit_done) { | 201 | while(!commit->commit_done) { |
198 | prepare_to_wait(&commit->commit_wait, &wait, | 202 | prepare_to_wait(&commit->commit_wait, &wait, |
199 | TASK_UNINTERRUPTIBLE); | 203 | TASK_UNINTERRUPTIBLE); |
@@ -203,6 +207,7 @@ static int wait_for_commit(struct btrfs_root *root, | |||
203 | schedule(); | 207 | schedule(); |
204 | mutex_lock(&root->fs_info->trans_mutex); | 208 | mutex_lock(&root->fs_info->trans_mutex); |
205 | } | 209 | } |
210 | mutex_unlock(&root->fs_info->trans_mutex); | ||
206 | finish_wait(&commit->commit_wait, &wait); | 211 | finish_wait(&commit->commit_wait, &wait); |
207 | return 0; | 212 | return 0; |
208 | } | 213 | } |
@@ -279,7 +284,6 @@ static int add_dirty_roots(struct btrfs_trans_handle *trans, | |||
279 | &root->root_item); | 284 | &root->root_item); |
280 | if (err) | 285 | if (err) |
281 | break; | 286 | break; |
282 | |||
283 | refs = btrfs_root_refs(&tmp_item); | 287 | refs = btrfs_root_refs(&tmp_item); |
284 | btrfs_set_root_refs(&tmp_item, refs - 1); | 288 | btrfs_set_root_refs(&tmp_item, refs - 1); |
285 | err = btrfs_update_root(trans, root->fs_info->tree_root, | 289 | err = btrfs_update_root(trans, root->fs_info->tree_root, |
@@ -333,31 +337,53 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
333 | struct btrfs_transaction *cur_trans; | 337 | struct btrfs_transaction *cur_trans; |
334 | struct btrfs_transaction *prev_trans = NULL; | 338 | struct btrfs_transaction *prev_trans = NULL; |
335 | struct list_head dirty_fs_roots; | 339 | struct list_head dirty_fs_roots; |
340 | struct radix_tree_root pinned_copy; | ||
336 | DEFINE_WAIT(wait); | 341 | DEFINE_WAIT(wait); |
337 | 342 | ||
343 | init_bit_radix(&pinned_copy); | ||
338 | INIT_LIST_HEAD(&dirty_fs_roots); | 344 | INIT_LIST_HEAD(&dirty_fs_roots); |
339 | 345 | ||
340 | mutex_lock(&root->fs_info->trans_mutex); | 346 | mutex_lock(&root->fs_info->trans_mutex); |
341 | if (trans->transaction->in_commit) { | 347 | if (trans->transaction->in_commit) { |
342 | cur_trans = trans->transaction; | 348 | cur_trans = trans->transaction; |
343 | trans->transaction->use_count++; | 349 | trans->transaction->use_count++; |
350 | mutex_unlock(&root->fs_info->trans_mutex); | ||
344 | btrfs_end_transaction(trans, root); | 351 | btrfs_end_transaction(trans, root); |
352 | |||
353 | mutex_unlock(&root->fs_info->fs_mutex); | ||
345 | ret = wait_for_commit(root, cur_trans); | 354 | ret = wait_for_commit(root, cur_trans); |
346 | BUG_ON(ret); | 355 | BUG_ON(ret); |
347 | put_transaction(cur_trans); | 356 | put_transaction(cur_trans); |
348 | mutex_unlock(&root->fs_info->trans_mutex); | 357 | mutex_lock(&root->fs_info->fs_mutex); |
349 | return 0; | 358 | return 0; |
350 | } | 359 | } |
351 | cur_trans = trans->transaction; | ||
352 | trans->transaction->in_commit = 1; | 360 | trans->transaction->in_commit = 1; |
361 | cur_trans = trans->transaction; | ||
362 | if (cur_trans->list.prev != &root->fs_info->trans_list) { | ||
363 | prev_trans = list_entry(cur_trans->list.prev, | ||
364 | struct btrfs_transaction, list); | ||
365 | if (!prev_trans->commit_done) { | ||
366 | prev_trans->use_count++; | ||
367 | mutex_unlock(&root->fs_info->fs_mutex); | ||
368 | mutex_unlock(&root->fs_info->trans_mutex); | ||
369 | |||
370 | wait_for_commit(root, prev_trans); | ||
371 | put_transaction(prev_trans); | ||
372 | |||
373 | mutex_lock(&root->fs_info->fs_mutex); | ||
374 | mutex_lock(&root->fs_info->trans_mutex); | ||
375 | } | ||
376 | } | ||
353 | while (trans->transaction->num_writers > 1) { | 377 | while (trans->transaction->num_writers > 1) { |
354 | WARN_ON(cur_trans != trans->transaction); | 378 | WARN_ON(cur_trans != trans->transaction); |
355 | prepare_to_wait(&trans->transaction->writer_wait, &wait, | 379 | prepare_to_wait(&trans->transaction->writer_wait, &wait, |
356 | TASK_UNINTERRUPTIBLE); | 380 | TASK_UNINTERRUPTIBLE); |
357 | if (trans->transaction->num_writers <= 1) | 381 | if (trans->transaction->num_writers <= 1) |
358 | break; | 382 | break; |
383 | mutex_unlock(&root->fs_info->fs_mutex); | ||
359 | mutex_unlock(&root->fs_info->trans_mutex); | 384 | mutex_unlock(&root->fs_info->trans_mutex); |
360 | schedule(); | 385 | schedule(); |
386 | mutex_lock(&root->fs_info->fs_mutex); | ||
361 | mutex_lock(&root->fs_info->trans_mutex); | 387 | mutex_lock(&root->fs_info->trans_mutex); |
362 | finish_wait(&trans->transaction->writer_wait, &wait); | 388 | finish_wait(&trans->transaction->writer_wait, &wait); |
363 | } | 389 | } |
@@ -372,34 +398,22 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
372 | 398 | ||
373 | cur_trans = root->fs_info->running_transaction; | 399 | cur_trans = root->fs_info->running_transaction; |
374 | root->fs_info->running_transaction = NULL; | 400 | root->fs_info->running_transaction = NULL; |
375 | if (cur_trans->list.prev != &root->fs_info->trans_list) { | ||
376 | prev_trans = list_entry(cur_trans->list.prev, | ||
377 | struct btrfs_transaction, list); | ||
378 | if (prev_trans->commit_done) | ||
379 | prev_trans = NULL; | ||
380 | else | ||
381 | prev_trans->use_count++; | ||
382 | } | ||
383 | btrfs_set_super_generation(&root->fs_info->super_copy, | 401 | btrfs_set_super_generation(&root->fs_info->super_copy, |
384 | cur_trans->transid); | 402 | cur_trans->transid); |
385 | btrfs_set_super_root(&root->fs_info->super_copy, | 403 | btrfs_set_super_root(&root->fs_info->super_copy, |
386 | bh_blocknr(root->fs_info->tree_root->node)); | 404 | bh_blocknr(root->fs_info->tree_root->node)); |
387 | memcpy(root->fs_info->disk_super, &root->fs_info->super_copy, | 405 | memcpy(root->fs_info->disk_super, &root->fs_info->super_copy, |
388 | sizeof(root->fs_info->super_copy)); | 406 | sizeof(root->fs_info->super_copy)); |
407 | |||
408 | btrfs_copy_pinned(root, &pinned_copy); | ||
409 | |||
389 | mutex_unlock(&root->fs_info->trans_mutex); | 410 | mutex_unlock(&root->fs_info->trans_mutex); |
390 | mutex_unlock(&root->fs_info->fs_mutex); | 411 | mutex_unlock(&root->fs_info->fs_mutex); |
391 | ret = btrfs_write_and_wait_transaction(trans, root); | 412 | ret = btrfs_write_and_wait_transaction(trans, root); |
392 | if (prev_trans) { | ||
393 | mutex_lock(&root->fs_info->trans_mutex); | ||
394 | wait_for_commit(root, prev_trans); | ||
395 | put_transaction(prev_trans); | ||
396 | mutex_unlock(&root->fs_info->trans_mutex); | ||
397 | } | ||
398 | BUG_ON(ret); | 413 | BUG_ON(ret); |
399 | write_ctree_super(trans, root); | 414 | write_ctree_super(trans, root); |
400 | |||
401 | mutex_lock(&root->fs_info->fs_mutex); | 415 | mutex_lock(&root->fs_info->fs_mutex); |
402 | btrfs_finish_extent_commit(trans, root); | 416 | btrfs_finish_extent_commit(trans, root, &pinned_copy); |
403 | mutex_lock(&root->fs_info->trans_mutex); | 417 | mutex_lock(&root->fs_info->trans_mutex); |
404 | cur_trans->commit_done = 1; | 418 | cur_trans->commit_done = 1; |
405 | wake_up(&cur_trans->commit_wait); | 419 | wake_up(&cur_trans->commit_wait); |