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 /fs/btrfs/file-item.c | |
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>
Diffstat (limited to 'fs/btrfs/file-item.c')
-rw-r--r-- | fs/btrfs/file-item.c | 43 |
1 files changed, 39 insertions, 4 deletions
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 | ||