On 19.02.20 г. 9:04 ч., Qu Wenruo wrote:
> There is a report about tree-checker rejecting some leaves due to bad
> EXTENT_DATA.
>
> The offending EXTENT_DATA looks like:
> item 72 key (1359622 EXTENT_DATA 475136) itemoff 11140 itemsize 53
> generation 954719 type 1 (regular)
> extent data disk byte 0 nr 0
> extent data offset 0 nr 18446744073709486080 ram 18446744073709486080
> extent compression 0 (none)
>
> Add such check to both original and lowmem mode to detect such problem.
>
> Reported-by: Samir Benmendil <me@xxxxxx>
> Signed-off-by: Qu Wenruo <wqu@xxxxxxxx>
> ---
> check/main.c | 4 ++++
> check/mode-common.h | 7 +++++++
> check/mode-lowmem.c | 7 +++++++
> check/mode-original.h | 1 +
> 4 files changed, 19 insertions(+)
>
> diff --git a/check/main.c b/check/main.c
> index d02dd1636852..f71bf4f74129 100644
> --- a/check/main.c
> +++ b/check/main.c
> @@ -597,6 +597,8 @@ static void print_inode_error(struct btrfs_root *root, struct inode_record *rec)
> fprintf(stderr, ", odd file extent");
> if (errors & I_ERR_BAD_FILE_EXTENT)
> fprintf(stderr, ", bad file extent");
> + if (errors & I_ERR_FILE_EXTENT_OVERFLOW)
> + fprintf(stderr, ", file extent end overflow");
> if (errors & I_ERR_FILE_EXTENT_OVERLAP)
> fprintf(stderr, ", file extent overlap");
> if (errors & I_ERR_FILE_EXTENT_TOO_LARGE)
> @@ -1595,6 +1597,8 @@ static int process_file_extent(struct btrfs_root *root,
> num_bytes = btrfs_file_extent_num_bytes(eb, fi);
> disk_bytenr = btrfs_file_extent_disk_bytenr(eb, fi);
> extent_offset = btrfs_file_extent_offset(eb, fi);
> + if (u64_add_overflow(key->offset, num_bytes))
> + rec->errors |= I_ERR_FILE_EXTENT_OVERFLOW;
> if (num_bytes == 0 || (num_bytes & mask))
> rec->errors |= I_ERR_BAD_FILE_EXTENT;
> if (num_bytes + extent_offset >
> diff --git a/check/mode-common.h b/check/mode-common.h
> index edf9257edaf0..daa5741e1d67 100644
> --- a/check/mode-common.h
> +++ b/check/mode-common.h
> @@ -173,4 +173,11 @@ static inline u32 btrfs_type_to_imode(u8 type)
>
> return imode_by_btrfs_type[(type)];
> }
> +
> +static inline bool u64_add_overflow(u64 a, u64 b)
Rename this to check_add_overflow and use the generic version from the
kernel :
#define check_add_overflow(a, b, d) ({ \
typeof(a) __a = (a); \
typeof(b) __b = (b); \
typeof(d) __d = (d); \
(void) (&__a == &__b); \
(void) (&__a == __d); \
__builtin_add_overflow(__a, __b, __d); \
})
> +{
> + if (a > (u64)-1 - b)
> + return true;
> + return false;
> +}
> #endif
> diff --git a/check/mode-lowmem.c b/check/mode-lowmem.c
> index 630fabf66919..d257a44f3086 100644
> --- a/check/mode-lowmem.c
> +++ b/check/mode-lowmem.c
> @@ -2085,6 +2085,13 @@ static int check_file_extent(struct btrfs_root *root, struct btrfs_path *path,
> err |= INVALID_GENERATION;
> }
>
> + /* Extent end shouldn't overflow */
> + if (u64_add_overflow(fkey.offset, extent_num_bytes)) {
> + error(
> + "file extent end over flow, file offset %llu extent num bytes %llu",
> + fkey.offset, extent_num_bytes);
> + err |= FILE_EXTENT_ERROR;
> + }
> /*
> * Check EXTENT_DATA csum
> *
> diff --git a/check/mode-original.h b/check/mode-original.h
> index b075a95c9757..07d741f4a1b5 100644
> --- a/check/mode-original.h
> +++ b/check/mode-original.h
> @@ -186,6 +186,7 @@ struct unaligned_extent_rec_t {
> #define I_ERR_MISMATCH_DIR_HASH (1 << 18)
> #define I_ERR_INVALID_IMODE (1 << 19)
> #define I_ERR_INVALID_GEN (1 << 20)
> +#define I_ERR_FILE_EXTENT_OVERFLOW (1 << 21)
>
> struct inode_record {
> struct list_head backrefs;
>