summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmds-check.c51
1 files changed, 40 insertions, 11 deletions
diff --git a/cmds-check.c b/cmds-check.c
index 7d5625da..15e44956 100644
--- a/cmds-check.c
+++ b/cmds-check.c
@@ -2473,12 +2473,6 @@ static int repair_inode_no_item(struct btrfs_trans_handle *trans,
int type_recovered = 0;
int ret = 0;
- /*
- * TODO:
- * 1. salvage data from existing file extent and
- * punch hole to keep fi ext consistent.
- * 2. salvage data from extent tree
- */
printf("Trying to rebuild inode:%llu\n", rec->ino);
type_recovered = !find_file_type(rec, &filetype);
@@ -2492,9 +2486,7 @@ static int repair_inode_no_item(struct btrfs_trans_handle *trans,
* For undetermined one, use FILE as fallback.
*
* TODO:
- * 1. If found extent belong to it in extent tree, it must be FILE
- * Need extra hook in extent tree scan.
- * 2. If found backref(inode_index/item is already handled) to it,
+ * 1. If found backref(inode_index/item is already handled) to it,
* it must be DIR.
* Need new inode-inode ref structure to allow search for that.
*/
@@ -2506,7 +2498,10 @@ static int repair_inode_no_item(struct btrfs_trans_handle *trans,
} else if (rec->found_dir_item) {
type_recovered = 1;
filetype = BTRFS_FT_DIR;
- } else {
+ } else if (!list_empty(&rec->orphan_extents)) {
+ type_recovered = 1;
+ filetype = BTRFS_FT_REG_FILE;
+ } else{
printf("Can't determint the filetype for inode %llu, assume it is a normal file\n",
rec->ino);
type_recovered = 1;
@@ -2597,6 +2592,37 @@ out:
return ret;
}
+static int repair_inode_discount_extent(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct btrfs_path *path,
+ struct inode_record *rec)
+{
+ struct rb_node *node;
+ struct file_extent_hole *hole;
+ int ret = 0;
+
+ node = rb_first(&rec->holes);
+
+ while (node) {
+ hole = rb_entry(node, struct file_extent_hole, node);
+ ret = btrfs_punch_hole(trans, root, rec->ino,
+ hole->start, hole->len);
+ if (ret < 0)
+ goto out;
+ ret = del_file_extent_hole(&rec->holes, hole->start,
+ hole->len);
+ if (ret < 0)
+ goto out;
+ if (RB_EMPTY_ROOT(&rec->holes))
+ rec->errors &= ~I_ERR_FILE_EXTENT_DISCOUNT;
+ node = rb_first(&rec->holes);
+ }
+ printf("Fixed discount file extents for inode: %llu in root: %llu\n",
+ rec->ino, root->objectid);
+out:
+ return ret;
+}
+
static int try_repair_inode(struct btrfs_root *root, struct inode_record *rec)
{
struct btrfs_trans_handle *trans;
@@ -2607,7 +2633,8 @@ static int try_repair_inode(struct btrfs_root *root, struct inode_record *rec)
I_ERR_NO_ORPHAN_ITEM |
I_ERR_LINK_COUNT_WRONG |
I_ERR_NO_INODE_ITEM |
- I_ERR_FILE_EXTENT_ORPHAN)))
+ I_ERR_FILE_EXTENT_ORPHAN |
+ I_ERR_FILE_EXTENT_DISCOUNT)))
return rec->errors;
path = btrfs_alloc_path();
@@ -2631,6 +2658,8 @@ static int try_repair_inode(struct btrfs_root *root, struct inode_record *rec)
ret = repair_inode_no_item(trans, root, path, rec);
if (!ret && rec->errors & I_ERR_FILE_EXTENT_ORPHAN)
ret = repair_inode_orphan_extent(trans, root, path, rec);
+ if (!ret && rec->errors & I_ERR_FILE_EXTENT_DISCOUNT)
+ ret = repair_inode_discount_extent(trans, root, path, rec);
if (!ret && rec->errors & I_ERR_DIR_ISIZE_WRONG)
ret = repair_inode_isize(trans, root, path, rec);
if (!ret && rec->errors & I_ERR_NO_ORPHAN_ITEM)