diff options
Diffstat (limited to 'fs/btrfs/file.c')
| -rw-r--r-- | fs/btrfs/file.c | 669 |
1 files changed, 266 insertions, 403 deletions
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 77f759302e12..feaa13b105d9 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
| @@ -179,18 +179,14 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end, | |||
| 179 | } | 179 | } |
| 180 | flags = em->flags; | 180 | flags = em->flags; |
| 181 | if (skip_pinned && test_bit(EXTENT_FLAG_PINNED, &em->flags)) { | 181 | if (skip_pinned && test_bit(EXTENT_FLAG_PINNED, &em->flags)) { |
| 182 | if (em->start <= start && | 182 | if (testend && em->start + em->len >= start + len) { |
| 183 | (!testend || em->start + em->len >= start + len)) { | ||
| 184 | free_extent_map(em); | 183 | free_extent_map(em); |
| 185 | write_unlock(&em_tree->lock); | 184 | write_unlock(&em_tree->lock); |
| 186 | break; | 185 | break; |
| 187 | } | 186 | } |
| 188 | if (start < em->start) { | 187 | start = em->start + em->len; |
| 189 | len = em->start - start; | 188 | if (testend) |
| 190 | } else { | ||
| 191 | len = start + len - (em->start + em->len); | 189 | len = start + len - (em->start + em->len); |
| 192 | start = em->start + em->len; | ||
| 193 | } | ||
| 194 | free_extent_map(em); | 190 | free_extent_map(em); |
| 195 | write_unlock(&em_tree->lock); | 191 | write_unlock(&em_tree->lock); |
| 196 | continue; | 192 | continue; |
| @@ -265,319 +261,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 | 261 | * 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 | 262 | * it is either truncated or split. Anything entirely inside the range |
| 267 | * is deleted from the tree. | 263 | * 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 | */ | 264 | */ |
| 272 | noinline int btrfs_drop_extents(struct btrfs_trans_handle *trans, | 265 | int btrfs_drop_extents(struct btrfs_trans_handle *trans, struct inode *inode, |
| 273 | struct btrfs_root *root, struct inode *inode, | 266 | 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 | { | 267 | { |
| 277 | u64 extent_end = 0; | 268 | 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; | 269 | struct extent_buffer *leaf; |
| 286 | struct btrfs_file_extent_item *extent; | 270 | struct btrfs_file_extent_item *fi; |
| 287 | struct btrfs_path *path; | 271 | struct btrfs_path *path; |
| 288 | struct btrfs_key key; | 272 | struct btrfs_key key; |
| 289 | struct btrfs_file_extent_item old; | 273 | struct btrfs_key new_key; |
| 290 | int keep; | 274 | u64 search_start = start; |
| 291 | int slot; | 275 | u64 disk_bytenr = 0; |
| 292 | int bookend; | 276 | u64 num_bytes = 0; |
| 293 | int found_type = 0; | 277 | u64 extent_offset = 0; |
| 294 | int found_extent; | 278 | u64 extent_end = 0; |
| 295 | int found_inline; | 279 | int del_nr = 0; |
| 280 | int del_slot = 0; | ||
| 281 | int extent_type; | ||
| 296 | int recow; | 282 | int recow; |
| 297 | int ret; | 283 | int ret; |
| 298 | 284 | ||
| 299 | inline_limit = 0; | ||
| 300 | if (drop_cache) | 285 | if (drop_cache) |
| 301 | btrfs_drop_extent_cache(inode, start, end - 1, 0); | 286 | btrfs_drop_extent_cache(inode, start, end - 1, 0); |
| 302 | 287 | ||
| 303 | path = btrfs_alloc_path(); | 288 | path = btrfs_alloc_path(); |
| 304 | if (!path) | 289 | if (!path) |
| 305 | return -ENOMEM; | 290 | return -ENOMEM; |
| 291 | |||
| 306 | while (1) { | 292 | while (1) { |
| 307 | recow = 0; | 293 | recow = 0; |
| 308 | btrfs_release_path(root, path); | ||
| 309 | ret = btrfs_lookup_file_extent(trans, root, path, inode->i_ino, | 294 | ret = btrfs_lookup_file_extent(trans, root, path, inode->i_ino, |
| 310 | search_start, -1); | 295 | search_start, -1); |
| 311 | if (ret < 0) | 296 | if (ret < 0) |
| 312 | goto out; | 297 | break; |
| 313 | if (ret > 0) { | 298 | if (ret > 0 && path->slots[0] > 0 && search_start == start) { |
| 314 | if (path->slots[0] == 0) { | 299 | leaf = path->nodes[0]; |
| 315 | ret = 0; | 300 | btrfs_item_key_to_cpu(leaf, &key, path->slots[0] - 1); |
| 316 | goto out; | 301 | if (key.objectid == inode->i_ino && |
| 317 | } | 302 | key.type == BTRFS_EXTENT_DATA_KEY) |
| 318 | path->slots[0]--; | 303 | path->slots[0]--; |
| 319 | } | 304 | } |
| 305 | ret = 0; | ||
| 320 | next_slot: | 306 | 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]; | 307 | leaf = path->nodes[0]; |
| 329 | slot = path->slots[0]; | 308 | if (path->slots[0] >= btrfs_header_nritems(leaf)) { |
| 330 | ret = 0; | 309 | BUG_ON(del_nr > 0); |
| 331 | btrfs_item_key_to_cpu(leaf, &key, slot); | 310 | ret = btrfs_next_leaf(root, path); |
| 332 | if (btrfs_key_type(&key) == BTRFS_EXTENT_DATA_KEY && | 311 | if (ret < 0) |
| 333 | key.offset >= end) { | 312 | break; |
| 334 | goto out; | 313 | if (ret > 0) { |
| 335 | } | 314 | ret = 0; |
| 336 | if (btrfs_key_type(&key) > BTRFS_EXTENT_DATA_KEY || | 315 | 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 | } | 316 | } |
| 317 | leaf = path->nodes[0]; | ||
| 318 | recow = 1; | ||
| 319 | } | ||
| 320 | |||
| 321 | btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); | ||
| 322 | if (key.objectid > inode->i_ino || | ||
| 323 | key.type > BTRFS_EXTENT_DATA_KEY || key.offset >= end) | ||
| 324 | break; | ||
| 325 | |||
| 326 | fi = btrfs_item_ptr(leaf, path->slots[0], | ||
| 327 | struct btrfs_file_extent_item); | ||
| 328 | extent_type = btrfs_file_extent_type(leaf, fi); | ||
| 329 | |||
| 330 | if (extent_type == BTRFS_FILE_EXTENT_REG || | ||
| 331 | extent_type == BTRFS_FILE_EXTENT_PREALLOC) { | ||
| 332 | disk_bytenr = btrfs_file_extent_disk_bytenr(leaf, fi); | ||
| 333 | num_bytes = btrfs_file_extent_disk_num_bytes(leaf, fi); | ||
| 334 | extent_offset = btrfs_file_extent_offset(leaf, fi); | ||
| 335 | extent_end = key.offset + | ||
| 336 | btrfs_file_extent_num_bytes(leaf, fi); | ||
| 337 | } else if (extent_type == BTRFS_FILE_EXTENT_INLINE) { | ||
| 338 | extent_end = key.offset + | ||
| 339 | btrfs_file_extent_inline_len(leaf, fi); | ||
| 372 | } else { | 340 | } else { |
| 341 | WARN_ON(1); | ||
| 373 | extent_end = search_start; | 342 | extent_end = search_start; |
| 374 | } | 343 | } |
| 375 | 344 | ||
| 376 | /* we found nothing we can drop */ | 345 | if (extent_end <= search_start) { |
| 377 | if ((!found_extent && !found_inline) || | 346 | 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; | 347 | goto next_slot; |
| 391 | } | 348 | } |
| 392 | 349 | ||
| 393 | if (end <= extent_end && start >= key.offset && found_inline) | 350 | search_start = max(key.offset, start); |
| 394 | *hint_byte = EXTENT_MAP_INLINE; | 351 | if (recow) { |
| 395 | 352 | btrfs_release_path(root, path); | |
| 396 | if (found_extent) { | 353 | 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 | } | 354 | } |
| 406 | 355 | ||
| 407 | if (bookend && found_extent) { | 356 | /* |
| 408 | if (locked_end < extent_end) { | 357 | * | - range to drop - | |
| 409 | ret = try_lock_extent(&BTRFS_I(inode)->io_tree, | 358 | * | -------- extent -------- | |
| 410 | locked_end, extent_end - 1, | 359 | */ |
| 411 | GFP_NOFS); | 360 | if (start > key.offset && end < extent_end) { |
| 412 | if (!ret) { | 361 | BUG_ON(del_nr > 0); |
| 413 | btrfs_release_path(root, path); | 362 | BUG_ON(extent_type == BTRFS_FILE_EXTENT_INLINE); |
| 414 | lock_extent(&BTRFS_I(inode)->io_tree, | 363 | |
| 415 | locked_end, extent_end - 1, | 364 | memcpy(&new_key, &key, sizeof(new_key)); |
| 416 | GFP_NOFS); | 365 | new_key.offset = start; |
| 417 | locked_end = extent_end; | 366 | ret = btrfs_duplicate_item(trans, root, path, |
| 418 | continue; | 367 | &new_key); |
| 419 | } | 368 | if (ret == -EAGAIN) { |
| 420 | locked_end = extent_end; | 369 | btrfs_release_path(root, path); |
| 370 | continue; | ||
| 421 | } | 371 | } |
| 422 | disk_bytenr = le64_to_cpu(old.disk_bytenr); | 372 | if (ret < 0) |
| 423 | if (disk_bytenr != 0) { | 373 | break; |
| 374 | |||
| 375 | leaf = path->nodes[0]; | ||
| 376 | fi = btrfs_item_ptr(leaf, path->slots[0] - 1, | ||
| 377 | struct btrfs_file_extent_item); | ||
| 378 | btrfs_set_file_extent_num_bytes(leaf, fi, | ||
| 379 | start - key.offset); | ||
| 380 | |||
| 381 | fi = btrfs_item_ptr(leaf, path->slots[0], | ||
| 382 | struct btrfs_file_extent_item); | ||
| 383 | |||
| 384 | extent_offset += start - key.offset; | ||
| 385 | btrfs_set_file_extent_offset(leaf, fi, extent_offset); | ||
| 386 | btrfs_set_file_extent_num_bytes(leaf, fi, | ||
| 387 | extent_end - start); | ||
| 388 | btrfs_mark_buffer_dirty(leaf); | ||
| 389 | |||
| 390 | if (disk_bytenr > 0) { | ||
| 424 | ret = btrfs_inc_extent_ref(trans, root, | 391 | ret = btrfs_inc_extent_ref(trans, root, |
| 425 | disk_bytenr, | 392 | disk_bytenr, num_bytes, 0, |
| 426 | le64_to_cpu(old.disk_num_bytes), 0, | 393 | root->root_key.objectid, |
| 427 | root->root_key.objectid, | 394 | new_key.objectid, |
| 428 | key.objectid, key.offset - | 395 | start - extent_offset); |
| 429 | le64_to_cpu(old.offset)); | ||
| 430 | BUG_ON(ret); | 396 | BUG_ON(ret); |
| 397 | *hint_byte = disk_bytenr; | ||
| 431 | } | 398 | } |
| 399 | key.offset = start; | ||
| 432 | } | 400 | } |
| 401 | /* | ||
| 402 | * | ---- range to drop ----- | | ||
| 403 | * | -------- extent -------- | | ||
| 404 | */ | ||
| 405 | if (start <= key.offset && end < extent_end) { | ||
| 406 | BUG_ON(extent_type == BTRFS_FILE_EXTENT_INLINE); | ||
| 433 | 407 | ||
| 434 | if (found_inline) { | 408 | memcpy(&new_key, &key, sizeof(new_key)); |
| 435 | u64 mask = root->sectorsize - 1; | 409 | new_key.offset = end; |
| 436 | search_start = (extent_end + mask) & ~mask; | 410 | btrfs_set_item_key_safe(trans, root, path, &new_key); |
| 437 | } else | 411 | |
| 438 | search_start = extent_end; | 412 | extent_offset += end - key.offset; |
| 439 | 413 | btrfs_set_file_extent_offset(leaf, fi, extent_offset); | |
| 440 | /* truncate existing extent */ | 414 | btrfs_set_file_extent_num_bytes(leaf, fi, |
| 441 | if (start > key.offset) { | 415 | extent_end - end); |
| 442 | u64 new_num; | 416 | btrfs_mark_buffer_dirty(leaf); |
| 443 | u64 old_num; | 417 | if (disk_bytenr > 0) { |
| 444 | keep = 1; | 418 | inode_sub_bytes(inode, end - key.offset); |
| 445 | WARN_ON(start & (root->sectorsize - 1)); | 419 | *hint_byte = disk_bytenr; |
| 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 | } | 420 | } |
| 421 | break; | ||
| 476 | } | 422 | } |
| 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 | 423 | ||
| 508 | btrfs_release_path(root, path); | 424 | search_start = extent_end; |
| 509 | path->leave_spinning = 1; | 425 | /* |
| 510 | ret = btrfs_insert_empty_item(trans, root, path, &ins, | 426 | * | ---- range to drop ----- | |
| 511 | sizeof(*extent)); | 427 | * | -------- extent -------- | |
| 512 | BUG_ON(ret); | 428 | */ |
| 429 | if (start > key.offset && end >= extent_end) { | ||
| 430 | BUG_ON(del_nr > 0); | ||
| 431 | BUG_ON(extent_type == BTRFS_FILE_EXTENT_INLINE); | ||
| 513 | 432 | ||
| 514 | leaf = path->nodes[0]; | 433 | btrfs_set_file_extent_num_bytes(leaf, fi, |
| 515 | extent = btrfs_item_ptr(leaf, path->slots[0], | 434 | start - key.offset); |
| 516 | struct btrfs_file_extent_item); | 435 | btrfs_mark_buffer_dirty(leaf); |
| 517 | write_extent_buffer(leaf, &old, | 436 | if (disk_bytenr > 0) { |
| 518 | (unsigned long)extent, sizeof(old)); | 437 | inode_sub_bytes(inode, extent_end - start); |
| 519 | 438 | *hint_byte = disk_bytenr; | |
| 520 | btrfs_set_file_extent_compression(leaf, extent, | 439 | } |
| 521 | compression); | 440 | if (end == extent_end) |
| 522 | btrfs_set_file_extent_encryption(leaf, extent, | 441 | 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 | 442 | ||
| 533 | /* | 443 | path->slots[0]++; |
| 534 | * set the ram bytes to the size of the full extent | 444 | 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 | } | 445 | } |
| 552 | 446 | ||
| 553 | if (found_extent && !keep) { | 447 | /* |
| 554 | u64 old_disk_bytenr = le64_to_cpu(old.disk_bytenr); | 448 | * | ---- range to drop ----- | |
| 449 | * | ------ extent ------ | | ||
| 450 | */ | ||
| 451 | if (start <= key.offset && end >= extent_end) { | ||
| 452 | if (del_nr == 0) { | ||
| 453 | del_slot = path->slots[0]; | ||
| 454 | del_nr = 1; | ||
| 455 | } else { | ||
| 456 | BUG_ON(del_slot + del_nr != path->slots[0]); | ||
| 457 | del_nr++; | ||
| 458 | } | ||
| 555 | 459 | ||
| 556 | if (old_disk_bytenr != 0) { | 460 | if (extent_type == BTRFS_FILE_EXTENT_INLINE) { |
| 557 | inode_sub_bytes(inode, | 461 | inode_sub_bytes(inode, |
| 558 | le64_to_cpu(old.num_bytes)); | 462 | extent_end - key.offset); |
| 463 | extent_end = ALIGN(extent_end, | ||
| 464 | root->sectorsize); | ||
| 465 | } else if (disk_bytenr > 0) { | ||
| 559 | ret = btrfs_free_extent(trans, root, | 466 | ret = btrfs_free_extent(trans, root, |
| 560 | old_disk_bytenr, | 467 | disk_bytenr, num_bytes, 0, |
| 561 | le64_to_cpu(old.disk_num_bytes), | 468 | root->root_key.objectid, |
| 562 | 0, root->root_key.objectid, | ||
| 563 | key.objectid, key.offset - | 469 | key.objectid, key.offset - |
| 564 | le64_to_cpu(old.offset)); | 470 | extent_offset); |
| 565 | BUG_ON(ret); | 471 | BUG_ON(ret); |
| 566 | *hint_byte = old_disk_bytenr; | 472 | inode_sub_bytes(inode, |
| 473 | extent_end - key.offset); | ||
| 474 | *hint_byte = disk_bytenr; | ||
| 567 | } | 475 | } |
| 568 | } | ||
| 569 | 476 | ||
| 570 | if (search_start >= end) { | 477 | if (end == extent_end) |
| 571 | ret = 0; | 478 | break; |
| 572 | goto out; | 479 | |
| 480 | if (path->slots[0] + 1 < btrfs_header_nritems(leaf)) { | ||
| 481 | path->slots[0]++; | ||
| 482 | goto next_slot; | ||
| 483 | } | ||
| 484 | |||
| 485 | ret = btrfs_del_items(trans, root, path, del_slot, | ||
| 486 | del_nr); | ||
| 487 | BUG_ON(ret); | ||
| 488 | |||
| 489 | del_nr = 0; | ||
| 490 | del_slot = 0; | ||
| 491 | |||
| 492 | btrfs_release_path(root, path); | ||
| 493 | continue; | ||
| 573 | } | 494 | } |
| 495 | |||
| 496 | BUG_ON(1); | ||
| 574 | } | 497 | } |
| 575 | out: | 498 | |
| 576 | btrfs_free_path(path); | 499 | if (del_nr > 0) { |
| 577 | if (locked_end > orig_locked_end) { | 500 | ret = btrfs_del_items(trans, root, path, del_slot, del_nr); |
| 578 | unlock_extent(&BTRFS_I(inode)->io_tree, orig_locked_end, | 501 | BUG_ON(ret); |
| 579 | locked_end - 1, GFP_NOFS); | ||
| 580 | } | 502 | } |
| 503 | |||
| 504 | btrfs_free_path(path); | ||
| 581 | return ret; | 505 | return ret; |
| 582 | } | 506 | } |
| 583 | 507 | ||
| @@ -620,23 +544,23 @@ static int extent_mergeable(struct extent_buffer *leaf, int slot, | |||
| 620 | * two or three. | 544 | * two or three. |
| 621 | */ | 545 | */ |
| 622 | int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, | 546 | int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, |
| 623 | struct btrfs_root *root, | ||
| 624 | struct inode *inode, u64 start, u64 end) | 547 | struct inode *inode, u64 start, u64 end) |
| 625 | { | 548 | { |
| 549 | struct btrfs_root *root = BTRFS_I(inode)->root; | ||
| 626 | struct extent_buffer *leaf; | 550 | struct extent_buffer *leaf; |
| 627 | struct btrfs_path *path; | 551 | struct btrfs_path *path; |
| 628 | struct btrfs_file_extent_item *fi; | 552 | struct btrfs_file_extent_item *fi; |
| 629 | struct btrfs_key key; | 553 | struct btrfs_key key; |
| 554 | struct btrfs_key new_key; | ||
| 630 | u64 bytenr; | 555 | u64 bytenr; |
| 631 | u64 num_bytes; | 556 | u64 num_bytes; |
| 632 | u64 extent_end; | 557 | u64 extent_end; |
| 633 | u64 orig_offset; | 558 | u64 orig_offset; |
| 634 | u64 other_start; | 559 | u64 other_start; |
| 635 | u64 other_end; | 560 | u64 other_end; |
| 636 | u64 split = start; | 561 | u64 split; |
| 637 | u64 locked_end = end; | 562 | int del_nr = 0; |
| 638 | int extent_type; | 563 | int del_slot = 0; |
| 639 | int split_end = 1; | ||
| 640 | int ret; | 564 | int ret; |
| 641 | 565 | ||
| 642 | btrfs_drop_extent_cache(inode, start, end - 1, 0); | 566 | btrfs_drop_extent_cache(inode, start, end - 1, 0); |
| @@ -644,12 +568,10 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, | |||
| 644 | path = btrfs_alloc_path(); | 568 | path = btrfs_alloc_path(); |
| 645 | BUG_ON(!path); | 569 | BUG_ON(!path); |
| 646 | again: | 570 | again: |
| 571 | split = start; | ||
| 647 | key.objectid = inode->i_ino; | 572 | key.objectid = inode->i_ino; |
| 648 | key.type = BTRFS_EXTENT_DATA_KEY; | 573 | key.type = BTRFS_EXTENT_DATA_KEY; |
| 649 | if (split == start) | 574 | key.offset = split; |
| 650 | key.offset = split; | ||
| 651 | else | ||
| 652 | key.offset = split - 1; | ||
| 653 | 575 | ||
| 654 | ret = btrfs_search_slot(trans, root, &key, path, -1, 1); | 576 | ret = btrfs_search_slot(trans, root, &key, path, -1, 1); |
| 655 | if (ret > 0 && path->slots[0] > 0) | 577 | if (ret > 0 && path->slots[0] > 0) |
| @@ -661,8 +583,8 @@ again: | |||
| 661 | key.type != BTRFS_EXTENT_DATA_KEY); | 583 | key.type != BTRFS_EXTENT_DATA_KEY); |
| 662 | fi = btrfs_item_ptr(leaf, path->slots[0], | 584 | fi = btrfs_item_ptr(leaf, path->slots[0], |
| 663 | struct btrfs_file_extent_item); | 585 | struct btrfs_file_extent_item); |
| 664 | extent_type = btrfs_file_extent_type(leaf, fi); | 586 | BUG_ON(btrfs_file_extent_type(leaf, fi) != |
| 665 | BUG_ON(extent_type != BTRFS_FILE_EXTENT_PREALLOC); | 587 | BTRFS_FILE_EXTENT_PREALLOC); |
| 666 | extent_end = key.offset + btrfs_file_extent_num_bytes(leaf, fi); | 588 | extent_end = key.offset + btrfs_file_extent_num_bytes(leaf, fi); |
| 667 | BUG_ON(key.offset > start || extent_end < end); | 589 | BUG_ON(key.offset > start || extent_end < end); |
| 668 | 590 | ||
| @@ -670,150 +592,91 @@ again: | |||
| 670 | num_bytes = btrfs_file_extent_disk_num_bytes(leaf, fi); | 592 | num_bytes = btrfs_file_extent_disk_num_bytes(leaf, fi); |
| 671 | orig_offset = key.offset - btrfs_file_extent_offset(leaf, fi); | 593 | orig_offset = key.offset - btrfs_file_extent_offset(leaf, fi); |
| 672 | 594 | ||
| 673 | if (key.offset == start) | 595 | while (start > key.offset || end < extent_end) { |
| 674 | split = end; | 596 | if (key.offset == start) |
| 675 | 597 | split = end; | |
| 676 | if (key.offset == start && extent_end == end) { | 598 | |
| 677 | int del_nr = 0; | 599 | memcpy(&new_key, &key, sizeof(new_key)); |
| 678 | int del_slot = 0; | 600 | new_key.offset = split; |
| 679 | other_start = end; | 601 | ret = btrfs_duplicate_item(trans, root, path, &new_key); |
| 680 | other_end = 0; | 602 | if (ret == -EAGAIN) { |
| 681 | if (extent_mergeable(leaf, path->slots[0] + 1, inode->i_ino, | 603 | btrfs_release_path(root, path); |
| 682 | bytenr, &other_start, &other_end)) { | 604 | 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 | } | 605 | } |
| 606 | BUG_ON(ret < 0); | ||
| 709 | 607 | ||
| 710 | fi = btrfs_item_ptr(leaf, del_slot - 1, | 608 | leaf = path->nodes[0]; |
| 609 | fi = btrfs_item_ptr(leaf, path->slots[0] - 1, | ||
| 711 | struct btrfs_file_extent_item); | 610 | 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, | 611 | btrfs_set_file_extent_num_bytes(leaf, fi, |
| 714 | extent_end - key.offset); | 612 | split - key.offset); |
| 613 | |||
| 614 | fi = btrfs_item_ptr(leaf, path->slots[0], | ||
| 615 | struct btrfs_file_extent_item); | ||
| 616 | |||
| 617 | btrfs_set_file_extent_offset(leaf, fi, split - orig_offset); | ||
| 618 | btrfs_set_file_extent_num_bytes(leaf, fi, | ||
| 619 | extent_end - split); | ||
| 715 | btrfs_mark_buffer_dirty(leaf); | 620 | btrfs_mark_buffer_dirty(leaf); |
| 716 | 621 | ||
| 717 | ret = btrfs_del_items(trans, root, path, del_slot, del_nr); | 622 | ret = btrfs_inc_extent_ref(trans, root, bytenr, num_bytes, 0, |
| 623 | root->root_key.objectid, | ||
| 624 | inode->i_ino, orig_offset); | ||
| 718 | BUG_ON(ret); | 625 | 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 | 626 | ||
| 744 | if (extent_end == end) { | 627 | if (split == start) { |
| 745 | split_end = 0; | 628 | key.offset = start; |
| 746 | extent_type = BTRFS_FILE_EXTENT_REG; | 629 | } else { |
| 747 | } | 630 | 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]--; | 631 | path->slots[0]--; |
| 771 | fi = btrfs_item_ptr(leaf, path->slots[0], | 632 | 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 | } | 633 | } |
| 777 | } | 634 | } |
| 778 | 635 | ||
| 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], | 636 | fi = btrfs_item_ptr(leaf, path->slots[0], |
| 793 | struct btrfs_file_extent_item); | 637 | 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 | 638 | ||
| 807 | release: | 639 | other_start = end; |
| 808 | btrfs_release_path(root, path); | 640 | other_end = 0; |
| 809 | if (split_end && split == start) { | 641 | if (extent_mergeable(leaf, path->slots[0] + 1, inode->i_ino, |
| 810 | split = end; | 642 | bytenr, &other_start, &other_end)) { |
| 811 | goto again; | 643 | extent_end = other_end; |
| 644 | del_slot = path->slots[0] + 1; | ||
| 645 | del_nr++; | ||
| 646 | ret = btrfs_free_extent(trans, root, bytenr, num_bytes, | ||
| 647 | 0, root->root_key.objectid, | ||
| 648 | inode->i_ino, orig_offset); | ||
| 649 | BUG_ON(ret); | ||
| 812 | } | 650 | } |
| 813 | if (locked_end > end) { | 651 | other_start = 0; |
| 814 | unlock_extent(&BTRFS_I(inode)->io_tree, end, locked_end - 1, | 652 | other_end = start; |
| 815 | GFP_NOFS); | 653 | if (extent_mergeable(leaf, path->slots[0] - 1, inode->i_ino, |
| 654 | bytenr, &other_start, &other_end)) { | ||
| 655 | key.offset = other_start; | ||
| 656 | del_slot = path->slots[0]; | ||
| 657 | del_nr++; | ||
| 658 | ret = btrfs_free_extent(trans, root, bytenr, num_bytes, | ||
| 659 | 0, root->root_key.objectid, | ||
| 660 | inode->i_ino, orig_offset); | ||
| 661 | BUG_ON(ret); | ||
| 816 | } | 662 | } |
| 663 | if (del_nr == 0) { | ||
| 664 | btrfs_set_file_extent_type(leaf, fi, | ||
| 665 | BTRFS_FILE_EXTENT_REG); | ||
| 666 | btrfs_mark_buffer_dirty(leaf); | ||
| 667 | goto out; | ||
| 668 | } | ||
| 669 | |||
| 670 | fi = btrfs_item_ptr(leaf, del_slot - 1, | ||
| 671 | struct btrfs_file_extent_item); | ||
| 672 | btrfs_set_file_extent_type(leaf, fi, BTRFS_FILE_EXTENT_REG); | ||
| 673 | btrfs_set_file_extent_num_bytes(leaf, fi, | ||
| 674 | extent_end - key.offset); | ||
| 675 | btrfs_mark_buffer_dirty(leaf); | ||
| 676 | |||
| 677 | ret = btrfs_del_items(trans, root, path, del_slot, del_nr); | ||
| 678 | BUG_ON(ret); | ||
| 679 | out: | ||
| 817 | btrfs_free_path(path); | 680 | btrfs_free_path(path); |
| 818 | return 0; | 681 | return 0; |
| 819 | } | 682 | } |
