aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/file-item.c
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/file-item.c
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/file-item.c')
-rw-r--r--fs/btrfs/file-item.c50
1 files changed, 39 insertions, 11 deletions
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}