diff options
-rw-r--r-- | fs/btrfs/disk-io.c | 17 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 8 | ||||
-rw-r--r-- | fs/btrfs/relocation.c | 3 | ||||
-rw-r--r-- | fs/btrfs/transaction.c | 56 | ||||
-rw-r--r-- | fs/btrfs/transaction.h | 2 |
5 files changed, 57 insertions, 29 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 898263f56d96..b8ed1d4fe509 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -1658,15 +1658,20 @@ static int cleaner_kthread(void *arg) | |||
1658 | struct btrfs_root *root = arg; | 1658 | struct btrfs_root *root = arg; |
1659 | 1659 | ||
1660 | do { | 1660 | do { |
1661 | int again = 0; | ||
1662 | |||
1661 | if (!(root->fs_info->sb->s_flags & MS_RDONLY) && | 1663 | if (!(root->fs_info->sb->s_flags & MS_RDONLY) && |
1662 | mutex_trylock(&root->fs_info->cleaner_mutex)) { | 1664 | down_read_trylock(&root->fs_info->sb->s_umount)) { |
1663 | btrfs_run_delayed_iputs(root); | 1665 | if (mutex_trylock(&root->fs_info->cleaner_mutex)) { |
1664 | btrfs_clean_old_snapshots(root); | 1666 | btrfs_run_delayed_iputs(root); |
1665 | mutex_unlock(&root->fs_info->cleaner_mutex); | 1667 | again = btrfs_clean_one_deleted_snapshot(root); |
1668 | mutex_unlock(&root->fs_info->cleaner_mutex); | ||
1669 | } | ||
1666 | btrfs_run_defrag_inodes(root->fs_info); | 1670 | btrfs_run_defrag_inodes(root->fs_info); |
1671 | up_read(&root->fs_info->sb->s_umount); | ||
1667 | } | 1672 | } |
1668 | 1673 | ||
1669 | if (!try_to_freeze()) { | 1674 | if (!try_to_freeze() && !again) { |
1670 | set_current_state(TASK_INTERRUPTIBLE); | 1675 | set_current_state(TASK_INTERRUPTIBLE); |
1671 | if (!kthread_should_stop()) | 1676 | if (!kthread_should_stop()) |
1672 | schedule(); | 1677 | schedule(); |
@@ -3358,8 +3363,8 @@ int btrfs_commit_super(struct btrfs_root *root) | |||
3358 | 3363 | ||
3359 | mutex_lock(&root->fs_info->cleaner_mutex); | 3364 | mutex_lock(&root->fs_info->cleaner_mutex); |
3360 | btrfs_run_delayed_iputs(root); | 3365 | btrfs_run_delayed_iputs(root); |
3361 | btrfs_clean_old_snapshots(root); | ||
3362 | mutex_unlock(&root->fs_info->cleaner_mutex); | 3366 | mutex_unlock(&root->fs_info->cleaner_mutex); |
3367 | wake_up_process(root->fs_info->cleaner_kthread); | ||
3363 | 3368 | ||
3364 | /* wait until ongoing cleanup work done */ | 3369 | /* wait until ongoing cleanup work done */ |
3365 | down_write(&root->fs_info->cleanup_work_sem); | 3370 | down_write(&root->fs_info->cleanup_work_sem); |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 7505856df9f3..be09157ff91b 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -7286,6 +7286,8 @@ static noinline int walk_up_tree(struct btrfs_trans_handle *trans, | |||
7286 | * reference count by one. if update_ref is true, this function | 7286 | * reference count by one. if update_ref is true, this function |
7287 | * also make sure backrefs for the shared block and all lower level | 7287 | * also make sure backrefs for the shared block and all lower level |
7288 | * blocks are properly updated. | 7288 | * blocks are properly updated. |
7289 | * | ||
7290 | * If called with for_reloc == 0, may exit early with -EAGAIN | ||
7289 | */ | 7291 | */ |
7290 | int btrfs_drop_snapshot(struct btrfs_root *root, | 7292 | int btrfs_drop_snapshot(struct btrfs_root *root, |
7291 | struct btrfs_block_rsv *block_rsv, int update_ref, | 7293 | struct btrfs_block_rsv *block_rsv, int update_ref, |
@@ -7386,6 +7388,12 @@ int btrfs_drop_snapshot(struct btrfs_root *root, | |||
7386 | wc->reada_count = BTRFS_NODEPTRS_PER_BLOCK(root); | 7388 | wc->reada_count = BTRFS_NODEPTRS_PER_BLOCK(root); |
7387 | 7389 | ||
7388 | while (1) { | 7390 | while (1) { |
7391 | if (!for_reloc && btrfs_fs_closing(root->fs_info)) { | ||
7392 | pr_debug("btrfs: drop snapshot early exit\n"); | ||
7393 | err = -EAGAIN; | ||
7394 | goto out_end_trans; | ||
7395 | } | ||
7396 | |||
7389 | ret = walk_down_tree(trans, root, path, wc); | 7397 | ret = walk_down_tree(trans, root, path, wc); |
7390 | if (ret < 0) { | 7398 | if (ret < 0) { |
7391 | err = ret; | 7399 | err = ret; |
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index 86f192ffc212..4ef5f7455fb3 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c | |||
@@ -4148,10 +4148,7 @@ int btrfs_relocate_block_group(struct btrfs_root *extent_root, u64 group_start) | |||
4148 | 4148 | ||
4149 | while (1) { | 4149 | while (1) { |
4150 | mutex_lock(&fs_info->cleaner_mutex); | 4150 | mutex_lock(&fs_info->cleaner_mutex); |
4151 | |||
4152 | btrfs_clean_old_snapshots(fs_info->tree_root); | ||
4153 | ret = relocate_block_group(rc); | 4151 | ret = relocate_block_group(rc); |
4154 | |||
4155 | mutex_unlock(&fs_info->cleaner_mutex); | 4152 | mutex_unlock(&fs_info->cleaner_mutex); |
4156 | if (ret < 0) { | 4153 | if (ret < 0) { |
4157 | err = ret; | 4154 | err = ret; |
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 6c0a72ab6de0..5a5ea99f29ed 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -948,7 +948,7 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans, | |||
948 | int btrfs_add_dead_root(struct btrfs_root *root) | 948 | int btrfs_add_dead_root(struct btrfs_root *root) |
949 | { | 949 | { |
950 | spin_lock(&root->fs_info->trans_lock); | 950 | spin_lock(&root->fs_info->trans_lock); |
951 | list_add(&root->root_list, &root->fs_info->dead_roots); | 951 | list_add_tail(&root->root_list, &root->fs_info->dead_roots); |
952 | spin_unlock(&root->fs_info->trans_lock); | 952 | spin_unlock(&root->fs_info->trans_lock); |
953 | return 0; | 953 | return 0; |
954 | } | 954 | } |
@@ -1873,31 +1873,49 @@ cleanup_transaction: | |||
1873 | } | 1873 | } |
1874 | 1874 | ||
1875 | /* | 1875 | /* |
1876 | * interface function to delete all the snapshots we have scheduled for deletion | 1876 | * return < 0 if error |
1877 | * 0 if there are no more dead_roots at the time of call | ||
1878 | * 1 there are more to be processed, call me again | ||
1879 | * | ||
1880 | * The return value indicates there are certainly more snapshots to delete, but | ||
1881 | * if there comes a new one during processing, it may return 0. We don't mind, | ||
1882 | * because btrfs_commit_super will poke cleaner thread and it will process it a | ||
1883 | * few seconds later. | ||
1877 | */ | 1884 | */ |
1878 | int btrfs_clean_old_snapshots(struct btrfs_root *root) | 1885 | int btrfs_clean_one_deleted_snapshot(struct btrfs_root *root) |
1879 | { | 1886 | { |
1880 | LIST_HEAD(list); | 1887 | int ret; |
1881 | struct btrfs_fs_info *fs_info = root->fs_info; | 1888 | struct btrfs_fs_info *fs_info = root->fs_info; |
1882 | 1889 | ||
1890 | if (fs_info->sb->s_flags & MS_RDONLY) { | ||
1891 | pr_debug("btrfs: cleaner called for RO fs!\n"); | ||
1892 | return 0; | ||
1893 | } | ||
1894 | |||
1883 | spin_lock(&fs_info->trans_lock); | 1895 | spin_lock(&fs_info->trans_lock); |
1884 | list_splice_init(&fs_info->dead_roots, &list); | 1896 | if (list_empty(&fs_info->dead_roots)) { |
1897 | spin_unlock(&fs_info->trans_lock); | ||
1898 | return 0; | ||
1899 | } | ||
1900 | root = list_first_entry(&fs_info->dead_roots, | ||
1901 | struct btrfs_root, root_list); | ||
1902 | list_del(&root->root_list); | ||
1885 | spin_unlock(&fs_info->trans_lock); | 1903 | spin_unlock(&fs_info->trans_lock); |
1886 | 1904 | ||
1887 | while (!list_empty(&list)) { | 1905 | pr_debug("btrfs: cleaner removing %llu\n", |
1888 | int ret; | 1906 | (unsigned long long)root->objectid); |
1889 | |||
1890 | root = list_entry(list.next, struct btrfs_root, root_list); | ||
1891 | list_del(&root->root_list); | ||
1892 | 1907 | ||
1893 | btrfs_kill_all_delayed_nodes(root); | 1908 | btrfs_kill_all_delayed_nodes(root); |
1894 | 1909 | ||
1895 | if (btrfs_header_backref_rev(root->node) < | 1910 | if (btrfs_header_backref_rev(root->node) < |
1896 | BTRFS_MIXED_BACKREF_REV) | 1911 | BTRFS_MIXED_BACKREF_REV) |
1897 | ret = btrfs_drop_snapshot(root, NULL, 0, 0); | 1912 | ret = btrfs_drop_snapshot(root, NULL, 0, 0); |
1898 | else | 1913 | else |
1899 | ret =btrfs_drop_snapshot(root, NULL, 1, 0); | 1914 | ret = btrfs_drop_snapshot(root, NULL, 1, 0); |
1900 | BUG_ON(ret < 0); | 1915 | /* |
1901 | } | 1916 | * If we encounter a transaction abort during snapshot cleaning, we |
1902 | return 0; | 1917 | * don't want to crash here |
1918 | */ | ||
1919 | BUG_ON(ret < 0 && ret != -EAGAIN && ret != -EROFS); | ||
1920 | return 1; | ||
1903 | } | 1921 | } |
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h index 3c8e0d25c8e4..f6edd5e6baa3 100644 --- a/fs/btrfs/transaction.h +++ b/fs/btrfs/transaction.h | |||
@@ -123,7 +123,7 @@ int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans, | |||
123 | 123 | ||
124 | int btrfs_add_dead_root(struct btrfs_root *root); | 124 | int btrfs_add_dead_root(struct btrfs_root *root); |
125 | int btrfs_defrag_root(struct btrfs_root *root); | 125 | int btrfs_defrag_root(struct btrfs_root *root); |
126 | int btrfs_clean_old_snapshots(struct btrfs_root *root); | 126 | int btrfs_clean_one_deleted_snapshot(struct btrfs_root *root); |
127 | int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | 127 | int btrfs_commit_transaction(struct btrfs_trans_handle *trans, |
128 | struct btrfs_root *root); | 128 | struct btrfs_root *root); |
129 | int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans, | 129 | int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans, |