aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2008-02-20 12:07:25 -0500
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:04:00 -0400
commit065631f6dccea07bfad48d8981369f6d9cfd6e2b (patch)
treed9d5736f61d225d0418cf298092ac36fbe6099e2 /fs/btrfs
parent0740c82bc7585a23e100c9a59d5e2abbf99459fb (diff)
Btrfs: checksum file data at bio submission time instead of during writepage
When we checkum file data during writepage, the checksumming is done one page at a time, making it difficult to do bulk metadata modifications to insert checksums for large ranges of the file at once. This patch changes btrfs to checksum on a per-bio basis instead. The bios are checksummed before they are handed off to the block layer, so each bio is contiguous and only has pages from the same inode. Checksumming on a bio basis allows us to insert and modify the file checksum items in large groups. It also allows the checksumming to be done more easily by async worker threads. Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/ctree.h8
-rw-r--r--fs/btrfs/extent_io.c2
-rw-r--r--fs/btrfs/extent_io.h1
-rw-r--r--fs/btrfs/file-item.c50
-rw-r--r--fs/btrfs/inode.c32
5 files changed, 75 insertions, 18 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 086cb0525cd1..92d892f92075 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -1142,11 +1142,9 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
1142 struct btrfs_root *root, 1142 struct btrfs_root *root,
1143 struct btrfs_path *path, u64 objectid, 1143 struct btrfs_path *path, u64 objectid,
1144 u64 bytenr, int mod); 1144 u64 bytenr, int mod);
1145int btrfs_csum_file_block(struct btrfs_trans_handle *trans, 1145int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
1146 struct btrfs_root *root, 1146 struct btrfs_root *root, struct inode *inode,
1147 struct inode *inode, 1147 struct bio *bio);
1148 u64 objectid, u64 offset,
1149 char *data, size_t len);
1150struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans, 1148struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans,
1151 struct btrfs_root *root, 1149 struct btrfs_root *root,
1152 struct btrfs_path *path, 1150 struct btrfs_path *path,
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index fb6400895ed6..e8130c876330 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -1705,6 +1705,8 @@ static int submit_one_bio(int rw, struct bio *bio)
1705 (unsigned long long)bio->bi_sector); 1705 (unsigned long long)bio->bi_sector);
1706 WARN_ON(1); 1706 WARN_ON(1);
1707 } 1707 }
1708 if (tree->ops && tree->ops->submit_bio_hook)
1709 tree->ops->submit_bio_hook(rw, bio);
1708 1710
1709 submit_bio(rw, bio); 1711 submit_bio(rw, bio);
1710 if (bio_flagged(bio, BIO_EOPNOTSUPP)) 1712 if (bio_flagged(bio, BIO_EOPNOTSUPP))
diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h
index fcc4bb078c24..9d6654667089 100644
--- a/fs/btrfs/extent_io.h
+++ b/fs/btrfs/extent_io.h
@@ -28,6 +28,7 @@ struct extent_state;
28struct extent_io_ops { 28struct extent_io_ops {
29 int (*fill_delalloc)(struct inode *inode, u64 start, u64 end); 29 int (*fill_delalloc)(struct inode *inode, u64 start, u64 end);
30 int (*writepage_io_hook)(struct page *page, u64 start, u64 end); 30 int (*writepage_io_hook)(struct page *page, u64 start, u64 end);
31 int (*submit_bio_hook)(int rw, struct bio *bio);
31 int (*readpage_io_hook)(struct page *page, u64 start, u64 end); 32 int (*readpage_io_hook)(struct page *page, u64 start, u64 end);
32 int (*readpage_end_io_hook)(struct page *page, u64 start, u64 end, 33 int (*readpage_end_io_hook)(struct page *page, u64 start, u64 end,
33 struct extent_state *state); 34 struct extent_state *state);
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c
index 3ebbc058d082..3f0e71b0e5d9 100644
--- a/fs/btrfs/file-item.c
+++ b/fs/btrfs/file-item.c
@@ -16,6 +16,9 @@
16 * Boston, MA 021110-1307, USA. 16 * Boston, MA 021110-1307, USA.
17 */ 17 */
18 18
19#include <linux/bio.h>
20#include <linux/pagemap.h>
21#include <linux/highmem.h>
19#include "ctree.h" 22#include "ctree.h"
20#include "disk-io.h" 23#include "disk-io.h"
21#include "transaction.h" 24#include "transaction.h"
@@ -131,28 +134,35 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
131 return ret; 134 return ret;
132} 135}
133 136
134int btrfs_csum_file_block(struct btrfs_trans_handle *trans, 137int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
135 struct btrfs_root *root, 138 struct btrfs_root *root, struct inode *inode,
136 struct inode *inode, 139 struct bio *bio)
137 u64 objectid, u64 offset,
138 char *data, size_t len)
139{ 140{
141 u64 objectid = inode->i_ino;
142 u64 offset;
140 int ret; 143 int ret;
141 struct btrfs_key file_key; 144 struct btrfs_key file_key;
142 struct btrfs_key found_key; 145 struct btrfs_key found_key;
143 u64 next_offset = (u64)-1; 146 u64 next_offset;
144 int found_next = 0; 147 int found_next;
145 struct btrfs_path *path; 148 struct btrfs_path *path;
146 struct btrfs_csum_item *item; 149 struct btrfs_csum_item *item;
150 struct btrfs_csum_item *item_end;
147 struct extent_buffer *leaf = NULL; 151 struct extent_buffer *leaf = NULL;
148 u64 csum_offset; 152 u64 csum_offset;
149 u32 csum_result = ~(u32)0; 153 u32 csum_result;
150 u32 nritems; 154 u32 nritems;
151 u32 ins_size; 155 u32 ins_size;
156 int bio_index = 0;
157 struct bio_vec *bvec = bio->bi_io_vec;
158 char *data;
152 159
153 path = btrfs_alloc_path(); 160 path = btrfs_alloc_path();
154 BUG_ON(!path); 161 BUG_ON(!path);
155 162again:
163 next_offset = (u64)-1;
164 found_next = 0;
165 offset = page_offset(bvec->bv_page) + bvec->bv_offset;
156 file_key.objectid = objectid; 166 file_key.objectid = objectid;
157 file_key.offset = offset; 167 file_key.offset = offset;
158 btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY); 168 btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY);
@@ -259,7 +269,15 @@ csum:
259 item = (struct btrfs_csum_item *)((unsigned char *)item + 269 item = (struct btrfs_csum_item *)((unsigned char *)item +
260 csum_offset * BTRFS_CRC32_SIZE); 270 csum_offset * BTRFS_CRC32_SIZE);
261found: 271found:
262 csum_result = btrfs_csum_data(root, data, csum_result, len); 272 item_end = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item);
273 item_end = (struct btrfs_csum_item *)((unsigned char *)item_end +
274 btrfs_item_size_nr(leaf, path->slots[0]));
275next_bvec:
276 data = kmap_atomic(bvec->bv_page, KM_IRQ0);
277 csum_result = ~(u32)0;
278 csum_result = btrfs_csum_data(root, data + bvec->bv_offset,
279 csum_result, bvec->bv_len);
280 kunmap_atomic(data, KM_IRQ0);
263 btrfs_csum_final(csum_result, (char *)&csum_result); 281 btrfs_csum_final(csum_result, (char *)&csum_result);
264 if (csum_result == 0) { 282 if (csum_result == 0) {
265 printk("csum result is 0 for inode %lu offset %Lu\n", inode->i_ino, offset); 283 printk("csum result is 0 for inode %lu offset %Lu\n", inode->i_ino, offset);
@@ -267,9 +285,19 @@ found:
267 285
268 write_extent_buffer(leaf, &csum_result, (unsigned long)item, 286 write_extent_buffer(leaf, &csum_result, (unsigned long)item,
269 BTRFS_CRC32_SIZE); 287 BTRFS_CRC32_SIZE);
288 bio_index++;
289 bvec++;
290 if (bio_index < bio->bi_vcnt) {
291 item = (struct btrfs_csum_item *)((char *)item + BTRFS_CRC32_SIZE);
292 if (item < item_end)
293 goto next_bvec;
294 }
270 btrfs_mark_buffer_dirty(path->nodes[0]); 295 btrfs_mark_buffer_dirty(path->nodes[0]);
296 if (bio_index < bio->bi_vcnt) {
297 btrfs_release_path(root, path);
298 goto again;
299 }
271fail: 300fail:
272 btrfs_release_path(root, path);
273 btrfs_free_path(path); 301 btrfs_free_path(path);
274 return ret; 302 return ret;
275} 303}
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 3e79572a5cb1..bbb71fad861a 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -16,6 +16,7 @@
16 * Boston, MA 021110-1307, USA. 16 * Boston, MA 021110-1307, USA.
17 */ 17 */
18 18
19#include <linux/bio.h>
19#include <linux/buffer_head.h> 20#include <linux/buffer_head.h>
20#include <linux/fs.h> 21#include <linux/fs.h>
21#include <linux/pagemap.h> 22#include <linux/pagemap.h>
@@ -294,6 +295,32 @@ int btrfs_clear_bit_hook(struct inode *inode, u64 start, u64 end,
294 return 0; 295 return 0;
295} 296}
296 297
298int btrfs_submit_bio_hook(int rw, struct bio *bio)
299{
300 // struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
301 struct bio_vec *bvec = bio->bi_io_vec;
302 struct inode *inode = bvec->bv_page->mapping->host;
303 struct btrfs_root *root = BTRFS_I(inode)->root;
304 struct btrfs_trans_handle *trans;
305 int ret = 0;
306
307 if (rw != WRITE)
308 return 0;
309
310 if (btrfs_test_opt(root, NODATASUM) ||
311 btrfs_test_flag(inode, NODATASUM))
312 return 0;
313
314 mutex_lock(&root->fs_info->fs_mutex);
315 trans = btrfs_start_transaction(root, 1);
316 btrfs_set_trans_block_group(trans, inode);
317 btrfs_csum_file_blocks(trans, root, inode, bio);
318 ret = btrfs_end_transaction(trans, root);
319 BUG_ON(ret);
320 mutex_unlock(&root->fs_info->fs_mutex);
321 return ret;
322}
323#if 0
297int btrfs_writepage_io_hook(struct page *page, u64 start, u64 end) 324int btrfs_writepage_io_hook(struct page *page, u64 start, u64 end)
298{ 325{
299 struct inode *inode = page->mapping->host; 326 struct inode *inode = page->mapping->host;
@@ -318,7 +345,7 @@ int btrfs_writepage_io_hook(struct page *page, u64 start, u64 end)
318 mutex_unlock(&root->fs_info->fs_mutex); 345 mutex_unlock(&root->fs_info->fs_mutex);
319 return ret; 346 return ret;
320} 347}
321 348#endif
322int btrfs_readpage_io_hook(struct page *page, u64 start, u64 end) 349int btrfs_readpage_io_hook(struct page *page, u64 start, u64 end)
323{ 350{
324 int ret = 0; 351 int ret = 0;
@@ -3022,7 +3049,8 @@ static struct file_operations btrfs_dir_file_operations = {
3022 3049
3023static struct extent_io_ops btrfs_extent_io_ops = { 3050static struct extent_io_ops btrfs_extent_io_ops = {
3024 .fill_delalloc = run_delalloc_range, 3051 .fill_delalloc = run_delalloc_range,
3025 .writepage_io_hook = btrfs_writepage_io_hook, 3052 // .writepage_io_hook = btrfs_writepage_io_hook,
3053 .submit_bio_hook = btrfs_submit_bio_hook,
3026 .readpage_io_hook = btrfs_readpage_io_hook, 3054 .readpage_io_hook = btrfs_readpage_io_hook,
3027 .readpage_end_io_hook = btrfs_readpage_end_io_hook, 3055 .readpage_end_io_hook = btrfs_readpage_end_io_hook,
3028 .set_bit_hook = btrfs_set_bit_hook, 3056 .set_bit_hook = btrfs_set_bit_hook,