diff options
Diffstat (limited to 'fs/btrfs/disk-io.c')
-rw-r--r-- | fs/btrfs/disk-io.c | 116 |
1 files changed, 107 insertions, 9 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 52569b57692d..31ca9f89388d 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -16,6 +16,7 @@ | |||
16 | * Boston, MA 021110-1307, USA. | 16 | * Boston, MA 021110-1307, USA. |
17 | */ | 17 | */ |
18 | 18 | ||
19 | #include <linux/version.h> | ||
19 | #include <linux/fs.h> | 20 | #include <linux/fs.h> |
20 | #include <linux/blkdev.h> | 21 | #include <linux/blkdev.h> |
21 | #include <linux/scatterlist.h> | 22 | #include <linux/scatterlist.h> |
@@ -24,6 +25,12 @@ | |||
24 | #include <linux/writeback.h> | 25 | #include <linux/writeback.h> |
25 | #include <linux/buffer_head.h> // for block_sync_page | 26 | #include <linux/buffer_head.h> // for block_sync_page |
26 | #include <linux/workqueue.h> | 27 | #include <linux/workqueue.h> |
28 | #include <linux/kthread.h> | ||
29 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) | ||
30 | # include <linux/freezer.h> | ||
31 | #else | ||
32 | # include <linux/sched.h> | ||
33 | #endif | ||
27 | #include "crc32c.h" | 34 | #include "crc32c.h" |
28 | #include "ctree.h" | 35 | #include "ctree.h" |
29 | #include "disk-io.h" | 36 | #include "disk-io.h" |
@@ -1100,6 +1107,87 @@ static void end_workqueue_fn(struct btrfs_work *work) | |||
1100 | #endif | 1107 | #endif |
1101 | } | 1108 | } |
1102 | 1109 | ||
1110 | static int cleaner_kthread(void *arg) | ||
1111 | { | ||
1112 | struct btrfs_root *root = arg; | ||
1113 | |||
1114 | do { | ||
1115 | smp_mb(); | ||
1116 | if (root->fs_info->closing) | ||
1117 | break; | ||
1118 | |||
1119 | vfs_check_frozen(root->fs_info->sb, SB_FREEZE_WRITE); | ||
1120 | mutex_lock(&root->fs_info->cleaner_mutex); | ||
1121 | printk("cleaner awake\n"); | ||
1122 | btrfs_clean_old_snapshots(root); | ||
1123 | printk("cleaner done\n"); | ||
1124 | mutex_unlock(&root->fs_info->cleaner_mutex); | ||
1125 | |||
1126 | if (freezing(current)) { | ||
1127 | refrigerator(); | ||
1128 | } else { | ||
1129 | smp_mb(); | ||
1130 | if (root->fs_info->closing) | ||
1131 | break; | ||
1132 | set_current_state(TASK_INTERRUPTIBLE); | ||
1133 | schedule(); | ||
1134 | __set_current_state(TASK_RUNNING); | ||
1135 | } | ||
1136 | } while (!kthread_should_stop()); | ||
1137 | return 0; | ||
1138 | } | ||
1139 | |||
1140 | static int transaction_kthread(void *arg) | ||
1141 | { | ||
1142 | struct btrfs_root *root = arg; | ||
1143 | struct btrfs_trans_handle *trans; | ||
1144 | struct btrfs_transaction *cur; | ||
1145 | unsigned long now; | ||
1146 | unsigned long delay; | ||
1147 | int ret; | ||
1148 | |||
1149 | do { | ||
1150 | smp_mb(); | ||
1151 | if (root->fs_info->closing) | ||
1152 | break; | ||
1153 | |||
1154 | delay = HZ * 30; | ||
1155 | vfs_check_frozen(root->fs_info->sb, SB_FREEZE_WRITE); | ||
1156 | mutex_lock(&root->fs_info->transaction_kthread_mutex); | ||
1157 | |||
1158 | mutex_lock(&root->fs_info->trans_mutex); | ||
1159 | cur = root->fs_info->running_transaction; | ||
1160 | if (!cur) { | ||
1161 | mutex_unlock(&root->fs_info->trans_mutex); | ||
1162 | goto sleep; | ||
1163 | } | ||
1164 | now = get_seconds(); | ||
1165 | if (now < cur->start_time || now - cur->start_time < 30) { | ||
1166 | mutex_unlock(&root->fs_info->trans_mutex); | ||
1167 | delay = HZ * 5; | ||
1168 | goto sleep; | ||
1169 | } | ||
1170 | mutex_unlock(&root->fs_info->trans_mutex); | ||
1171 | btrfs_defrag_dirty_roots(root->fs_info); | ||
1172 | trans = btrfs_start_transaction(root, 1); | ||
1173 | ret = btrfs_commit_transaction(trans, root); | ||
1174 | sleep: | ||
1175 | wake_up_process(root->fs_info->cleaner_kthread); | ||
1176 | mutex_unlock(&root->fs_info->transaction_kthread_mutex); | ||
1177 | |||
1178 | if (freezing(current)) { | ||
1179 | refrigerator(); | ||
1180 | } else { | ||
1181 | if (root->fs_info->closing) | ||
1182 | break; | ||
1183 | set_current_state(TASK_INTERRUPTIBLE); | ||
1184 | schedule_timeout(delay); | ||
1185 | __set_current_state(TASK_RUNNING); | ||
1186 | } | ||
1187 | } while (!kthread_should_stop()); | ||
1188 | return 0; | ||
1189 | } | ||
1190 | |||
1103 | struct btrfs_root *open_ctree(struct super_block *sb, | 1191 | struct btrfs_root *open_ctree(struct super_block *sb, |
1104 | struct btrfs_fs_devices *fs_devices, | 1192 | struct btrfs_fs_devices *fs_devices, |
1105 | char *options) | 1193 | char *options) |
@@ -1189,11 +1277,6 @@ struct btrfs_root *open_ctree(struct super_block *sb, | |||
1189 | fs_info->btree_inode->i_mapping, GFP_NOFS); | 1277 | fs_info->btree_inode->i_mapping, GFP_NOFS); |
1190 | fs_info->do_barriers = 1; | 1278 | fs_info->do_barriers = 1; |
1191 | 1279 | ||
1192 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,18) | ||
1193 | INIT_WORK(&fs_info->trans_work, btrfs_transaction_cleaner, fs_info); | ||
1194 | #else | ||
1195 | INIT_DELAYED_WORK(&fs_info->trans_work, btrfs_transaction_cleaner); | ||
1196 | #endif | ||
1197 | BTRFS_I(fs_info->btree_inode)->root = tree_root; | 1280 | BTRFS_I(fs_info->btree_inode)->root = tree_root; |
1198 | memset(&BTRFS_I(fs_info->btree_inode)->location, 0, | 1281 | memset(&BTRFS_I(fs_info->btree_inode)->location, 0, |
1199 | sizeof(struct btrfs_key)); | 1282 | sizeof(struct btrfs_key)); |
@@ -1204,6 +1287,8 @@ struct btrfs_root *open_ctree(struct super_block *sb, | |||
1204 | mutex_init(&fs_info->drop_mutex); | 1287 | mutex_init(&fs_info->drop_mutex); |
1205 | mutex_init(&fs_info->alloc_mutex); | 1288 | mutex_init(&fs_info->alloc_mutex); |
1206 | mutex_init(&fs_info->chunk_mutex); | 1289 | mutex_init(&fs_info->chunk_mutex); |
1290 | mutex_init(&fs_info->transaction_kthread_mutex); | ||
1291 | mutex_init(&fs_info->cleaner_mutex); | ||
1207 | 1292 | ||
1208 | #if 0 | 1293 | #if 0 |
1209 | ret = add_hasher(fs_info, "crc32c"); | 1294 | ret = add_hasher(fs_info, "crc32c"); |
@@ -1247,7 +1332,6 @@ struct btrfs_root *open_ctree(struct super_block *sb, | |||
1247 | btrfs_start_workers(&fs_info->submit_workers, 1); | 1332 | btrfs_start_workers(&fs_info->submit_workers, 1); |
1248 | btrfs_start_workers(&fs_info->endio_workers, fs_info->thread_pool_size); | 1333 | btrfs_start_workers(&fs_info->endio_workers, fs_info->thread_pool_size); |
1249 | 1334 | ||
1250 | |||
1251 | err = -EINVAL; | 1335 | err = -EINVAL; |
1252 | if (btrfs_super_num_devices(disk_super) > fs_devices->open_devices) { | 1336 | if (btrfs_super_num_devices(disk_super) > fs_devices->open_devices) { |
1253 | printk("Btrfs: wanted %llu devices, but found %llu\n", | 1337 | printk("Btrfs: wanted %llu devices, but found %llu\n", |
@@ -1341,9 +1425,22 @@ struct btrfs_root *open_ctree(struct super_block *sb, | |||
1341 | fs_info->data_alloc_profile = (u64)-1; | 1425 | fs_info->data_alloc_profile = (u64)-1; |
1342 | fs_info->metadata_alloc_profile = (u64)-1; | 1426 | fs_info->metadata_alloc_profile = (u64)-1; |
1343 | fs_info->system_alloc_profile = fs_info->metadata_alloc_profile; | 1427 | fs_info->system_alloc_profile = fs_info->metadata_alloc_profile; |
1428 | fs_info->cleaner_kthread = kthread_run(cleaner_kthread, tree_root, | ||
1429 | "btrfs-cleaner"); | ||
1430 | if (!fs_info->cleaner_kthread) | ||
1431 | goto fail_extent_root; | ||
1432 | |||
1433 | fs_info->transaction_kthread = kthread_run(transaction_kthread, | ||
1434 | tree_root, | ||
1435 | "btrfs-transaction"); | ||
1436 | if (!fs_info->transaction_kthread) | ||
1437 | goto fail_trans_kthread; | ||
1438 | |||
1344 | 1439 | ||
1345 | return tree_root; | 1440 | return tree_root; |
1346 | 1441 | ||
1442 | fail_trans_kthread: | ||
1443 | kthread_stop(fs_info->cleaner_kthread); | ||
1347 | fail_extent_root: | 1444 | fail_extent_root: |
1348 | free_extent_buffer(extent_root->node); | 1445 | free_extent_buffer(extent_root->node); |
1349 | fail_tree_root: | 1446 | fail_tree_root: |
@@ -1562,8 +1659,11 @@ int close_ctree(struct btrfs_root *root) | |||
1562 | fs_info->closing = 1; | 1659 | fs_info->closing = 1; |
1563 | smp_mb(); | 1660 | smp_mb(); |
1564 | 1661 | ||
1565 | btrfs_transaction_flush_work(root); | 1662 | kthread_stop(root->fs_info->transaction_kthread); |
1663 | kthread_stop(root->fs_info->cleaner_kthread); | ||
1664 | |||
1566 | btrfs_defrag_dirty_roots(root->fs_info); | 1665 | btrfs_defrag_dirty_roots(root->fs_info); |
1666 | btrfs_clean_old_snapshots(root); | ||
1567 | trans = btrfs_start_transaction(root, 1); | 1667 | trans = btrfs_start_transaction(root, 1); |
1568 | ret = btrfs_commit_transaction(trans, root); | 1668 | ret = btrfs_commit_transaction(trans, root); |
1569 | /* run commit again to drop the original snapshot */ | 1669 | /* run commit again to drop the original snapshot */ |
@@ -1574,8 +1674,6 @@ int close_ctree(struct btrfs_root *root) | |||
1574 | 1674 | ||
1575 | write_ctree_super(NULL, root); | 1675 | write_ctree_super(NULL, root); |
1576 | 1676 | ||
1577 | btrfs_transaction_flush_work(root); | ||
1578 | |||
1579 | if (fs_info->delalloc_bytes) { | 1677 | if (fs_info->delalloc_bytes) { |
1580 | printk("btrfs: at unmount delalloc count %Lu\n", | 1678 | printk("btrfs: at unmount delalloc count %Lu\n", |
1581 | fs_info->delalloc_bytes); | 1679 | fs_info->delalloc_bytes); |