diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-04-09 16:28:12 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:04:01 -0400 |
commit | ce9adaa5a792c2099a83246265eb4055bc38b6b8 (patch) | |
tree | 3ac03bb73cd3aad0c0b194d387cbb5b136c92fa7 /fs/btrfs | |
parent | 728131d8e40c2a47c59ca91a806299c4708029f9 (diff) |
Btrfs: Do metadata checksums for reads via a workqueue
Before, metadata checksumming was done by the callers of read_tree_block,
which would set EXTENT_CSUM bits in the extent tree to show that a given
range of pages was already checksummed and didn't need to be verified
again.
But, those bits could go away via try_to_releasepage, and the end
result was bogus checksum failures on pages that never left the cache.
The new code validates checksums when the page is read. It is a little
tricky because metadata blocks can span pages and a single read may
end up going via multiple bios.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/ctree.c | 5 | ||||
-rw-r--r-- | fs/btrfs/ctree.h | 4 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 258 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 4 | ||||
-rw-r--r-- | fs/btrfs/extent_io.c | 100 | ||||
-rw-r--r-- | fs/btrfs/extent_io.h | 4 | ||||
-rw-r--r-- | fs/btrfs/transaction.c | 2 |
7 files changed, 310 insertions, 67 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index c92c6b0ee582..efce173a935c 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -158,9 +158,6 @@ int __btrfs_cow_block(struct btrfs_trans_handle *trans, | |||
158 | } else { | 158 | } else { |
159 | root_gen = 0; | 159 | root_gen = 0; |
160 | } | 160 | } |
161 | if (!(buf->flags & EXTENT_CSUM)) | ||
162 | WARN_ON(1); | ||
163 | |||
164 | WARN_ON(root->ref_cows && trans->transid != | 161 | WARN_ON(root->ref_cows && trans->transid != |
165 | root->fs_info->running_transaction->transid); | 162 | root->fs_info->running_transaction->transid); |
166 | WARN_ON(root->ref_cows && trans->transid != root->last_trans); | 163 | WARN_ON(root->ref_cows && trans->transid != root->last_trans); |
@@ -247,8 +244,6 @@ int btrfs_cow_block(struct btrfs_trans_handle *trans, | |||
247 | root->fs_info->generation); | 244 | root->fs_info->generation); |
248 | WARN_ON(1); | 245 | WARN_ON(1); |
249 | } | 246 | } |
250 | if (!(buf->flags & EXTENT_CSUM)) | ||
251 | WARN_ON(1); | ||
252 | 247 | ||
253 | header_trans = btrfs_header_generation(buf); | 248 | header_trans = btrfs_header_generation(buf); |
254 | spin_lock(&root->fs_info->hash_lock); | 249 | spin_lock(&root->fs_info->hash_lock); |
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 4b3b20459f6e..e803c4daad21 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -485,6 +485,10 @@ struct btrfs_fs_info { | |||
485 | struct list_head trans_list; | 485 | struct list_head trans_list; |
486 | struct list_head hashers; | 486 | struct list_head hashers; |
487 | struct list_head dead_roots; | 487 | struct list_head dead_roots; |
488 | struct list_head end_io_work_list; | ||
489 | struct work_struct end_io_work; | ||
490 | spinlock_t end_io_work_lock; | ||
491 | |||
488 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,18) | 492 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,18) |
489 | struct work_struct trans_work; | 493 | struct work_struct trans_work; |
490 | #else | 494 | #else |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index e444b99e02da..82109204788c 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/radix-tree.h> | 24 | #include <linux/radix-tree.h> |
25 | #include <linux/writeback.h> | 25 | #include <linux/writeback.h> |
26 | #include <linux/buffer_head.h> // for block_sync_page | 26 | #include <linux/buffer_head.h> // for block_sync_page |
27 | #include <linux/workqueue.h> | ||
27 | #include "ctree.h" | 28 | #include "ctree.h" |
28 | #include "disk-io.h" | 29 | #include "disk-io.h" |
29 | #include "transaction.h" | 30 | #include "transaction.h" |
@@ -45,6 +46,16 @@ static int check_tree_block(struct btrfs_root *root, struct extent_buffer *buf) | |||
45 | #endif | 46 | #endif |
46 | 47 | ||
47 | static struct extent_io_ops btree_extent_io_ops; | 48 | static struct extent_io_ops btree_extent_io_ops; |
49 | static struct workqueue_struct *end_io_workqueue; | ||
50 | |||
51 | struct end_io_wq { | ||
52 | struct bio *bio; | ||
53 | bio_end_io_t *end_io; | ||
54 | void *private; | ||
55 | struct btrfs_fs_info *info; | ||
56 | int error; | ||
57 | struct list_head list; | ||
58 | }; | ||
48 | 59 | ||
49 | struct extent_map *btree_get_extent(struct inode *inode, struct page *page, | 60 | struct extent_map *btree_get_extent(struct inode *inode, struct page *page, |
50 | size_t page_offset, u64 start, u64 len, | 61 | size_t page_offset, u64 start, u64 len, |
@@ -219,11 +230,108 @@ static int btree_writepage_io_hook(struct page *page, u64 start, u64 end) | |||
219 | return 0; | 230 | return 0; |
220 | } | 231 | } |
221 | 232 | ||
233 | int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end, | ||
234 | struct extent_state *state) | ||
235 | { | ||
236 | struct extent_io_tree *tree; | ||
237 | u64 found_start; | ||
238 | int found_level; | ||
239 | unsigned long len; | ||
240 | struct extent_buffer *eb; | ||
241 | struct btrfs_root *root = BTRFS_I(page->mapping->host)->root; | ||
242 | int ret; | ||
243 | |||
244 | tree = &BTRFS_I(page->mapping->host)->io_tree; | ||
245 | if (page->private == EXTENT_PAGE_PRIVATE) | ||
246 | goto out; | ||
247 | if (!page->private) | ||
248 | goto out; | ||
249 | len = page->private >> 2; | ||
250 | if (len == 0) { | ||
251 | WARN_ON(1); | ||
252 | } | ||
253 | eb = alloc_extent_buffer(tree, start, len, page, GFP_NOFS); | ||
254 | read_extent_buffer_pages(tree, eb, start + PAGE_CACHE_SIZE, 1, | ||
255 | btree_get_extent); | ||
256 | btrfs_clear_buffer_defrag(eb); | ||
257 | found_start = btrfs_header_bytenr(eb); | ||
258 | if (found_start != start) { | ||
259 | printk("warning: eb start incorrect %Lu buffer %Lu len %lu\n", | ||
260 | start, found_start, len); | ||
261 | WARN_ON(1); | ||
262 | goto err; | ||
263 | } | ||
264 | if (eb->first_page != page) { | ||
265 | printk("bad first page %lu %lu\n", eb->first_page->index, | ||
266 | page->index); | ||
267 | WARN_ON(1); | ||
268 | goto err; | ||
269 | } | ||
270 | found_level = btrfs_header_level(eb); | ||
271 | |||
272 | ret = csum_tree_block(root, eb, 1); | ||
273 | |||
274 | end = min_t(u64, eb->len, PAGE_CACHE_SIZE); | ||
275 | end = eb->start + end - 1; | ||
276 | release_extent_buffer_tail_pages(eb); | ||
277 | err: | ||
278 | free_extent_buffer(eb); | ||
279 | out: | ||
280 | return 0; | ||
281 | } | ||
282 | |||
283 | #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23) | ||
284 | static void end_workqueue_bio(struct bio *bio, int err) | ||
285 | #else | ||
286 | static int end_workqueue_bio(struct bio *bio, | ||
287 | unsigned int bytes_done, int err) | ||
288 | #endif | ||
289 | { | ||
290 | struct end_io_wq *end_io_wq = bio->bi_private; | ||
291 | struct btrfs_fs_info *fs_info; | ||
292 | unsigned long flags; | ||
293 | |||
294 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23) | ||
295 | if (bio->bi_size) | ||
296 | return 1; | ||
297 | #endif | ||
298 | |||
299 | fs_info = end_io_wq->info; | ||
300 | spin_lock_irqsave(&fs_info->end_io_work_lock, flags); | ||
301 | end_io_wq->error = err; | ||
302 | list_add_tail(&end_io_wq->list, &fs_info->end_io_work_list); | ||
303 | spin_unlock_irqrestore(&fs_info->end_io_work_lock, flags); | ||
304 | queue_work(end_io_workqueue, &fs_info->end_io_work); | ||
305 | |||
306 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23) | ||
307 | return 0; | ||
308 | #endif | ||
309 | } | ||
310 | |||
222 | static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio) | 311 | static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio) |
223 | { | 312 | { |
224 | struct btrfs_root *root = BTRFS_I(inode)->root; | 313 | struct btrfs_root *root = BTRFS_I(inode)->root; |
314 | struct end_io_wq *end_io_wq; | ||
225 | u64 offset; | 315 | u64 offset; |
226 | offset = bio->bi_sector << 9; | 316 | offset = bio->bi_sector << 9; |
317 | |||
318 | if (rw & (1 << BIO_RW)) { | ||
319 | return btrfs_map_bio(BTRFS_I(inode)->root, rw, bio); | ||
320 | } | ||
321 | |||
322 | end_io_wq = kmalloc(sizeof(*end_io_wq), GFP_NOFS); | ||
323 | if (!end_io_wq) | ||
324 | return -ENOMEM; | ||
325 | |||
326 | end_io_wq->private = bio->bi_private; | ||
327 | end_io_wq->end_io = bio->bi_end_io; | ||
328 | end_io_wq->info = root->fs_info; | ||
329 | end_io_wq->error = 0; | ||
330 | end_io_wq->bio = bio; | ||
331 | |||
332 | bio->bi_private = end_io_wq; | ||
333 | bio->bi_end_io = end_workqueue_bio; | ||
334 | |||
227 | if (offset == BTRFS_SUPER_INFO_OFFSET) { | 335 | if (offset == BTRFS_SUPER_INFO_OFFSET) { |
228 | bio->bi_bdev = root->fs_info->sb->s_bdev; | 336 | bio->bi_bdev = root->fs_info->sb->s_bdev; |
229 | submit_bio(rw, bio); | 337 | submit_bio(rw, bio); |
@@ -363,36 +471,7 @@ static int close_all_devices(struct btrfs_fs_info *fs_info) | |||
363 | int btrfs_verify_block_csum(struct btrfs_root *root, | 471 | int btrfs_verify_block_csum(struct btrfs_root *root, |
364 | struct extent_buffer *buf) | 472 | struct extent_buffer *buf) |
365 | { | 473 | { |
366 | struct extent_io_tree *io_tree; | 474 | return btrfs_buffer_uptodate(buf); |
367 | u64 end; | ||
368 | int ret; | ||
369 | |||
370 | io_tree = &BTRFS_I(root->fs_info->btree_inode)->io_tree; | ||
371 | if (buf->flags & EXTENT_CSUM) | ||
372 | return 0; | ||
373 | |||
374 | end = min_t(u64, buf->len, PAGE_CACHE_SIZE); | ||
375 | end = buf->start + end - 1; | ||
376 | if (test_range_bit(io_tree, buf->start, end, EXTENT_CSUM, 1)) { | ||
377 | buf->flags |= EXTENT_CSUM; | ||
378 | return 0; | ||
379 | } | ||
380 | lock_extent(io_tree, buf->start, end, GFP_NOFS); | ||
381 | |||
382 | if (test_range_bit(io_tree, buf->start, end, EXTENT_CSUM, 1)) { | ||
383 | buf->flags |= EXTENT_CSUM; | ||
384 | ret = 0; | ||
385 | goto out_unlock; | ||
386 | } | ||
387 | WARN_ON(buf->flags & EXTENT_CSUM); | ||
388 | |||
389 | ret = csum_tree_block(root, buf, 1); | ||
390 | set_extent_bits(io_tree, buf->start, end, EXTENT_CSUM, GFP_NOFS); | ||
391 | buf->flags |= EXTENT_CSUM; | ||
392 | |||
393 | out_unlock: | ||
394 | unlock_extent(io_tree, buf->start, end, GFP_NOFS); | ||
395 | return ret; | ||
396 | } | 475 | } |
397 | 476 | ||
398 | struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root, | 477 | struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root, |
@@ -430,11 +509,15 @@ struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr, | |||
430 | buf = btrfs_find_create_tree_block(root, bytenr, blocksize); | 509 | buf = btrfs_find_create_tree_block(root, bytenr, blocksize); |
431 | if (!buf) | 510 | if (!buf) |
432 | return NULL; | 511 | return NULL; |
433 | read_extent_buffer_pages(&BTRFS_I(btree_inode)->io_tree, buf, 0, 1, | ||
434 | btree_get_extent); | ||
435 | 512 | ||
436 | ret = btrfs_verify_block_csum(root, buf); | 513 | ret = read_extent_buffer_pages(&BTRFS_I(btree_inode)->io_tree, buf, 0, |
514 | 1, btree_get_extent); | ||
515 | |||
516 | if (ret == 0) { | ||
517 | buf->flags |= EXTENT_UPTODATE; | ||
518 | } | ||
437 | return buf; | 519 | return buf; |
520 | |||
438 | } | 521 | } |
439 | 522 | ||
440 | int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, | 523 | int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, |
@@ -724,6 +807,99 @@ static int setup_bdi(struct btrfs_fs_info *info, struct backing_dev_info *bdi) | |||
724 | return 0; | 807 | return 0; |
725 | } | 808 | } |
726 | 809 | ||
810 | static int bio_ready_for_csum(struct bio *bio) | ||
811 | { | ||
812 | u64 length = 0; | ||
813 | u64 buf_len = 0; | ||
814 | u64 start = 0; | ||
815 | struct page *page; | ||
816 | struct extent_io_tree *io_tree = NULL; | ||
817 | struct btrfs_fs_info *info = NULL; | ||
818 | struct bio_vec *bvec; | ||
819 | int i; | ||
820 | int ret; | ||
821 | |||
822 | bio_for_each_segment(bvec, bio, i) { | ||
823 | page = bvec->bv_page; | ||
824 | if (page->private == EXTENT_PAGE_PRIVATE) { | ||
825 | length += bvec->bv_len; | ||
826 | continue; | ||
827 | } | ||
828 | if (!page->private) { | ||
829 | length += bvec->bv_len; | ||
830 | continue; | ||
831 | } | ||
832 | length = bvec->bv_len; | ||
833 | buf_len = page->private >> 2; | ||
834 | start = page_offset(page) + bvec->bv_offset; | ||
835 | io_tree = &BTRFS_I(page->mapping->host)->io_tree; | ||
836 | info = BTRFS_I(page->mapping->host)->root->fs_info; | ||
837 | } | ||
838 | /* are we fully contained in this bio? */ | ||
839 | if (buf_len <= length) | ||
840 | return 1; | ||
841 | |||
842 | ret = extent_range_uptodate(io_tree, start + length, | ||
843 | start + buf_len - 1); | ||
844 | if (ret == 1) | ||
845 | return ret; | ||
846 | return ret; | ||
847 | } | ||
848 | |||
849 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,18) | ||
850 | void btrfs_end_io_csum(void *p) | ||
851 | #else | ||
852 | void btrfs_end_io_csum(struct work_struct *work) | ||
853 | #endif | ||
854 | { | ||
855 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,18) | ||
856 | struct btrfs_fs_info *fs_info = p; | ||
857 | #else | ||
858 | struct btrfs_fs_info *fs_info = container_of(work, | ||
859 | struct btrfs_fs_info, | ||
860 | end_io_work); | ||
861 | #endif | ||
862 | unsigned long flags; | ||
863 | struct end_io_wq *end_io_wq; | ||
864 | struct bio *bio; | ||
865 | struct list_head *next; | ||
866 | int error; | ||
867 | int was_empty; | ||
868 | |||
869 | while(1) { | ||
870 | spin_lock_irqsave(&fs_info->end_io_work_lock, flags); | ||
871 | if (list_empty(&fs_info->end_io_work_list)) { | ||
872 | spin_unlock_irqrestore(&fs_info->end_io_work_lock, | ||
873 | flags); | ||
874 | return; | ||
875 | } | ||
876 | next = fs_info->end_io_work_list.next; | ||
877 | list_del(next); | ||
878 | spin_unlock_irqrestore(&fs_info->end_io_work_lock, flags); | ||
879 | |||
880 | end_io_wq = list_entry(next, struct end_io_wq, list); | ||
881 | |||
882 | bio = end_io_wq->bio; | ||
883 | if (!bio_ready_for_csum(bio)) { | ||
884 | spin_lock_irqsave(&fs_info->end_io_work_lock, flags); | ||
885 | was_empty = list_empty(&fs_info->end_io_work_list); | ||
886 | list_add_tail(&end_io_wq->list, | ||
887 | &fs_info->end_io_work_list); | ||
888 | spin_unlock_irqrestore(&fs_info->end_io_work_lock, | ||
889 | flags); | ||
890 | if (was_empty) | ||
891 | return; | ||
892 | continue; | ||
893 | } | ||
894 | error = end_io_wq->error; | ||
895 | bio->bi_private = end_io_wq->private; | ||
896 | bio->bi_end_io = end_io_wq->end_io; | ||
897 | kfree(end_io_wq); | ||
898 | bio_endio(bio, error); | ||
899 | } | ||
900 | } | ||
901 | |||
902 | |||
727 | struct btrfs_root *open_ctree(struct super_block *sb, | 903 | struct btrfs_root *open_ctree(struct super_block *sb, |
728 | struct btrfs_fs_devices *fs_devices) | 904 | struct btrfs_fs_devices *fs_devices) |
729 | { | 905 | { |
@@ -750,11 +926,16 @@ struct btrfs_root *open_ctree(struct super_block *sb, | |||
750 | err = -ENOMEM; | 926 | err = -ENOMEM; |
751 | goto fail; | 927 | goto fail; |
752 | } | 928 | } |
929 | end_io_workqueue = create_workqueue("btrfs-end-io"); | ||
930 | BUG_ON(!end_io_workqueue); | ||
931 | |||
753 | INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_NOFS); | 932 | INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_NOFS); |
754 | INIT_LIST_HEAD(&fs_info->trans_list); | 933 | INIT_LIST_HEAD(&fs_info->trans_list); |
755 | INIT_LIST_HEAD(&fs_info->dead_roots); | 934 | INIT_LIST_HEAD(&fs_info->dead_roots); |
756 | INIT_LIST_HEAD(&fs_info->hashers); | 935 | INIT_LIST_HEAD(&fs_info->hashers); |
936 | INIT_LIST_HEAD(&fs_info->end_io_work_list); | ||
757 | spin_lock_init(&fs_info->hash_lock); | 937 | spin_lock_init(&fs_info->hash_lock); |
938 | spin_lock_init(&fs_info->end_io_work_lock); | ||
758 | spin_lock_init(&fs_info->delalloc_lock); | 939 | spin_lock_init(&fs_info->delalloc_lock); |
759 | spin_lock_init(&fs_info->new_trans_lock); | 940 | spin_lock_init(&fs_info->new_trans_lock); |
760 | 941 | ||
@@ -799,6 +980,7 @@ struct btrfs_root *open_ctree(struct super_block *sb, | |||
799 | fs_info->btree_inode->i_mapping, GFP_NOFS); | 980 | fs_info->btree_inode->i_mapping, GFP_NOFS); |
800 | fs_info->do_barriers = 1; | 981 | fs_info->do_barriers = 1; |
801 | 982 | ||
983 | INIT_WORK(&fs_info->end_io_work, btrfs_end_io_csum); | ||
802 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,18) | 984 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,18) |
803 | INIT_WORK(&fs_info->trans_work, btrfs_transaction_cleaner, fs_info); | 985 | INIT_WORK(&fs_info->trans_work, btrfs_transaction_cleaner, fs_info); |
804 | #else | 986 | #else |
@@ -1044,6 +1226,8 @@ int close_ctree(struct btrfs_root *root) | |||
1044 | extent_io_tree_empty_lru(&BTRFS_I(fs_info->btree_inode)->io_tree); | 1226 | extent_io_tree_empty_lru(&BTRFS_I(fs_info->btree_inode)->io_tree); |
1045 | 1227 | ||
1046 | truncate_inode_pages(fs_info->btree_inode->i_mapping, 0); | 1228 | truncate_inode_pages(fs_info->btree_inode->i_mapping, 0); |
1229 | flush_workqueue(end_io_workqueue); | ||
1230 | destroy_workqueue(end_io_workqueue); | ||
1047 | 1231 | ||
1048 | iput(fs_info->btree_inode); | 1232 | iput(fs_info->btree_inode); |
1049 | #if 0 | 1233 | #if 0 |
@@ -1171,12 +1355,18 @@ int btrfs_read_buffer(struct extent_buffer *buf) | |||
1171 | { | 1355 | { |
1172 | struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root; | 1356 | struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root; |
1173 | struct inode *btree_inode = root->fs_info->btree_inode; | 1357 | struct inode *btree_inode = root->fs_info->btree_inode; |
1174 | return read_extent_buffer_pages(&BTRFS_I(btree_inode)->io_tree, | 1358 | int ret; |
1359 | ret = read_extent_buffer_pages(&BTRFS_I(btree_inode)->io_tree, | ||
1175 | buf, 0, 1, btree_get_extent); | 1360 | buf, 0, 1, btree_get_extent); |
1361 | if (ret == 0) { | ||
1362 | buf->flags |= EXTENT_UPTODATE; | ||
1363 | } | ||
1364 | return ret; | ||
1176 | } | 1365 | } |
1177 | 1366 | ||
1178 | static struct extent_io_ops btree_extent_io_ops = { | 1367 | static struct extent_io_ops btree_extent_io_ops = { |
1179 | .writepage_io_hook = btree_writepage_io_hook, | 1368 | .writepage_io_hook = btree_writepage_io_hook, |
1369 | .readpage_end_io_hook = btree_readpage_end_io_hook, | ||
1180 | .submit_bio_hook = btree_submit_bio_hook, | 1370 | .submit_bio_hook = btree_submit_bio_hook, |
1181 | /* note we're sharing with inode.c for the merge bio hook */ | 1371 | /* note we're sharing with inode.c for the merge bio hook */ |
1182 | .merge_bio_hook = btrfs_merge_bio_hook, | 1372 | .merge_bio_hook = btrfs_merge_bio_hook, |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 0cb742884cdf..283b08a32a43 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -1898,10 +1898,6 @@ struct extent_buffer *__btrfs_alloc_free_block(struct btrfs_trans_handle *trans, | |||
1898 | 1898 | ||
1899 | set_extent_dirty(&trans->transaction->dirty_pages, buf->start, | 1899 | set_extent_dirty(&trans->transaction->dirty_pages, buf->start, |
1900 | buf->start + buf->len - 1, GFP_NOFS); | 1900 | buf->start + buf->len - 1, GFP_NOFS); |
1901 | set_extent_bits(&BTRFS_I(root->fs_info->btree_inode)->io_tree, | ||
1902 | buf->start, buf->start + buf->len - 1, | ||
1903 | EXTENT_CSUM, GFP_NOFS); | ||
1904 | buf->flags |= EXTENT_CSUM; | ||
1905 | if (!btrfs_test_opt(root, SSD)) | 1901 | if (!btrfs_test_opt(root, SSD)) |
1906 | btrfs_set_buffer_defrag(buf); | 1902 | btrfs_set_buffer_defrag(buf); |
1907 | trans->blocks_used++; | 1903 | trans->blocks_used++; |
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 13cc2360e375..cfc383c17a3a 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c | |||
@@ -2592,6 +2592,22 @@ static inline struct page *extent_buffer_page(struct extent_buffer *eb, | |||
2592 | return p; | 2592 | return p; |
2593 | } | 2593 | } |
2594 | 2594 | ||
2595 | int release_extent_buffer_tail_pages(struct extent_buffer *eb) | ||
2596 | { | ||
2597 | unsigned long num_pages = num_extent_pages(eb->start, eb->len); | ||
2598 | struct page *page; | ||
2599 | unsigned long i; | ||
2600 | |||
2601 | if (num_pages == 1) | ||
2602 | return 0; | ||
2603 | for (i = 1; i < num_pages; i++) { | ||
2604 | page = extent_buffer_page(eb, i); | ||
2605 | page_cache_release(page); | ||
2606 | } | ||
2607 | return 0; | ||
2608 | } | ||
2609 | |||
2610 | |||
2595 | int invalidate_extent_lru(struct extent_io_tree *tree, u64 start, | 2611 | int invalidate_extent_lru(struct extent_io_tree *tree, u64 start, |
2596 | unsigned long len) | 2612 | unsigned long len) |
2597 | { | 2613 | { |
@@ -2609,9 +2625,6 @@ int invalidate_extent_lru(struct extent_io_tree *tree, u64 start, | |||
2609 | if (eb->start <= start && eb->start + eb->len > start) { | 2625 | if (eb->start <= start && eb->start + eb->len > start) { |
2610 | eb->flags &= ~EXTENT_UPTODATE; | 2626 | eb->flags &= ~EXTENT_UPTODATE; |
2611 | } | 2627 | } |
2612 | if (eb->start == start) { | ||
2613 | eb->flags &= ~EXTENT_CSUM; | ||
2614 | } | ||
2615 | cur = cur->next; | 2628 | cur = cur->next; |
2616 | } while (cur != lru); | 2629 | } while (cur != lru); |
2617 | out: | 2630 | out: |
@@ -2682,7 +2695,6 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree, | |||
2682 | page_cache_get(page0); | 2695 | page_cache_get(page0); |
2683 | mark_page_accessed(page0); | 2696 | mark_page_accessed(page0); |
2684 | set_page_extent_mapped(page0); | 2697 | set_page_extent_mapped(page0); |
2685 | WARN_ON(!PageUptodate(page0)); | ||
2686 | set_page_extent_head(page0, len); | 2698 | set_page_extent_head(page0, len); |
2687 | } else { | 2699 | } else { |
2688 | i = 0; | 2700 | i = 0; |
@@ -2933,13 +2945,39 @@ int set_extent_buffer_uptodate(struct extent_io_tree *tree, | |||
2933 | } | 2945 | } |
2934 | EXPORT_SYMBOL(set_extent_buffer_uptodate); | 2946 | EXPORT_SYMBOL(set_extent_buffer_uptodate); |
2935 | 2947 | ||
2948 | int extent_range_uptodate(struct extent_io_tree *tree, | ||
2949 | u64 start, u64 end) | ||
2950 | { | ||
2951 | struct page *page; | ||
2952 | int ret; | ||
2953 | int pg_uptodate = 1; | ||
2954 | int uptodate; | ||
2955 | unsigned long index; | ||
2956 | |||
2957 | ret = test_range_bit(tree, start, end, EXTENT_UPTODATE, 1); | ||
2958 | if (ret) | ||
2959 | return 1; | ||
2960 | while(start <= end) { | ||
2961 | index = start >> PAGE_CACHE_SHIFT; | ||
2962 | page = find_get_page(tree->mapping, index); | ||
2963 | uptodate = PageUptodate(page); | ||
2964 | page_cache_release(page); | ||
2965 | if (!uptodate) { | ||
2966 | pg_uptodate = 0; | ||
2967 | break; | ||
2968 | } | ||
2969 | start += PAGE_CACHE_SIZE; | ||
2970 | } | ||
2971 | return pg_uptodate; | ||
2972 | } | ||
2973 | |||
2936 | int extent_buffer_uptodate(struct extent_io_tree *tree, | 2974 | int extent_buffer_uptodate(struct extent_io_tree *tree, |
2937 | struct extent_buffer *eb) | 2975 | struct extent_buffer *eb) |
2938 | { | 2976 | { |
2939 | int ret = 0; | 2977 | int ret = 0; |
2940 | int ret2; | 2978 | int ret2; |
2941 | int num_pages; | 2979 | unsigned long num_pages; |
2942 | int i; | 2980 | unsigned long i; |
2943 | struct page *page; | 2981 | struct page *page; |
2944 | int pg_uptodate = 1; | 2982 | int pg_uptodate = 1; |
2945 | 2983 | ||
@@ -2975,13 +3013,16 @@ int read_extent_buffer_pages(struct extent_io_tree *tree, | |||
2975 | struct page *page; | 3013 | struct page *page; |
2976 | int err; | 3014 | int err; |
2977 | int ret = 0; | 3015 | int ret = 0; |
3016 | int locked_pages = 0; | ||
3017 | int all_uptodate = 1; | ||
3018 | int inc_all_pages = 0; | ||
2978 | unsigned long num_pages; | 3019 | unsigned long num_pages; |
2979 | struct bio *bio = NULL; | 3020 | struct bio *bio = NULL; |
2980 | 3021 | ||
2981 | if (eb->flags & EXTENT_UPTODATE) | 3022 | if (eb->flags & EXTENT_UPTODATE) |
2982 | return 0; | 3023 | return 0; |
2983 | 3024 | ||
2984 | if (0 && test_range_bit(tree, eb->start, eb->start + eb->len - 1, | 3025 | if (test_range_bit(tree, eb->start, eb->start + eb->len - 1, |
2985 | EXTENT_UPTODATE, 1)) { | 3026 | EXTENT_UPTODATE, 1)) { |
2986 | return 0; | 3027 | return 0; |
2987 | } | 3028 | } |
@@ -2997,17 +3038,30 @@ int read_extent_buffer_pages(struct extent_io_tree *tree, | |||
2997 | num_pages = num_extent_pages(eb->start, eb->len); | 3038 | num_pages = num_extent_pages(eb->start, eb->len); |
2998 | for (i = start_i; i < num_pages; i++) { | 3039 | for (i = start_i; i < num_pages; i++) { |
2999 | page = extent_buffer_page(eb, i); | 3040 | page = extent_buffer_page(eb, i); |
3000 | if (PageUptodate(page)) { | ||
3001 | continue; | ||
3002 | } | ||
3003 | if (!wait) { | 3041 | if (!wait) { |
3004 | if (TestSetPageLocked(page)) { | 3042 | if (TestSetPageLocked(page)) |
3005 | continue; | 3043 | goto unlock_exit; |
3006 | } | ||
3007 | } else { | 3044 | } else { |
3008 | lock_page(page); | 3045 | lock_page(page); |
3009 | } | 3046 | } |
3047 | locked_pages++; | ||
3048 | if (!PageUptodate(page)) { | ||
3049 | all_uptodate = 0; | ||
3050 | } | ||
3051 | } | ||
3052 | if (all_uptodate) { | ||
3053 | if (start_i == 0) | ||
3054 | eb->flags |= EXTENT_UPTODATE; | ||
3055 | goto unlock_exit; | ||
3056 | } | ||
3057 | |||
3058 | for (i = start_i; i < num_pages; i++) { | ||
3059 | page = extent_buffer_page(eb, i); | ||
3060 | if (inc_all_pages) | ||
3061 | page_cache_get(page); | ||
3010 | if (!PageUptodate(page)) { | 3062 | if (!PageUptodate(page)) { |
3063 | if (start_i == 0) | ||
3064 | inc_all_pages = 1; | ||
3011 | err = __extent_read_full_page(tree, page, | 3065 | err = __extent_read_full_page(tree, page, |
3012 | get_extent, &bio); | 3066 | get_extent, &bio); |
3013 | if (err) { | 3067 | if (err) { |
@@ -3034,6 +3088,16 @@ int read_extent_buffer_pages(struct extent_io_tree *tree, | |||
3034 | if (!ret) | 3088 | if (!ret) |
3035 | eb->flags |= EXTENT_UPTODATE; | 3089 | eb->flags |= EXTENT_UPTODATE; |
3036 | return ret; | 3090 | return ret; |
3091 | |||
3092 | unlock_exit: | ||
3093 | i = start_i; | ||
3094 | while(locked_pages > 0) { | ||
3095 | page = extent_buffer_page(eb, i); | ||
3096 | i++; | ||
3097 | unlock_page(page); | ||
3098 | locked_pages--; | ||
3099 | } | ||
3100 | return ret; | ||
3037 | } | 3101 | } |
3038 | EXPORT_SYMBOL(read_extent_buffer_pages); | 3102 | EXPORT_SYMBOL(read_extent_buffer_pages); |
3039 | 3103 | ||
@@ -3048,7 +3112,6 @@ void read_extent_buffer(struct extent_buffer *eb, void *dstv, | |||
3048 | char *dst = (char *)dstv; | 3112 | char *dst = (char *)dstv; |
3049 | size_t start_offset = eb->start & ((u64)PAGE_CACHE_SIZE - 1); | 3113 | size_t start_offset = eb->start & ((u64)PAGE_CACHE_SIZE - 1); |
3050 | unsigned long i = (start_offset + start) >> PAGE_CACHE_SHIFT; | 3114 | unsigned long i = (start_offset + start) >> PAGE_CACHE_SHIFT; |
3051 | unsigned long num_pages = num_extent_pages(eb->start, eb->len); | ||
3052 | 3115 | ||
3053 | WARN_ON(start > eb->len); | 3116 | WARN_ON(start > eb->len); |
3054 | WARN_ON(start + len > eb->start + eb->len); | 3117 | WARN_ON(start + len > eb->start + eb->len); |
@@ -3057,11 +3120,6 @@ void read_extent_buffer(struct extent_buffer *eb, void *dstv, | |||
3057 | 3120 | ||
3058 | while(len > 0) { | 3121 | while(len > 0) { |
3059 | page = extent_buffer_page(eb, i); | 3122 | page = extent_buffer_page(eb, i); |
3060 | if (!PageUptodate(page)) { | ||
3061 | printk("page %lu not up to date i %lu, total %lu, len %lu\n", page->index, i, num_pages, eb->len); | ||
3062 | WARN_ON(1); | ||
3063 | } | ||
3064 | WARN_ON(!PageUptodate(page)); | ||
3065 | 3123 | ||
3066 | cur = min(len, (PAGE_CACHE_SIZE - offset)); | 3124 | cur = min(len, (PAGE_CACHE_SIZE - offset)); |
3067 | kaddr = kmap_atomic(page, KM_USER1); | 3125 | kaddr = kmap_atomic(page, KM_USER1); |
@@ -3105,7 +3163,6 @@ printk("bad mapping eb start %Lu len %lu, wanted %lu %lu\n", eb->start, eb->len, | |||
3105 | } | 3163 | } |
3106 | 3164 | ||
3107 | p = extent_buffer_page(eb, i); | 3165 | p = extent_buffer_page(eb, i); |
3108 | WARN_ON(!PageUptodate(p)); | ||
3109 | kaddr = kmap_atomic(p, km); | 3166 | kaddr = kmap_atomic(p, km); |
3110 | *token = kaddr; | 3167 | *token = kaddr; |
3111 | *map = kaddr + offset; | 3168 | *map = kaddr + offset; |
@@ -3165,7 +3222,6 @@ int memcmp_extent_buffer(struct extent_buffer *eb, const void *ptrv, | |||
3165 | 3222 | ||
3166 | while(len > 0) { | 3223 | while(len > 0) { |
3167 | page = extent_buffer_page(eb, i); | 3224 | page = extent_buffer_page(eb, i); |
3168 | WARN_ON(!PageUptodate(page)); | ||
3169 | 3225 | ||
3170 | cur = min(len, (PAGE_CACHE_SIZE - offset)); | 3226 | cur = min(len, (PAGE_CACHE_SIZE - offset)); |
3171 | 3227 | ||
diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index d9f5bc4dbd7f..9d2991d1d3ce 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h | |||
@@ -13,7 +13,6 @@ | |||
13 | #define EXTENT_DEFRAG (1 << 6) | 13 | #define EXTENT_DEFRAG (1 << 6) |
14 | #define EXTENT_DEFRAG_DONE (1 << 7) | 14 | #define EXTENT_DEFRAG_DONE (1 << 7) |
15 | #define EXTENT_BUFFER_FILLED (1 << 8) | 15 | #define EXTENT_BUFFER_FILLED (1 << 8) |
16 | #define EXTENT_CSUM (1 << 9) | ||
17 | #define EXTENT_IOBITS (EXTENT_LOCKED | EXTENT_WRITEBACK) | 16 | #define EXTENT_IOBITS (EXTENT_LOCKED | EXTENT_WRITEBACK) |
18 | 17 | ||
19 | /* | 18 | /* |
@@ -218,4 +217,7 @@ int map_private_extent_buffer(struct extent_buffer *eb, unsigned long offset, | |||
218 | void unmap_extent_buffer(struct extent_buffer *eb, char *token, int km); | 217 | void unmap_extent_buffer(struct extent_buffer *eb, char *token, int km); |
219 | int invalidate_extent_lru(struct extent_io_tree *tree, u64 start, | 218 | int invalidate_extent_lru(struct extent_io_tree *tree, u64 start, |
220 | unsigned long len); | 219 | unsigned long len); |
220 | int release_extent_buffer_tail_pages(struct extent_buffer *eb); | ||
221 | int extent_range_uptodate(struct extent_io_tree *tree, | ||
222 | u64 start, u64 end); | ||
221 | #endif | 223 | #endif |
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 5e9f69244f9f..1ed179c020af 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -843,7 +843,7 @@ void btrfs_transaction_flush_work(struct btrfs_root *root) | |||
843 | 843 | ||
844 | void __init btrfs_init_transaction_sys(void) | 844 | void __init btrfs_init_transaction_sys(void) |
845 | { | 845 | { |
846 | trans_wq = create_workqueue("btrfs"); | 846 | trans_wq = create_workqueue("btrfs-transaction"); |
847 | } | 847 | } |
848 | 848 | ||
849 | void btrfs_exit_transaction_sys(void) | 849 | void btrfs_exit_transaction_sys(void) |