diff options
Diffstat (limited to 'fs/btrfs/file-item.c')
-rw-r--r-- | fs/btrfs/file-item.c | 185 |
1 files changed, 69 insertions, 116 deletions
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c index 234ed441736c..a3ad2ce00116 100644 --- a/fs/btrfs/file-item.c +++ b/fs/btrfs/file-item.c | |||
@@ -74,8 +74,7 @@ out: | |||
74 | struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans, | 74 | struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans, |
75 | struct btrfs_root *root, | 75 | struct btrfs_root *root, |
76 | struct btrfs_path *path, | 76 | struct btrfs_path *path, |
77 | u64 objectid, u64 offset, | 77 | u64 bytenr, int cow) |
78 | int cow) | ||
79 | { | 78 | { |
80 | int ret; | 79 | int ret; |
81 | struct btrfs_key file_key; | 80 | struct btrfs_key file_key; |
@@ -87,9 +86,9 @@ struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans, | |||
87 | btrfs_super_csum_size(&root->fs_info->super_copy); | 86 | btrfs_super_csum_size(&root->fs_info->super_copy); |
88 | int csums_in_item; | 87 | int csums_in_item; |
89 | 88 | ||
90 | file_key.objectid = objectid; | 89 | file_key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; |
91 | file_key.offset = offset; | 90 | file_key.offset = bytenr; |
92 | btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY); | 91 | btrfs_set_key_type(&file_key, BTRFS_EXTENT_CSUM_KEY); |
93 | ret = btrfs_search_slot(trans, root, &file_key, path, 0, cow); | 92 | ret = btrfs_search_slot(trans, root, &file_key, path, 0, cow); |
94 | if (ret < 0) | 93 | if (ret < 0) |
95 | goto fail; | 94 | goto fail; |
@@ -100,11 +99,10 @@ struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans, | |||
100 | goto fail; | 99 | goto fail; |
101 | path->slots[0]--; | 100 | path->slots[0]--; |
102 | btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); | 101 | btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); |
103 | if (btrfs_key_type(&found_key) != BTRFS_CSUM_ITEM_KEY || | 102 | if (btrfs_key_type(&found_key) != BTRFS_EXTENT_CSUM_KEY) |
104 | found_key.objectid != objectid) { | ||
105 | goto fail; | 103 | goto fail; |
106 | } | 104 | |
107 | csum_offset = (offset - found_key.offset) >> | 105 | csum_offset = (bytenr - found_key.offset) >> |
108 | root->fs_info->sb->s_blocksize_bits; | 106 | root->fs_info->sb->s_blocksize_bits; |
109 | csums_in_item = btrfs_item_size_nr(leaf, path->slots[0]); | 107 | csums_in_item = btrfs_item_size_nr(leaf, path->slots[0]); |
110 | csums_in_item /= csum_size; | 108 | csums_in_item /= csum_size; |
@@ -143,7 +141,7 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans, | |||
143 | } | 141 | } |
144 | 142 | ||
145 | int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode, | 143 | int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode, |
146 | struct bio *bio) | 144 | struct bio *bio, u32 *dst) |
147 | { | 145 | { |
148 | u32 sum; | 146 | u32 sum; |
149 | struct bio_vec *bvec = bio->bi_io_vec; | 147 | struct bio_vec *bvec = bio->bi_io_vec; |
@@ -151,6 +149,7 @@ int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode, | |||
151 | u64 offset; | 149 | u64 offset; |
152 | u64 item_start_offset = 0; | 150 | u64 item_start_offset = 0; |
153 | u64 item_last_offset = 0; | 151 | u64 item_last_offset = 0; |
152 | u64 disk_bytenr; | ||
154 | u32 diff; | 153 | u32 diff; |
155 | u16 csum_size = | 154 | u16 csum_size = |
156 | btrfs_super_csum_size(&root->fs_info->super_copy); | 155 | btrfs_super_csum_size(&root->fs_info->super_copy); |
@@ -165,21 +164,22 @@ int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode, | |||
165 | 164 | ||
166 | WARN_ON(bio->bi_vcnt <= 0); | 165 | WARN_ON(bio->bi_vcnt <= 0); |
167 | 166 | ||
167 | disk_bytenr = (u64)bio->bi_sector << 9; | ||
168 | while(bio_index < bio->bi_vcnt) { | 168 | while(bio_index < bio->bi_vcnt) { |
169 | offset = page_offset(bvec->bv_page) + bvec->bv_offset; | 169 | offset = page_offset(bvec->bv_page) + bvec->bv_offset; |
170 | ret = btrfs_find_ordered_sum(inode, offset, &sum); | 170 | ret = btrfs_find_ordered_sum(inode, offset, disk_bytenr, &sum); |
171 | if (ret == 0) | 171 | if (ret == 0) |
172 | goto found; | 172 | goto found; |
173 | 173 | ||
174 | if (!item || offset < item_start_offset || | 174 | if (!item || disk_bytenr < item_start_offset || |
175 | offset >= item_last_offset) { | 175 | disk_bytenr >= item_last_offset) { |
176 | struct btrfs_key found_key; | 176 | struct btrfs_key found_key; |
177 | u32 item_size; | 177 | u32 item_size; |
178 | 178 | ||
179 | if (item) | 179 | if (item) |
180 | btrfs_release_path(root, path); | 180 | btrfs_release_path(root, path); |
181 | item = btrfs_lookup_csum(NULL, root, path, | 181 | item = btrfs_lookup_csum(NULL, root->fs_info->csum_root, |
182 | inode->i_ino, offset, 0); | 182 | path, disk_bytenr, 0); |
183 | if (IS_ERR(item)) { | 183 | if (IS_ERR(item)) { |
184 | ret = PTR_ERR(item); | 184 | ret = PTR_ERR(item); |
185 | if (ret == -ENOENT || ret == -EFBIG) | 185 | if (ret == -ENOENT || ret == -EFBIG) |
@@ -208,7 +208,7 @@ int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode, | |||
208 | * this byte range must be able to fit inside | 208 | * this byte range must be able to fit inside |
209 | * a single leaf so it will also fit inside a u32 | 209 | * a single leaf so it will also fit inside a u32 |
210 | */ | 210 | */ |
211 | diff = offset - item_start_offset; | 211 | diff = disk_bytenr - item_start_offset; |
212 | diff = diff / root->sectorsize; | 212 | diff = diff / root->sectorsize; |
213 | diff = diff * csum_size; | 213 | diff = diff * csum_size; |
214 | 214 | ||
@@ -216,7 +216,11 @@ int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode, | |||
216 | ((unsigned long)item) + diff, | 216 | ((unsigned long)item) + diff, |
217 | csum_size); | 217 | csum_size); |
218 | found: | 218 | found: |
219 | set_state_private(io_tree, offset, sum); | 219 | if (dst) |
220 | *dst++ = sum; | ||
221 | else | ||
222 | set_state_private(io_tree, offset, sum); | ||
223 | disk_bytenr += bvec->bv_len; | ||
220 | bio_index++; | 224 | bio_index++; |
221 | bvec++; | 225 | bvec++; |
222 | } | 226 | } |
@@ -224,75 +228,8 @@ found: | |||
224 | return 0; | 228 | return 0; |
225 | } | 229 | } |
226 | 230 | ||
227 | int btrfs_csum_file_bytes(struct btrfs_root *root, struct inode *inode, | ||
228 | u64 start, unsigned long len) | ||
229 | { | ||
230 | struct btrfs_ordered_sum *sums; | ||
231 | struct btrfs_sector_sum *sector_sum; | ||
232 | struct btrfs_ordered_extent *ordered; | ||
233 | char *data; | ||
234 | struct page *page; | ||
235 | unsigned long total_bytes = 0; | ||
236 | unsigned long this_sum_bytes = 0; | ||
237 | |||
238 | sums = kzalloc(btrfs_ordered_sum_size(root, len), GFP_NOFS); | ||
239 | if (!sums) | ||
240 | return -ENOMEM; | ||
241 | |||
242 | sector_sum = sums->sums; | ||
243 | sums->file_offset = start; | ||
244 | sums->len = len; | ||
245 | INIT_LIST_HEAD(&sums->list); | ||
246 | ordered = btrfs_lookup_ordered_extent(inode, sums->file_offset); | ||
247 | BUG_ON(!ordered); | ||
248 | |||
249 | while(len > 0) { | ||
250 | if (start >= ordered->file_offset + ordered->len || | ||
251 | start < ordered->file_offset) { | ||
252 | sums->len = this_sum_bytes; | ||
253 | this_sum_bytes = 0; | ||
254 | btrfs_add_ordered_sum(inode, ordered, sums); | ||
255 | btrfs_put_ordered_extent(ordered); | ||
256 | |||
257 | sums = kzalloc(btrfs_ordered_sum_size(root, len), | ||
258 | GFP_NOFS); | ||
259 | BUG_ON(!sums); | ||
260 | sector_sum = sums->sums; | ||
261 | sums->len = len; | ||
262 | sums->file_offset = start; | ||
263 | ordered = btrfs_lookup_ordered_extent(inode, | ||
264 | sums->file_offset); | ||
265 | BUG_ON(!ordered); | ||
266 | } | ||
267 | |||
268 | page = find_get_page(inode->i_mapping, | ||
269 | start >> PAGE_CACHE_SHIFT); | ||
270 | |||
271 | data = kmap_atomic(page, KM_USER0); | ||
272 | sector_sum->sum = ~(u32)0; | ||
273 | sector_sum->sum = btrfs_csum_data(root, data, sector_sum->sum, | ||
274 | PAGE_CACHE_SIZE); | ||
275 | kunmap_atomic(data, KM_USER0); | ||
276 | btrfs_csum_final(sector_sum->sum, | ||
277 | (char *)§or_sum->sum); | ||
278 | sector_sum->offset = page_offset(page); | ||
279 | page_cache_release(page); | ||
280 | |||
281 | sector_sum++; | ||
282 | total_bytes += PAGE_CACHE_SIZE; | ||
283 | this_sum_bytes += PAGE_CACHE_SIZE; | ||
284 | start += PAGE_CACHE_SIZE; | ||
285 | |||
286 | WARN_ON(len < PAGE_CACHE_SIZE); | ||
287 | len -= PAGE_CACHE_SIZE; | ||
288 | } | ||
289 | btrfs_add_ordered_sum(inode, ordered, sums); | ||
290 | btrfs_put_ordered_extent(ordered); | ||
291 | return 0; | ||
292 | } | ||
293 | |||
294 | int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode, | 231 | int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode, |
295 | struct bio *bio) | 232 | struct bio *bio, u64 file_start, int contig) |
296 | { | 233 | { |
297 | struct btrfs_ordered_sum *sums; | 234 | struct btrfs_ordered_sum *sums; |
298 | struct btrfs_sector_sum *sector_sum; | 235 | struct btrfs_sector_sum *sector_sum; |
@@ -303,6 +240,7 @@ int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode, | |||
303 | unsigned long total_bytes = 0; | 240 | unsigned long total_bytes = 0; |
304 | unsigned long this_sum_bytes = 0; | 241 | unsigned long this_sum_bytes = 0; |
305 | u64 offset; | 242 | u64 offset; |
243 | u64 disk_bytenr; | ||
306 | 244 | ||
307 | WARN_ON(bio->bi_vcnt <= 0); | 245 | WARN_ON(bio->bi_vcnt <= 0); |
308 | sums = kzalloc(btrfs_ordered_sum_size(root, bio->bi_size), GFP_NOFS); | 246 | sums = kzalloc(btrfs_ordered_sum_size(root, bio->bi_size), GFP_NOFS); |
@@ -310,16 +248,25 @@ int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode, | |||
310 | return -ENOMEM; | 248 | return -ENOMEM; |
311 | 249 | ||
312 | sector_sum = sums->sums; | 250 | sector_sum = sums->sums; |
313 | sums->file_offset = page_offset(bvec->bv_page) + bvec->bv_offset; | 251 | disk_bytenr = (u64)bio->bi_sector << 9; |
314 | sums->len = bio->bi_size; | 252 | sums->len = bio->bi_size; |
315 | INIT_LIST_HEAD(&sums->list); | 253 | INIT_LIST_HEAD(&sums->list); |
316 | ordered = btrfs_lookup_ordered_extent(inode, sums->file_offset); | 254 | |
255 | if (contig) | ||
256 | offset = file_start; | ||
257 | else | ||
258 | offset = page_offset(bvec->bv_page) + bvec->bv_offset; | ||
259 | |||
260 | ordered = btrfs_lookup_ordered_extent(inode, offset); | ||
317 | BUG_ON(!ordered); | 261 | BUG_ON(!ordered); |
262 | sums->bytenr = ordered->start; | ||
318 | 263 | ||
319 | while(bio_index < bio->bi_vcnt) { | 264 | while(bio_index < bio->bi_vcnt) { |
320 | offset = page_offset(bvec->bv_page) + bvec->bv_offset; | 265 | if (!contig) |
321 | if (offset >= ordered->file_offset + ordered->len || | 266 | offset = page_offset(bvec->bv_page) + bvec->bv_offset; |
322 | offset < ordered->file_offset) { | 267 | |
268 | if (!contig && (offset >= ordered->file_offset + ordered->len || | ||
269 | offset < ordered->file_offset)) { | ||
323 | unsigned long bytes_left; | 270 | unsigned long bytes_left; |
324 | sums->len = this_sum_bytes; | 271 | sums->len = this_sum_bytes; |
325 | this_sum_bytes = 0; | 272 | this_sum_bytes = 0; |
@@ -333,10 +280,9 @@ int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode, | |||
333 | BUG_ON(!sums); | 280 | BUG_ON(!sums); |
334 | sector_sum = sums->sums; | 281 | sector_sum = sums->sums; |
335 | sums->len = bytes_left; | 282 | sums->len = bytes_left; |
336 | sums->file_offset = offset; | 283 | ordered = btrfs_lookup_ordered_extent(inode, offset); |
337 | ordered = btrfs_lookup_ordered_extent(inode, | ||
338 | sums->file_offset); | ||
339 | BUG_ON(!ordered); | 284 | BUG_ON(!ordered); |
285 | sums->bytenr = ordered->start; | ||
340 | } | 286 | } |
341 | 287 | ||
342 | data = kmap_atomic(bvec->bv_page, KM_USER0); | 288 | data = kmap_atomic(bvec->bv_page, KM_USER0); |
@@ -348,13 +294,14 @@ int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode, | |||
348 | kunmap_atomic(data, KM_USER0); | 294 | kunmap_atomic(data, KM_USER0); |
349 | btrfs_csum_final(sector_sum->sum, | 295 | btrfs_csum_final(sector_sum->sum, |
350 | (char *)§or_sum->sum); | 296 | (char *)§or_sum->sum); |
351 | sector_sum->offset = page_offset(bvec->bv_page) + | 297 | sector_sum->bytenr = disk_bytenr; |
352 | bvec->bv_offset; | ||
353 | 298 | ||
354 | sector_sum++; | 299 | sector_sum++; |
355 | bio_index++; | 300 | bio_index++; |
356 | total_bytes += bvec->bv_len; | 301 | total_bytes += bvec->bv_len; |
357 | this_sum_bytes += bvec->bv_len; | 302 | this_sum_bytes += bvec->bv_len; |
303 | disk_bytenr += bvec->bv_len; | ||
304 | offset += bvec->bv_len; | ||
358 | bvec++; | 305 | bvec++; |
359 | } | 306 | } |
360 | this_sum_bytes = 0; | 307 | this_sum_bytes = 0; |
@@ -364,11 +311,10 @@ int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode, | |||
364 | } | 311 | } |
365 | 312 | ||
366 | int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, | 313 | int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, |
367 | struct btrfs_root *root, struct inode *inode, | 314 | struct btrfs_root *root, |
368 | struct btrfs_ordered_sum *sums) | 315 | struct btrfs_ordered_sum *sums) |
369 | { | 316 | { |
370 | u64 objectid = inode->i_ino; | 317 | u64 bytenr; |
371 | u64 offset; | ||
372 | int ret; | 318 | int ret; |
373 | struct btrfs_key file_key; | 319 | struct btrfs_key file_key; |
374 | struct btrfs_key found_key; | 320 | struct btrfs_key found_key; |
@@ -396,13 +342,12 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, | |||
396 | again: | 342 | again: |
397 | next_offset = (u64)-1; | 343 | next_offset = (u64)-1; |
398 | found_next = 0; | 344 | found_next = 0; |
399 | offset = sector_sum->offset; | 345 | file_key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; |
400 | file_key.objectid = objectid; | 346 | file_key.offset = sector_sum->bytenr; |
401 | file_key.offset = offset; | 347 | bytenr = sector_sum->bytenr; |
402 | btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY); | 348 | btrfs_set_key_type(&file_key, BTRFS_EXTENT_CSUM_KEY); |
403 | 349 | ||
404 | mutex_lock(&BTRFS_I(inode)->csum_mutex); | 350 | item = btrfs_lookup_csum(trans, root, path, sector_sum->bytenr, 1); |
405 | item = btrfs_lookup_csum(trans, root, path, objectid, offset, 1); | ||
406 | if (!IS_ERR(item)) { | 351 | if (!IS_ERR(item)) { |
407 | leaf = path->nodes[0]; | 352 | leaf = path->nodes[0]; |
408 | ret = 0; | 353 | ret = 0; |
@@ -432,8 +377,8 @@ again: | |||
432 | slot = 0; | 377 | slot = 0; |
433 | } | 378 | } |
434 | btrfs_item_key_to_cpu(path->nodes[0], &found_key, slot); | 379 | btrfs_item_key_to_cpu(path->nodes[0], &found_key, slot); |
435 | if (found_key.objectid != objectid || | 380 | if (found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || |
436 | found_key.type != BTRFS_CSUM_ITEM_KEY) { | 381 | found_key.type != BTRFS_EXTENT_CSUM_KEY) { |
437 | found_next = 1; | 382 | found_next = 1; |
438 | goto insert; | 383 | goto insert; |
439 | } | 384 | } |
@@ -460,10 +405,10 @@ again: | |||
460 | path->slots[0]--; | 405 | path->slots[0]--; |
461 | leaf = path->nodes[0]; | 406 | leaf = path->nodes[0]; |
462 | btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); | 407 | btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); |
463 | csum_offset = (offset - found_key.offset) >> | 408 | csum_offset = (bytenr - found_key.offset) >> |
464 | root->fs_info->sb->s_blocksize_bits; | 409 | root->fs_info->sb->s_blocksize_bits; |
465 | if (btrfs_key_type(&found_key) != BTRFS_CSUM_ITEM_KEY || | 410 | if (btrfs_key_type(&found_key) != BTRFS_EXTENT_CSUM_KEY || |
466 | found_key.objectid != objectid || | 411 | found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || |
467 | csum_offset >= MAX_CSUM_ITEMS(root, csum_size)) { | 412 | csum_offset >= MAX_CSUM_ITEMS(root, csum_size)) { |
468 | goto insert; | 413 | goto insert; |
469 | } | 414 | } |
@@ -482,8 +427,18 @@ insert: | |||
482 | btrfs_release_path(root, path); | 427 | btrfs_release_path(root, path); |
483 | csum_offset = 0; | 428 | csum_offset = 0; |
484 | if (found_next) { | 429 | if (found_next) { |
485 | u64 tmp = min((u64)i_size_read(inode), next_offset); | 430 | u64 tmp = total_bytes + root->sectorsize; |
486 | tmp -= offset & ~((u64)root->sectorsize -1); | 431 | u64 next_sector = sector_sum->bytenr; |
432 | struct btrfs_sector_sum *next = sector_sum + 1; | ||
433 | |||
434 | while(tmp < sums->len) { | ||
435 | if (next_sector + root->sectorsize != next->bytenr) | ||
436 | break; | ||
437 | tmp += root->sectorsize; | ||
438 | next_sector = next->bytenr; | ||
439 | next++; | ||
440 | } | ||
441 | tmp = min(tmp, next_offset - file_key.offset); | ||
487 | tmp >>= root->fs_info->sb->s_blocksize_bits; | 442 | tmp >>= root->fs_info->sb->s_blocksize_bits; |
488 | tmp = max((u64)1, tmp); | 443 | tmp = max((u64)1, tmp); |
489 | tmp = min(tmp, (u64)MAX_CSUM_ITEMS(root, csum_size)); | 444 | tmp = min(tmp, (u64)MAX_CSUM_ITEMS(root, csum_size)); |
@@ -510,7 +465,6 @@ found: | |||
510 | item_end = (struct btrfs_csum_item *)((unsigned char *)item_end + | 465 | item_end = (struct btrfs_csum_item *)((unsigned char *)item_end + |
511 | btrfs_item_size_nr(leaf, path->slots[0])); | 466 | btrfs_item_size_nr(leaf, path->slots[0])); |
512 | eb_token = NULL; | 467 | eb_token = NULL; |
513 | mutex_unlock(&BTRFS_I(inode)->csum_mutex); | ||
514 | cond_resched(); | 468 | cond_resched(); |
515 | next_sector: | 469 | next_sector: |
516 | 470 | ||
@@ -541,9 +495,9 @@ next_sector: | |||
541 | if (total_bytes < sums->len) { | 495 | if (total_bytes < sums->len) { |
542 | item = (struct btrfs_csum_item *)((char *)item + | 496 | item = (struct btrfs_csum_item *)((char *)item + |
543 | csum_size); | 497 | csum_size); |
544 | if (item < item_end && offset + PAGE_CACHE_SIZE == | 498 | if (item < item_end && bytenr + PAGE_CACHE_SIZE == |
545 | sector_sum->offset) { | 499 | sector_sum->bytenr) { |
546 | offset = sector_sum->offset; | 500 | bytenr = sector_sum->bytenr; |
547 | goto next_sector; | 501 | goto next_sector; |
548 | } | 502 | } |
549 | } | 503 | } |
@@ -562,7 +516,6 @@ out: | |||
562 | return ret; | 516 | return ret; |
563 | 517 | ||
564 | fail_unlock: | 518 | fail_unlock: |
565 | mutex_unlock(&BTRFS_I(inode)->csum_mutex); | ||
566 | goto out; | 519 | goto out; |
567 | } | 520 | } |
568 | 521 | ||