diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-07-18 06:17:13 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:04:05 -0400 |
commit | 3edf7d33f4edb1e4a9bb0a4c0a84d95fb4d22a09 (patch) | |
tree | 8698a6dd1d0d038f1b56f79c92783518d36f2145 | |
parent | eb84ae039e10f1f80443d846ba1350122bbdc753 (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.h | 4 | ||||
-rw-r--r-- | fs/btrfs/file-item.c | 43 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 6 | ||||
-rw-r--r-- | fs/btrfs/ordered-data.c | 36 | ||||
-rw-r--r-- | fs/btrfs/ordered-data.h | 11 |
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, | |||
1579 | int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, | 1579 | int 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); |
1582 | int btrfs_csum_one_bio(struct btrfs_root *root, | 1582 | int 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); |
1584 | struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans, | 1584 | struct 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 | ||
137 | int btrfs_csum_one_bio(struct btrfs_root *root, | 137 | int 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 *)§or_sum->sum); | 192 | (char *)§or_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) { | ||
205 | printk("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 | */ |
191 | int btrfs_add_ordered_sum(struct inode *inode, struct btrfs_ordered_sum *sum) | 192 | int 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; | 539 | printk("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 | } |
547 | out: | 547 | out: |
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 | ||
40 | struct btrfs_ordered_sum { | 40 | struct 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); |
115 | int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset, | 120 | int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset, |
116 | u64 start, u64 len); | 121 | u64 start, u64 len); |
117 | int btrfs_add_ordered_sum(struct inode *inode, struct btrfs_ordered_sum *sum); | 122 | int btrfs_add_ordered_sum(struct inode *inode, |
123 | struct btrfs_ordered_extent *entry, | ||
124 | struct btrfs_ordered_sum *sum); | ||
118 | struct btrfs_ordered_extent *btrfs_lookup_ordered_extent(struct inode *inode, | 125 | struct btrfs_ordered_extent *btrfs_lookup_ordered_extent(struct inode *inode, |
119 | u64 file_offset); | 126 | u64 file_offset); |
120 | void btrfs_start_ordered_extent(struct inode *inode, | 127 | void btrfs_start_ordered_extent(struct inode *inode, |