diff --git a/check/main.c b/check/main.c index e88e7277..aeab0855 100644 --- a/check/main.c +++ b/check/main.c @@ -7915,6 +7915,62 @@ static int record_unaligned_extent_rec(struct extent_record *rec) return ret; } +static int repair_extent_item_generation(struct extent_record *rec) +{ + struct btrfs_trans_handle *trans; + struct btrfs_path path; + struct btrfs_key key; + struct btrfs_extent_item *ei; + struct btrfs_root *extent_root = gfs_info->extent_root; + u64 new_gen = 0;; + int ret; + + key.objectid = rec->start; + key.type = BTRFS_METADATA_ITEM_KEY; + key.offset = (u64)-1; + + get_extent_item_generation(rec->start, &new_gen); + trans = btrfs_start_transaction(extent_root, 1); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + errno = -ret; + error("failed to start transaction: %m"); + return ret; + } + btrfs_init_path(&path); + ret = btrfs_search_slot(trans, extent_root, &key, &path, 0, 1); + /* Not possible */ + if (ret == 0) + ret = -EUCLEAN; + if (ret < 0) + goto out; + ret = btrfs_previous_extent_item(extent_root, &path, rec->start); + if (ret > 0) + ret = -ENOENT; + if (ret < 0) + goto out; + + if (!new_gen) + new_gen = trans->transid; + ei = btrfs_item_ptr(path.nodes[0], path.slots[0], + struct btrfs_extent_item); + btrfs_set_extent_generation(path.nodes[0], ei, new_gen); + ret = btrfs_commit_transaction(trans, extent_root); + if (ret < 0) { + errno = -ret; + error("failed to commit transaction: %m"); + goto out; + } + printf("Reset extent item (%llu) generation to %llu\n", + key.objectid, new_gen); + rec->generation = new_gen; +out: + btrfs_release_path(&path); + if (ret < 0) + btrfs_abort_transaction(trans, ret); + return ret; +} + static int check_extent_refs(struct btrfs_root *root, struct cache_tree *extent_cache) { @@ -8005,11 +8061,20 @@ static int check_extent_refs(struct btrfs_root *root, } if (rec->generation > super_gen + 1) { - error( + bool repaired = false; + + if (repair) { + ret = repair_extent_item_generation(rec); + if (ret == 0) + repaired = true; + } + if (!repaired) { + error( "invalid generation for extent %llu, have %llu expect (0, %llu]", - rec->start, rec->generation, - super_gen + 1); - cur_err = 1; + rec->start, rec->generation, + super_gen + 1); + cur_err = 1; + } } if (rec->refs != rec->extent_item_refs) { fprintf(stderr, "ref mismatch on [%llu %llu] ",