diff options
author | Chris Mason <chris.mason@oracle.com> | 2012-03-28 20:31:37 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2012-03-28 20:31:37 -0400 |
commit | 1d4284bd6e8d7dd1d5521a6747bdb6dc1caf0225 (patch) | |
tree | a7dde6312ec24eb6368cad7a3efedbf368a5a70c /fs/btrfs/disk-io.c | |
parent | b5d67f64f9bc656970dacba245410f0faedad18e (diff) | |
parent | 65139ed99234d8505948cdb7a835452eb5c191f9 (diff) |
Merge branch 'error-handling' into for-linus
Conflicts:
fs/btrfs/ctree.c
fs/btrfs/disk-io.c
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/extent_io.h
fs/btrfs/inode.c
fs/btrfs/scrub.c
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/disk-io.c')
-rw-r--r-- | fs/btrfs/disk-io.c | 261 |
1 files changed, 186 insertions, 75 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 6107b695841..7b55eee15a5 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -48,20 +48,19 @@ | |||
48 | static struct extent_io_ops btree_extent_io_ops; | 48 | static struct extent_io_ops btree_extent_io_ops; |
49 | static void end_workqueue_fn(struct btrfs_work *work); | 49 | static void end_workqueue_fn(struct btrfs_work *work); |
50 | static void free_fs_root(struct btrfs_root *root); | 50 | static void free_fs_root(struct btrfs_root *root); |
51 | static void btrfs_check_super_valid(struct btrfs_fs_info *fs_info, | 51 | static int btrfs_check_super_valid(struct btrfs_fs_info *fs_info, |
52 | int read_only); | 52 | int read_only); |
53 | static int btrfs_destroy_ordered_operations(struct btrfs_root *root); | 53 | static void btrfs_destroy_ordered_operations(struct btrfs_root *root); |
54 | static int btrfs_destroy_ordered_extents(struct btrfs_root *root); | 54 | static void btrfs_destroy_ordered_extents(struct btrfs_root *root); |
55 | static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans, | 55 | static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans, |
56 | struct btrfs_root *root); | 56 | struct btrfs_root *root); |
57 | static int btrfs_destroy_pending_snapshots(struct btrfs_transaction *t); | 57 | static void btrfs_destroy_pending_snapshots(struct btrfs_transaction *t); |
58 | static int btrfs_destroy_delalloc_inodes(struct btrfs_root *root); | 58 | static void btrfs_destroy_delalloc_inodes(struct btrfs_root *root); |
59 | static int btrfs_destroy_marked_extents(struct btrfs_root *root, | 59 | static int btrfs_destroy_marked_extents(struct btrfs_root *root, |
60 | struct extent_io_tree *dirty_pages, | 60 | struct extent_io_tree *dirty_pages, |
61 | int mark); | 61 | int mark); |
62 | static int btrfs_destroy_pinned_extent(struct btrfs_root *root, | 62 | static int btrfs_destroy_pinned_extent(struct btrfs_root *root, |
63 | struct extent_io_tree *pinned_extents); | 63 | struct extent_io_tree *pinned_extents); |
64 | static int btrfs_cleanup_transaction(struct btrfs_root *root); | ||
65 | 64 | ||
66 | /* | 65 | /* |
67 | * end_io_wq structs are used to do processing in task context when an IO is | 66 | * end_io_wq structs are used to do processing in task context when an IO is |
@@ -99,6 +98,7 @@ struct async_submit_bio { | |||
99 | */ | 98 | */ |
100 | u64 bio_offset; | 99 | u64 bio_offset; |
101 | struct btrfs_work work; | 100 | struct btrfs_work work; |
101 | int error; | ||
102 | }; | 102 | }; |
103 | 103 | ||
104 | /* | 104 | /* |
@@ -332,7 +332,7 @@ static int verify_parent_transid(struct extent_io_tree *io_tree, | |||
332 | return 0; | 332 | return 0; |
333 | 333 | ||
334 | lock_extent_bits(io_tree, eb->start, eb->start + eb->len - 1, | 334 | lock_extent_bits(io_tree, eb->start, eb->start + eb->len - 1, |
335 | 0, &cached_state, GFP_NOFS); | 335 | 0, &cached_state); |
336 | if (extent_buffer_uptodate(eb) && | 336 | if (extent_buffer_uptodate(eb) && |
337 | btrfs_header_generation(eb) == parent_transid) { | 337 | btrfs_header_generation(eb) == parent_transid) { |
338 | ret = 0; | 338 | ret = 0; |
@@ -425,7 +425,6 @@ static int csum_dirty_buffer(struct btrfs_root *root, struct page *page) | |||
425 | eb = (struct extent_buffer *)page->private; | 425 | eb = (struct extent_buffer *)page->private; |
426 | if (page != eb->pages[0]) | 426 | if (page != eb->pages[0]) |
427 | return 0; | 427 | return 0; |
428 | |||
429 | found_start = btrfs_header_bytenr(eb); | 428 | found_start = btrfs_header_bytenr(eb); |
430 | if (found_start != start) { | 429 | if (found_start != start) { |
431 | WARN_ON(1); | 430 | WARN_ON(1); |
@@ -727,11 +726,14 @@ unsigned long btrfs_async_submit_limit(struct btrfs_fs_info *info) | |||
727 | static void run_one_async_start(struct btrfs_work *work) | 726 | static void run_one_async_start(struct btrfs_work *work) |
728 | { | 727 | { |
729 | struct async_submit_bio *async; | 728 | struct async_submit_bio *async; |
729 | int ret; | ||
730 | 730 | ||
731 | async = container_of(work, struct async_submit_bio, work); | 731 | async = container_of(work, struct async_submit_bio, work); |
732 | async->submit_bio_start(async->inode, async->rw, async->bio, | 732 | ret = async->submit_bio_start(async->inode, async->rw, async->bio, |
733 | async->mirror_num, async->bio_flags, | 733 | async->mirror_num, async->bio_flags, |
734 | async->bio_offset); | 734 | async->bio_offset); |
735 | if (ret) | ||
736 | async->error = ret; | ||
735 | } | 737 | } |
736 | 738 | ||
737 | static void run_one_async_done(struct btrfs_work *work) | 739 | static void run_one_async_done(struct btrfs_work *work) |
@@ -752,6 +754,12 @@ static void run_one_async_done(struct btrfs_work *work) | |||
752 | waitqueue_active(&fs_info->async_submit_wait)) | 754 | waitqueue_active(&fs_info->async_submit_wait)) |
753 | wake_up(&fs_info->async_submit_wait); | 755 | wake_up(&fs_info->async_submit_wait); |
754 | 756 | ||
757 | /* If an error occured we just want to clean up the bio and move on */ | ||
758 | if (async->error) { | ||
759 | bio_endio(async->bio, async->error); | ||
760 | return; | ||
761 | } | ||
762 | |||
755 | async->submit_bio_done(async->inode, async->rw, async->bio, | 763 | async->submit_bio_done(async->inode, async->rw, async->bio, |
756 | async->mirror_num, async->bio_flags, | 764 | async->mirror_num, async->bio_flags, |
757 | async->bio_offset); | 765 | async->bio_offset); |
@@ -793,6 +801,8 @@ int btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct inode *inode, | |||
793 | async->bio_flags = bio_flags; | 801 | async->bio_flags = bio_flags; |
794 | async->bio_offset = bio_offset; | 802 | async->bio_offset = bio_offset; |
795 | 803 | ||
804 | async->error = 0; | ||
805 | |||
796 | atomic_inc(&fs_info->nr_async_submits); | 806 | atomic_inc(&fs_info->nr_async_submits); |
797 | 807 | ||
798 | if (rw & REQ_SYNC) | 808 | if (rw & REQ_SYNC) |
@@ -814,15 +824,18 @@ static int btree_csum_one_bio(struct bio *bio) | |||
814 | struct bio_vec *bvec = bio->bi_io_vec; | 824 | struct bio_vec *bvec = bio->bi_io_vec; |
815 | int bio_index = 0; | 825 | int bio_index = 0; |
816 | struct btrfs_root *root; | 826 | struct btrfs_root *root; |
827 | int ret = 0; | ||
817 | 828 | ||
818 | WARN_ON(bio->bi_vcnt <= 0); | 829 | WARN_ON(bio->bi_vcnt <= 0); |
819 | while (bio_index < bio->bi_vcnt) { | 830 | while (bio_index < bio->bi_vcnt) { |
820 | root = BTRFS_I(bvec->bv_page->mapping->host)->root; | 831 | root = BTRFS_I(bvec->bv_page->mapping->host)->root; |
821 | csum_dirty_buffer(root, bvec->bv_page); | 832 | ret = csum_dirty_buffer(root, bvec->bv_page); |
833 | if (ret) | ||
834 | break; | ||
822 | bio_index++; | 835 | bio_index++; |
823 | bvec++; | 836 | bvec++; |
824 | } | 837 | } |
825 | return 0; | 838 | return ret; |
826 | } | 839 | } |
827 | 840 | ||
828 | static int __btree_submit_bio_start(struct inode *inode, int rw, | 841 | static int __btree_submit_bio_start(struct inode *inode, int rw, |
@@ -834,8 +847,7 @@ static int __btree_submit_bio_start(struct inode *inode, int rw, | |||
834 | * when we're called for a write, we're already in the async | 847 | * when we're called for a write, we're already in the async |
835 | * submission context. Just jump into btrfs_map_bio | 848 | * submission context. Just jump into btrfs_map_bio |
836 | */ | 849 | */ |
837 | btree_csum_one_bio(bio); | 850 | return btree_csum_one_bio(bio); |
838 | return 0; | ||
839 | } | 851 | } |
840 | 852 | ||
841 | static int __btree_submit_bio_done(struct inode *inode, int rw, struct bio *bio, | 853 | static int __btree_submit_bio_done(struct inode *inode, int rw, struct bio *bio, |
@@ -863,7 +875,8 @@ static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio, | |||
863 | */ | 875 | */ |
864 | ret = btrfs_bio_wq_end_io(BTRFS_I(inode)->root->fs_info, | 876 | ret = btrfs_bio_wq_end_io(BTRFS_I(inode)->root->fs_info, |
865 | bio, 1); | 877 | bio, 1); |
866 | BUG_ON(ret); | 878 | if (ret) |
879 | return ret; | ||
867 | return btrfs_map_bio(BTRFS_I(inode)->root, rw, bio, | 880 | return btrfs_map_bio(BTRFS_I(inode)->root, rw, bio, |
868 | mirror_num, 0); | 881 | mirror_num, 0); |
869 | } | 882 | } |
@@ -1080,8 +1093,8 @@ struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr, | |||
1080 | 1093 | ||
1081 | } | 1094 | } |
1082 | 1095 | ||
1083 | int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, | 1096 | void clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, |
1084 | struct extent_buffer *buf) | 1097 | struct extent_buffer *buf) |
1085 | { | 1098 | { |
1086 | if (btrfs_header_generation(buf) == | 1099 | if (btrfs_header_generation(buf) == |
1087 | root->fs_info->running_transaction->transid) { | 1100 | root->fs_info->running_transaction->transid) { |
@@ -1091,8 +1104,14 @@ int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, | |||
1091 | spin_lock(&root->fs_info->delalloc_lock); | 1104 | spin_lock(&root->fs_info->delalloc_lock); |
1092 | if (root->fs_info->dirty_metadata_bytes >= buf->len) | 1105 | if (root->fs_info->dirty_metadata_bytes >= buf->len) |
1093 | root->fs_info->dirty_metadata_bytes -= buf->len; | 1106 | root->fs_info->dirty_metadata_bytes -= buf->len; |
1094 | else | 1107 | else { |
1095 | WARN_ON(1); | 1108 | spin_unlock(&root->fs_info->delalloc_lock); |
1109 | btrfs_panic(root->fs_info, -EOVERFLOW, | ||
1110 | "Can't clear %lu bytes from " | ||
1111 | " dirty_mdatadata_bytes (%lu)", | ||
1112 | buf->len, | ||
1113 | root->fs_info->dirty_metadata_bytes); | ||
1114 | } | ||
1096 | spin_unlock(&root->fs_info->delalloc_lock); | 1115 | spin_unlock(&root->fs_info->delalloc_lock); |
1097 | } | 1116 | } |
1098 | 1117 | ||
@@ -1100,13 +1119,12 @@ int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, | |||
1100 | btrfs_set_lock_blocking(buf); | 1119 | btrfs_set_lock_blocking(buf); |
1101 | clear_extent_buffer_dirty(buf); | 1120 | clear_extent_buffer_dirty(buf); |
1102 | } | 1121 | } |
1103 | return 0; | ||
1104 | } | 1122 | } |
1105 | 1123 | ||
1106 | static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, | 1124 | static void __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, |
1107 | u32 stripesize, struct btrfs_root *root, | 1125 | u32 stripesize, struct btrfs_root *root, |
1108 | struct btrfs_fs_info *fs_info, | 1126 | struct btrfs_fs_info *fs_info, |
1109 | u64 objectid) | 1127 | u64 objectid) |
1110 | { | 1128 | { |
1111 | root->node = NULL; | 1129 | root->node = NULL; |
1112 | root->commit_root = NULL; | 1130 | root->commit_root = NULL; |
@@ -1158,13 +1176,12 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, | |||
1158 | root->defrag_running = 0; | 1176 | root->defrag_running = 0; |
1159 | root->root_key.objectid = objectid; | 1177 | root->root_key.objectid = objectid; |
1160 | root->anon_dev = 0; | 1178 | root->anon_dev = 0; |
1161 | return 0; | ||
1162 | } | 1179 | } |
1163 | 1180 | ||
1164 | static int find_and_setup_root(struct btrfs_root *tree_root, | 1181 | static int __must_check find_and_setup_root(struct btrfs_root *tree_root, |
1165 | struct btrfs_fs_info *fs_info, | 1182 | struct btrfs_fs_info *fs_info, |
1166 | u64 objectid, | 1183 | u64 objectid, |
1167 | struct btrfs_root *root) | 1184 | struct btrfs_root *root) |
1168 | { | 1185 | { |
1169 | int ret; | 1186 | int ret; |
1170 | u32 blocksize; | 1187 | u32 blocksize; |
@@ -1177,7 +1194,8 @@ static int find_and_setup_root(struct btrfs_root *tree_root, | |||
1177 | &root->root_item, &root->root_key); | 1194 | &root->root_item, &root->root_key); |
1178 | if (ret > 0) | 1195 | if (ret > 0) |
1179 | return -ENOENT; | 1196 | return -ENOENT; |
1180 | BUG_ON(ret); | 1197 | else if (ret < 0) |
1198 | return ret; | ||
1181 | 1199 | ||
1182 | generation = btrfs_root_generation(&root->root_item); | 1200 | generation = btrfs_root_generation(&root->root_item); |
1183 | blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item)); | 1201 | blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item)); |
@@ -1346,7 +1364,7 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root, | |||
1346 | root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item), | 1364 | root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item), |
1347 | blocksize, generation); | 1365 | blocksize, generation); |
1348 | root->commit_root = btrfs_root_node(root); | 1366 | root->commit_root = btrfs_root_node(root); |
1349 | BUG_ON(!root->node); | 1367 | BUG_ON(!root->node); /* -ENOMEM */ |
1350 | out: | 1368 | out: |
1351 | if (location->objectid != BTRFS_TREE_LOG_OBJECTID) { | 1369 | if (location->objectid != BTRFS_TREE_LOG_OBJECTID) { |
1352 | root->ref_cows = 1; | 1370 | root->ref_cows = 1; |
@@ -1537,9 +1555,10 @@ static int transaction_kthread(void *arg) | |||
1537 | u64 transid; | 1555 | u64 transid; |
1538 | unsigned long now; | 1556 | unsigned long now; |
1539 | unsigned long delay; | 1557 | unsigned long delay; |
1540 | int ret; | 1558 | bool cannot_commit; |
1541 | 1559 | ||
1542 | do { | 1560 | do { |
1561 | cannot_commit = false; | ||
1543 | delay = HZ * 30; | 1562 | delay = HZ * 30; |
1544 | vfs_check_frozen(root->fs_info->sb, SB_FREEZE_WRITE); | 1563 | vfs_check_frozen(root->fs_info->sb, SB_FREEZE_WRITE); |
1545 | mutex_lock(&root->fs_info->transaction_kthread_mutex); | 1564 | mutex_lock(&root->fs_info->transaction_kthread_mutex); |
@@ -1561,11 +1580,14 @@ static int transaction_kthread(void *arg) | |||
1561 | transid = cur->transid; | 1580 | transid = cur->transid; |
1562 | spin_unlock(&root->fs_info->trans_lock); | 1581 | spin_unlock(&root->fs_info->trans_lock); |
1563 | 1582 | ||
1583 | /* If the file system is aborted, this will always fail. */ | ||
1564 | trans = btrfs_join_transaction(root); | 1584 | trans = btrfs_join_transaction(root); |
1565 | BUG_ON(IS_ERR(trans)); | 1585 | if (IS_ERR(trans)) { |
1586 | cannot_commit = true; | ||
1587 | goto sleep; | ||
1588 | } | ||
1566 | if (transid == trans->transid) { | 1589 | if (transid == trans->transid) { |
1567 | ret = btrfs_commit_transaction(trans, root); | 1590 | btrfs_commit_transaction(trans, root); |
1568 | BUG_ON(ret); | ||
1569 | } else { | 1591 | } else { |
1570 | btrfs_end_transaction(trans, root); | 1592 | btrfs_end_transaction(trans, root); |
1571 | } | 1593 | } |
@@ -1576,7 +1598,8 @@ sleep: | |||
1576 | if (!try_to_freeze()) { | 1598 | if (!try_to_freeze()) { |
1577 | set_current_state(TASK_INTERRUPTIBLE); | 1599 | set_current_state(TASK_INTERRUPTIBLE); |
1578 | if (!kthread_should_stop() && | 1600 | if (!kthread_should_stop() && |
1579 | !btrfs_transaction_blocked(root->fs_info)) | 1601 | (!btrfs_transaction_blocked(root->fs_info) || |
1602 | cannot_commit)) | ||
1580 | schedule_timeout(delay); | 1603 | schedule_timeout(delay); |
1581 | __set_current_state(TASK_RUNNING); | 1604 | __set_current_state(TASK_RUNNING); |
1582 | } | 1605 | } |
@@ -2028,7 +2051,12 @@ int open_ctree(struct super_block *sb, | |||
2028 | /* check FS state, whether FS is broken. */ | 2051 | /* check FS state, whether FS is broken. */ |
2029 | fs_info->fs_state |= btrfs_super_flags(disk_super); | 2052 | fs_info->fs_state |= btrfs_super_flags(disk_super); |
2030 | 2053 | ||
2031 | btrfs_check_super_valid(fs_info, sb->s_flags & MS_RDONLY); | 2054 | ret = btrfs_check_super_valid(fs_info, sb->s_flags & MS_RDONLY); |
2055 | if (ret) { | ||
2056 | printk(KERN_ERR "btrfs: superblock contains fatal errors\n"); | ||
2057 | err = ret; | ||
2058 | goto fail_alloc; | ||
2059 | } | ||
2032 | 2060 | ||
2033 | /* | 2061 | /* |
2034 | * run through our array of backup supers and setup | 2062 | * run through our array of backup supers and setup |
@@ -2218,6 +2246,14 @@ int open_ctree(struct super_block *sb, | |||
2218 | goto fail_sb_buffer; | 2246 | goto fail_sb_buffer; |
2219 | } | 2247 | } |
2220 | 2248 | ||
2249 | if ((features & BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS) && | ||
2250 | (leafsize != nodesize || sectorsize != nodesize)) { | ||
2251 | printk(KERN_WARNING "btrfs: unequal leaf/node/sector sizes " | ||
2252 | "are not allowed for mixed block groups on %s\n", | ||
2253 | sb->s_id); | ||
2254 | goto fail_sb_buffer; | ||
2255 | } | ||
2256 | |||
2221 | mutex_lock(&fs_info->chunk_mutex); | 2257 | mutex_lock(&fs_info->chunk_mutex); |
2222 | ret = btrfs_read_sys_array(tree_root); | 2258 | ret = btrfs_read_sys_array(tree_root); |
2223 | mutex_unlock(&fs_info->chunk_mutex); | 2259 | mutex_unlock(&fs_info->chunk_mutex); |
@@ -2237,7 +2273,7 @@ int open_ctree(struct super_block *sb, | |||
2237 | chunk_root->node = read_tree_block(chunk_root, | 2273 | chunk_root->node = read_tree_block(chunk_root, |
2238 | btrfs_super_chunk_root(disk_super), | 2274 | btrfs_super_chunk_root(disk_super), |
2239 | blocksize, generation); | 2275 | blocksize, generation); |
2240 | BUG_ON(!chunk_root->node); | 2276 | BUG_ON(!chunk_root->node); /* -ENOMEM */ |
2241 | if (!test_bit(EXTENT_BUFFER_UPTODATE, &chunk_root->node->bflags)) { | 2277 | if (!test_bit(EXTENT_BUFFER_UPTODATE, &chunk_root->node->bflags)) { |
2242 | printk(KERN_WARNING "btrfs: failed to read chunk root on %s\n", | 2278 | printk(KERN_WARNING "btrfs: failed to read chunk root on %s\n", |
2243 | sb->s_id); | 2279 | sb->s_id); |
@@ -2377,21 +2413,31 @@ retry_root_backup: | |||
2377 | log_tree_root->node = read_tree_block(tree_root, bytenr, | 2413 | log_tree_root->node = read_tree_block(tree_root, bytenr, |
2378 | blocksize, | 2414 | blocksize, |
2379 | generation + 1); | 2415 | generation + 1); |
2416 | /* returns with log_tree_root freed on success */ | ||
2380 | ret = btrfs_recover_log_trees(log_tree_root); | 2417 | ret = btrfs_recover_log_trees(log_tree_root); |
2381 | BUG_ON(ret); | 2418 | if (ret) { |
2419 | btrfs_error(tree_root->fs_info, ret, | ||
2420 | "Failed to recover log tree"); | ||
2421 | free_extent_buffer(log_tree_root->node); | ||
2422 | kfree(log_tree_root); | ||
2423 | goto fail_trans_kthread; | ||
2424 | } | ||
2382 | 2425 | ||
2383 | if (sb->s_flags & MS_RDONLY) { | 2426 | if (sb->s_flags & MS_RDONLY) { |
2384 | ret = btrfs_commit_super(tree_root); | 2427 | ret = btrfs_commit_super(tree_root); |
2385 | BUG_ON(ret); | 2428 | if (ret) |
2429 | goto fail_trans_kthread; | ||
2386 | } | 2430 | } |
2387 | } | 2431 | } |
2388 | 2432 | ||
2389 | ret = btrfs_find_orphan_roots(tree_root); | 2433 | ret = btrfs_find_orphan_roots(tree_root); |
2390 | BUG_ON(ret); | 2434 | if (ret) |
2435 | goto fail_trans_kthread; | ||
2391 | 2436 | ||
2392 | if (!(sb->s_flags & MS_RDONLY)) { | 2437 | if (!(sb->s_flags & MS_RDONLY)) { |
2393 | ret = btrfs_cleanup_fs_roots(fs_info); | 2438 | ret = btrfs_cleanup_fs_roots(fs_info); |
2394 | BUG_ON(ret); | 2439 | if (ret) { |
2440 | } | ||
2395 | 2441 | ||
2396 | ret = btrfs_recover_relocation(tree_root); | 2442 | ret = btrfs_recover_relocation(tree_root); |
2397 | if (ret < 0) { | 2443 | if (ret < 0) { |
@@ -2811,6 +2857,8 @@ int write_all_supers(struct btrfs_root *root, int max_mirrors) | |||
2811 | if (total_errors > max_errors) { | 2857 | if (total_errors > max_errors) { |
2812 | printk(KERN_ERR "btrfs: %d errors while writing supers\n", | 2858 | printk(KERN_ERR "btrfs: %d errors while writing supers\n", |
2813 | total_errors); | 2859 | total_errors); |
2860 | |||
2861 | /* This shouldn't happen. FUA is masked off if unsupported */ | ||
2814 | BUG(); | 2862 | BUG(); |
2815 | } | 2863 | } |
2816 | 2864 | ||
@@ -2827,9 +2875,9 @@ int write_all_supers(struct btrfs_root *root, int max_mirrors) | |||
2827 | } | 2875 | } |
2828 | mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); | 2876 | mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); |
2829 | if (total_errors > max_errors) { | 2877 | if (total_errors > max_errors) { |
2830 | printk(KERN_ERR "btrfs: %d errors while writing supers\n", | 2878 | btrfs_error(root->fs_info, -EIO, |
2831 | total_errors); | 2879 | "%d errors while writing supers", total_errors); |
2832 | BUG(); | 2880 | return -EIO; |
2833 | } | 2881 | } |
2834 | return 0; | 2882 | return 0; |
2835 | } | 2883 | } |
@@ -2843,7 +2891,20 @@ int write_ctree_super(struct btrfs_trans_handle *trans, | |||
2843 | return ret; | 2891 | return ret; |
2844 | } | 2892 | } |
2845 | 2893 | ||
2846 | int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root) | 2894 | /* Kill all outstanding I/O */ |
2895 | void btrfs_abort_devices(struct btrfs_root *root) | ||
2896 | { | ||
2897 | struct list_head *head; | ||
2898 | struct btrfs_device *dev; | ||
2899 | mutex_lock(&root->fs_info->fs_devices->device_list_mutex); | ||
2900 | head = &root->fs_info->fs_devices->devices; | ||
2901 | list_for_each_entry_rcu(dev, head, dev_list) { | ||
2902 | blk_abort_queue(dev->bdev->bd_disk->queue); | ||
2903 | } | ||
2904 | mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); | ||
2905 | } | ||
2906 | |||
2907 | void btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root) | ||
2847 | { | 2908 | { |
2848 | spin_lock(&fs_info->fs_roots_radix_lock); | 2909 | spin_lock(&fs_info->fs_roots_radix_lock); |
2849 | radix_tree_delete(&fs_info->fs_roots_radix, | 2910 | radix_tree_delete(&fs_info->fs_roots_radix, |
@@ -2856,7 +2917,6 @@ int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root) | |||
2856 | __btrfs_remove_free_space_cache(root->free_ino_pinned); | 2917 | __btrfs_remove_free_space_cache(root->free_ino_pinned); |
2857 | __btrfs_remove_free_space_cache(root->free_ino_ctl); | 2918 | __btrfs_remove_free_space_cache(root->free_ino_ctl); |
2858 | free_fs_root(root); | 2919 | free_fs_root(root); |
2859 | return 0; | ||
2860 | } | 2920 | } |
2861 | 2921 | ||
2862 | static void free_fs_root(struct btrfs_root *root) | 2922 | static void free_fs_root(struct btrfs_root *root) |
@@ -2873,7 +2933,7 @@ static void free_fs_root(struct btrfs_root *root) | |||
2873 | kfree(root); | 2933 | kfree(root); |
2874 | } | 2934 | } |
2875 | 2935 | ||
2876 | static int del_fs_roots(struct btrfs_fs_info *fs_info) | 2936 | static void del_fs_roots(struct btrfs_fs_info *fs_info) |
2877 | { | 2937 | { |
2878 | int ret; | 2938 | int ret; |
2879 | struct btrfs_root *gang[8]; | 2939 | struct btrfs_root *gang[8]; |
@@ -2902,7 +2962,6 @@ static int del_fs_roots(struct btrfs_fs_info *fs_info) | |||
2902 | for (i = 0; i < ret; i++) | 2962 | for (i = 0; i < ret; i++) |
2903 | btrfs_free_fs_root(fs_info, gang[i]); | 2963 | btrfs_free_fs_root(fs_info, gang[i]); |
2904 | } | 2964 | } |
2905 | return 0; | ||
2906 | } | 2965 | } |
2907 | 2966 | ||
2908 | int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info) | 2967 | int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info) |
@@ -2951,14 +3010,21 @@ int btrfs_commit_super(struct btrfs_root *root) | |||
2951 | if (IS_ERR(trans)) | 3010 | if (IS_ERR(trans)) |
2952 | return PTR_ERR(trans); | 3011 | return PTR_ERR(trans); |
2953 | ret = btrfs_commit_transaction(trans, root); | 3012 | ret = btrfs_commit_transaction(trans, root); |
2954 | BUG_ON(ret); | 3013 | if (ret) |
3014 | return ret; | ||
2955 | /* run commit again to drop the original snapshot */ | 3015 | /* run commit again to drop the original snapshot */ |
2956 | trans = btrfs_join_transaction(root); | 3016 | trans = btrfs_join_transaction(root); |
2957 | if (IS_ERR(trans)) | 3017 | if (IS_ERR(trans)) |
2958 | return PTR_ERR(trans); | 3018 | return PTR_ERR(trans); |
2959 | btrfs_commit_transaction(trans, root); | 3019 | ret = btrfs_commit_transaction(trans, root); |
3020 | if (ret) | ||
3021 | return ret; | ||
2960 | ret = btrfs_write_and_wait_transaction(NULL, root); | 3022 | ret = btrfs_write_and_wait_transaction(NULL, root); |
2961 | BUG_ON(ret); | 3023 | if (ret) { |
3024 | btrfs_error(root->fs_info, ret, | ||
3025 | "Failed to sync btree inode to disk."); | ||
3026 | return ret; | ||
3027 | } | ||
2962 | 3028 | ||
2963 | ret = write_ctree_super(NULL, root, 0); | 3029 | ret = write_ctree_super(NULL, root, 0); |
2964 | return ret; | 3030 | return ret; |
@@ -3209,15 +3275,23 @@ out: | |||
3209 | return 0; | 3275 | return 0; |
3210 | } | 3276 | } |
3211 | 3277 | ||
3212 | static void btrfs_check_super_valid(struct btrfs_fs_info *fs_info, | 3278 | static int btrfs_check_super_valid(struct btrfs_fs_info *fs_info, |
3213 | int read_only) | 3279 | int read_only) |
3214 | { | 3280 | { |
3281 | if (btrfs_super_csum_type(fs_info->super_copy) >= ARRAY_SIZE(btrfs_csum_sizes)) { | ||
3282 | printk(KERN_ERR "btrfs: unsupported checksum algorithm\n"); | ||
3283 | return -EINVAL; | ||
3284 | } | ||
3285 | |||
3215 | if (read_only) | 3286 | if (read_only) |
3216 | return; | 3287 | return 0; |
3217 | 3288 | ||
3218 | if (fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) | 3289 | if (fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) { |
3219 | printk(KERN_WARNING "warning: mount fs with errors, " | 3290 | printk(KERN_WARNING "warning: mount fs with errors, " |
3220 | "running btrfsck is recommended\n"); | 3291 | "running btrfsck is recommended\n"); |
3292 | } | ||
3293 | |||
3294 | return 0; | ||
3221 | } | 3295 | } |
3222 | 3296 | ||
3223 | int btrfs_error_commit_super(struct btrfs_root *root) | 3297 | int btrfs_error_commit_super(struct btrfs_root *root) |
@@ -3239,7 +3313,7 @@ int btrfs_error_commit_super(struct btrfs_root *root) | |||
3239 | return ret; | 3313 | return ret; |
3240 | } | 3314 | } |
3241 | 3315 | ||
3242 | static int btrfs_destroy_ordered_operations(struct btrfs_root *root) | 3316 | static void btrfs_destroy_ordered_operations(struct btrfs_root *root) |
3243 | { | 3317 | { |
3244 | struct btrfs_inode *btrfs_inode; | 3318 | struct btrfs_inode *btrfs_inode; |
3245 | struct list_head splice; | 3319 | struct list_head splice; |
@@ -3261,11 +3335,9 @@ static int btrfs_destroy_ordered_operations(struct btrfs_root *root) | |||
3261 | 3335 | ||
3262 | spin_unlock(&root->fs_info->ordered_extent_lock); | 3336 | spin_unlock(&root->fs_info->ordered_extent_lock); |
3263 | mutex_unlock(&root->fs_info->ordered_operations_mutex); | 3337 | mutex_unlock(&root->fs_info->ordered_operations_mutex); |
3264 | |||
3265 | return 0; | ||
3266 | } | 3338 | } |
3267 | 3339 | ||
3268 | static int btrfs_destroy_ordered_extents(struct btrfs_root *root) | 3340 | static void btrfs_destroy_ordered_extents(struct btrfs_root *root) |
3269 | { | 3341 | { |
3270 | struct list_head splice; | 3342 | struct list_head splice; |
3271 | struct btrfs_ordered_extent *ordered; | 3343 | struct btrfs_ordered_extent *ordered; |
@@ -3297,12 +3369,10 @@ static int btrfs_destroy_ordered_extents(struct btrfs_root *root) | |||
3297 | } | 3369 | } |
3298 | 3370 | ||
3299 | spin_unlock(&root->fs_info->ordered_extent_lock); | 3371 | spin_unlock(&root->fs_info->ordered_extent_lock); |
3300 | |||
3301 | return 0; | ||
3302 | } | 3372 | } |
3303 | 3373 | ||
3304 | static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans, | 3374 | int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans, |
3305 | struct btrfs_root *root) | 3375 | struct btrfs_root *root) |
3306 | { | 3376 | { |
3307 | struct rb_node *node; | 3377 | struct rb_node *node; |
3308 | struct btrfs_delayed_ref_root *delayed_refs; | 3378 | struct btrfs_delayed_ref_root *delayed_refs; |
@@ -3311,6 +3381,7 @@ static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans, | |||
3311 | 3381 | ||
3312 | delayed_refs = &trans->delayed_refs; | 3382 | delayed_refs = &trans->delayed_refs; |
3313 | 3383 | ||
3384 | again: | ||
3314 | spin_lock(&delayed_refs->lock); | 3385 | spin_lock(&delayed_refs->lock); |
3315 | if (delayed_refs->num_entries == 0) { | 3386 | if (delayed_refs->num_entries == 0) { |
3316 | spin_unlock(&delayed_refs->lock); | 3387 | spin_unlock(&delayed_refs->lock); |
@@ -3332,6 +3403,7 @@ static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans, | |||
3332 | struct btrfs_delayed_ref_head *head; | 3403 | struct btrfs_delayed_ref_head *head; |
3333 | 3404 | ||
3334 | head = btrfs_delayed_node_to_head(ref); | 3405 | head = btrfs_delayed_node_to_head(ref); |
3406 | spin_unlock(&delayed_refs->lock); | ||
3335 | mutex_lock(&head->mutex); | 3407 | mutex_lock(&head->mutex); |
3336 | kfree(head->extent_op); | 3408 | kfree(head->extent_op); |
3337 | delayed_refs->num_heads--; | 3409 | delayed_refs->num_heads--; |
@@ -3339,8 +3411,9 @@ static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans, | |||
3339 | delayed_refs->num_heads_ready--; | 3411 | delayed_refs->num_heads_ready--; |
3340 | list_del_init(&head->cluster); | 3412 | list_del_init(&head->cluster); |
3341 | mutex_unlock(&head->mutex); | 3413 | mutex_unlock(&head->mutex); |
3414 | btrfs_put_delayed_ref(ref); | ||
3415 | goto again; | ||
3342 | } | 3416 | } |
3343 | |||
3344 | spin_unlock(&delayed_refs->lock); | 3417 | spin_unlock(&delayed_refs->lock); |
3345 | btrfs_put_delayed_ref(ref); | 3418 | btrfs_put_delayed_ref(ref); |
3346 | 3419 | ||
@@ -3353,7 +3426,7 @@ static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans, | |||
3353 | return ret; | 3426 | return ret; |
3354 | } | 3427 | } |
3355 | 3428 | ||
3356 | static int btrfs_destroy_pending_snapshots(struct btrfs_transaction *t) | 3429 | static void btrfs_destroy_pending_snapshots(struct btrfs_transaction *t) |
3357 | { | 3430 | { |
3358 | struct btrfs_pending_snapshot *snapshot; | 3431 | struct btrfs_pending_snapshot *snapshot; |
3359 | struct list_head splice; | 3432 | struct list_head splice; |
@@ -3371,11 +3444,9 @@ static int btrfs_destroy_pending_snapshots(struct btrfs_transaction *t) | |||
3371 | 3444 | ||
3372 | kfree(snapshot); | 3445 | kfree(snapshot); |
3373 | } | 3446 | } |
3374 | |||
3375 | return 0; | ||
3376 | } | 3447 | } |
3377 | 3448 | ||
3378 | static int btrfs_destroy_delalloc_inodes(struct btrfs_root *root) | 3449 | static void btrfs_destroy_delalloc_inodes(struct btrfs_root *root) |
3379 | { | 3450 | { |
3380 | struct btrfs_inode *btrfs_inode; | 3451 | struct btrfs_inode *btrfs_inode; |
3381 | struct list_head splice; | 3452 | struct list_head splice; |
@@ -3395,8 +3466,6 @@ static int btrfs_destroy_delalloc_inodes(struct btrfs_root *root) | |||
3395 | } | 3466 | } |
3396 | 3467 | ||
3397 | spin_unlock(&root->fs_info->delalloc_lock); | 3468 | spin_unlock(&root->fs_info->delalloc_lock); |
3398 | |||
3399 | return 0; | ||
3400 | } | 3469 | } |
3401 | 3470 | ||
3402 | static int btrfs_destroy_marked_extents(struct btrfs_root *root, | 3471 | static int btrfs_destroy_marked_extents(struct btrfs_root *root, |
@@ -3487,13 +3556,43 @@ static int btrfs_destroy_pinned_extent(struct btrfs_root *root, | |||
3487 | return 0; | 3556 | return 0; |
3488 | } | 3557 | } |
3489 | 3558 | ||
3490 | static int btrfs_cleanup_transaction(struct btrfs_root *root) | 3559 | void btrfs_cleanup_one_transaction(struct btrfs_transaction *cur_trans, |
3560 | struct btrfs_root *root) | ||
3561 | { | ||
3562 | btrfs_destroy_delayed_refs(cur_trans, root); | ||
3563 | btrfs_block_rsv_release(root, &root->fs_info->trans_block_rsv, | ||
3564 | cur_trans->dirty_pages.dirty_bytes); | ||
3565 | |||
3566 | /* FIXME: cleanup wait for commit */ | ||
3567 | cur_trans->in_commit = 1; | ||
3568 | cur_trans->blocked = 1; | ||
3569 | if (waitqueue_active(&root->fs_info->transaction_blocked_wait)) | ||
3570 | wake_up(&root->fs_info->transaction_blocked_wait); | ||
3571 | |||
3572 | cur_trans->blocked = 0; | ||
3573 | if (waitqueue_active(&root->fs_info->transaction_wait)) | ||
3574 | wake_up(&root->fs_info->transaction_wait); | ||
3575 | |||
3576 | cur_trans->commit_done = 1; | ||
3577 | if (waitqueue_active(&cur_trans->commit_wait)) | ||
3578 | wake_up(&cur_trans->commit_wait); | ||
3579 | |||
3580 | btrfs_destroy_pending_snapshots(cur_trans); | ||
3581 | |||
3582 | btrfs_destroy_marked_extents(root, &cur_trans->dirty_pages, | ||
3583 | EXTENT_DIRTY); | ||
3584 | |||
3585 | /* | ||
3586 | memset(cur_trans, 0, sizeof(*cur_trans)); | ||
3587 | kmem_cache_free(btrfs_transaction_cachep, cur_trans); | ||
3588 | */ | ||
3589 | } | ||
3590 | |||
3591 | int btrfs_cleanup_transaction(struct btrfs_root *root) | ||
3491 | { | 3592 | { |
3492 | struct btrfs_transaction *t; | 3593 | struct btrfs_transaction *t; |
3493 | LIST_HEAD(list); | 3594 | LIST_HEAD(list); |
3494 | 3595 | ||
3495 | WARN_ON(1); | ||
3496 | |||
3497 | mutex_lock(&root->fs_info->transaction_kthread_mutex); | 3596 | mutex_lock(&root->fs_info->transaction_kthread_mutex); |
3498 | 3597 | ||
3499 | spin_lock(&root->fs_info->trans_lock); | 3598 | spin_lock(&root->fs_info->trans_lock); |
@@ -3558,6 +3657,17 @@ static int btrfs_cleanup_transaction(struct btrfs_root *root) | |||
3558 | return 0; | 3657 | return 0; |
3559 | } | 3658 | } |
3560 | 3659 | ||
3660 | static int btree_writepage_io_failed_hook(struct bio *bio, struct page *page, | ||
3661 | u64 start, u64 end, | ||
3662 | struct extent_state *state) | ||
3663 | { | ||
3664 | struct super_block *sb = page->mapping->host->i_sb; | ||
3665 | struct btrfs_fs_info *fs_info = btrfs_sb(sb); | ||
3666 | btrfs_error(fs_info, -EIO, | ||
3667 | "Error occured while writing out btree at %llu", start); | ||
3668 | return -EIO; | ||
3669 | } | ||
3670 | |||
3561 | static struct extent_io_ops btree_extent_io_ops = { | 3671 | static struct extent_io_ops btree_extent_io_ops = { |
3562 | .write_cache_pages_lock_hook = btree_lock_page_hook, | 3672 | .write_cache_pages_lock_hook = btree_lock_page_hook, |
3563 | .readpage_end_io_hook = btree_readpage_end_io_hook, | 3673 | .readpage_end_io_hook = btree_readpage_end_io_hook, |
@@ -3565,4 +3675,5 @@ static struct extent_io_ops btree_extent_io_ops = { | |||
3565 | .submit_bio_hook = btree_submit_bio_hook, | 3675 | .submit_bio_hook = btree_submit_bio_hook, |
3566 | /* note we're sharing with inode.c for the merge bio hook */ | 3676 | /* note we're sharing with inode.c for the merge bio hook */ |
3567 | .merge_bio_hook = btrfs_merge_bio_hook, | 3677 | .merge_bio_hook = btrfs_merge_bio_hook, |
3678 | .writepage_io_failed_hook = btree_writepage_io_failed_hook, | ||
3568 | }; | 3679 | }; |