[PATCH v2 02/13] f2fs: add inline tail disk layout definition

From: Wu Bo
Date: Tue Sep 10 2024 - 23:43:42 EST


When inline tail is enabled, use a compact block address array. And the
rest space is used to save file tail data. The layout of an inode block
as following:

| inode block | 4096 | inline tail enable |
| --------------- | ---- | --------------------------|
| inode info | 360 | |
| --------------- | ---- | --------------------------|
| | | extra info | 0~36 |
| | | **compact_addr[16] | 64 |
| addr table[923] | 3692 | reserved | 4 |
| | | **tail data | |
| | | inline_xattr | 200 |
| --------------- | ---- | --------------------------|
| nid table[5] | 20 |
| node footer | 24 |

So if we define compact address array size is 16, then we can have
3392~3428 bytes to store tail data.

Signed-off-by: Wu Bo <bo.wu@xxxxxxxx>
---
fs/f2fs/f2fs.h | 27 ++++++++++++++++++++++++++-
fs/f2fs/inode.c | 6 ++++++
2 files changed, 32 insertions(+), 1 deletion(-)

diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 3956740ca7e2..e02a6619b90a 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -476,12 +476,17 @@ static inline bool __has_cursum_space(struct f2fs_journal *journal,

/* for inline stuff */
#define DEF_INLINE_RESERVED_SIZE 1
+#define COMPACT_ADDRS_PER_INODE 16
static inline int get_extra_isize(struct inode *inode);
static inline int get_inline_xattr_addrs(struct inode *inode);
+static inline int get_reserved_addrs(struct inode *inode);
#define MAX_INLINE_DATA(inode) (sizeof(__le32) * \
(CUR_ADDRS_PER_INODE(inode) - \
get_inline_xattr_addrs(inode) - \
- DEF_INLINE_RESERVED_SIZE))
+ get_reserved_addrs(inode)))
+
+#define MAX_INLINE_TAIL(inode) (MAX_INLINE_DATA(inode) + \
+ (PAGE_SIZE * COMPACT_ADDRS_PER_INODE))

/* for inline dir */
#define NR_INLINE_DENTRY(inode) (MAX_INLINE_DATA(inode) * BITS_PER_BYTE / \
@@ -805,6 +810,7 @@ enum {
FI_ATOMIC_COMMITTED, /* indicate atomic commit completed except disk sync */
FI_ATOMIC_REPLACE, /* indicate atomic replace */
FI_OPENED_FILE, /* indicate file has been opened */
+ FI_INLINE_TAIL, /* used for inline tail */
FI_MAX, /* max flag, never be used */
};

@@ -3002,6 +3008,7 @@ static inline void f2fs_change_bit(unsigned int nr, char *addr)
#define F2FS_DIRSYNC_FL 0x00010000 /* dirsync behaviour (directories only) */
#define F2FS_PROJINHERIT_FL 0x20000000 /* Create with parents projid */
#define F2FS_CASEFOLD_FL 0x40000000 /* Casefolded file */
+#define F2FS_INLINE_TAIL 0x80000000 /* Has inline tail */

#define F2FS_QUOTA_DEFAULT_FL (F2FS_NOATIME_FL | F2FS_IMMUTABLE_FL)

@@ -3263,6 +3270,11 @@ static inline int f2fs_has_inline_data(struct inode *inode)
return is_inode_flag_set(inode, FI_INLINE_DATA);
}

+static inline int f2fs_has_inline_tail(struct inode *inode)
+{
+ return is_inode_flag_set(inode, FI_INLINE_TAIL);
+}
+
static inline int f2fs_exist_data(struct inode *inode)
{
return is_inode_flag_set(inode, FI_DATA_EXIST);
@@ -3299,6 +3311,9 @@ static inline void *inline_data_addr(struct inode *inode, struct page *page)
{
__le32 *addr = get_dnode_addr(inode, page);

+ if (f2fs_has_inline_tail(inode))
+ addr += COMPACT_ADDRS_PER_INODE;
+
return (void *)(addr + DEF_INLINE_RESERVED_SIZE);
}

@@ -3428,6 +3443,16 @@ static inline int get_extra_isize(struct inode *inode)
return F2FS_I(inode)->i_extra_isize / sizeof(__le32);
}

+static inline int get_reserved_addrs(struct inode *inode)
+{
+ int size = DEF_INLINE_RESERVED_SIZE;
+
+ if (f2fs_has_inline_tail(inode))
+ size += COMPACT_ADDRS_PER_INODE;
+
+ return size;
+}
+
static inline int get_inline_xattr_addrs(struct inode *inode)
{
return F2FS_I(inode)->i_inline_xattr_size;
diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
index aef57172014f..88dfcf16da0e 100644
--- a/fs/f2fs/inode.c
+++ b/fs/f2fs/inode.c
@@ -425,6 +425,8 @@ static int do_read_inode(struct inode *inode)
fi->i_dir_level = ri->i_dir_level;

get_inline_info(inode, ri);
+ if (fi->i_flags & F2FS_INLINE_TAIL)
+ set_bit(FI_INLINE_TAIL, fi->flags);

fi->i_extra_isize = f2fs_has_extra_attr(inode) ?
le16_to_cpu(ri->i_extra_isize) : 0;
@@ -666,6 +668,10 @@ void f2fs_update_inode(struct inode *inode, struct page *node_page)
memset(&ri->i_ext, 0, sizeof(ri->i_ext));
}
set_raw_inline(inode, ri);
+ if (is_inode_flag_set(inode, FI_INLINE_TAIL))
+ F2FS_I(inode)->i_flags |= F2FS_INLINE_TAIL;
+ else
+ F2FS_I(inode)->i_flags &= ~F2FS_INLINE_TAIL;

ri->i_atime = cpu_to_le64(inode_get_atime_sec(inode));
ri->i_ctime = cpu_to_le64(inode_get_ctime_sec(inode));
--
2.35.3