aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2008-07-18 06:17:13 -0400
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:04:05 -0400
commit3edf7d33f4edb1e4a9bb0a4c0a84d95fb4d22a09 (patch)
tree8698a6dd1d0d038f1b56f79c92783518d36f2145
parenteb84ae039e10f1f80443d846ba1350122bbdc753 (diff)
Btrfs: Handle data checksumming on bios that span multiple ordered extents
Data checksumming is done right before the bio is sent down the IO stack, which means a single bio might span more than one ordered extent. In this case, the checksumming data is split between two ordered extents. Signed-off-by: Chris Mason <chris.mason@oracle.com>
-rw-r--r--fs/btrfs/ctree.h4
-rw-r--r--fs/btrfs/file-item.c43
-rw-r--r--fs/btrfs/inode.c6
-rw-r--r--fs/btrfs/ordered-data.c36
-rw-r--r--fs/btrfs/ordered-data.h11
5 files changed, 69 insertions, 31 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index acbce542d291..96ab2797c09a 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -1579,8 +1579,8 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
1579int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, 1579int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
1580 struct btrfs_root *root, struct inode *inode, 1580 struct btrfs_root *root, struct inode *inode,
1581 struct btrfs_ordered_sum *sums); 1581 struct btrfs_ordered_sum *sums);
1582int btrfs_csum_one_bio(struct btrfs_root *root, 1582int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode,
1583 struct bio *bio, struct btrfs_ordered_sum **sums_ret); 1583 struct bio *bio);
1584struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans, 1584struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans,
1585 struct btrfs_root *root, 1585 struct btrfs_root *root,
1586 struct btrfs_path *path, 1586 struct btrfs_path *path,
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c
index 345caf8ff516..e02f1e5acb0a 100644
--- a/fs/btrfs/file-item.c
+++ b/fs/btrfs/file-item.c
@@ -134,26 +134,53 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
134 return ret; 134 return ret;
135} 135}
136 136
137int btrfs_csum_one_bio(struct btrfs_root *root, 137int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode,
138 struct bio *bio, struct btrfs_ordered_sum **sums_ret) 138 struct bio *bio)
139{ 139{
140 struct btrfs_ordered_sum *sums; 140 struct btrfs_ordered_sum *sums;
141 struct btrfs_sector_sum *sector_sum; 141 struct btrfs_sector_sum *sector_sum;
142 struct btrfs_ordered_extent *ordered;
142 char *data; 143 char *data;
143 struct bio_vec *bvec = bio->bi_io_vec; 144 struct bio_vec *bvec = bio->bi_io_vec;
144 int bio_index = 0; 145 int bio_index = 0;
146 unsigned long total_bytes = 0;
147 unsigned long this_sum_bytes = 0;
148 u64 offset;
145 149
146 WARN_ON(bio->bi_vcnt <= 0); 150 WARN_ON(bio->bi_vcnt <= 0);
147 sums = kzalloc(btrfs_ordered_sum_size(root, bio->bi_size), GFP_NOFS); 151 sums = kzalloc(btrfs_ordered_sum_size(root, bio->bi_size), GFP_NOFS);
148 if (!sums) 152 if (!sums)
149 return -ENOMEM; 153 return -ENOMEM;
150 *sums_ret = sums; 154
151 sector_sum = &sums->sums; 155 sector_sum = &sums->sums;
152 sums->file_offset = page_offset(bvec->bv_page); 156 sums->file_offset = page_offset(bvec->bv_page) + bvec->bv_offset;
153 sums->len = bio->bi_size; 157 sums->len = bio->bi_size;
154 INIT_LIST_HEAD(&sums->list); 158 INIT_LIST_HEAD(&sums->list);
159 ordered = btrfs_lookup_ordered_extent(inode, sums->file_offset);
160 BUG_ON(!ordered);
155 161
156 while(bio_index < bio->bi_vcnt) { 162 while(bio_index < bio->bi_vcnt) {
163 offset = page_offset(bvec->bv_page) + bvec->bv_offset;
164 if (offset >= ordered->file_offset + ordered->len) {
165 unsigned long bytes_left;
166 sums->len = this_sum_bytes;
167 this_sum_bytes = 0;
168 btrfs_add_ordered_sum(inode, ordered, sums);
169 btrfs_put_ordered_extent(ordered);
170
171 bytes_left = bio->bi_size - total_bytes;
172
173 sums = kzalloc(btrfs_ordered_sum_size(root, bytes_left),
174 GFP_NOFS);
175 BUG_ON(!sums);
176 sector_sum = &sums->sums;
177 sums->len = bytes_left;
178 sums->file_offset = offset;
179 ordered = btrfs_lookup_ordered_extent(inode,
180 sums->file_offset);
181 BUG_ON(!ordered);
182 }
183
157 data = kmap_atomic(bvec->bv_page, KM_USER0); 184 data = kmap_atomic(bvec->bv_page, KM_USER0);
158 sector_sum->sum = ~(u32)0; 185 sector_sum->sum = ~(u32)0;
159 sector_sum->sum = btrfs_csum_data(root, 186 sector_sum->sum = btrfs_csum_data(root,
@@ -165,10 +192,18 @@ int btrfs_csum_one_bio(struct btrfs_root *root,
165 (char *)&sector_sum->sum); 192 (char *)&sector_sum->sum);
166 sector_sum->offset = page_offset(bvec->bv_page) + 193 sector_sum->offset = page_offset(bvec->bv_page) +
167 bvec->bv_offset; 194 bvec->bv_offset;
195
168 sector_sum++; 196 sector_sum++;
169 bio_index++; 197 bio_index++;
198 total_bytes += bvec->bv_len;
199 this_sum_bytes += bvec->bv_len;
170 bvec++; 200 bvec++;
171 } 201 }
202 btrfs_add_ordered_sum(inode, ordered, sums);
203 btrfs_put_ordered_extent(ordered);
204 if (total_bytes != bio->bi_size) {
205printk("warning, total bytes %lu bio size %u\n", total_bytes, bio->bi_size);
206 }
172 return 0; 207 return 0;
173} 208}
174 209
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index f37e09e724f7..4d729d90d2b8 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -351,12 +351,8 @@ int __btrfs_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
351{ 351{
352 struct btrfs_root *root = BTRFS_I(inode)->root; 352 struct btrfs_root *root = BTRFS_I(inode)->root;
353 int ret = 0; 353 int ret = 0;
354 struct btrfs_ordered_sum *sums;
355 354
356 ret = btrfs_csum_one_bio(root, bio, &sums); 355 ret = btrfs_csum_one_bio(root, inode, bio);
357 BUG_ON(ret);
358
359 ret = btrfs_add_ordered_sum(inode, sums);
360 BUG_ON(ret); 356 BUG_ON(ret);
361 357
362 return btrfs_map_bio(root, rw, bio, mirror_num, 1); 358 return btrfs_map_bio(root, rw, bio, mirror_num, 1);
diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c
index 230fd3ca6b2c..1ddb7bceea99 100644
--- a/fs/btrfs/ordered-data.c
+++ b/fs/btrfs/ordered-data.c
@@ -186,22 +186,17 @@ int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
186 186
187/* 187/*
188 * Add a struct btrfs_ordered_sum into the list of checksums to be inserted 188 * Add a struct btrfs_ordered_sum into the list of checksums to be inserted
189 * when an ordered extent is finished. 189 * when an ordered extent is finished. If the list covers more than one
190 * ordered extent, it is split across multiples.
190 */ 191 */
191int btrfs_add_ordered_sum(struct inode *inode, struct btrfs_ordered_sum *sum) 192int btrfs_add_ordered_sum(struct inode *inode,
193 struct btrfs_ordered_extent *entry,
194 struct btrfs_ordered_sum *sum)
192{ 195{
193 struct btrfs_ordered_inode_tree *tree; 196 struct btrfs_ordered_inode_tree *tree;
194 struct rb_node *node;
195 struct btrfs_ordered_extent *entry;
196 197
197 tree = &BTRFS_I(inode)->ordered_tree; 198 tree = &BTRFS_I(inode)->ordered_tree;
198 mutex_lock(&tree->mutex); 199 mutex_lock(&tree->mutex);
199 node = tree_search(tree, sum->file_offset);
200 BUG_ON(!node);
201
202 entry = rb_entry(node, struct btrfs_ordered_extent, rb_node);
203 BUG_ON(!offset_in_entry(entry, sum->file_offset));
204
205 list_add_tail(&sum->list, &entry->list); 200 list_add_tail(&sum->list, &entry->list);
206 mutex_unlock(&tree->mutex); 201 mutex_unlock(&tree->mutex);
207 return 0; 202 return 0;
@@ -524,8 +519,10 @@ int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u32 *sum)
524 struct btrfs_ordered_extent *ordered; 519 struct btrfs_ordered_extent *ordered;
525 struct btrfs_ordered_inode_tree *tree = &BTRFS_I(inode)->ordered_tree; 520 struct btrfs_ordered_inode_tree *tree = &BTRFS_I(inode)->ordered_tree;
526 struct list_head *cur; 521 struct list_head *cur;
522 unsigned long num_sectors;
523 unsigned long i;
524 u32 sectorsize = BTRFS_I(inode)->root->sectorsize;
527 int ret = 1; 525 int ret = 1;
528 int index;
529 526
530 ordered = btrfs_lookup_ordered_extent(inode, offset); 527 ordered = btrfs_lookup_ordered_extent(inode, offset);
531 if (!ordered) 528 if (!ordered)
@@ -534,14 +531,17 @@ int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u32 *sum)
534 mutex_lock(&tree->mutex); 531 mutex_lock(&tree->mutex);
535 list_for_each_prev(cur, &ordered->list) { 532 list_for_each_prev(cur, &ordered->list) {
536 ordered_sum = list_entry(cur, struct btrfs_ordered_sum, list); 533 ordered_sum = list_entry(cur, struct btrfs_ordered_sum, list);
537 if (offset >= ordered_sum->file_offset && 534 if (offset >= ordered_sum->file_offset) {
538 offset < ordered_sum->file_offset + ordered_sum->len) { 535 num_sectors = ordered_sum->len / sectorsize;
539 index = (offset - ordered_sum->file_offset) /
540 BTRFS_I(inode)->root->sectorsize;;
541 sector_sums = &ordered_sum->sums; 536 sector_sums = &ordered_sum->sums;
542 *sum = sector_sums[index].sum; 537 for (i = 0; i < num_sectors; i++) {
543 ret = 0; 538 if (sector_sums[i].offset == offset) {
544 goto out; 539printk("find ordered sum inode %lu offset %Lu\n", inode->i_ino, offset);
540 *sum = sector_sums[i].sum;
541 ret = 0;
542 goto out;
543 }
544 }
545 } 545 }
546 } 546 }
547out: 547out:
diff --git a/fs/btrfs/ordered-data.h b/fs/btrfs/ordered-data.h
index 98f491d1022b..1794efd13ca3 100644
--- a/fs/btrfs/ordered-data.h
+++ b/fs/btrfs/ordered-data.h
@@ -39,7 +39,11 @@ struct btrfs_sector_sum {
39 39
40struct btrfs_ordered_sum { 40struct btrfs_ordered_sum {
41 u64 file_offset; 41 u64 file_offset;
42 u64 len; 42 /*
43 * this is the length in bytes covered by the sums array below.
44 * But, the sums array may not be contiguous in the file.
45 */
46 unsigned long len;
43 struct list_head list; 47 struct list_head list;
44 /* last field is a variable length array of btrfs_sector_sums */ 48 /* last field is a variable length array of btrfs_sector_sums */
45 struct btrfs_sector_sum sums; 49 struct btrfs_sector_sum sums;
@@ -95,6 +99,7 @@ static inline int btrfs_ordered_sum_size(struct btrfs_root *root, u64 bytes)
95{ 99{
96 unsigned long num_sectors = (bytes + root->sectorsize - 1) / 100 unsigned long num_sectors = (bytes + root->sectorsize - 1) /
97 root->sectorsize; 101 root->sectorsize;
102 num_sectors++;
98 return sizeof(struct btrfs_ordered_sum) + 103 return sizeof(struct btrfs_ordered_sum) +
99 num_sectors * sizeof(struct btrfs_sector_sum); 104 num_sectors * sizeof(struct btrfs_sector_sum);
100} 105}
@@ -114,7 +119,9 @@ int btrfs_dec_test_ordered_pending(struct inode *inode,
114 u64 file_offset, u64 io_size); 119 u64 file_offset, u64 io_size);
115int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset, 120int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
116 u64 start, u64 len); 121 u64 start, u64 len);
117int btrfs_add_ordered_sum(struct inode *inode, struct btrfs_ordered_sum *sum); 122int btrfs_add_ordered_sum(struct inode *inode,
123 struct btrfs_ordered_extent *entry,
124 struct btrfs_ordered_sum *sum);
118struct btrfs_ordered_extent *btrfs_lookup_ordered_extent(struct inode *inode, 125struct btrfs_ordered_extent *btrfs_lookup_ordered_extent(struct inode *inode,
119 u64 file_offset); 126 u64 file_offset);
120void btrfs_start_ordered_extent(struct inode *inode, 127void btrfs_start_ordered_extent(struct inode *inode,