diff options
Diffstat (limited to 'fs/btrfs/file-item.c')
-rw-r--r-- | fs/btrfs/file-item.c | 85 |
1 files changed, 55 insertions, 30 deletions
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c index a7bfc9541803..4f53159bdb9d 100644 --- a/fs/btrfs/file-item.c +++ b/fs/btrfs/file-item.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include "ctree.h" | 23 | #include "ctree.h" |
24 | #include "disk-io.h" | 24 | #include "disk-io.h" |
25 | #include "transaction.h" | 25 | #include "transaction.h" |
26 | #include "volumes.h" | ||
26 | #include "print-tree.h" | 27 | #include "print-tree.h" |
27 | 28 | ||
28 | #define __MAX_CSUM_ITEMS(r, size) ((unsigned long)(((BTRFS_LEAF_DATA_SIZE(r) - \ | 29 | #define __MAX_CSUM_ITEMS(r, size) ((unsigned long)(((BTRFS_LEAF_DATA_SIZE(r) - \ |
@@ -152,28 +153,54 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans, | |||
152 | return ret; | 153 | return ret; |
153 | } | 154 | } |
154 | 155 | ||
156 | static void btrfs_io_bio_endio_readpage(struct btrfs_io_bio *bio, int err) | ||
157 | { | ||
158 | kfree(bio->csum_allocated); | ||
159 | } | ||
160 | |||
155 | static int __btrfs_lookup_bio_sums(struct btrfs_root *root, | 161 | static int __btrfs_lookup_bio_sums(struct btrfs_root *root, |
156 | struct inode *inode, struct bio *bio, | 162 | struct inode *inode, struct bio *bio, |
157 | u64 logical_offset, u32 *dst, int dio) | 163 | u64 logical_offset, u32 *dst, int dio) |
158 | { | 164 | { |
159 | u32 sum[16]; | ||
160 | int len; | ||
161 | struct bio_vec *bvec = bio->bi_io_vec; | 165 | struct bio_vec *bvec = bio->bi_io_vec; |
162 | int bio_index = 0; | 166 | struct btrfs_io_bio *btrfs_bio = btrfs_io_bio(bio); |
167 | struct btrfs_csum_item *item = NULL; | ||
168 | struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; | ||
169 | struct btrfs_path *path; | ||
170 | u8 *csum; | ||
163 | u64 offset = 0; | 171 | u64 offset = 0; |
164 | u64 item_start_offset = 0; | 172 | u64 item_start_offset = 0; |
165 | u64 item_last_offset = 0; | 173 | u64 item_last_offset = 0; |
166 | u64 disk_bytenr; | 174 | u64 disk_bytenr; |
167 | u32 diff; | 175 | u32 diff; |
168 | u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); | 176 | int nblocks; |
177 | int bio_index = 0; | ||
169 | int count; | 178 | int count; |
170 | struct btrfs_path *path; | 179 | u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); |
171 | struct btrfs_csum_item *item = NULL; | ||
172 | struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; | ||
173 | 180 | ||
174 | path = btrfs_alloc_path(); | 181 | path = btrfs_alloc_path(); |
175 | if (!path) | 182 | if (!path) |
176 | return -ENOMEM; | 183 | return -ENOMEM; |
184 | |||
185 | nblocks = bio->bi_size >> inode->i_sb->s_blocksize_bits; | ||
186 | if (!dst) { | ||
187 | if (nblocks * csum_size > BTRFS_BIO_INLINE_CSUM_SIZE) { | ||
188 | btrfs_bio->csum_allocated = kmalloc(nblocks * csum_size, | ||
189 | GFP_NOFS); | ||
190 | if (!btrfs_bio->csum_allocated) { | ||
191 | btrfs_free_path(path); | ||
192 | return -ENOMEM; | ||
193 | } | ||
194 | btrfs_bio->csum = btrfs_bio->csum_allocated; | ||
195 | btrfs_bio->end_io = btrfs_io_bio_endio_readpage; | ||
196 | } else { | ||
197 | btrfs_bio->csum = btrfs_bio->csum_inline; | ||
198 | } | ||
199 | csum = btrfs_bio->csum; | ||
200 | } else { | ||
201 | csum = (u8 *)dst; | ||
202 | } | ||
203 | |||
177 | if (bio->bi_size > PAGE_CACHE_SIZE * 8) | 204 | if (bio->bi_size > PAGE_CACHE_SIZE * 8) |
178 | path->reada = 2; | 205 | path->reada = 2; |
179 | 206 | ||
@@ -194,11 +221,10 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root, | |||
194 | if (dio) | 221 | if (dio) |
195 | offset = logical_offset; | 222 | offset = logical_offset; |
196 | while (bio_index < bio->bi_vcnt) { | 223 | while (bio_index < bio->bi_vcnt) { |
197 | len = min_t(int, ARRAY_SIZE(sum), bio->bi_vcnt - bio_index); | ||
198 | if (!dio) | 224 | if (!dio) |
199 | offset = page_offset(bvec->bv_page) + bvec->bv_offset; | 225 | offset = page_offset(bvec->bv_page) + bvec->bv_offset; |
200 | count = btrfs_find_ordered_sum(inode, offset, disk_bytenr, sum, | 226 | count = btrfs_find_ordered_sum(inode, offset, disk_bytenr, |
201 | len); | 227 | (u32 *)csum, nblocks); |
202 | if (count) | 228 | if (count) |
203 | goto found; | 229 | goto found; |
204 | 230 | ||
@@ -213,7 +239,7 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root, | |||
213 | path, disk_bytenr, 0); | 239 | path, disk_bytenr, 0); |
214 | if (IS_ERR(item)) { | 240 | if (IS_ERR(item)) { |
215 | count = 1; | 241 | count = 1; |
216 | sum[0] = 0; | 242 | memset(csum, 0, csum_size); |
217 | if (BTRFS_I(inode)->root->root_key.objectid == | 243 | if (BTRFS_I(inode)->root->root_key.objectid == |
218 | BTRFS_DATA_RELOC_TREE_OBJECTID) { | 244 | BTRFS_DATA_RELOC_TREE_OBJECTID) { |
219 | set_extent_bits(io_tree, offset, | 245 | set_extent_bits(io_tree, offset, |
@@ -222,9 +248,7 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root, | |||
222 | } else { | 248 | } else { |
223 | printk(KERN_INFO "btrfs no csum found " | 249 | printk(KERN_INFO "btrfs no csum found " |
224 | "for inode %llu start %llu\n", | 250 | "for inode %llu start %llu\n", |
225 | (unsigned long long) | 251 | btrfs_ino(inode), offset); |
226 | btrfs_ino(inode), | ||
227 | (unsigned long long)offset); | ||
228 | } | 252 | } |
229 | item = NULL; | 253 | item = NULL; |
230 | btrfs_release_path(path); | 254 | btrfs_release_path(path); |
@@ -249,23 +273,14 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root, | |||
249 | diff = disk_bytenr - item_start_offset; | 273 | diff = disk_bytenr - item_start_offset; |
250 | diff = diff / root->sectorsize; | 274 | diff = diff / root->sectorsize; |
251 | diff = diff * csum_size; | 275 | diff = diff * csum_size; |
252 | count = min_t(int, len, (item_last_offset - disk_bytenr) >> | 276 | count = min_t(int, nblocks, (item_last_offset - disk_bytenr) >> |
253 | inode->i_sb->s_blocksize_bits); | 277 | inode->i_sb->s_blocksize_bits); |
254 | read_extent_buffer(path->nodes[0], sum, | 278 | read_extent_buffer(path->nodes[0], csum, |
255 | ((unsigned long)item) + diff, | 279 | ((unsigned long)item) + diff, |
256 | csum_size * count); | 280 | csum_size * count); |
257 | found: | 281 | found: |
258 | if (dst) { | 282 | csum += count * csum_size; |
259 | memcpy(dst, sum, count * csum_size); | 283 | nblocks -= count; |
260 | dst += count; | ||
261 | } else { | ||
262 | if (dio) | ||
263 | extent_cache_csums_dio(io_tree, offset, sum, | ||
264 | count); | ||
265 | else | ||
266 | extent_cache_csums(io_tree, bio, bio_index, sum, | ||
267 | count); | ||
268 | } | ||
269 | while (count--) { | 284 | while (count--) { |
270 | disk_bytenr += bvec->bv_len; | 285 | disk_bytenr += bvec->bv_len; |
271 | offset += bvec->bv_len; | 286 | offset += bvec->bv_len; |
@@ -284,9 +299,19 @@ int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode, | |||
284 | } | 299 | } |
285 | 300 | ||
286 | int btrfs_lookup_bio_sums_dio(struct btrfs_root *root, struct inode *inode, | 301 | int btrfs_lookup_bio_sums_dio(struct btrfs_root *root, struct inode *inode, |
287 | struct bio *bio, u64 offset) | 302 | struct btrfs_dio_private *dip, struct bio *bio, |
303 | u64 offset) | ||
288 | { | 304 | { |
289 | return __btrfs_lookup_bio_sums(root, inode, bio, offset, NULL, 1); | 305 | int len = (bio->bi_sector << 9) - dip->disk_bytenr; |
306 | u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); | ||
307 | int ret; | ||
308 | |||
309 | len >>= inode->i_sb->s_blocksize_bits; | ||
310 | len *= csum_size; | ||
311 | |||
312 | ret = __btrfs_lookup_bio_sums(root, inode, bio, offset, | ||
313 | (u32 *)(dip->csum + len), 1); | ||
314 | return ret; | ||
290 | } | 315 | } |
291 | 316 | ||
292 | int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, | 317 | int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, |