2023-04-19 21:17:17 +00:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0 */
|
|
|
|
|
|
|
|
#ifndef BTRFS_FILE_ITEM_H
|
|
|
|
#define BTRFS_FILE_ITEM_H
|
|
|
|
|
|
|
|
#include "kerncompat.h"
|
2023-08-28 20:12:13 +00:00
|
|
|
#include <stdbool.h>
|
|
|
|
#include <stddef.h>
|
|
|
|
#include "kernel-lib/bitops.h"
|
|
|
|
#include "kernel-shared/ctree.h"
|
|
|
|
#include "kernel-shared/uapi/btrfs_tree.h"
|
2023-04-19 21:17:17 +00:00
|
|
|
#include "kernel-shared/accessors.h"
|
|
|
|
|
|
|
|
struct bio;
|
|
|
|
struct inode;
|
|
|
|
struct btrfs_ordered_sum;
|
|
|
|
struct btrfs_inode;
|
2023-08-28 20:12:13 +00:00
|
|
|
struct btrfs_trans_handle;
|
2023-04-19 21:17:17 +00:00
|
|
|
struct extent_map;
|
2023-08-28 20:12:13 +00:00
|
|
|
struct extent_buffer;
|
|
|
|
struct list_head;
|
2023-04-19 21:17:17 +00:00
|
|
|
|
|
|
|
#define BTRFS_FILE_EXTENT_INLINE_DATA_START \
|
|
|
|
(offsetof(struct btrfs_file_extent_item, disk_bytenr))
|
|
|
|
|
|
|
|
static inline u32 BTRFS_MAX_INLINE_DATA_SIZE(const struct btrfs_fs_info *info)
|
|
|
|
{
|
2023-06-27 14:15:35 +00:00
|
|
|
return BTRFS_MAX_ITEM_SIZE(info) - BTRFS_FILE_EXTENT_INLINE_DATA_START;
|
2023-04-19 21:17:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2023-06-27 14:15:35 +00:00
|
|
|
* Return the number of bytes used by the item on disk, minus the size of any
|
2023-04-19 21:17:17 +00:00
|
|
|
* extent headers. If a file is compressed on disk, this is the compressed
|
|
|
|
* size.
|
|
|
|
*/
|
|
|
|
static inline u32 btrfs_file_extent_inline_item_len(
|
|
|
|
const struct extent_buffer *eb,
|
|
|
|
int nr)
|
|
|
|
{
|
|
|
|
return btrfs_item_size(eb, nr) - BTRFS_FILE_EXTENT_INLINE_DATA_START;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline unsigned long btrfs_file_extent_inline_start(
|
|
|
|
const struct btrfs_file_extent_item *e)
|
|
|
|
{
|
|
|
|
return (unsigned long)e + BTRFS_FILE_EXTENT_INLINE_DATA_START;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline u32 btrfs_file_extent_calc_inline_size(u32 datasize)
|
|
|
|
{
|
|
|
|
return BTRFS_FILE_EXTENT_INLINE_DATA_START + datasize;
|
|
|
|
}
|
|
|
|
|
|
|
|
int btrfs_del_csums(struct btrfs_trans_handle *trans,
|
|
|
|
struct btrfs_root *root, u64 bytenr, u64 len);
|
|
|
|
blk_status_t btrfs_lookup_bio_sums(struct inode *inode, struct bio *bio, u8 *dst);
|
|
|
|
int btrfs_insert_hole_extent(struct btrfs_trans_handle *trans,
|
|
|
|
struct btrfs_root *root, u64 objectid, u64 pos,
|
|
|
|
u64 num_bytes);
|
|
|
|
int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
|
|
|
|
struct btrfs_root *root,
|
|
|
|
struct btrfs_path *path, u64 objectid,
|
|
|
|
u64 bytenr, int mod);
|
|
|
|
int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
|
|
|
|
struct btrfs_root *root,
|
|
|
|
struct btrfs_ordered_sum *sums);
|
|
|
|
blk_status_t btrfs_csum_one_bio(struct btrfs_inode *inode, struct bio *bio,
|
|
|
|
u64 offset, bool one_ordered);
|
|
|
|
int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
|
|
|
|
struct list_head *list, int search_commit,
|
|
|
|
bool nowait);
|
|
|
|
void btrfs_extent_item_to_extent_map(struct btrfs_inode *inode,
|
|
|
|
const struct btrfs_path *path,
|
|
|
|
struct btrfs_file_extent_item *fi,
|
|
|
|
struct extent_map *em);
|
|
|
|
int btrfs_inode_clear_file_extent_range(struct btrfs_inode *inode, u64 start,
|
|
|
|
u64 len);
|
|
|
|
int btrfs_inode_set_file_extent_range(struct btrfs_inode *inode, u64 start, u64 len);
|
|
|
|
void btrfs_inode_safe_disk_i_size_write(struct btrfs_inode *inode, u64 new_i_size);
|
|
|
|
u64 btrfs_file_extent_end(const struct btrfs_path *path);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* MODIFIED:
|
|
|
|
* - This function doesn't exist in the kernel.
|
|
|
|
*/
|
|
|
|
int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
|
|
|
|
struct btrfs_root *root,
|
|
|
|
u64 objectid, u64 pos, u64 offset,
|
|
|
|
u64 disk_num_bytes, u64 num_bytes);
|
2023-05-18 02:10:42 +00:00
|
|
|
int btrfs_csum_file_block(struct btrfs_trans_handle *trans, u64 logical,
|
|
|
|
u64 csum_objectid, u32 csum_type, const char *data);
|
2023-04-19 21:17:17 +00:00
|
|
|
int btrfs_insert_inline_extent(struct btrfs_trans_handle *trans,
|
|
|
|
struct btrfs_root *root, u64 objectid,
|
|
|
|
u64 offset, const char *buffer, size_t size);
|
btrfs-progs: convert: fix inline extent size for symlink
[BUG]
Sometimes test case btrfs/012 fails randomly, with the failure to read a
symlink:
QA output created by 012
Checking converted btrfs against the original one:
-OK
+readlink: Structure needs cleaning
Checking saved ext2 image against the original one:
OK
Furthermore, this will trigger a kernel error message:
BTRFS critical (device dm-2): regular/prealloc extent found for non-regular inode 133081
[CAUSE]
For that specific inode 133081, the tree dump looks like this:
item 127 key (133081 INODE_ITEM 0) itemoff 40984 itemsize 160
generation 1 transid 1 size 4095 nbytes 4096
block group 0 mode 120777 links 1 uid 0 gid 0 rdev 0
sequence 0 flags 0x0(none)
item 128 key (133081 INODE_REF 133080) itemoff 40972 itemsize 12
index 2 namelen 2 name: l3
item 129 key (133081 EXTENT_DATA 0) itemoff 40919 itemsize 53
generation 4 type 1 (regular)
extent data disk byte 2147483648 nr 38080512
extent data offset 37974016 nr 4096 ram 38080512
extent compression 0 (none)
Note that, the symlink inode size is 4095 at the max size (PATH_MAX,
removing the terminating NUL).
But the nbytes is 4096, exactly matching the sector size of the btrfs.
Thus it results the creation of a regular extent, but for btrfs we do
not accept a symlink with a regular/preallocated extent, thus kernel
rejects such read and failed the readlink call.
The root cause is in the convert code, where for symlinks we always
create a data extent with its size + 1, causing the above problem.
I guess the original code is to handle the terminating NUL, but in btrfs
we never need to store the terminating NUL for inline extents nor
file names.
Thus this pitfall in btrfs-convert leads to the above invalid data
extent and fail the test case.
[FIX]
- Fix the ext2 and reiserfs symbolic link creation code
To remove the terminating NUL.
- Add extra checks for the size of a symbolic link
Btrfs has extra limits on the size of a symbolic link, as btrfs must
store symbolic link targets as inlined extents.
This means for 4K node sized btrfs, the size limit is smaller than the
usual PATH_MAX - 1 (only around 4000 bytes instead of 4095).
So for certain nodesize, some filesystems can not be converted to
btrfs.
(this should be rare, because the default nodesize is 16K already)
- Split the symbolic link and inline data extent size checks
For symbolic links the real limit is PATH_MAX - 1 (removing the
terminating NUL), but for inline data extents the limit is
sectorsize - 1, which can be different from 4096 - 1 (e.g. 64K sector
size).
Pull-request: #884
Signed-off-by: Qu Wenruo <wqu@suse.com>
2024-09-03 01:59:34 +00:00
|
|
|
/*
|
|
|
|
* For symlink we allow up to PATH_MAX - 1 (PATH_MAX includes the terminating NUL,
|
|
|
|
* but fs doesn't store that terminating NUL).
|
|
|
|
*
|
|
|
|
* But for inlined data extents, the up limit is sectorsize - 1 (inclusive), or a
|
|
|
|
* regular extent should be created instead.
|
|
|
|
*/
|
|
|
|
static inline u32 btrfs_symlink_max_size(struct btrfs_fs_info *fs_info)
|
|
|
|
{
|
|
|
|
return min_t(u32, BTRFS_MAX_INLINE_DATA_SIZE(fs_info),
|
|
|
|
PATH_MAX - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline u32 btrfs_data_inline_max_size(struct btrfs_fs_info *fs_info)
|
|
|
|
{
|
|
|
|
return min_t(u32, BTRFS_MAX_INLINE_DATA_SIZE(fs_info),
|
|
|
|
fs_info->sectorsize - 1);
|
|
|
|
}
|
2023-04-19 21:17:17 +00:00
|
|
|
|
|
|
|
#endif
|