On 2020/2/19 下午5:19, Nikolay Borisov wrote:
>
>
> 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 :
That's also my first idea.
But I'm not a fan of the 3rd parameter, and there is no other type other
than u64, so I hesitate to use the generic one.
However since you mentioned the kernel one, I guess it's time to
backport it to user space.
Thanks,
Qu
>
> #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;
>>