+static int repair_inode_orphan_extent(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct btrfs_path *path,
+ struct inode_record *rec)
+{
+ struct orphan_data_extent *orphan;
+ struct orphan_data_extent *tmp;
+ int ret = 0;
+
+ list_for_each_entry_safe(orphan, tmp, &rec->orphan_extents, list) {
+ /*
+ * Check for conflicting file extents
+ *
+ * Here we don't know whether the extents is compressed or not,
+ * so we can only assume it not compressed nor data offset,
+ * and use its disk_len as extent length.
+ */
+ ret = btrfs_get_extent(NULL, root, path, orphan->objectid,
+ orphan->offset, orphan->disk_len, 0);
+ btrfs_release_path(path);
+ if (ret < 0)
+ goto out;
+ if (!ret) {
+ fprintf(stderr,
+ "orphan extent (%llu, %llu) conflicts, delete the orphan\n",
+ orphan->disk_bytenr, orphan->disk_len);
+ ret = btrfs_free_extent(trans,
+ root->fs_info->extent_root,
+ orphan->disk_bytenr, orphan->disk_len,
+ 0, root->objectid, orphan->objectid,
+ orphan->offset);
+ if (ret < 0)
+ goto out;
+ }
+ ret = btrfs_insert_file_extent(trans, root, orphan->objectid,
+ orphan->offset, orphan->disk_bytenr,
+ orphan->disk_len, orphan->disk_len);
+ if (ret < 0)
+ goto out;
+
+ /* Update file size info */
+ rec->found_size += orphan->disk_len;
+ if (rec->found_size == rec->nbytes)
+ rec->errors &= ~I_ERR_FILE_NBYTES_WRONG;
+
+ /* Update the file extent hole info too */
+ ret = del_file_extent_hole(&rec->holes, orphan->offset,
+ orphan->disk_len);
+ if (ret < 0)
+ goto out;
+ if (RB_EMPTY_ROOT(&rec->holes))
+ rec->errors &= ~I_ERR_FILE_EXTENT_DISCOUNT;
+
+ list_del(&orphan->list);
+ free(orphan);
+ }
+ rec->errors &= ~I_ERR_FILE_EXTENT_ORPHAN;
+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 found = 0;
+ int ret = 0;
+
+ node = rb_first(&rec->holes);
+
+ while (node) {
+ found = 1;
+ 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);
+ }
+ /* special case for a file losing all its file extent */
+ if (!found) {
+ ret = btrfs_punch_hole(trans, root, rec->ino, 0,
+ round_up(rec->isize, root->sectorsize));
+ if (ret < 0)
+ goto out;
+ }
+ printf("Fixed discount file extents for inode: %llu in root: %llu\n",
+ rec->ino, root->objectid);
+out:
+ return ret;
+}
+