@@ -627,6 +627,8 @@ static void print_inode_error(struct btrfs_root *root, struct inode_record *rec)
if (errors & I_ERR_INVALID_NLINK)
fprintf(stderr, ", directory has invalid nlink %d",
rec->nlink);
+ if (errors & I_ERR_NO_GC_ITEM)
+ fprintf(stderr, ", no gc item");
fprintf(stderr, "\n");
/* Print the holes if needed */
@@ -884,6 +886,42 @@ static int check_orphan_item(struct btrfs_root *root, u64 ino)
return ret;
}
+static void check_inode_gc_item(struct btrfs_root *root, struct inode_record *rec)
+{
+ struct btrfs_root *gc_root;
+ struct rb_node *n;
+ struct btrfs_path path;
+ struct btrfs_key key = {
+ .objectid = root->root_key.objectid,
+ .type = BTRFS_GC_INODE_ITEM_KEY,
+ .offset = rec->ino,
+ };
+ int ret;
+
+ /*
+ * We may choose to do something fancy with the location of our
+ * GC_INODE_ITEM entries, so just search all of the gc roots for our
+ * inode.
+ */
+ for (n = rb_first(&gfs_info->global_roots_tree); n; n = rb_next(n)) {
+ gc_root = rb_entry(n, struct btrfs_root, rb_node);
+ if (gc_root->root_key.objectid != BTRFS_GC_TREE_OBJECTID)
+ continue;
+ btrfs_init_path(&path);
+ ret = btrfs_search_slot(NULL, gc_root, &key, &path, 0, 0);
+ btrfs_release_path(&path);
+
+ /*
+ * Found our GC item, that means we don't need an orphan item so
+ * we can clear both of these errors.
+ */
+ if (ret == 0) {
+ rec->errors &= ~(I_ERR_NO_GC_ITEM | I_ERR_NO_ORPHAN_ITEM);
+ break;
+ }
+ }
+}
+
static int process_inode_item(struct extent_buffer *eb,
int slot, struct btrfs_key *key,
struct shared_node *active_node)
@@ -907,8 +945,11 @@ static int process_inode_item(struct extent_buffer *eb,
if (btrfs_inode_flags(eb, item) & BTRFS_INODE_NODATASUM)
rec->nodatasum = 1;
rec->found_inode_item = 1;
- if (rec->nlink == 0)
+ if (rec->nlink == 0) {
rec->errors |= I_ERR_NO_ORPHAN_ITEM;
+ if (btrfs_fs_incompat(gfs_info, EXTENT_TREE_V2))
+ rec->errors |= I_ERR_NO_GC_ITEM;
+ }
flags = btrfs_inode_flags(eb, item);
if (S_ISLNK(rec->imode) &&
flags & (BTRFS_INODE_IMMUTABLE | BTRFS_INODE_APPEND))
@@ -2569,7 +2610,7 @@ static int repair_inode_no_item(struct btrfs_trans_handle *trans,
rec->found_dir_item = 1;
rec->imode = mode | btrfs_type_to_imode(filetype);
rec->nlink = 0;
- rec->errors &= ~I_ERR_NO_INODE_ITEM;
+ rec->errors &= ~(I_ERR_NO_INODE_ITEM | I_ERR_NO_GC_ITEM);
/* Ensure the inode_nlinks repair function will be called */
rec->errors |= I_ERR_LINK_COUNT_WRONG;
out:
@@ -3082,8 +3123,16 @@ static int check_inode_recs(struct btrfs_root *root,
if (rec->errors & I_ERR_NO_ORPHAN_ITEM) {
ret = check_orphan_item(root, rec->ino);
+
+ /*
+ * If we have an orphan item we need to not have a gc
+ * item.
+ */
if (ret == 0)
- rec->errors &= ~I_ERR_NO_ORPHAN_ITEM;
+ rec->errors &= ~(I_ERR_NO_ORPHAN_ITEM |
+ I_ERR_NO_GC_ITEM);
+
+ check_inode_gc_item(root, rec);
if (can_free_inode_rec(rec)) {
free_inode_rec(rec);
continue;
@@ -187,6 +187,7 @@ struct unaligned_extent_rec_t {
#define I_ERR_INVALID_IMODE (1 << 19)
#define I_ERR_INVALID_GEN (1 << 20)
#define I_ERR_INVALID_NLINK (1 << 21)
+#define I_ERR_NO_GC_ITEM (1 << 22)
struct inode_record {
struct list_head backrefs;
If we have a GC item then we can treat the inode record like it has an ORPHAN item, simply ignore it if we have either the ORPHAN item or the GC item. Signed-off-by: Josef Bacik <josef@toxicpanda.com> --- check/main.c | 55 ++++++++++++++++++++++++++++++++++++++++--- check/mode-original.h | 1 + 2 files changed, 53 insertions(+), 3 deletions(-)