diff options
-rw-r--r-- | fs/btrfs/disk-io.c | 5 | ||||
-rw-r--r-- | fs/btrfs/super.c | 18 | ||||
-rw-r--r-- | fs/btrfs/transaction.c | 45 | ||||
-rw-r--r-- | fs/btrfs/transaction.h | 4 |
4 files changed, 49 insertions, 23 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 2c18a4eb4d5a..dcaf55695e6f 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -1657,9 +1657,10 @@ static int transaction_kthread(void *arg) | |||
1657 | spin_unlock(&root->fs_info->trans_lock); | 1657 | spin_unlock(&root->fs_info->trans_lock); |
1658 | 1658 | ||
1659 | /* If the file system is aborted, this will always fail. */ | 1659 | /* If the file system is aborted, this will always fail. */ |
1660 | trans = btrfs_join_transaction(root); | 1660 | trans = btrfs_attach_transaction(root); |
1661 | if (IS_ERR(trans)) { | 1661 | if (IS_ERR(trans)) { |
1662 | cannot_commit = true; | 1662 | if (PTR_ERR(trans) != -ENOENT) |
1663 | cannot_commit = true; | ||
1663 | goto sleep; | 1664 | goto sleep; |
1664 | } | 1665 | } |
1665 | if (transid == trans->transid) { | 1666 | if (transid == trans->transid) { |
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index fb260bbf59c6..f8b803f30ed8 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c | |||
@@ -854,10 +854,10 @@ int btrfs_sync_fs(struct super_block *sb, int wait) | |||
854 | 854 | ||
855 | btrfs_wait_ordered_extents(root, 0); | 855 | btrfs_wait_ordered_extents(root, 0); |
856 | 856 | ||
857 | trans = btrfs_join_transaction_freeze(root); | 857 | trans = btrfs_attach_transaction(root); |
858 | if (IS_ERR(trans)) { | 858 | if (IS_ERR(trans)) { |
859 | /* Frozen, don't bother */ | 859 | /* no transaction, don't bother */ |
860 | if (PTR_ERR(trans) == -EPERM) | 860 | if (PTR_ERR(trans) == -ENOENT) |
861 | return 0; | 861 | return 0; |
862 | return PTR_ERR(trans); | 862 | return PTR_ERR(trans); |
863 | } | 863 | } |
@@ -1511,7 +1511,17 @@ static long btrfs_control_ioctl(struct file *file, unsigned int cmd, | |||
1511 | 1511 | ||
1512 | static int btrfs_freeze(struct super_block *sb) | 1512 | static int btrfs_freeze(struct super_block *sb) |
1513 | { | 1513 | { |
1514 | return 0; | 1514 | struct btrfs_trans_handle *trans; |
1515 | struct btrfs_root *root = btrfs_sb(sb)->tree_root; | ||
1516 | |||
1517 | trans = btrfs_attach_transaction(root); | ||
1518 | if (IS_ERR(trans)) { | ||
1519 | /* no transaction, don't bother */ | ||
1520 | if (PTR_ERR(trans) == -ENOENT) | ||
1521 | return 0; | ||
1522 | return PTR_ERR(trans); | ||
1523 | } | ||
1524 | return btrfs_commit_transaction(trans, root); | ||
1515 | } | 1525 | } |
1516 | 1526 | ||
1517 | static int btrfs_unfreeze(struct super_block *sb) | 1527 | static int btrfs_unfreeze(struct super_block *sb) |
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index d0a2b7e49381..69139a356f71 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -53,7 +53,7 @@ static noinline void switch_commit_root(struct btrfs_root *root) | |||
53 | /* | 53 | /* |
54 | * either allocate a new transaction or hop into the existing one | 54 | * either allocate a new transaction or hop into the existing one |
55 | */ | 55 | */ |
56 | static noinline int join_transaction(struct btrfs_root *root, int nofail) | 56 | static noinline int join_transaction(struct btrfs_root *root, int type) |
57 | { | 57 | { |
58 | struct btrfs_transaction *cur_trans; | 58 | struct btrfs_transaction *cur_trans; |
59 | struct btrfs_fs_info *fs_info = root->fs_info; | 59 | struct btrfs_fs_info *fs_info = root->fs_info; |
@@ -67,7 +67,13 @@ loop: | |||
67 | } | 67 | } |
68 | 68 | ||
69 | if (fs_info->trans_no_join) { | 69 | if (fs_info->trans_no_join) { |
70 | if (!nofail) { | 70 | /* |
71 | * If we are JOIN_NOLOCK we're already committing a current | ||
72 | * transaction, we just need a handle to deal with something | ||
73 | * when committing the transaction, such as inode cache and | ||
74 | * space cache. It is a special case. | ||
75 | */ | ||
76 | if (type != TRANS_JOIN_NOLOCK) { | ||
71 | spin_unlock(&fs_info->trans_lock); | 77 | spin_unlock(&fs_info->trans_lock); |
72 | return -EBUSY; | 78 | return -EBUSY; |
73 | } | 79 | } |
@@ -87,6 +93,13 @@ loop: | |||
87 | } | 93 | } |
88 | spin_unlock(&fs_info->trans_lock); | 94 | spin_unlock(&fs_info->trans_lock); |
89 | 95 | ||
96 | /* | ||
97 | * If we are ATTACH, we just want to catch the current transaction, | ||
98 | * and commit it. If there is no transaction, just return ENOENT. | ||
99 | */ | ||
100 | if (type == TRANS_ATTACH) | ||
101 | return -ENOENT; | ||
102 | |||
90 | cur_trans = kmem_cache_alloc(btrfs_transaction_cachep, GFP_NOFS); | 103 | cur_trans = kmem_cache_alloc(btrfs_transaction_cachep, GFP_NOFS); |
91 | if (!cur_trans) | 104 | if (!cur_trans) |
92 | return -ENOMEM; | 105 | return -ENOMEM; |
@@ -340,27 +353,28 @@ again: | |||
340 | * because we're already holding a ref. We need this because we could | 353 | * because we're already holding a ref. We need this because we could |
341 | * have raced in and did an fsync() on a file which can kick a commit | 354 | * have raced in and did an fsync() on a file which can kick a commit |
342 | * and then we deadlock with somebody doing a freeze. | 355 | * and then we deadlock with somebody doing a freeze. |
356 | * | ||
357 | * If we are ATTACH, it means we just want to catch the current | ||
358 | * transaction and commit it, so we needn't do sb_start_intwrite(). | ||
343 | */ | 359 | */ |
344 | if (type != TRANS_JOIN_NOLOCK && | 360 | if (type < TRANS_JOIN_NOLOCK) |
345 | !__sb_start_write(root->fs_info->sb, SB_FREEZE_FS, false)) { | ||
346 | if (type == TRANS_JOIN_FREEZE) { | ||
347 | kmem_cache_free(btrfs_trans_handle_cachep, h); | ||
348 | return ERR_PTR(-EPERM); | ||
349 | } | ||
350 | sb_start_intwrite(root->fs_info->sb); | 361 | sb_start_intwrite(root->fs_info->sb); |
351 | } | ||
352 | 362 | ||
353 | if (may_wait_transaction(root, type)) | 363 | if (may_wait_transaction(root, type)) |
354 | wait_current_trans(root); | 364 | wait_current_trans(root); |
355 | 365 | ||
356 | do { | 366 | do { |
357 | ret = join_transaction(root, type == TRANS_JOIN_NOLOCK); | 367 | ret = join_transaction(root, type); |
358 | if (ret == -EBUSY) | 368 | if (ret == -EBUSY) |
359 | wait_current_trans(root); | 369 | wait_current_trans(root); |
360 | } while (ret == -EBUSY); | 370 | } while (ret == -EBUSY); |
361 | 371 | ||
362 | if (ret < 0) { | 372 | if (ret < 0) { |
363 | sb_end_intwrite(root->fs_info->sb); | 373 | /* We must get the transaction if we are JOIN_NOLOCK. */ |
374 | BUG_ON(type == TRANS_JOIN_NOLOCK); | ||
375 | |||
376 | if (type < TRANS_JOIN_NOLOCK) | ||
377 | sb_end_intwrite(root->fs_info->sb); | ||
364 | kmem_cache_free(btrfs_trans_handle_cachep, h); | 378 | kmem_cache_free(btrfs_trans_handle_cachep, h); |
365 | return ERR_PTR(ret); | 379 | return ERR_PTR(ret); |
366 | } | 380 | } |
@@ -432,9 +446,9 @@ struct btrfs_trans_handle *btrfs_start_ioctl_transaction(struct btrfs_root *root | |||
432 | return start_transaction(root, 0, TRANS_USERSPACE, 0); | 446 | return start_transaction(root, 0, TRANS_USERSPACE, 0); |
433 | } | 447 | } |
434 | 448 | ||
435 | struct btrfs_trans_handle *btrfs_join_transaction_freeze(struct btrfs_root *root) | 449 | struct btrfs_trans_handle *btrfs_attach_transaction(struct btrfs_root *root) |
436 | { | 450 | { |
437 | return start_transaction(root, 0, TRANS_JOIN_FREEZE, 0); | 451 | return start_transaction(root, 0, TRANS_ATTACH, 0); |
438 | } | 452 | } |
439 | 453 | ||
440 | /* wait for a transaction commit to be fully complete */ | 454 | /* wait for a transaction commit to be fully complete */ |
@@ -605,7 +619,7 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, | |||
605 | } | 619 | } |
606 | } | 620 | } |
607 | 621 | ||
608 | if (lock) | 622 | if (trans->type < TRANS_JOIN_NOLOCK) |
609 | sb_end_intwrite(root->fs_info->sb); | 623 | sb_end_intwrite(root->fs_info->sb); |
610 | 624 | ||
611 | WARN_ON(cur_trans != info->running_transaction); | 625 | WARN_ON(cur_trans != info->running_transaction); |
@@ -1678,7 +1692,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
1678 | put_transaction(cur_trans); | 1692 | put_transaction(cur_trans); |
1679 | put_transaction(cur_trans); | 1693 | put_transaction(cur_trans); |
1680 | 1694 | ||
1681 | sb_end_intwrite(root->fs_info->sb); | 1695 | if (trans->type < TRANS_JOIN_NOLOCK) |
1696 | sb_end_intwrite(root->fs_info->sb); | ||
1682 | 1697 | ||
1683 | trace_btrfs_transaction_commit(root); | 1698 | trace_btrfs_transaction_commit(root); |
1684 | 1699 | ||
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h index 0630bd19396a..80961947a6b2 100644 --- a/fs/btrfs/transaction.h +++ b/fs/btrfs/transaction.h | |||
@@ -52,7 +52,7 @@ enum btrfs_trans_type { | |||
52 | TRANS_JOIN, | 52 | TRANS_JOIN, |
53 | TRANS_USERSPACE, | 53 | TRANS_USERSPACE, |
54 | TRANS_JOIN_NOLOCK, | 54 | TRANS_JOIN_NOLOCK, |
55 | TRANS_JOIN_FREEZE, | 55 | TRANS_ATTACH, |
56 | }; | 56 | }; |
57 | 57 | ||
58 | struct btrfs_trans_handle { | 58 | struct btrfs_trans_handle { |
@@ -109,7 +109,7 @@ struct btrfs_trans_handle *btrfs_start_transaction_noflush( | |||
109 | struct btrfs_root *root, int num_items); | 109 | struct btrfs_root *root, int num_items); |
110 | struct btrfs_trans_handle *btrfs_join_transaction(struct btrfs_root *root); | 110 | struct btrfs_trans_handle *btrfs_join_transaction(struct btrfs_root *root); |
111 | struct btrfs_trans_handle *btrfs_join_transaction_nolock(struct btrfs_root *root); | 111 | struct btrfs_trans_handle *btrfs_join_transaction_nolock(struct btrfs_root *root); |
112 | struct btrfs_trans_handle *btrfs_join_transaction_freeze(struct btrfs_root *root); | 112 | struct btrfs_trans_handle *btrfs_attach_transaction(struct btrfs_root *root); |
113 | struct btrfs_trans_handle *btrfs_start_ioctl_transaction(struct btrfs_root *root); | 113 | struct btrfs_trans_handle *btrfs_start_ioctl_transaction(struct btrfs_root *root); |
114 | int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid); | 114 | int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid); |
115 | int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans, | 115 | int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans, |