diff options
author | Yan, Zheng <zheng.yan@oracle.com> | 2009-11-12 04:34:08 -0500 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2009-12-15 21:24:52 -0500 |
commit | 920bbbfb05c9fce22e088d20eb9dcb8f96342de9 (patch) | |
tree | b972b3f39ebefb9c026300c1981d18cad769e431 /fs/btrfs/file.c | |
parent | ad48fd754676bfae4139be1a897b1ea58f9aaf21 (diff) |
Btrfs: Rewrite btrfs_drop_extents
Rewrite btrfs_drop_extents by using btrfs_duplicate_item, so we can
avoid calling lock_extent within transaction.
Signed-off-by: Yan Zheng <zheng.yan@oracle.com>
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/file.c')
-rw-r--r-- | fs/btrfs/file.c | 659 |
1 files changed, 263 insertions, 396 deletions
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 06550affbd27..3d2e45ce5d25 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
@@ -265,319 +265,247 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end, | |||
265 | * If an extent intersects the range but is not entirely inside the range | 265 | * If an extent intersects the range but is not entirely inside the range |
266 | * it is either truncated or split. Anything entirely inside the range | 266 | * it is either truncated or split. Anything entirely inside the range |
267 | * is deleted from the tree. | 267 | * is deleted from the tree. |
268 | * | ||
269 | * inline_limit is used to tell this code which offsets in the file to keep | ||
270 | * if they contain inline extents. | ||
271 | */ | 268 | */ |
272 | noinline int btrfs_drop_extents(struct btrfs_trans_handle *trans, | 269 | int btrfs_drop_extents(struct btrfs_trans_handle *trans, struct inode *inode, |
273 | struct btrfs_root *root, struct inode *inode, | 270 | u64 start, u64 end, u64 *hint_byte, int drop_cache) |
274 | u64 start, u64 end, u64 locked_end, | ||
275 | u64 inline_limit, u64 *hint_byte, int drop_cache) | ||
276 | { | 271 | { |
277 | u64 extent_end = 0; | 272 | struct btrfs_root *root = BTRFS_I(inode)->root; |
278 | u64 search_start = start; | ||
279 | u64 ram_bytes = 0; | ||
280 | u64 disk_bytenr = 0; | ||
281 | u64 orig_locked_end = locked_end; | ||
282 | u8 compression; | ||
283 | u8 encryption; | ||
284 | u16 other_encoding = 0; | ||
285 | struct extent_buffer *leaf; | 273 | struct extent_buffer *leaf; |
286 | struct btrfs_file_extent_item *extent; | 274 | struct btrfs_file_extent_item *fi; |
287 | struct btrfs_path *path; | 275 | struct btrfs_path *path; |
288 | struct btrfs_key key; | 276 | struct btrfs_key key; |
289 | struct btrfs_file_extent_item old; | 277 | struct btrfs_key new_key; |
290 | int keep; | 278 | u64 search_start = start; |
291 | int slot; | 279 | u64 disk_bytenr = 0; |
292 | int bookend; | 280 | u64 num_bytes = 0; |
293 | int found_type = 0; | 281 | u64 extent_offset = 0; |
294 | int found_extent; | 282 | u64 extent_end = 0; |
295 | int found_inline; | 283 | int del_nr = 0; |
284 | int del_slot = 0; | ||
285 | int extent_type; | ||
296 | int recow; | 286 | int recow; |
297 | int ret; | 287 | int ret; |
298 | 288 | ||
299 | inline_limit = 0; | ||
300 | if (drop_cache) | 289 | if (drop_cache) |
301 | btrfs_drop_extent_cache(inode, start, end - 1, 0); | 290 | btrfs_drop_extent_cache(inode, start, end - 1, 0); |
302 | 291 | ||
303 | path = btrfs_alloc_path(); | 292 | path = btrfs_alloc_path(); |
304 | if (!path) | 293 | if (!path) |
305 | return -ENOMEM; | 294 | return -ENOMEM; |
295 | |||
306 | while (1) { | 296 | while (1) { |
307 | recow = 0; | 297 | recow = 0; |
308 | btrfs_release_path(root, path); | ||
309 | ret = btrfs_lookup_file_extent(trans, root, path, inode->i_ino, | 298 | ret = btrfs_lookup_file_extent(trans, root, path, inode->i_ino, |
310 | search_start, -1); | 299 | search_start, -1); |
311 | if (ret < 0) | 300 | if (ret < 0) |
312 | goto out; | 301 | break; |
313 | if (ret > 0) { | 302 | if (ret > 0 && path->slots[0] > 0 && search_start == start) { |
314 | if (path->slots[0] == 0) { | 303 | leaf = path->nodes[0]; |
315 | ret = 0; | 304 | btrfs_item_key_to_cpu(leaf, &key, path->slots[0] - 1); |
316 | goto out; | 305 | if (key.objectid == inode->i_ino && |
317 | } | 306 | key.type == BTRFS_EXTENT_DATA_KEY) |
318 | path->slots[0]--; | 307 | path->slots[0]--; |
319 | } | 308 | } |
309 | ret = 0; | ||
320 | next_slot: | 310 | next_slot: |
321 | keep = 0; | ||
322 | bookend = 0; | ||
323 | found_extent = 0; | ||
324 | found_inline = 0; | ||
325 | compression = 0; | ||
326 | encryption = 0; | ||
327 | extent = NULL; | ||
328 | leaf = path->nodes[0]; | 311 | leaf = path->nodes[0]; |
329 | slot = path->slots[0]; | 312 | if (path->slots[0] >= btrfs_header_nritems(leaf)) { |
330 | ret = 0; | 313 | BUG_ON(del_nr > 0); |
331 | btrfs_item_key_to_cpu(leaf, &key, slot); | 314 | ret = btrfs_next_leaf(root, path); |
332 | if (btrfs_key_type(&key) == BTRFS_EXTENT_DATA_KEY && | 315 | if (ret < 0) |
333 | key.offset >= end) { | 316 | break; |
334 | goto out; | 317 | if (ret > 0) { |
335 | } | 318 | ret = 0; |
336 | if (btrfs_key_type(&key) > BTRFS_EXTENT_DATA_KEY || | 319 | break; |
337 | key.objectid != inode->i_ino) { | ||
338 | goto out; | ||
339 | } | ||
340 | if (recow) { | ||
341 | search_start = max(key.offset, start); | ||
342 | continue; | ||
343 | } | ||
344 | if (btrfs_key_type(&key) == BTRFS_EXTENT_DATA_KEY) { | ||
345 | extent = btrfs_item_ptr(leaf, slot, | ||
346 | struct btrfs_file_extent_item); | ||
347 | found_type = btrfs_file_extent_type(leaf, extent); | ||
348 | compression = btrfs_file_extent_compression(leaf, | ||
349 | extent); | ||
350 | encryption = btrfs_file_extent_encryption(leaf, | ||
351 | extent); | ||
352 | other_encoding = btrfs_file_extent_other_encoding(leaf, | ||
353 | extent); | ||
354 | if (found_type == BTRFS_FILE_EXTENT_REG || | ||
355 | found_type == BTRFS_FILE_EXTENT_PREALLOC) { | ||
356 | extent_end = | ||
357 | btrfs_file_extent_disk_bytenr(leaf, | ||
358 | extent); | ||
359 | if (extent_end) | ||
360 | *hint_byte = extent_end; | ||
361 | |||
362 | extent_end = key.offset + | ||
363 | btrfs_file_extent_num_bytes(leaf, extent); | ||
364 | ram_bytes = btrfs_file_extent_ram_bytes(leaf, | ||
365 | extent); | ||
366 | found_extent = 1; | ||
367 | } else if (found_type == BTRFS_FILE_EXTENT_INLINE) { | ||
368 | found_inline = 1; | ||
369 | extent_end = key.offset + | ||
370 | btrfs_file_extent_inline_len(leaf, extent); | ||
371 | } | 320 | } |
321 | leaf = path->nodes[0]; | ||
322 | recow = 1; | ||
323 | } | ||
324 | |||
325 | btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); | ||
326 | if (key.objectid > inode->i_ino || | ||
327 | key.type > BTRFS_EXTENT_DATA_KEY || key.offset >= end) | ||
328 | break; | ||
329 | |||
330 | fi = btrfs_item_ptr(leaf, path->slots[0], | ||
331 | struct btrfs_file_extent_item); | ||
332 | extent_type = btrfs_file_extent_type(leaf, fi); | ||
333 | |||
334 | if (extent_type == BTRFS_FILE_EXTENT_REG || | ||
335 | extent_type == BTRFS_FILE_EXTENT_PREALLOC) { | ||
336 | disk_bytenr = btrfs_file_extent_disk_bytenr(leaf, fi); | ||
337 | num_bytes = btrfs_file_extent_disk_num_bytes(leaf, fi); | ||
338 | extent_offset = btrfs_file_extent_offset(leaf, fi); | ||
339 | extent_end = key.offset + | ||
340 | btrfs_file_extent_num_bytes(leaf, fi); | ||
341 | } else if (extent_type == BTRFS_FILE_EXTENT_INLINE) { | ||
342 | extent_end = key.offset + | ||
343 | btrfs_file_extent_inline_len(leaf, fi); | ||
372 | } else { | 344 | } else { |
345 | WARN_ON(1); | ||
373 | extent_end = search_start; | 346 | extent_end = search_start; |
374 | } | 347 | } |
375 | 348 | ||
376 | /* we found nothing we can drop */ | 349 | if (extent_end <= search_start) { |
377 | if ((!found_extent && !found_inline) || | 350 | path->slots[0]++; |
378 | search_start >= extent_end) { | ||
379 | int nextret; | ||
380 | u32 nritems; | ||
381 | nritems = btrfs_header_nritems(leaf); | ||
382 | if (slot >= nritems - 1) { | ||
383 | nextret = btrfs_next_leaf(root, path); | ||
384 | if (nextret) | ||
385 | goto out; | ||
386 | recow = 1; | ||
387 | } else { | ||
388 | path->slots[0]++; | ||
389 | } | ||
390 | goto next_slot; | 351 | goto next_slot; |
391 | } | 352 | } |
392 | 353 | ||
393 | if (end <= extent_end && start >= key.offset && found_inline) | 354 | search_start = max(key.offset, start); |
394 | *hint_byte = EXTENT_MAP_INLINE; | 355 | if (recow) { |
395 | 356 | btrfs_release_path(root, path); | |
396 | if (found_extent) { | 357 | continue; |
397 | read_extent_buffer(leaf, &old, (unsigned long)extent, | ||
398 | sizeof(old)); | ||
399 | } | ||
400 | |||
401 | if (end < extent_end && end >= key.offset) { | ||
402 | bookend = 1; | ||
403 | if (found_inline && start <= key.offset) | ||
404 | keep = 1; | ||
405 | } | 358 | } |
406 | 359 | ||
407 | if (bookend && found_extent) { | 360 | /* |
408 | if (locked_end < extent_end) { | 361 | * | - range to drop - | |
409 | ret = try_lock_extent(&BTRFS_I(inode)->io_tree, | 362 | * | -------- extent -------- | |
410 | locked_end, extent_end - 1, | 363 | */ |
411 | GFP_NOFS); | 364 | if (start > key.offset && end < extent_end) { |
412 | if (!ret) { | 365 | BUG_ON(del_nr > 0); |
413 | btrfs_release_path(root, path); | 366 | BUG_ON(extent_type == BTRFS_FILE_EXTENT_INLINE); |
414 | lock_extent(&BTRFS_I(inode)->io_tree, | 367 | |
415 | locked_end, extent_end - 1, | 368 | memcpy(&new_key, &key, sizeof(new_key)); |
416 | GFP_NOFS); | 369 | new_key.offset = start; |
417 | locked_end = extent_end; | 370 | ret = btrfs_duplicate_item(trans, root, path, |
418 | continue; | 371 | &new_key); |
419 | } | 372 | if (ret == -EAGAIN) { |
420 | locked_end = extent_end; | 373 | btrfs_release_path(root, path); |
374 | continue; | ||
421 | } | 375 | } |
422 | disk_bytenr = le64_to_cpu(old.disk_bytenr); | 376 | if (ret < 0) |
423 | if (disk_bytenr != 0) { | 377 | break; |
378 | |||
379 | leaf = path->nodes[0]; | ||
380 | fi = btrfs_item_ptr(leaf, path->slots[0] - 1, | ||
381 | struct btrfs_file_extent_item); | ||
382 | btrfs_set_file_extent_num_bytes(leaf, fi, | ||
383 | start - key.offset); | ||
384 | |||
385 | fi = btrfs_item_ptr(leaf, path->slots[0], | ||
386 | struct btrfs_file_extent_item); | ||
387 | |||
388 | extent_offset += start - key.offset; | ||
389 | btrfs_set_file_extent_offset(leaf, fi, extent_offset); | ||
390 | btrfs_set_file_extent_num_bytes(leaf, fi, | ||
391 | extent_end - start); | ||
392 | btrfs_mark_buffer_dirty(leaf); | ||
393 | |||
394 | if (disk_bytenr > 0) { | ||
424 | ret = btrfs_inc_extent_ref(trans, root, | 395 | ret = btrfs_inc_extent_ref(trans, root, |
425 | disk_bytenr, | 396 | disk_bytenr, num_bytes, 0, |
426 | le64_to_cpu(old.disk_num_bytes), 0, | 397 | root->root_key.objectid, |
427 | root->root_key.objectid, | 398 | new_key.objectid, |
428 | key.objectid, key.offset - | 399 | start - extent_offset); |
429 | le64_to_cpu(old.offset)); | ||
430 | BUG_ON(ret); | 400 | BUG_ON(ret); |
401 | *hint_byte = disk_bytenr; | ||
431 | } | 402 | } |
403 | key.offset = start; | ||
432 | } | 404 | } |
405 | /* | ||
406 | * | ---- range to drop ----- | | ||
407 | * | -------- extent -------- | | ||
408 | */ | ||
409 | if (start <= key.offset && end < extent_end) { | ||
410 | BUG_ON(extent_type == BTRFS_FILE_EXTENT_INLINE); | ||
411 | |||
412 | memcpy(&new_key, &key, sizeof(new_key)); | ||
413 | new_key.offset = end; | ||
414 | btrfs_set_item_key_safe(trans, root, path, &new_key); | ||
433 | 415 | ||
434 | if (found_inline) { | 416 | extent_offset += end - key.offset; |
435 | u64 mask = root->sectorsize - 1; | 417 | btrfs_set_file_extent_offset(leaf, fi, extent_offset); |
436 | search_start = (extent_end + mask) & ~mask; | 418 | btrfs_set_file_extent_num_bytes(leaf, fi, |
437 | } else | 419 | extent_end - end); |
438 | search_start = extent_end; | 420 | btrfs_mark_buffer_dirty(leaf); |
439 | 421 | if (disk_bytenr > 0) { | |
440 | /* truncate existing extent */ | 422 | inode_sub_bytes(inode, end - key.offset); |
441 | if (start > key.offset) { | 423 | *hint_byte = disk_bytenr; |
442 | u64 new_num; | ||
443 | u64 old_num; | ||
444 | keep = 1; | ||
445 | WARN_ON(start & (root->sectorsize - 1)); | ||
446 | if (found_extent) { | ||
447 | new_num = start - key.offset; | ||
448 | old_num = btrfs_file_extent_num_bytes(leaf, | ||
449 | extent); | ||
450 | *hint_byte = | ||
451 | btrfs_file_extent_disk_bytenr(leaf, | ||
452 | extent); | ||
453 | if (btrfs_file_extent_disk_bytenr(leaf, | ||
454 | extent)) { | ||
455 | inode_sub_bytes(inode, old_num - | ||
456 | new_num); | ||
457 | } | ||
458 | btrfs_set_file_extent_num_bytes(leaf, | ||
459 | extent, new_num); | ||
460 | btrfs_mark_buffer_dirty(leaf); | ||
461 | } else if (key.offset < inline_limit && | ||
462 | (end > extent_end) && | ||
463 | (inline_limit < extent_end)) { | ||
464 | u32 new_size; | ||
465 | new_size = btrfs_file_extent_calc_inline_size( | ||
466 | inline_limit - key.offset); | ||
467 | inode_sub_bytes(inode, extent_end - | ||
468 | inline_limit); | ||
469 | btrfs_set_file_extent_ram_bytes(leaf, extent, | ||
470 | new_size); | ||
471 | if (!compression && !encryption) { | ||
472 | btrfs_truncate_item(trans, root, path, | ||
473 | new_size, 1); | ||
474 | } | ||
475 | } | 424 | } |
425 | break; | ||
476 | } | 426 | } |
477 | /* delete the entire extent */ | ||
478 | if (!keep) { | ||
479 | if (found_inline) | ||
480 | inode_sub_bytes(inode, extent_end - | ||
481 | key.offset); | ||
482 | ret = btrfs_del_item(trans, root, path); | ||
483 | /* TODO update progress marker and return */ | ||
484 | BUG_ON(ret); | ||
485 | extent = NULL; | ||
486 | btrfs_release_path(root, path); | ||
487 | /* the extent will be freed later */ | ||
488 | } | ||
489 | if (bookend && found_inline && start <= key.offset) { | ||
490 | u32 new_size; | ||
491 | new_size = btrfs_file_extent_calc_inline_size( | ||
492 | extent_end - end); | ||
493 | inode_sub_bytes(inode, end - key.offset); | ||
494 | btrfs_set_file_extent_ram_bytes(leaf, extent, | ||
495 | new_size); | ||
496 | if (!compression && !encryption) | ||
497 | ret = btrfs_truncate_item(trans, root, path, | ||
498 | new_size, 0); | ||
499 | BUG_ON(ret); | ||
500 | } | ||
501 | /* create bookend, splitting the extent in two */ | ||
502 | if (bookend && found_extent) { | ||
503 | struct btrfs_key ins; | ||
504 | ins.objectid = inode->i_ino; | ||
505 | ins.offset = end; | ||
506 | btrfs_set_key_type(&ins, BTRFS_EXTENT_DATA_KEY); | ||
507 | 427 | ||
508 | btrfs_release_path(root, path); | 428 | search_start = extent_end; |
509 | path->leave_spinning = 1; | 429 | /* |
510 | ret = btrfs_insert_empty_item(trans, root, path, &ins, | 430 | * | ---- range to drop ----- | |
511 | sizeof(*extent)); | 431 | * | -------- extent -------- | |
512 | BUG_ON(ret); | 432 | */ |
433 | if (start > key.offset && end >= extent_end) { | ||
434 | BUG_ON(del_nr > 0); | ||
435 | BUG_ON(extent_type == BTRFS_FILE_EXTENT_INLINE); | ||
513 | 436 | ||
514 | leaf = path->nodes[0]; | 437 | btrfs_set_file_extent_num_bytes(leaf, fi, |
515 | extent = btrfs_item_ptr(leaf, path->slots[0], | 438 | start - key.offset); |
516 | struct btrfs_file_extent_item); | 439 | btrfs_mark_buffer_dirty(leaf); |
517 | write_extent_buffer(leaf, &old, | 440 | if (disk_bytenr > 0) { |
518 | (unsigned long)extent, sizeof(old)); | 441 | inode_sub_bytes(inode, extent_end - start); |
519 | 442 | *hint_byte = disk_bytenr; | |
520 | btrfs_set_file_extent_compression(leaf, extent, | 443 | } |
521 | compression); | 444 | if (end == extent_end) |
522 | btrfs_set_file_extent_encryption(leaf, extent, | 445 | break; |
523 | encryption); | ||
524 | btrfs_set_file_extent_other_encoding(leaf, extent, | ||
525 | other_encoding); | ||
526 | btrfs_set_file_extent_offset(leaf, extent, | ||
527 | le64_to_cpu(old.offset) + end - key.offset); | ||
528 | WARN_ON(le64_to_cpu(old.num_bytes) < | ||
529 | (extent_end - end)); | ||
530 | btrfs_set_file_extent_num_bytes(leaf, extent, | ||
531 | extent_end - end); | ||
532 | 446 | ||
533 | /* | 447 | path->slots[0]++; |
534 | * set the ram bytes to the size of the full extent | 448 | goto next_slot; |
535 | * before splitting. This is a worst case flag, | ||
536 | * but its the best we can do because we don't know | ||
537 | * how splitting affects compression | ||
538 | */ | ||
539 | btrfs_set_file_extent_ram_bytes(leaf, extent, | ||
540 | ram_bytes); | ||
541 | btrfs_set_file_extent_type(leaf, extent, found_type); | ||
542 | |||
543 | btrfs_unlock_up_safe(path, 1); | ||
544 | btrfs_mark_buffer_dirty(path->nodes[0]); | ||
545 | btrfs_set_lock_blocking(path->nodes[0]); | ||
546 | |||
547 | path->leave_spinning = 0; | ||
548 | btrfs_release_path(root, path); | ||
549 | if (disk_bytenr != 0) | ||
550 | inode_add_bytes(inode, extent_end - end); | ||
551 | } | 449 | } |
552 | 450 | ||
553 | if (found_extent && !keep) { | 451 | /* |
554 | u64 old_disk_bytenr = le64_to_cpu(old.disk_bytenr); | 452 | * | ---- range to drop ----- | |
453 | * | ------ extent ------ | | ||
454 | */ | ||
455 | if (start <= key.offset && end >= extent_end) { | ||
456 | if (del_nr == 0) { | ||
457 | del_slot = path->slots[0]; | ||
458 | del_nr = 1; | ||
459 | } else { | ||
460 | BUG_ON(del_slot + del_nr != path->slots[0]); | ||
461 | del_nr++; | ||
462 | } | ||
555 | 463 | ||
556 | if (old_disk_bytenr != 0) { | 464 | if (extent_type == BTRFS_FILE_EXTENT_INLINE) { |
557 | inode_sub_bytes(inode, | 465 | inode_sub_bytes(inode, |
558 | le64_to_cpu(old.num_bytes)); | 466 | extent_end - key.offset); |
467 | extent_end = ALIGN(extent_end, | ||
468 | root->sectorsize); | ||
469 | } else if (disk_bytenr > 0) { | ||
559 | ret = btrfs_free_extent(trans, root, | 470 | ret = btrfs_free_extent(trans, root, |
560 | old_disk_bytenr, | 471 | disk_bytenr, num_bytes, 0, |
561 | le64_to_cpu(old.disk_num_bytes), | 472 | root->root_key.objectid, |
562 | 0, root->root_key.objectid, | ||
563 | key.objectid, key.offset - | 473 | key.objectid, key.offset - |
564 | le64_to_cpu(old.offset)); | 474 | extent_offset); |
565 | BUG_ON(ret); | 475 | BUG_ON(ret); |
566 | *hint_byte = old_disk_bytenr; | 476 | inode_sub_bytes(inode, |
477 | extent_end - key.offset); | ||
478 | *hint_byte = disk_bytenr; | ||
567 | } | 479 | } |
568 | } | ||
569 | 480 | ||
570 | if (search_start >= end) { | 481 | if (end == extent_end) |
571 | ret = 0; | 482 | break; |
572 | goto out; | 483 | |
484 | if (path->slots[0] + 1 < btrfs_header_nritems(leaf)) { | ||
485 | path->slots[0]++; | ||
486 | goto next_slot; | ||
487 | } | ||
488 | |||
489 | ret = btrfs_del_items(trans, root, path, del_slot, | ||
490 | del_nr); | ||
491 | BUG_ON(ret); | ||
492 | |||
493 | del_nr = 0; | ||
494 | del_slot = 0; | ||
495 | |||
496 | btrfs_release_path(root, path); | ||
497 | continue; | ||
573 | } | 498 | } |
499 | |||
500 | BUG_ON(1); | ||
574 | } | 501 | } |
575 | out: | 502 | |
576 | btrfs_free_path(path); | 503 | if (del_nr > 0) { |
577 | if (locked_end > orig_locked_end) { | 504 | ret = btrfs_del_items(trans, root, path, del_slot, del_nr); |
578 | unlock_extent(&BTRFS_I(inode)->io_tree, orig_locked_end, | 505 | BUG_ON(ret); |
579 | locked_end - 1, GFP_NOFS); | ||
580 | } | 506 | } |
507 | |||
508 | btrfs_free_path(path); | ||
581 | return ret; | 509 | return ret; |
582 | } | 510 | } |
583 | 511 | ||
@@ -620,23 +548,23 @@ static int extent_mergeable(struct extent_buffer *leaf, int slot, | |||
620 | * two or three. | 548 | * two or three. |
621 | */ | 549 | */ |
622 | int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, | 550 | int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, |
623 | struct btrfs_root *root, | ||
624 | struct inode *inode, u64 start, u64 end) | 551 | struct inode *inode, u64 start, u64 end) |
625 | { | 552 | { |
553 | struct btrfs_root *root = BTRFS_I(inode)->root; | ||
626 | struct extent_buffer *leaf; | 554 | struct extent_buffer *leaf; |
627 | struct btrfs_path *path; | 555 | struct btrfs_path *path; |
628 | struct btrfs_file_extent_item *fi; | 556 | struct btrfs_file_extent_item *fi; |
629 | struct btrfs_key key; | 557 | struct btrfs_key key; |
558 | struct btrfs_key new_key; | ||
630 | u64 bytenr; | 559 | u64 bytenr; |
631 | u64 num_bytes; | 560 | u64 num_bytes; |
632 | u64 extent_end; | 561 | u64 extent_end; |
633 | u64 orig_offset; | 562 | u64 orig_offset; |
634 | u64 other_start; | 563 | u64 other_start; |
635 | u64 other_end; | 564 | u64 other_end; |
636 | u64 split = start; | 565 | u64 split; |
637 | u64 locked_end = end; | 566 | int del_nr = 0; |
638 | int extent_type; | 567 | int del_slot = 0; |
639 | int split_end = 1; | ||
640 | int ret; | 568 | int ret; |
641 | 569 | ||
642 | btrfs_drop_extent_cache(inode, start, end - 1, 0); | 570 | btrfs_drop_extent_cache(inode, start, end - 1, 0); |
@@ -644,12 +572,10 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, | |||
644 | path = btrfs_alloc_path(); | 572 | path = btrfs_alloc_path(); |
645 | BUG_ON(!path); | 573 | BUG_ON(!path); |
646 | again: | 574 | again: |
575 | split = start; | ||
647 | key.objectid = inode->i_ino; | 576 | key.objectid = inode->i_ino; |
648 | key.type = BTRFS_EXTENT_DATA_KEY; | 577 | key.type = BTRFS_EXTENT_DATA_KEY; |
649 | if (split == start) | 578 | key.offset = split; |
650 | key.offset = split; | ||
651 | else | ||
652 | key.offset = split - 1; | ||
653 | 579 | ||
654 | ret = btrfs_search_slot(trans, root, &key, path, -1, 1); | 580 | ret = btrfs_search_slot(trans, root, &key, path, -1, 1); |
655 | if (ret > 0 && path->slots[0] > 0) | 581 | if (ret > 0 && path->slots[0] > 0) |
@@ -661,8 +587,8 @@ again: | |||
661 | key.type != BTRFS_EXTENT_DATA_KEY); | 587 | key.type != BTRFS_EXTENT_DATA_KEY); |
662 | fi = btrfs_item_ptr(leaf, path->slots[0], | 588 | fi = btrfs_item_ptr(leaf, path->slots[0], |
663 | struct btrfs_file_extent_item); | 589 | struct btrfs_file_extent_item); |
664 | extent_type = btrfs_file_extent_type(leaf, fi); | 590 | BUG_ON(btrfs_file_extent_type(leaf, fi) != |
665 | BUG_ON(extent_type != BTRFS_FILE_EXTENT_PREALLOC); | 591 | BTRFS_FILE_EXTENT_PREALLOC); |
666 | extent_end = key.offset + btrfs_file_extent_num_bytes(leaf, fi); | 592 | extent_end = key.offset + btrfs_file_extent_num_bytes(leaf, fi); |
667 | BUG_ON(key.offset > start || extent_end < end); | 593 | BUG_ON(key.offset > start || extent_end < end); |
668 | 594 | ||
@@ -670,150 +596,91 @@ again: | |||
670 | num_bytes = btrfs_file_extent_disk_num_bytes(leaf, fi); | 596 | num_bytes = btrfs_file_extent_disk_num_bytes(leaf, fi); |
671 | orig_offset = key.offset - btrfs_file_extent_offset(leaf, fi); | 597 | orig_offset = key.offset - btrfs_file_extent_offset(leaf, fi); |
672 | 598 | ||
673 | if (key.offset == start) | 599 | while (start > key.offset || end < extent_end) { |
674 | split = end; | 600 | if (key.offset == start) |
675 | 601 | split = end; | |
676 | if (key.offset == start && extent_end == end) { | 602 | |
677 | int del_nr = 0; | 603 | memcpy(&new_key, &key, sizeof(new_key)); |
678 | int del_slot = 0; | 604 | new_key.offset = split; |
679 | other_start = end; | 605 | ret = btrfs_duplicate_item(trans, root, path, &new_key); |
680 | other_end = 0; | 606 | if (ret == -EAGAIN) { |
681 | if (extent_mergeable(leaf, path->slots[0] + 1, inode->i_ino, | 607 | btrfs_release_path(root, path); |
682 | bytenr, &other_start, &other_end)) { | 608 | goto again; |
683 | extent_end = other_end; | ||
684 | del_slot = path->slots[0] + 1; | ||
685 | del_nr++; | ||
686 | ret = btrfs_free_extent(trans, root, bytenr, num_bytes, | ||
687 | 0, root->root_key.objectid, | ||
688 | inode->i_ino, orig_offset); | ||
689 | BUG_ON(ret); | ||
690 | } | ||
691 | other_start = 0; | ||
692 | other_end = start; | ||
693 | if (extent_mergeable(leaf, path->slots[0] - 1, inode->i_ino, | ||
694 | bytenr, &other_start, &other_end)) { | ||
695 | key.offset = other_start; | ||
696 | del_slot = path->slots[0]; | ||
697 | del_nr++; | ||
698 | ret = btrfs_free_extent(trans, root, bytenr, num_bytes, | ||
699 | 0, root->root_key.objectid, | ||
700 | inode->i_ino, orig_offset); | ||
701 | BUG_ON(ret); | ||
702 | } | ||
703 | split_end = 0; | ||
704 | if (del_nr == 0) { | ||
705 | btrfs_set_file_extent_type(leaf, fi, | ||
706 | BTRFS_FILE_EXTENT_REG); | ||
707 | goto done; | ||
708 | } | 609 | } |
610 | BUG_ON(ret < 0); | ||
709 | 611 | ||
710 | fi = btrfs_item_ptr(leaf, del_slot - 1, | 612 | leaf = path->nodes[0]; |
613 | fi = btrfs_item_ptr(leaf, path->slots[0] - 1, | ||
711 | struct btrfs_file_extent_item); | 614 | struct btrfs_file_extent_item); |
712 | btrfs_set_file_extent_type(leaf, fi, BTRFS_FILE_EXTENT_REG); | ||
713 | btrfs_set_file_extent_num_bytes(leaf, fi, | 615 | btrfs_set_file_extent_num_bytes(leaf, fi, |
714 | extent_end - key.offset); | 616 | split - key.offset); |
617 | |||
618 | fi = btrfs_item_ptr(leaf, path->slots[0], | ||
619 | struct btrfs_file_extent_item); | ||
620 | |||
621 | btrfs_set_file_extent_offset(leaf, fi, split - orig_offset); | ||
622 | btrfs_set_file_extent_num_bytes(leaf, fi, | ||
623 | extent_end - split); | ||
715 | btrfs_mark_buffer_dirty(leaf); | 624 | btrfs_mark_buffer_dirty(leaf); |
716 | 625 | ||
717 | ret = btrfs_del_items(trans, root, path, del_slot, del_nr); | 626 | ret = btrfs_inc_extent_ref(trans, root, bytenr, num_bytes, 0, |
627 | root->root_key.objectid, | ||
628 | inode->i_ino, orig_offset); | ||
718 | BUG_ON(ret); | 629 | BUG_ON(ret); |
719 | goto release; | ||
720 | } else if (split == start) { | ||
721 | if (locked_end < extent_end) { | ||
722 | ret = try_lock_extent(&BTRFS_I(inode)->io_tree, | ||
723 | locked_end, extent_end - 1, GFP_NOFS); | ||
724 | if (!ret) { | ||
725 | btrfs_release_path(root, path); | ||
726 | lock_extent(&BTRFS_I(inode)->io_tree, | ||
727 | locked_end, extent_end - 1, GFP_NOFS); | ||
728 | locked_end = extent_end; | ||
729 | goto again; | ||
730 | } | ||
731 | locked_end = extent_end; | ||
732 | } | ||
733 | btrfs_set_file_extent_num_bytes(leaf, fi, split - key.offset); | ||
734 | } else { | ||
735 | BUG_ON(key.offset != start); | ||
736 | key.offset = split; | ||
737 | btrfs_set_file_extent_offset(leaf, fi, key.offset - | ||
738 | orig_offset); | ||
739 | btrfs_set_file_extent_num_bytes(leaf, fi, extent_end - split); | ||
740 | btrfs_set_item_key_safe(trans, root, path, &key); | ||
741 | extent_end = split; | ||
742 | } | ||
743 | 630 | ||
744 | if (extent_end == end) { | 631 | if (split == start) { |
745 | split_end = 0; | 632 | key.offset = start; |
746 | extent_type = BTRFS_FILE_EXTENT_REG; | 633 | } else { |
747 | } | 634 | BUG_ON(start != key.offset); |
748 | if (extent_end == end && split == start) { | ||
749 | other_start = end; | ||
750 | other_end = 0; | ||
751 | if (extent_mergeable(leaf, path->slots[0] + 1, inode->i_ino, | ||
752 | bytenr, &other_start, &other_end)) { | ||
753 | path->slots[0]++; | ||
754 | fi = btrfs_item_ptr(leaf, path->slots[0], | ||
755 | struct btrfs_file_extent_item); | ||
756 | key.offset = split; | ||
757 | btrfs_set_item_key_safe(trans, root, path, &key); | ||
758 | btrfs_set_file_extent_offset(leaf, fi, key.offset - | ||
759 | orig_offset); | ||
760 | btrfs_set_file_extent_num_bytes(leaf, fi, | ||
761 | other_end - split); | ||
762 | goto done; | ||
763 | } | ||
764 | } | ||
765 | if (extent_end == end && split == end) { | ||
766 | other_start = 0; | ||
767 | other_end = start; | ||
768 | if (extent_mergeable(leaf, path->slots[0] - 1 , inode->i_ino, | ||
769 | bytenr, &other_start, &other_end)) { | ||
770 | path->slots[0]--; | 635 | path->slots[0]--; |
771 | fi = btrfs_item_ptr(leaf, path->slots[0], | 636 | extent_end = end; |
772 | struct btrfs_file_extent_item); | ||
773 | btrfs_set_file_extent_num_bytes(leaf, fi, extent_end - | ||
774 | other_start); | ||
775 | goto done; | ||
776 | } | 637 | } |
777 | } | 638 | } |
778 | 639 | ||
779 | btrfs_mark_buffer_dirty(leaf); | ||
780 | |||
781 | ret = btrfs_inc_extent_ref(trans, root, bytenr, num_bytes, 0, | ||
782 | root->root_key.objectid, | ||
783 | inode->i_ino, orig_offset); | ||
784 | BUG_ON(ret); | ||
785 | btrfs_release_path(root, path); | ||
786 | |||
787 | key.offset = start; | ||
788 | ret = btrfs_insert_empty_item(trans, root, path, &key, sizeof(*fi)); | ||
789 | BUG_ON(ret); | ||
790 | |||
791 | leaf = path->nodes[0]; | ||
792 | fi = btrfs_item_ptr(leaf, path->slots[0], | 640 | fi = btrfs_item_ptr(leaf, path->slots[0], |
793 | struct btrfs_file_extent_item); | 641 | struct btrfs_file_extent_item); |
794 | btrfs_set_file_extent_generation(leaf, fi, trans->transid); | ||
795 | btrfs_set_file_extent_type(leaf, fi, extent_type); | ||
796 | btrfs_set_file_extent_disk_bytenr(leaf, fi, bytenr); | ||
797 | btrfs_set_file_extent_disk_num_bytes(leaf, fi, num_bytes); | ||
798 | btrfs_set_file_extent_offset(leaf, fi, key.offset - orig_offset); | ||
799 | btrfs_set_file_extent_num_bytes(leaf, fi, extent_end - key.offset); | ||
800 | btrfs_set_file_extent_ram_bytes(leaf, fi, num_bytes); | ||
801 | btrfs_set_file_extent_compression(leaf, fi, 0); | ||
802 | btrfs_set_file_extent_encryption(leaf, fi, 0); | ||
803 | btrfs_set_file_extent_other_encoding(leaf, fi, 0); | ||
804 | done: | ||
805 | btrfs_mark_buffer_dirty(leaf); | ||
806 | 642 | ||
807 | release: | 643 | other_start = end; |
808 | btrfs_release_path(root, path); | 644 | other_end = 0; |
809 | if (split_end && split == start) { | 645 | if (extent_mergeable(leaf, path->slots[0] + 1, inode->i_ino, |
810 | split = end; | 646 | bytenr, &other_start, &other_end)) { |
811 | goto again; | 647 | extent_end = other_end; |
648 | del_slot = path->slots[0] + 1; | ||
649 | del_nr++; | ||
650 | ret = btrfs_free_extent(trans, root, bytenr, num_bytes, | ||
651 | 0, root->root_key.objectid, | ||
652 | inode->i_ino, orig_offset); | ||
653 | BUG_ON(ret); | ||
812 | } | 654 | } |
813 | if (locked_end > end) { | 655 | other_start = 0; |
814 | unlock_extent(&BTRFS_I(inode)->io_tree, end, locked_end - 1, | 656 | other_end = start; |
815 | GFP_NOFS); | 657 | if (extent_mergeable(leaf, path->slots[0] - 1, inode->i_ino, |
658 | bytenr, &other_start, &other_end)) { | ||
659 | key.offset = other_start; | ||
660 | del_slot = path->slots[0]; | ||
661 | del_nr++; | ||
662 | ret = btrfs_free_extent(trans, root, bytenr, num_bytes, | ||
663 | 0, root->root_key.objectid, | ||
664 | inode->i_ino, orig_offset); | ||
665 | BUG_ON(ret); | ||
816 | } | 666 | } |
667 | if (del_nr == 0) { | ||
668 | btrfs_set_file_extent_type(leaf, fi, | ||
669 | BTRFS_FILE_EXTENT_REG); | ||
670 | btrfs_mark_buffer_dirty(leaf); | ||
671 | goto out; | ||
672 | } | ||
673 | |||
674 | fi = btrfs_item_ptr(leaf, del_slot - 1, | ||
675 | struct btrfs_file_extent_item); | ||
676 | btrfs_set_file_extent_type(leaf, fi, BTRFS_FILE_EXTENT_REG); | ||
677 | btrfs_set_file_extent_num_bytes(leaf, fi, | ||
678 | extent_end - key.offset); | ||
679 | btrfs_mark_buffer_dirty(leaf); | ||
680 | |||
681 | ret = btrfs_del_items(trans, root, path, del_slot, del_nr); | ||
682 | BUG_ON(ret); | ||
683 | out: | ||
817 | btrfs_free_path(path); | 684 | btrfs_free_path(path); |
818 | return 0; | 685 | return 0; |
819 | } | 686 | } |