|
31 | 31 | #include "kernel-shared/extent_io.h" |
32 | 32 | #include "kernel-shared/disk-io.h" |
33 | 33 | #include "kernel-shared/tree-checker.h" |
| 34 | +#include "kernel-shared/volumes.h" |
34 | 35 | #include "common/extent-cache.h" |
| 36 | +#include "common/messages.h" |
35 | 37 | #include "check/repair.h" |
36 | 38 |
|
37 | 39 | int opt_check_repair = 0; |
@@ -354,6 +356,82 @@ int btrfs_fix_block_accounting(struct btrfs_trans_handle *trans) |
354 | 356 | return ret; |
355 | 357 | } |
356 | 358 |
|
| 359 | +int btrfs_remove_dev_extent(struct btrfs_fs_info *fs_info, u64 devid, u64 physical) |
| 360 | +{ |
| 361 | + struct btrfs_trans_handle *trans; |
| 362 | + struct btrfs_root *dev_root = fs_info->dev_root; |
| 363 | + struct btrfs_key key = { |
| 364 | + .objectid = devid, |
| 365 | + .type = BTRFS_DEV_EXTENT_KEY, |
| 366 | + .offset = physical, |
| 367 | + }; |
| 368 | + struct btrfs_path path = { 0 }; |
| 369 | + struct btrfs_dev_extent *dext; |
| 370 | + struct btrfs_device *dev; |
| 371 | + u64 length; |
| 372 | + int ret; |
| 373 | + |
| 374 | + dev = btrfs_find_device_by_devid(fs_info->fs_devices, devid, 0); |
| 375 | + if (!dev) { |
| 376 | + ret = -ENOENT; |
| 377 | + error("failed to find devid %llu", devid); |
| 378 | + return ret; |
| 379 | + } |
| 380 | + trans = btrfs_start_transaction(dev_root, 1); |
| 381 | + if (IS_ERR(trans)) { |
| 382 | + ret = PTR_ERR(trans); |
| 383 | + errno = -ret; |
| 384 | + error_msg(ERROR_MSG_START_TRANS, "%m"); |
| 385 | + return ret; |
| 386 | + } |
| 387 | + ret = btrfs_search_slot(trans, dev_root, &key, &path, -1, 1); |
| 388 | + if (ret > 0) |
| 389 | + ret = -ENOENT; |
| 390 | + if (ret < 0) { |
| 391 | + errno = -ret; |
| 392 | + error("failed to locate dev extent, devid %llu physical %llu: %m", |
| 393 | + devid, physical); |
| 394 | + goto abort; |
| 395 | + } |
| 396 | + dext = btrfs_item_ptr(path.nodes[0], path.slots[0], struct btrfs_dev_extent); |
| 397 | + length = btrfs_dev_extent_length(path.nodes[0], dext); |
| 398 | + ret = btrfs_del_item(trans, dev_root, &path); |
| 399 | + if (ret < 0) { |
| 400 | + errno = -ret; |
| 401 | + error("failed to delete dev extent, devid %llu physical %llu: %m", |
| 402 | + devid, physical); |
| 403 | + goto abort; |
| 404 | + } |
| 405 | + btrfs_release_path(&path); |
| 406 | + if (dev->bytes_used < length) { |
| 407 | + warning("devid %llu has bytes_used %llu, smaller than %llu", |
| 408 | + devid, dev->bytes_used, length); |
| 409 | + dev->bytes_used = 0; |
| 410 | + } else { |
| 411 | + dev->bytes_used -= length; |
| 412 | + } |
| 413 | + ret = btrfs_update_device(trans, dev); |
| 414 | + if (ret < 0) { |
| 415 | + errno = -ret; |
| 416 | + error("failed to update device, devid %llu: %m", devid); |
| 417 | + goto abort; |
| 418 | + } |
| 419 | + ret = btrfs_commit_transaction(trans, dev_root); |
| 420 | + if (ret < 0) { |
| 421 | + errno = -ret; |
| 422 | + error_msg(ERROR_MSG_COMMIT_TRANS, "%m"); |
| 423 | + } else { |
| 424 | + printf("removed orphan dev extent, devid %llu physical %llu length %llu\n", |
| 425 | + devid, physical, length); |
| 426 | + } |
| 427 | + return ret; |
| 428 | + |
| 429 | +abort: |
| 430 | + btrfs_release_path(&path); |
| 431 | + btrfs_abort_transaction(trans, ret); |
| 432 | + return ret; |
| 433 | +} |
| 434 | + |
357 | 435 | enum btrfs_tree_block_status btrfs_check_block_for_repair(struct extent_buffer *eb, |
358 | 436 | struct btrfs_key *first_key) |
359 | 437 | { |
|
0 commit comments