diff options
| author | Kelvin Zhang <zhangxp1998@gmail.com> | 2026-09-03 16:56:19 -0700 |
|---|---|---|
| committer | Jaegeuk Kim <jaegeuk@kernel.org> | 2026-09-04 16:17:59 +0000 |
| commit | fbf612f854377402bf223ca21fc2e2ed7367f324 (patch) | |
| tree | 83033960c08eb78ca51cb594818e52fccc740099 | |
| parent | 49d39bc4b877e02084c3a9b5eceb1cf2d10a735b (diff) | |
| download | linux-next-fbf612f854377402bf223ca21fc2e2ed7367f324.tar.gz linux-next-fbf612f854377402bf223ca21fc2e2ed7367f324.zip | |
f2fs: describe xattr block layout dynamically
The usable capacity of dedicated on-disk extended attribute blocks and
inline xattr regions scales with the filesystem block size.
Parameterize VALID_XATTR_BLOCK_SIZE and MAX_INLINE_XATTR_SIZE to
calculate usable xattr limits dynamically from sbi->blocksize rather than
hardcoding PAGE_SIZE or DEF_ADDRS_PER_INODE.
Update mount option consistency validation for inline_xattr_size to
evaluate allowed boundaries dynamically against the runtime block size.
Signed-off-by: Kelvin Zhang <zhangxp1998@gmail.com>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
| -rw-r--r-- | fs/f2fs/inode.c | 7 | ||||
| -rw-r--r-- | fs/f2fs/node.c | 2 | ||||
| -rw-r--r-- | fs/f2fs/super.c | 17 | ||||
| -rw-r--r-- | fs/f2fs/xattr.c | 8 | ||||
| -rw-r--r-- | fs/f2fs/xattr.h | 11 | ||||
| -rw-r--r-- | include/linux/f2fs_fs.h | 3 |
6 files changed, 34 insertions, 14 deletions
diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index fda9ee3bfc61..79c0a1301996 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -337,12 +337,13 @@ static bool sanity_check_inode(struct inode *inode, struct folio *node_folio) } if (f2fs_sb_has_flexible_inline_xattr(sbi) && - (fi->i_inline_xattr_size > MAX_INLINE_XATTR_SIZE || + (fi->i_inline_xattr_size > MAX_INLINE_XATTR_SIZE(i_blocksize(inode)) || (f2fs_has_inline_xattr(inode) && fi->i_inline_xattr_size < MIN_INLINE_XATTR_SIZE))) { - f2fs_warn(sbi, "%s: inode (ino=%llx) has corrupted i_inline_xattr_size: %d, min: %zu, max: %lu", + f2fs_warn(sbi, "%s: inode (ino=%llx) has corrupted i_inline_xattr_size: %d, min: %zu, max: %zu", __func__, inode->i_ino, fi->i_inline_xattr_size, - MIN_INLINE_XATTR_SIZE, MAX_INLINE_XATTR_SIZE); + MIN_INLINE_XATTR_SIZE, + (size_t)MAX_INLINE_XATTR_SIZE(i_blocksize(inode))); return false; } diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index e3f594f7bcce..7dabfada1b54 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -2919,7 +2919,7 @@ recover_xnid: /* 3: update and set xattr node page dirty */ if (folio) { memcpy(F2FS_NODE(xfolio), F2FS_NODE(folio), - VALID_XATTR_BLOCK_SIZE); + VALID_XATTR_BLOCK_SIZE(inode)); folio_mark_dirty(xfolio); } f2fs_folio_put(xfolio, true); diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index c1d76674ab7c..4c95229ac3f1 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -855,9 +855,11 @@ static int f2fs_parse_param(struct fs_context *fc, struct fs_parameter *param) break; case Opt_inline_xattr_size: if (result.int_32 < MIN_INLINE_XATTR_SIZE || - result.int_32 > MAX_INLINE_XATTR_SIZE) { + result.int_32 > + MAX_INLINE_XATTR_SIZE(F2FS_MAX_BLKSIZE)) { f2fs_err(NULL, "inline xattr size is out of range: %u ~ %u", - (u32)MIN_INLINE_XATTR_SIZE, (u32)MAX_INLINE_XATTR_SIZE); + (u32)MIN_INLINE_XATTR_SIZE, + (u32)MAX_INLINE_XATTR_SIZE(F2FS_MAX_BLKSIZE)); return -EINVAL; } ctx_set_opt(ctx, F2FS_MOUNT_INLINE_XATTR_SIZE); @@ -1596,6 +1598,8 @@ static int f2fs_check_opt_consistency(struct fs_context *fc, } if (ctx_test_opt(ctx, F2FS_MOUNT_INLINE_XATTR_SIZE)) { + int min_size, max_size; + if (!f2fs_sb_has_extra_attr(sbi) || !f2fs_sb_has_flexible_inline_xattr(sbi)) { f2fs_err(sbi, "extra_attr or flexible_inline_xattr feature is off"); @@ -1605,6 +1609,15 @@ static int f2fs_check_opt_consistency(struct fs_context *fc, f2fs_err(sbi, "inline_xattr_size option should be set with inline_xattr option"); return -EINVAL; } + min_size = MIN_INLINE_XATTR_SIZE; + max_size = MAX_INLINE_XATTR_SIZE(sbi->blocksize); + + if (F2FS_OPTION(sbi).inline_xattr_size < min_size || + F2FS_OPTION(sbi).inline_xattr_size > max_size) { + f2fs_err(sbi, "inline xattr size is out of range: %d ~ %d", + min_size, max_size); + return -EINVAL; + } } if (ctx_test_opt(ctx, F2FS_MOUNT_ATGC) && diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c index 6728d1488cad..99c863513725 100644 --- a/fs/f2fs/xattr.c +++ b/fs/f2fs/xattr.c @@ -310,7 +310,8 @@ static int read_xattr_block(struct inode *inode, void *txattr_addr) return PTR_ERR(xfolio); xattr_addr = folio_address(xfolio); - memcpy(txattr_addr + inline_size, xattr_addr, VALID_XATTR_BLOCK_SIZE); + memcpy(txattr_addr + inline_size, xattr_addr, + VALID_XATTR_BLOCK_SIZE(inode)); f2fs_folio_put(xfolio, true); return 0; @@ -393,7 +394,7 @@ static int read_all_xattrs(struct inode *inode, struct folio *ifolio, { struct f2fs_xattr_header *header; nid_t xnid = F2FS_I(inode)->i_xattr_nid; - unsigned int size = VALID_XATTR_BLOCK_SIZE; + unsigned int size = VALID_XATTR_BLOCK_SIZE(inode); unsigned int inline_size = inline_xattr_size(inode); void *txattr_addr; int err; @@ -502,7 +503,8 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize, if (inline_size) memcpy(inline_addr, txattr_addr, inline_size); - memcpy(xattr_addr, txattr_addr + inline_size, VALID_XATTR_BLOCK_SIZE); + memcpy(xattr_addr, txattr_addr + inline_size, + VALID_XATTR_BLOCK_SIZE(inode)); if (inline_size) folio_mark_dirty(ifolio ? ifolio : in_folio); diff --git a/fs/f2fs/xattr.h b/fs/f2fs/xattr.h index 7cd7ce58334b..75beab2d1ee3 100644 --- a/fs/f2fs/xattr.h +++ b/fs/f2fs/xattr.h @@ -71,21 +71,22 @@ struct f2fs_xattr_entry { for (entry = XATTR_FIRST_ENTRY(addr);\ !IS_XATTR_LAST_ENTRY(entry);\ entry = XATTR_NEXT_ENTRY(entry)) -#define VALID_XATTR_BLOCK_SIZE (PAGE_SIZE - sizeof(struct node_footer)) +#define VALID_XATTR_BLOCK_SIZE(i) (i_blocksize(i) - \ + sizeof(struct node_footer)) #define XATTR_PADDING_SIZE (sizeof(__u32)) #define XATTR_SIZE(i) ((F2FS_I(i)->i_xattr_nid ? \ - VALID_XATTR_BLOCK_SIZE : 0) + \ + VALID_XATTR_BLOCK_SIZE(i) : 0) + \ (inline_xattr_size(i))) #define MIN_OFFSET(i) XATTR_ALIGN(inline_xattr_size(i) + \ - VALID_XATTR_BLOCK_SIZE) + VALID_XATTR_BLOCK_SIZE(i)) #define MAX_VALUE_LEN(i) (MIN_OFFSET(i) - \ sizeof(struct f2fs_xattr_header) - \ sizeof(struct f2fs_xattr_entry)) #define MIN_INLINE_XATTR_SIZE (sizeof(struct f2fs_xattr_header) / sizeof(__le32)) -#define MAX_INLINE_XATTR_SIZE \ - (F2FS_DEF_ADDRS_PER_INODE(F2FS_BLKSIZE) - \ +#define MAX_INLINE_XATTR_SIZE(blocksize) \ + (F2FS_DEF_ADDRS_PER_INODE(blocksize) - \ F2FS_TOTAL_EXTRA_ATTR_SIZE / sizeof(__le32) - \ DEF_INLINE_RESERVED_SIZE - \ MIN_INLINE_DENTRY_SIZE / sizeof(__le32)) diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h index bec31591b398..e98bff846b23 100644 --- a/include/linux/f2fs_fs.h +++ b/include/linux/f2fs_fs.h @@ -15,7 +15,10 @@ #define F2FS_MIN_LOG_SECTOR_SIZE 9 /* 9 bits for 512 bytes */ #define F2FS_MAX_LOG_SECTOR_SIZE PAGE_SHIFT /* Max is Block Size */ #define F2FS_LOG_SECTORS_PER_BLOCK (PAGE_SHIFT - 9) /* log number for sector/blk */ +#define F2FS_MIN_LOG_BLOCKSIZE 12 +#define F2FS_MIN_BLKSIZE 4096UL #define F2FS_BLKSIZE PAGE_SIZE /* support only block == page */ +#define F2FS_MAX_BLKSIZE PAGE_SIZE #define F2FS_BLKSIZE_BITS PAGE_SHIFT /* bits for F2FS_BLKSIZE */ #define F2FS_MAX_EXTENSION 64 /* # of extension entries */ #define F2FS_EXTENSION_LEN 8 /* max size of extension */ |
