diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-10-15 16:19:22 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:03:56 -0400 |
commit | 19c00ddcc31ad4bdfb86b57085e06d6135b9b1d7 (patch) | |
tree | a48cbaac47070057912c1b35d270b61b7e14386c /fs | |
parent | 0f82731fc56448c2733f58e1f5db6c2cbfc90652 (diff) |
Btrfs: Add back metadata checksumming
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/ctree.h | 2 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 215 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 4 | ||||
-rw-r--r-- | fs/btrfs/extent_map.c | 83 | ||||
-rw-r--r-- | fs/btrfs/extent_map.h | 18 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 4 |
6 files changed, 245 insertions, 81 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index d1c6f023a302..1af0a966f85b 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -310,9 +310,11 @@ struct btrfs_fs_info { | |||
310 | struct extent_buffer *sb_buffer; | 310 | struct extent_buffer *sb_buffer; |
311 | struct super_block *sb; | 311 | struct super_block *sb; |
312 | struct inode *btree_inode; | 312 | struct inode *btree_inode; |
313 | spinlock_t hash_lock; | ||
313 | struct mutex trans_mutex; | 314 | struct mutex trans_mutex; |
314 | struct mutex fs_mutex; | 315 | struct mutex fs_mutex; |
315 | struct list_head trans_list; | 316 | struct list_head trans_list; |
317 | struct list_head hashers; | ||
316 | struct list_head dead_roots; | 318 | struct list_head dead_roots; |
317 | struct delayed_work trans_work; | 319 | struct delayed_work trans_work; |
318 | struct kobject super_kobj; | 320 | struct kobject super_kobj; |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 16f0260fca66..1176e5420c56 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -60,7 +60,7 @@ struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root, | |||
60 | struct extent_buffer *eb; | 60 | struct extent_buffer *eb; |
61 | 61 | ||
62 | eb = alloc_extent_buffer(&BTRFS_I(btree_inode)->extent_tree, | 62 | eb = alloc_extent_buffer(&BTRFS_I(btree_inode)->extent_tree, |
63 | bytenr, blocksize, GFP_NOFS); | 63 | bytenr, blocksize, NULL, GFP_NOFS); |
64 | return eb; | 64 | return eb; |
65 | } | 65 | } |
66 | 66 | ||
@@ -99,10 +99,102 @@ out: | |||
99 | return em; | 99 | return em; |
100 | } | 100 | } |
101 | 101 | ||
102 | u32 btrfs_csum_data(struct btrfs_root *root, char *data, u32 seed, size_t len) | ||
103 | { | ||
104 | return crc32c(seed, data, len); | ||
105 | } | ||
106 | |||
107 | void btrfs_csum_final(u32 crc, char *result) | ||
108 | { | ||
109 | *(__le32 *)result = ~cpu_to_le32(crc); | ||
110 | } | ||
111 | |||
112 | static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf, | ||
113 | int verify) | ||
114 | { | ||
115 | char result[BTRFS_CRC32_SIZE]; | ||
116 | unsigned long len; | ||
117 | unsigned long cur_len; | ||
118 | unsigned long offset = BTRFS_CSUM_SIZE; | ||
119 | char *map_token = NULL; | ||
120 | char *kaddr; | ||
121 | unsigned long map_start; | ||
122 | unsigned long map_len; | ||
123 | int err; | ||
124 | u32 crc = ~(u32)0; | ||
125 | |||
126 | len = buf->len - offset; | ||
127 | while(len > 0) { | ||
128 | err = map_private_extent_buffer(buf, offset, 32, | ||
129 | &map_token, &kaddr, | ||
130 | &map_start, &map_len, KM_USER0); | ||
131 | if (err) { | ||
132 | printk("failed to map extent buffer! %lu\n", | ||
133 | offset); | ||
134 | return 1; | ||
135 | } | ||
136 | cur_len = min(len, map_len - (offset - map_start)); | ||
137 | crc = btrfs_csum_data(root, kaddr + offset - map_start, | ||
138 | crc, cur_len); | ||
139 | len -= cur_len; | ||
140 | offset += cur_len; | ||
141 | unmap_extent_buffer(buf, map_token, KM_USER0); | ||
142 | } | ||
143 | btrfs_csum_final(crc, result); | ||
144 | |||
145 | if (verify) { | ||
146 | if (memcmp_extent_buffer(buf, result, 0, BTRFS_CRC32_SIZE)) { | ||
147 | printk("btrfs: %s checksum verify failed on %llu\n", | ||
148 | root->fs_info->sb->s_id, | ||
149 | buf->start); | ||
150 | return 1; | ||
151 | } | ||
152 | } else { | ||
153 | write_extent_buffer(buf, result, 0, BTRFS_CRC32_SIZE); | ||
154 | } | ||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | |||
159 | int csum_dirty_buffer(struct btrfs_root *root, struct page *page) | ||
160 | { | ||
161 | struct extent_map_tree *tree; | ||
162 | u64 start = page->index << PAGE_CACHE_SHIFT; | ||
163 | u64 found_start; | ||
164 | int found_level; | ||
165 | unsigned long len; | ||
166 | struct extent_buffer *eb; | ||
167 | tree = &BTRFS_I(page->mapping->host)->extent_tree; | ||
168 | |||
169 | if (page->private == EXTENT_PAGE_PRIVATE) | ||
170 | goto out; | ||
171 | if (!page->private) | ||
172 | goto out; | ||
173 | len = page->private >> 2; | ||
174 | if (len == 0) { | ||
175 | WARN_ON(1); | ||
176 | } | ||
177 | eb = alloc_extent_buffer(tree, start, len, page, GFP_NOFS); | ||
178 | read_extent_buffer_pages(tree, eb, start + PAGE_CACHE_SIZE, 1); | ||
179 | found_start = btrfs_header_bytenr(eb); | ||
180 | if (found_start != start) { | ||
181 | printk("warning: eb start incorrect %Lu buffer %Lu len %lu\n", | ||
182 | start, found_start, len); | ||
183 | } | ||
184 | found_level = btrfs_header_level(eb); | ||
185 | csum_tree_block(root, eb, 0); | ||
186 | free_extent_buffer(eb); | ||
187 | out: | ||
188 | return 0; | ||
189 | } | ||
190 | |||
102 | static int btree_writepage(struct page *page, struct writeback_control *wbc) | 191 | static int btree_writepage(struct page *page, struct writeback_control *wbc) |
103 | { | 192 | { |
104 | struct extent_map_tree *tree; | 193 | struct extent_map_tree *tree; |
194 | struct btrfs_root *root = BTRFS_I(page->mapping->host)->root; | ||
105 | tree = &BTRFS_I(page->mapping->host)->extent_tree; | 195 | tree = &BTRFS_I(page->mapping->host)->extent_tree; |
196 | |||
197 | csum_dirty_buffer(root, page); | ||
106 | return extent_write_full_page(tree, page, btree_get_extent, wbc); | 198 | return extent_write_full_page(tree, page, btree_get_extent, wbc); |
107 | } | 199 | } |
108 | int btree_readpage(struct file *file, struct page *page) | 200 | int btree_readpage(struct file *file, struct page *page) |
@@ -117,7 +209,6 @@ static int btree_releasepage(struct page *page, gfp_t unused_gfp_flags) | |||
117 | struct extent_map_tree *tree; | 209 | struct extent_map_tree *tree; |
118 | int ret; | 210 | int ret; |
119 | 211 | ||
120 | BUG_ON(page->private != 1); | ||
121 | tree = &BTRFS_I(page->mapping->host)->extent_tree; | 212 | tree = &BTRFS_I(page->mapping->host)->extent_tree; |
122 | ret = try_release_extent_mapping(tree, page); | 213 | ret = try_release_extent_mapping(tree, page); |
123 | if (ret == 1) { | 214 | if (ret == 1) { |
@@ -136,46 +227,6 @@ static void btree_invalidatepage(struct page *page, unsigned long offset) | |||
136 | btree_releasepage(page, GFP_NOFS); | 227 | btree_releasepage(page, GFP_NOFS); |
137 | } | 228 | } |
138 | 229 | ||
139 | int btrfs_csum_data(struct btrfs_root * root, char *data, size_t len, | ||
140 | char *result) | ||
141 | { | ||
142 | return 0; | ||
143 | #if 0 | ||
144 | u32 crc; | ||
145 | crc = crc32c(0, data, len); | ||
146 | memcpy(result, &crc, BTRFS_CRC32_SIZE); | ||
147 | return 0; | ||
148 | #endif | ||
149 | } | ||
150 | |||
151 | #if 0 | ||
152 | static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf, | ||
153 | int verify) | ||
154 | { | ||
155 | return 0; | ||
156 | char result[BTRFS_CRC32_SIZE]; | ||
157 | int ret; | ||
158 | struct btrfs_node *node; | ||
159 | |||
160 | ret = btrfs_csum_data(root, bh->b_data + BTRFS_CSUM_SIZE, | ||
161 | bh->b_size - BTRFS_CSUM_SIZE, result); | ||
162 | if (ret) | ||
163 | return ret; | ||
164 | if (verify) { | ||
165 | if (memcmp(bh->b_data, result, BTRFS_CRC32_SIZE)) { | ||
166 | printk("btrfs: %s checksum verify failed on %llu\n", | ||
167 | root->fs_info->sb->s_id, | ||
168 | (unsigned long long)bh_blocknr(bh)); | ||
169 | return 1; | ||
170 | } | ||
171 | } else { | ||
172 | node = btrfs_buffer_node(bh); | ||
173 | memcpy(node->header.csum, result, BTRFS_CRC32_SIZE); | ||
174 | } | ||
175 | return 0; | ||
176 | } | ||
177 | #endif | ||
178 | |||
179 | #if 0 | 230 | #if 0 |
180 | static int btree_writepage(struct page *page, struct writeback_control *wbc) | 231 | static int btree_writepage(struct page *page, struct writeback_control *wbc) |
181 | { | 232 | { |
@@ -215,7 +266,7 @@ int readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize) | |||
215 | if (!buf) | 266 | if (!buf) |
216 | return 0; | 267 | return 0; |
217 | read_extent_buffer_pages(&BTRFS_I(btree_inode)->extent_tree, | 268 | read_extent_buffer_pages(&BTRFS_I(btree_inode)->extent_tree, |
218 | buf, 0); | 269 | buf, 0, 0); |
219 | free_extent_buffer(buf); | 270 | free_extent_buffer(buf); |
220 | return ret; | 271 | return ret; |
221 | } | 272 | } |
@@ -225,12 +276,29 @@ struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr, | |||
225 | { | 276 | { |
226 | struct extent_buffer *buf = NULL; | 277 | struct extent_buffer *buf = NULL; |
227 | struct inode *btree_inode = root->fs_info->btree_inode; | 278 | struct inode *btree_inode = root->fs_info->btree_inode; |
279 | struct extent_map_tree *extent_tree; | ||
280 | int ret; | ||
281 | |||
282 | extent_tree = &BTRFS_I(btree_inode)->extent_tree; | ||
228 | 283 | ||
229 | buf = btrfs_find_create_tree_block(root, bytenr, blocksize); | 284 | buf = btrfs_find_create_tree_block(root, bytenr, blocksize); |
230 | if (!buf) | 285 | if (!buf) |
231 | return NULL; | 286 | return NULL; |
232 | read_extent_buffer_pages(&BTRFS_I(btree_inode)->extent_tree, | 287 | read_extent_buffer_pages(&BTRFS_I(btree_inode)->extent_tree, |
233 | buf, 1); | 288 | buf, 0, 1); |
289 | if (buf->flags & EXTENT_CSUM) { | ||
290 | return buf; | ||
291 | } | ||
292 | if (test_range_bit(extent_tree, buf->start, buf->start + buf->len - 1, | ||
293 | EXTENT_CSUM, 1)) { | ||
294 | buf->flags |= EXTENT_CSUM; | ||
295 | return buf; | ||
296 | } | ||
297 | ret = csum_tree_block(root, buf, 1); | ||
298 | set_extent_bits(extent_tree, buf->start, | ||
299 | buf->start + buf->len - 1, | ||
300 | EXTENT_CSUM, GFP_NOFS); | ||
301 | buf->flags |= EXTENT_CSUM; | ||
234 | return buf; | 302 | return buf; |
235 | } | 303 | } |
236 | 304 | ||
@@ -251,13 +319,6 @@ int wait_on_tree_block_writeback(struct btrfs_root *root, | |||
251 | return 0; | 319 | return 0; |
252 | } | 320 | } |
253 | 321 | ||
254 | int set_tree_block_dirty(struct btrfs_root *root, struct extent_buffer *buf) | ||
255 | { | ||
256 | struct inode *btree_inode = root->fs_info->btree_inode; | ||
257 | set_extent_buffer_dirty(&BTRFS_I(btree_inode)->extent_tree, buf); | ||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, | 322 | static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, |
262 | struct btrfs_root *root, | 323 | struct btrfs_root *root, |
263 | struct btrfs_fs_info *fs_info, | 324 | struct btrfs_fs_info *fs_info, |
@@ -416,7 +477,24 @@ struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, | |||
416 | 477 | ||
417 | return root; | 478 | return root; |
418 | } | 479 | } |
419 | 480 | #if 0 | |
481 | static int add_hasher(struct btrfs_fs_info *info, char *type) { | ||
482 | struct btrfs_hasher *hasher; | ||
483 | |||
484 | hasher = kmalloc(sizeof(*hasher), GFP_NOFS); | ||
485 | if (!hasher) | ||
486 | return -ENOMEM; | ||
487 | hasher->hash_tfm = crypto_alloc_hash(type, 0, CRYPTO_ALG_ASYNC); | ||
488 | if (!hasher->hash_tfm) { | ||
489 | kfree(hasher); | ||
490 | return -EINVAL; | ||
491 | } | ||
492 | spin_lock(&info->hash_lock); | ||
493 | list_add(&hasher->list, &info->hashers); | ||
494 | spin_unlock(&info->hash_lock); | ||
495 | return 0; | ||
496 | } | ||
497 | #endif | ||
420 | struct btrfs_root *open_ctree(struct super_block *sb) | 498 | struct btrfs_root *open_ctree(struct super_block *sb) |
421 | { | 499 | { |
422 | u32 sectorsize; | 500 | u32 sectorsize; |
@@ -440,6 +518,9 @@ struct btrfs_root *open_ctree(struct super_block *sb) | |||
440 | INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_NOFS); | 518 | INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_NOFS); |
441 | INIT_LIST_HEAD(&fs_info->trans_list); | 519 | INIT_LIST_HEAD(&fs_info->trans_list); |
442 | INIT_LIST_HEAD(&fs_info->dead_roots); | 520 | INIT_LIST_HEAD(&fs_info->dead_roots); |
521 | INIT_LIST_HEAD(&fs_info->hashers); | ||
522 | spin_lock_init(&fs_info->hash_lock); | ||
523 | |||
443 | memset(&fs_info->super_kobj, 0, sizeof(fs_info->super_kobj)); | 524 | memset(&fs_info->super_kobj, 0, sizeof(fs_info->super_kobj)); |
444 | init_completion(&fs_info->kobj_unregister); | 525 | init_completion(&fs_info->kobj_unregister); |
445 | sb_set_blocksize(sb, 4096); | 526 | sb_set_blocksize(sb, 4096); |
@@ -479,6 +560,14 @@ struct btrfs_root *open_ctree(struct super_block *sb) | |||
479 | mutex_init(&fs_info->trans_mutex); | 560 | mutex_init(&fs_info->trans_mutex); |
480 | mutex_init(&fs_info->fs_mutex); | 561 | mutex_init(&fs_info->fs_mutex); |
481 | 562 | ||
563 | #if 0 | ||
564 | ret = add_hasher(fs_info, "crc32c"); | ||
565 | if (ret) { | ||
566 | printk("btrfs: failed hash setup, modprobe cryptomgr?\n"); | ||
567 | err = -ENOMEM; | ||
568 | goto fail_iput; | ||
569 | } | ||
570 | #endif | ||
482 | __setup_root(512, 512, 512, tree_root, | 571 | __setup_root(512, 512, 512, tree_root, |
483 | fs_info, BTRFS_ROOT_TREE_OBJECTID); | 572 | fs_info, BTRFS_ROOT_TREE_OBJECTID); |
484 | 573 | ||
@@ -509,25 +598,21 @@ struct btrfs_root *open_ctree(struct super_block *sb) | |||
509 | i_size_write(fs_info->btree_inode, | 598 | i_size_write(fs_info->btree_inode, |
510 | btrfs_super_total_bytes(disk_super)); | 599 | btrfs_super_total_bytes(disk_super)); |
511 | 600 | ||
512 | |||
513 | if (strncmp((char *)(&disk_super->magic), BTRFS_MAGIC, | 601 | if (strncmp((char *)(&disk_super->magic), BTRFS_MAGIC, |
514 | sizeof(disk_super->magic))) { | 602 | sizeof(disk_super->magic))) { |
515 | printk("btrfs: valid FS not found on %s\n", sb->s_id); | 603 | printk("btrfs: valid FS not found on %s\n", sb->s_id); |
516 | goto fail_sb_buffer; | 604 | goto fail_sb_buffer; |
517 | } | 605 | } |
606 | |||
518 | blocksize = btrfs_level_size(tree_root, | 607 | blocksize = btrfs_level_size(tree_root, |
519 | btrfs_super_root_level(disk_super)); | 608 | btrfs_super_root_level(disk_super)); |
609 | |||
520 | tree_root->node = read_tree_block(tree_root, | 610 | tree_root->node = read_tree_block(tree_root, |
521 | btrfs_super_root(disk_super), | 611 | btrfs_super_root(disk_super), |
522 | blocksize); | 612 | blocksize); |
523 | if (!tree_root->node) | 613 | if (!tree_root->node) |
524 | goto fail_sb_buffer; | 614 | goto fail_sb_buffer; |
525 | 615 | ||
526 | #if 0 | ||
527 | btrfs_print_leaf(tree_root, tree_root->node); | ||
528 | err = -EIO; | ||
529 | goto fail_tree_root; | ||
530 | #endif | ||
531 | mutex_lock(&fs_info->fs_mutex); | 616 | mutex_lock(&fs_info->fs_mutex); |
532 | 617 | ||
533 | ret = find_and_setup_root(tree_root, fs_info, | 618 | ret = find_and_setup_root(tree_root, fs_info, |
@@ -634,9 +719,19 @@ int close_ctree(struct btrfs_root *root) | |||
634 | 719 | ||
635 | btrfs_free_block_groups(root->fs_info); | 720 | btrfs_free_block_groups(root->fs_info); |
636 | del_fs_roots(fs_info); | 721 | del_fs_roots(fs_info); |
637 | extent_map_tree_cleanup(&BTRFS_I(fs_info->btree_inode)->extent_tree); | 722 | extent_map_tree_empty_lru(&BTRFS_I(fs_info->btree_inode)->extent_tree); |
638 | truncate_inode_pages(fs_info->btree_inode->i_mapping, 0); | 723 | truncate_inode_pages(fs_info->btree_inode->i_mapping, 0); |
639 | iput(fs_info->btree_inode); | 724 | iput(fs_info->btree_inode); |
725 | #if 0 | ||
726 | while(!list_empty(&fs_info->hashers)) { | ||
727 | struct btrfs_hasher *hasher; | ||
728 | hasher = list_entry(fs_info->hashers.next, struct btrfs_hasher, | ||
729 | hashers); | ||
730 | list_del(&hasher->hashers); | ||
731 | crypto_free_hash(&fs_info->hash_tfm); | ||
732 | kfree(hasher); | ||
733 | } | ||
734 | #endif | ||
640 | kfree(fs_info->extent_root); | 735 | kfree(fs_info->extent_root); |
641 | kfree(fs_info->tree_root); | 736 | kfree(fs_info->tree_root); |
642 | return 0; | 737 | return 0; |
@@ -733,5 +828,5 @@ int btrfs_read_buffer(struct extent_buffer *buf) | |||
733 | struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root; | 828 | struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root; |
734 | struct inode *btree_inode = root->fs_info->btree_inode; | 829 | struct inode *btree_inode = root->fs_info->btree_inode; |
735 | return read_extent_buffer_pages(&BTRFS_I(btree_inode)->extent_tree, | 830 | return read_extent_buffer_pages(&BTRFS_I(btree_inode)->extent_tree, |
736 | buf, 1); | 831 | buf, 0, 1); |
737 | } | 832 | } |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index e4e68ea96483..6b2f2b414fa1 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -1178,6 +1178,10 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans, | |||
1178 | btrfs_set_buffer_uptodate(buf); | 1178 | btrfs_set_buffer_uptodate(buf); |
1179 | set_extent_dirty(&trans->transaction->dirty_pages, buf->start, | 1179 | set_extent_dirty(&trans->transaction->dirty_pages, buf->start, |
1180 | buf->start + buf->len - 1, GFP_NOFS); | 1180 | buf->start + buf->len - 1, GFP_NOFS); |
1181 | set_extent_bits(&BTRFS_I(root->fs_info->btree_inode)->extent_tree, | ||
1182 | buf->start, buf->start + buf->len - 1, | ||
1183 | EXTENT_CSUM, GFP_NOFS); | ||
1184 | buf->flags |= EXTENT_CSUM; | ||
1181 | btrfs_set_buffer_defrag(buf); | 1185 | btrfs_set_buffer_defrag(buf); |
1182 | trans->blocks_used++; | 1186 | trans->blocks_used++; |
1183 | return buf; | 1187 | return buf; |
diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c index f8aaba8a30a2..2a8bc4bd43a9 100644 --- a/fs/btrfs/extent_map.c +++ b/fs/btrfs/extent_map.c | |||
@@ -81,7 +81,7 @@ void extent_map_tree_init(struct extent_map_tree *tree, | |||
81 | } | 81 | } |
82 | EXPORT_SYMBOL(extent_map_tree_init); | 82 | EXPORT_SYMBOL(extent_map_tree_init); |
83 | 83 | ||
84 | void extent_map_tree_cleanup(struct extent_map_tree *tree) | 84 | void extent_map_tree_empty_lru(struct extent_map_tree *tree) |
85 | { | 85 | { |
86 | struct extent_buffer *eb; | 86 | struct extent_buffer *eb; |
87 | while(!list_empty(&tree->buffer_lru)) { | 87 | while(!list_empty(&tree->buffer_lru)) { |
@@ -91,7 +91,7 @@ void extent_map_tree_cleanup(struct extent_map_tree *tree) | |||
91 | free_extent_buffer(eb); | 91 | free_extent_buffer(eb); |
92 | } | 92 | } |
93 | } | 93 | } |
94 | EXPORT_SYMBOL(extent_map_tree_cleanup); | 94 | EXPORT_SYMBOL(extent_map_tree_empty_lru); |
95 | 95 | ||
96 | struct extent_map *alloc_extent_map(gfp_t mask) | 96 | struct extent_map *alloc_extent_map(gfp_t mask) |
97 | { | 97 | { |
@@ -1464,7 +1464,7 @@ void set_page_extent_mapped(struct page *page) | |||
1464 | if (!PagePrivate(page)) { | 1464 | if (!PagePrivate(page)) { |
1465 | SetPagePrivate(page); | 1465 | SetPagePrivate(page); |
1466 | WARN_ON(!page->mapping->a_ops->invalidatepage); | 1466 | WARN_ON(!page->mapping->a_ops->invalidatepage); |
1467 | set_page_private(page, 1); | 1467 | set_page_private(page, EXTENT_PAGE_PRIVATE); |
1468 | page_cache_get(page); | 1468 | page_cache_get(page); |
1469 | } | 1469 | } |
1470 | } | 1470 | } |
@@ -1979,8 +1979,9 @@ static struct extent_buffer *__alloc_extent_buffer(struct extent_map_tree *tree, | |||
1979 | 1979 | ||
1980 | spin_lock(&tree->lru_lock); | 1980 | spin_lock(&tree->lru_lock); |
1981 | eb = find_lru(tree, start, len); | 1981 | eb = find_lru(tree, start, len); |
1982 | if (eb) | 1982 | if (eb) { |
1983 | goto lru_add; | 1983 | goto lru_add; |
1984 | } | ||
1984 | spin_unlock(&tree->lru_lock); | 1985 | spin_unlock(&tree->lru_lock); |
1985 | 1986 | ||
1986 | if (eb) { | 1987 | if (eb) { |
@@ -2007,6 +2008,7 @@ static void __free_extent_buffer(struct extent_buffer *eb) | |||
2007 | 2008 | ||
2008 | struct extent_buffer *alloc_extent_buffer(struct extent_map_tree *tree, | 2009 | struct extent_buffer *alloc_extent_buffer(struct extent_map_tree *tree, |
2009 | u64 start, unsigned long len, | 2010 | u64 start, unsigned long len, |
2011 | struct page *page0, | ||
2010 | gfp_t mask) | 2012 | gfp_t mask) |
2011 | { | 2013 | { |
2012 | unsigned long num_pages = num_extent_pages(start, len); | 2014 | unsigned long num_pages = num_extent_pages(start, len); |
@@ -2024,7 +2026,18 @@ struct extent_buffer *alloc_extent_buffer(struct extent_map_tree *tree, | |||
2024 | if (eb->flags & EXTENT_BUFFER_FILLED) | 2026 | if (eb->flags & EXTENT_BUFFER_FILLED) |
2025 | return eb; | 2027 | return eb; |
2026 | 2028 | ||
2027 | for (i = 0; i < num_pages; i++, index++) { | 2029 | if (page0) { |
2030 | eb->first_page = page0; | ||
2031 | i = 1; | ||
2032 | index++; | ||
2033 | page_cache_get(page0); | ||
2034 | set_page_extent_mapped(page0); | ||
2035 | set_page_private(page0, EXTENT_PAGE_PRIVATE_FIRST_PAGE | | ||
2036 | len << 2); | ||
2037 | } else { | ||
2038 | i = 0; | ||
2039 | } | ||
2040 | for (; i < num_pages; i++, index++) { | ||
2028 | p = find_or_create_page(mapping, index, mask | __GFP_HIGHMEM); | 2041 | p = find_or_create_page(mapping, index, mask | __GFP_HIGHMEM); |
2029 | if (!p) { | 2042 | if (!p) { |
2030 | WARN_ON(1); | 2043 | WARN_ON(1); |
@@ -2036,8 +2049,13 @@ struct extent_buffer *alloc_extent_buffer(struct extent_map_tree *tree, | |||
2036 | goto fail; | 2049 | goto fail; |
2037 | } | 2050 | } |
2038 | set_page_extent_mapped(p); | 2051 | set_page_extent_mapped(p); |
2039 | if (i == 0) | 2052 | if (i == 0) { |
2040 | eb->first_page = p; | 2053 | eb->first_page = p; |
2054 | set_page_private(p, EXTENT_PAGE_PRIVATE_FIRST_PAGE | | ||
2055 | len << 2); | ||
2056 | } else { | ||
2057 | set_page_private(p, EXTENT_PAGE_PRIVATE); | ||
2058 | } | ||
2041 | if (!PageUptodate(p)) | 2059 | if (!PageUptodate(p)) |
2042 | uptodate = 0; | 2060 | uptodate = 0; |
2043 | unlock_page(p); | 2061 | unlock_page(p); |
@@ -2057,8 +2075,7 @@ struct extent_buffer *find_extent_buffer(struct extent_map_tree *tree, | |||
2057 | gfp_t mask) | 2075 | gfp_t mask) |
2058 | { | 2076 | { |
2059 | unsigned long num_pages = num_extent_pages(start, len); | 2077 | unsigned long num_pages = num_extent_pages(start, len); |
2060 | unsigned long i; | 2078 | unsigned long i; unsigned long index = start >> PAGE_CACHE_SHIFT; |
2061 | unsigned long index = start >> PAGE_CACHE_SHIFT; | ||
2062 | struct extent_buffer *eb; | 2079 | struct extent_buffer *eb; |
2063 | struct page *p; | 2080 | struct page *p; |
2064 | struct address_space *mapping = tree->mapping; | 2081 | struct address_space *mapping = tree->mapping; |
@@ -2082,8 +2099,15 @@ struct extent_buffer *find_extent_buffer(struct extent_map_tree *tree, | |||
2082 | goto fail; | 2099 | goto fail; |
2083 | } | 2100 | } |
2084 | set_page_extent_mapped(p); | 2101 | set_page_extent_mapped(p); |
2085 | if (i == 0) | 2102 | |
2103 | if (i == 0) { | ||
2086 | eb->first_page = p; | 2104 | eb->first_page = p; |
2105 | set_page_private(p, EXTENT_PAGE_PRIVATE_FIRST_PAGE | | ||
2106 | len << 2); | ||
2107 | } else { | ||
2108 | set_page_private(p, EXTENT_PAGE_PRIVATE); | ||
2109 | } | ||
2110 | |||
2087 | if (!PageUptodate(p)) | 2111 | if (!PageUptodate(p)) |
2088 | uptodate = 0; | 2112 | uptodate = 0; |
2089 | unlock_page(p); | 2113 | unlock_page(p); |
@@ -2174,7 +2198,21 @@ int set_extent_buffer_dirty(struct extent_map_tree *tree, | |||
2174 | 2198 | ||
2175 | num_pages = num_extent_pages(eb->start, eb->len); | 2199 | num_pages = num_extent_pages(eb->start, eb->len); |
2176 | for (i = 0; i < num_pages; i++) { | 2200 | for (i = 0; i < num_pages; i++) { |
2201 | struct page *page = extent_buffer_page(eb, i); | ||
2202 | /* writepage may need to do something special for the | ||
2203 | * first page, we have to make sure page->private is | ||
2204 | * properly set. releasepage may drop page->private | ||
2205 | * on us if the page isn't already dirty. | ||
2206 | */ | ||
2207 | if (i == 0) { | ||
2208 | lock_page(page); | ||
2209 | set_page_private(page, | ||
2210 | EXTENT_PAGE_PRIVATE_FIRST_PAGE | | ||
2211 | eb->len << 2); | ||
2212 | } | ||
2177 | __set_page_dirty_nobuffers(extent_buffer_page(eb, i)); | 2213 | __set_page_dirty_nobuffers(extent_buffer_page(eb, i)); |
2214 | if (i == 0) | ||
2215 | unlock_page(page); | ||
2178 | } | 2216 | } |
2179 | return set_extent_dirty(tree, eb->start, | 2217 | return set_extent_dirty(tree, eb->start, |
2180 | eb->start + eb->len - 1, GFP_NOFS); | 2218 | eb->start + eb->len - 1, GFP_NOFS); |
@@ -2217,9 +2255,12 @@ int extent_buffer_uptodate(struct extent_map_tree *tree, | |||
2217 | EXPORT_SYMBOL(extent_buffer_uptodate); | 2255 | EXPORT_SYMBOL(extent_buffer_uptodate); |
2218 | 2256 | ||
2219 | int read_extent_buffer_pages(struct extent_map_tree *tree, | 2257 | int read_extent_buffer_pages(struct extent_map_tree *tree, |
2220 | struct extent_buffer *eb, int wait) | 2258 | struct extent_buffer *eb, |
2259 | u64 start, | ||
2260 | int wait) | ||
2221 | { | 2261 | { |
2222 | unsigned long i; | 2262 | unsigned long i; |
2263 | unsigned long start_i; | ||
2223 | struct page *page; | 2264 | struct page *page; |
2224 | int err; | 2265 | int err; |
2225 | int ret = 0; | 2266 | int ret = 0; |
@@ -2232,9 +2273,16 @@ int read_extent_buffer_pages(struct extent_map_tree *tree, | |||
2232 | EXTENT_UPTODATE, 1)) { | 2273 | EXTENT_UPTODATE, 1)) { |
2233 | return 0; | 2274 | return 0; |
2234 | } | 2275 | } |
2276 | if (start) { | ||
2277 | WARN_ON(start < eb->start); | ||
2278 | start_i = (start >> PAGE_CACHE_SHIFT) - | ||
2279 | (eb->start >> PAGE_CACHE_SHIFT); | ||
2280 | } else { | ||
2281 | start_i = 0; | ||
2282 | } | ||
2235 | 2283 | ||
2236 | num_pages = num_extent_pages(eb->start, eb->len); | 2284 | num_pages = num_extent_pages(eb->start, eb->len); |
2237 | for (i = 0; i < num_pages; i++) { | 2285 | for (i = start_i; i < num_pages; i++) { |
2238 | page = extent_buffer_page(eb, i); | 2286 | page = extent_buffer_page(eb, i); |
2239 | if (PageUptodate(page)) { | 2287 | if (PageUptodate(page)) { |
2240 | continue; | 2288 | continue; |
@@ -2260,7 +2308,7 @@ int read_extent_buffer_pages(struct extent_map_tree *tree, | |||
2260 | return ret; | 2308 | return ret; |
2261 | } | 2309 | } |
2262 | 2310 | ||
2263 | for (i = 0; i < num_pages; i++) { | 2311 | for (i = start_i; i < num_pages; i++) { |
2264 | page = extent_buffer_page(eb, i); | 2312 | page = extent_buffer_page(eb, i); |
2265 | wait_on_page_locked(page); | 2313 | wait_on_page_locked(page); |
2266 | if (!PageUptodate(page)) { | 2314 | if (!PageUptodate(page)) { |
@@ -2314,7 +2362,7 @@ void read_extent_buffer(struct extent_buffer *eb, void *dstv, | |||
2314 | } | 2362 | } |
2315 | EXPORT_SYMBOL(read_extent_buffer); | 2363 | EXPORT_SYMBOL(read_extent_buffer); |
2316 | 2364 | ||
2317 | static int __map_extent_buffer(struct extent_buffer *eb, unsigned long start, | 2365 | int map_private_extent_buffer(struct extent_buffer *eb, unsigned long start, |
2318 | unsigned long min_len, char **token, char **map, | 2366 | unsigned long min_len, char **token, char **map, |
2319 | unsigned long *map_start, | 2367 | unsigned long *map_start, |
2320 | unsigned long *map_len, int km) | 2368 | unsigned long *map_len, int km) |
@@ -2337,6 +2385,10 @@ static int __map_extent_buffer(struct extent_buffer *eb, unsigned long start, | |||
2337 | offset = 0; | 2385 | offset = 0; |
2338 | *map_start = (i << PAGE_CACHE_SHIFT) - start_offset; | 2386 | *map_start = (i << PAGE_CACHE_SHIFT) - start_offset; |
2339 | } | 2387 | } |
2388 | if (start + min_len >= eb->len) { | ||
2389 | printk("bad mapping eb start %Lu len %lu, wanted %lu %lu\n", eb->start, eb->len, start, min_len); | ||
2390 | WARN_ON(1); | ||
2391 | } | ||
2340 | 2392 | ||
2341 | p = extent_buffer_page(eb, i); | 2393 | p = extent_buffer_page(eb, i); |
2342 | WARN_ON(!PageUptodate(p)); | 2394 | WARN_ON(!PageUptodate(p)); |
@@ -2346,6 +2398,7 @@ static int __map_extent_buffer(struct extent_buffer *eb, unsigned long start, | |||
2346 | *map_len = PAGE_CACHE_SIZE - offset; | 2398 | *map_len = PAGE_CACHE_SIZE - offset; |
2347 | return 0; | 2399 | return 0; |
2348 | } | 2400 | } |
2401 | EXPORT_SYMBOL(map_private_extent_buffer); | ||
2349 | 2402 | ||
2350 | int map_extent_buffer(struct extent_buffer *eb, unsigned long start, | 2403 | int map_extent_buffer(struct extent_buffer *eb, unsigned long start, |
2351 | unsigned long min_len, | 2404 | unsigned long min_len, |
@@ -2360,8 +2413,8 @@ int map_extent_buffer(struct extent_buffer *eb, unsigned long start, | |||
2360 | eb->map_token = NULL; | 2413 | eb->map_token = NULL; |
2361 | save = 1; | 2414 | save = 1; |
2362 | } | 2415 | } |
2363 | err = __map_extent_buffer(eb, start, min_len, token, map, | 2416 | err = map_private_extent_buffer(eb, start, min_len, token, map, |
2364 | map_start, map_len, km); | 2417 | map_start, map_len, km); |
2365 | if (!err && save) { | 2418 | if (!err && save) { |
2366 | eb->map_token = *token; | 2419 | eb->map_token = *token; |
2367 | eb->kaddr = *map; | 2420 | eb->kaddr = *map; |
diff --git a/fs/btrfs/extent_map.h b/fs/btrfs/extent_map.h index f1dc28d260eb..39d78d31b6a2 100644 --- a/fs/btrfs/extent_map.h +++ b/fs/btrfs/extent_map.h | |||
@@ -17,8 +17,17 @@ | |||
17 | #define EXTENT_DEFRAG (1 << 6) | 17 | #define EXTENT_DEFRAG (1 << 6) |
18 | #define EXTENT_DEFRAG_DONE (1 << 7) | 18 | #define EXTENT_DEFRAG_DONE (1 << 7) |
19 | #define EXTENT_BUFFER_FILLED (1 << 8) | 19 | #define EXTENT_BUFFER_FILLED (1 << 8) |
20 | #define EXTENT_CSUM (1 << 9) | ||
20 | #define EXTENT_IOBITS (EXTENT_LOCKED | EXTENT_WRITEBACK) | 21 | #define EXTENT_IOBITS (EXTENT_LOCKED | EXTENT_WRITEBACK) |
21 | 22 | ||
23 | /* | ||
24 | * page->private values. Every page that is controlled by the extent | ||
25 | * map has page->private set to one. | ||
26 | */ | ||
27 | |||
28 | #define EXTENT_PAGE_PRIVATE 1 | ||
29 | #define EXTENT_PAGE_PRIVATE_FIRST_PAGE 3 | ||
30 | |||
22 | 31 | ||
23 | struct extent_map_ops { | 32 | struct extent_map_ops { |
24 | int (*fill_delalloc)(struct inode *inode, u64 start, u64 end); | 33 | int (*fill_delalloc)(struct inode *inode, u64 start, u64 end); |
@@ -89,7 +98,7 @@ typedef struct extent_map *(get_extent_t)(struct inode *inode, | |||
89 | 98 | ||
90 | void extent_map_tree_init(struct extent_map_tree *tree, | 99 | void extent_map_tree_init(struct extent_map_tree *tree, |
91 | struct address_space *mapping, gfp_t mask); | 100 | struct address_space *mapping, gfp_t mask); |
92 | void extent_map_tree_cleanup(struct extent_map_tree *tree); | 101 | void extent_map_tree_empty_lru(struct extent_map_tree *tree); |
93 | struct extent_map *lookup_extent_mapping(struct extent_map_tree *tree, | 102 | struct extent_map *lookup_extent_mapping(struct extent_map_tree *tree, |
94 | u64 start, u64 end); | 103 | u64 start, u64 end); |
95 | int add_extent_mapping(struct extent_map_tree *tree, | 104 | int add_extent_mapping(struct extent_map_tree *tree, |
@@ -143,13 +152,14 @@ void set_page_extent_mapped(struct page *page); | |||
143 | 152 | ||
144 | struct extent_buffer *alloc_extent_buffer(struct extent_map_tree *tree, | 153 | struct extent_buffer *alloc_extent_buffer(struct extent_map_tree *tree, |
145 | u64 start, unsigned long len, | 154 | u64 start, unsigned long len, |
155 | struct page *page0, | ||
146 | gfp_t mask); | 156 | gfp_t mask); |
147 | struct extent_buffer *find_extent_buffer(struct extent_map_tree *tree, | 157 | struct extent_buffer *find_extent_buffer(struct extent_map_tree *tree, |
148 | u64 start, unsigned long len, | 158 | u64 start, unsigned long len, |
149 | gfp_t mask); | 159 | gfp_t mask); |
150 | void free_extent_buffer(struct extent_buffer *eb); | 160 | void free_extent_buffer(struct extent_buffer *eb); |
151 | int read_extent_buffer_pages(struct extent_map_tree *tree, | 161 | int read_extent_buffer_pages(struct extent_map_tree *tree, |
152 | struct extent_buffer *eb, int wait); | 162 | struct extent_buffer *eb, u64 start, int wait); |
153 | 163 | ||
154 | static inline void extent_buffer_get(struct extent_buffer *eb) | 164 | static inline void extent_buffer_get(struct extent_buffer *eb) |
155 | { | 165 | { |
@@ -187,5 +197,9 @@ int map_extent_buffer(struct extent_buffer *eb, unsigned long offset, | |||
187 | unsigned long min_len, char **token, char **map, | 197 | unsigned long min_len, char **token, char **map, |
188 | unsigned long *map_start, | 198 | unsigned long *map_start, |
189 | unsigned long *map_len, int km); | 199 | unsigned long *map_len, int km); |
200 | int map_private_extent_buffer(struct extent_buffer *eb, unsigned long offset, | ||
201 | unsigned long min_len, char **token, char **map, | ||
202 | unsigned long *map_start, | ||
203 | unsigned long *map_len, int km); | ||
190 | void unmap_extent_buffer(struct extent_buffer *eb, char *token, int km); | 204 | void unmap_extent_buffer(struct extent_buffer *eb, char *token, int km); |
191 | #endif | 205 | #endif |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 84f496c838c9..80f84b48a70f 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -1713,10 +1713,6 @@ static int btrfs_releasepage(struct page *page, gfp_t unused_gfp_flags) | |||
1713 | struct extent_map_tree *tree; | 1713 | struct extent_map_tree *tree; |
1714 | int ret; | 1714 | int ret; |
1715 | 1715 | ||
1716 | if (page->private != 1) { | ||
1717 | WARN_ON(1); | ||
1718 | return try_to_free_buffers(page); | ||
1719 | } | ||
1720 | tree = &BTRFS_I(page->mapping->host)->extent_tree; | 1716 | tree = &BTRFS_I(page->mapping->host)->extent_tree; |
1721 | ret = try_release_extent_mapping(tree, page); | 1717 | ret = try_release_extent_mapping(tree, page); |
1722 | if (ret == 1) { | 1718 | if (ret == 1) { |