在 8/5/2025 10:38 AM, Jaegeuk Kim 写道: > On 07/31, Chunhai Guo wrote: >> 在 7/31/2025 4:46 PM, Chao Yu 写道: >>> On 7/31/25 15:57, Chunhai Guo wrote: >>>> This patch allows privileged users to reserve nodes via the >>>> 'reserve_node' mount option, which is similar to the existing >>>> 'reserve_root' option. >>>> >>>> "-o reserve_node=<N>" means <N> nodes are reserved for privileged >>>> users only. >>>> >>>> Signed-off-by: Chunhai Guo <guochun...@vivo.com> >>>> --- >>>> v3->v4: Rebase this patch on >>>> https://lore.kernel.org/linux-f2fs-devel/20250731060338.1136086-1-c...@kernel.org >>>> v2->v3: Apply Chao's suggestion from v2. >>>> v1->v2: Add two missing handling parts. >>>> v1: >>>> https://lore.kernel.org/linux-f2fs-devel/20250729095238.607433-1-guochun...@vivo.com/ >>>> --- >>>> Documentation/filesystems/f2fs.rst | 9 ++++--- >>>> fs/f2fs/f2fs.h | 14 +++++++--- >>>> fs/f2fs/super.c | 43 +++++++++++++++++++++++++----- >>>> 3 files changed, 52 insertions(+), 14 deletions(-) >>>> >>>> diff --git a/Documentation/filesystems/f2fs.rst >>>> b/Documentation/filesystems/f2fs.rst >>>> index 03b1efa6d3b2..95dbcd7ac9a8 100644 >>>> --- a/Documentation/filesystems/f2fs.rst >>>> +++ b/Documentation/filesystems/f2fs.rst >>>> @@ -173,9 +173,12 @@ data_flush Enable data flushing before >>>> checkpoint in order to >>>> persist data of regular and symlink. >>>> reserve_root=%d Support configuring reserved space which is >>>> used for >>>> allocation from a privileged user with specified >>>> uid or >>>> - gid, unit: 4KB, the default limit is 0.2% of user >>>> blocks. >>>> -resuid=%d The user ID which may use the reserved blocks. >>>> -resgid=%d The group ID which may use the reserved blocks. >>>> + gid, unit: 4KB, the default limit is 12.5% of user >>>> blocks. >>>> +reserve_node=%d Support configuring reserved nodes which are >>>> used for >>>> + allocation from a privileged user with specified uid >>>> or >>>> + gid, the default limit is 12.5% of all nodes. >>>> +resuid=%d The user ID which may use the reserved blocks and >>>> nodes. >>>> +resgid=%d The group ID which may use the reserved blocks and >>>> nodes. >>>> fault_injection=%d Enable fault injection in all supported types with >>>> specified injection rate. >>>> fault_type=%d Support configuring fault injection type, >>>> should be >>>> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h >>>> index eb372af22edc..b9676ef16246 100644 >>>> --- a/fs/f2fs/f2fs.h >>>> +++ b/fs/f2fs/f2fs.h >>>> @@ -131,6 +131,7 @@ extern const char *f2fs_fault_name[FAULT_MAX]; >>>> * string rather than using the MS_LAZYTIME flag, so this must remain. >>>> */ >>>> #define F2FS_MOUNT_LAZYTIME 0x40000000 >>>> +#define F2FS_MOUNT_RESERVE_NODE 0x80000000 >>>> >>>> #define F2FS_OPTION(sbi) ((sbi)->mount_opt) >>>> #define clear_opt(sbi, option) (F2FS_OPTION(sbi).opt &= >>>> ~F2FS_MOUNT_##option) >>>> @@ -172,6 +173,7 @@ struct f2fs_rwsem { >>>> struct f2fs_mount_info { >>>> unsigned int opt; >>>> block_t root_reserved_blocks; /* root reserved blocks */ >>>> + block_t root_reserved_nodes; /* root reserved nodes */ >>>> kuid_t s_resuid; /* reserved blocks for uid */ >>>> kgid_t s_resgid; /* reserved blocks for gid */ >>>> int active_logs; /* # of active logs */ >>>> @@ -2355,7 +2357,7 @@ static inline bool f2fs_has_xattr_block(unsigned int >>>> ofs) >>>> return ofs == XATTR_NODE_OFFSET; >>>> } >>>> >>>> -static inline bool __allow_reserved_blocks(struct f2fs_sb_info *sbi, >>>> +static inline bool __allow_reserved_root(struct f2fs_sb_info *sbi, >>>> struct inode *inode, bool cap) >>>> { >>>> if (!inode) >>>> @@ -2380,7 +2382,7 @@ static inline unsigned int >>>> get_available_block_count(struct f2fs_sb_info *sbi, >>>> avail_user_block_count = sbi->user_block_count - >>>> sbi->current_reserved_blocks; >>>> >>>> - if (test_opt(sbi, RESERVE_ROOT) && !__allow_reserved_blocks(sbi, >>>> inode, cap)) >>>> + if (test_opt(sbi, RESERVE_ROOT) && !__allow_reserved_root(sbi, inode, >>>> cap)) >>>> avail_user_block_count -= >>>> F2FS_OPTION(sbi).root_reserved_blocks; >>>> >>>> if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) { >>>> @@ -2738,7 +2740,7 @@ static inline int inc_valid_node_count(struct >>>> f2fs_sb_info *sbi, >>>> struct inode *inode, bool is_inode) >>>> { >>>> block_t valid_block_count; >>>> - unsigned int valid_node_count; >>>> + unsigned int valid_node_count, avail_user_node_count; >>>> unsigned int avail_user_block_count; >>>> int err; >>>> >>>> @@ -2767,8 +2769,12 @@ static inline int inc_valid_node_count(struct >>>> f2fs_sb_info *sbi, >>>> goto enospc; >>>> } >>>> >>>> + avail_user_node_count = sbi->total_node_count - >>>> F2FS_RESERVED_NODE_NUM; >>>> + if (test_opt(sbi, RESERVE_NODE) && >>>> + !__allow_reserved_root(sbi, inode, false)) >>> Chunhai, >>> >>> Do we need to pass cap=true to __allow_reserved_root()? >>> >>> In addition, do we need to change cap as well for below statement? >>> >>> avail_user_block_count = get_available_block_count(sbi, inode, false); >> >> Hi Jaegeuk, >> >> >> Based on the description in commit a90a0884ac75 ("f2fs: check >> cap_resource only for data blocks"), it seems that inode or node blocks >> don't need to perform a check on the cap_resource. I'm not certain about >> the reasoning behind this. Could you please help to clarify it? > I don't quite remember as I had to fix the selinx issue long long time ago.
Got it. It seems hard to clarify the reason back then. Thanks >> >> Thanks, >> >>> Thanks, >>> >>>> + avail_user_node_count -= F2FS_OPTION(sbi).root_reserved_nodes; >>>> valid_node_count = sbi->total_valid_node_count + 1; >>>> - if (unlikely(valid_node_count > sbi->total_node_count)) { >>>> + if (unlikely(valid_node_count > avail_user_node_count)) { >>>> spin_unlock(&sbi->stat_lock); >>>> goto enospc; >>>> } >>>> diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c >>>> index 30c038413040..a24e855a38ed 100644 >>>> --- a/fs/f2fs/super.c >>>> +++ b/fs/f2fs/super.c >>>> @@ -143,6 +143,7 @@ enum { >>>> Opt_extent_cache, >>>> Opt_data_flush, >>>> Opt_reserve_root, >>>> + Opt_reserve_node, >>>> Opt_resgid, >>>> Opt_resuid, >>>> Opt_mode, >>>> @@ -265,6 +266,7 @@ static const struct fs_parameter_spec >>>> f2fs_param_specs[] = { >>>> fsparam_flag_no("extent_cache", Opt_extent_cache), >>>> fsparam_flag("data_flush", Opt_data_flush), >>>> fsparam_u32("reserve_root", Opt_reserve_root), >>>> + fsparam_u32("reserve_node", Opt_reserve_node), >>>> fsparam_gid("resgid", Opt_resgid), >>>> fsparam_uid("resuid", Opt_resuid), >>>> fsparam_enum("mode", Opt_mode, f2fs_param_mode), >>>> @@ -336,6 +338,7 @@ static match_table_t f2fs_checkpoint_tokens = { >>>> #define F2FS_SPEC_discard_unit (1 << 21) >>>> #define F2FS_SPEC_memory_mode (1 << 22) >>>> #define F2FS_SPEC_errors (1 << 23) >>>> +#define F2FS_SPEC_reserve_node (1 << 24) >>>> >>>> struct f2fs_fs_context { >>>> struct f2fs_mount_info info; >>>> @@ -437,22 +440,30 @@ static void f2fs_destroy_casefold_cache(void) { } >>>> >>>> static inline void limit_reserve_root(struct f2fs_sb_info *sbi) >>>> { >>>> - block_t limit = min((sbi->user_block_count >> 3), >>>> + block_t block_limit = min((sbi->user_block_count >> 3), >>>> sbi->user_block_count - sbi->reserved_blocks); >>>> + block_t node_limit = sbi->total_node_count >> 3; >>>> >>>> /* limit is 12.5% */ >>>> if (test_opt(sbi, RESERVE_ROOT) && >>>> - F2FS_OPTION(sbi).root_reserved_blocks > limit) { >>>> - F2FS_OPTION(sbi).root_reserved_blocks = limit; >>>> + F2FS_OPTION(sbi).root_reserved_blocks > block_limit) { >>>> + F2FS_OPTION(sbi).root_reserved_blocks = block_limit; >>>> f2fs_info(sbi, "Reduce reserved blocks for root = %u", >>>> F2FS_OPTION(sbi).root_reserved_blocks); >>>> } >>>> - if (!test_opt(sbi, RESERVE_ROOT) && >>>> + if (test_opt(sbi, RESERVE_NODE) && >>>> + F2FS_OPTION(sbi).root_reserved_nodes > node_limit) { >>>> + F2FS_OPTION(sbi).root_reserved_nodes = node_limit; >>>> + f2fs_info(sbi, "Reduce reserved nodes for root = %u", >>>> + F2FS_OPTION(sbi).root_reserved_nodes); >>>> + } >>>> + if (!test_opt(sbi, RESERVE_ROOT) && !test_opt(sbi, RESERVE_NODE) && >>>> (!uid_eq(F2FS_OPTION(sbi).s_resuid, >>>> make_kuid(&init_user_ns, F2FS_DEF_RESUID)) || >>>> !gid_eq(F2FS_OPTION(sbi).s_resgid, >>>> make_kgid(&init_user_ns, F2FS_DEF_RESGID)))) >>>> - f2fs_info(sbi, "Ignore s_resuid=%u, s_resgid=%u w/o >>>> reserve_root", >>>> + f2fs_info(sbi, "Ignore s_resuid=%u, s_resgid=%u w/o >>>> reserve_root" >>>> + " and reserve_node", >>>> from_kuid_munged(&init_user_ns, >>>> F2FS_OPTION(sbi).s_resuid), >>>> from_kgid_munged(&init_user_ns, >>>> @@ -841,6 +852,11 @@ static int f2fs_parse_param(struct fs_context *fc, >>>> struct fs_parameter *param) >>>> F2FS_CTX_INFO(ctx).root_reserved_blocks = result.uint_32; >>>> ctx->spec_mask |= F2FS_SPEC_reserve_root; >>>> break; >>>> + case Opt_reserve_node: >>>> + ctx_set_opt(ctx, F2FS_MOUNT_RESERVE_NODE); >>>> + F2FS_CTX_INFO(ctx).root_reserved_nodes = result.uint_32; >>>> + ctx->spec_mask |= F2FS_SPEC_reserve_node; >>>> + break; >>>> case Opt_resuid: >>>> F2FS_CTX_INFO(ctx).s_resuid = result.uid; >>>> ctx->spec_mask |= F2FS_SPEC_resuid; >>>> @@ -1424,6 +1440,14 @@ static int f2fs_check_opt_consistency(struct >>>> fs_context *fc, >>>> ctx_clear_opt(ctx, F2FS_MOUNT_RESERVE_ROOT); >>>> ctx->opt_mask &= ~F2FS_MOUNT_RESERVE_ROOT; >>>> } >>>> + if (test_opt(sbi, RESERVE_NODE) && >>>> + (ctx->opt_mask & F2FS_MOUNT_RESERVE_NODE) && >>>> + ctx_test_opt(ctx, F2FS_MOUNT_RESERVE_NODE)) { >>>> + f2fs_info(sbi, "Preserve previous reserve_node=%u", >>>> + F2FS_OPTION(sbi).root_reserved_nodes); >>>> + ctx_clear_opt(ctx, F2FS_MOUNT_RESERVE_NODE); >>>> + ctx->opt_mask &= ~F2FS_MOUNT_RESERVE_NODE; >>>> + } >>>> >>>> err = f2fs_check_test_dummy_encryption(fc, sb); >>>> if (err) >>>> @@ -1623,6 +1647,9 @@ static void f2fs_apply_options(struct fs_context >>>> *fc, struct super_block *sb) >>>> if (ctx->spec_mask & F2FS_SPEC_reserve_root) >>>> F2FS_OPTION(sbi).root_reserved_blocks = >>>> >>>> F2FS_CTX_INFO(ctx).root_reserved_blocks; >>>> + if (ctx->spec_mask & F2FS_SPEC_reserve_node) >>>> + F2FS_OPTION(sbi).root_reserved_nodes = >>>> + >>>> F2FS_CTX_INFO(ctx).root_reserved_nodes; >>>> if (ctx->spec_mask & F2FS_SPEC_resgid) >>>> F2FS_OPTION(sbi).s_resgid = F2FS_CTX_INFO(ctx).s_resgid; >>>> if (ctx->spec_mask & F2FS_SPEC_resuid) >>>> @@ -2342,9 +2369,11 @@ static int f2fs_show_options(struct seq_file *seq, >>>> struct dentry *root) >>>> else if (F2FS_OPTION(sbi).fs_mode == FS_MODE_FRAGMENT_BLK) >>>> seq_puts(seq, "fragment:block"); >>>> seq_printf(seq, ",active_logs=%u", F2FS_OPTION(sbi).active_logs); >>>> - if (test_opt(sbi, RESERVE_ROOT)) >>>> - seq_printf(seq, ",reserve_root=%u,resuid=%u,resgid=%u", >>>> + if (test_opt(sbi, RESERVE_ROOT) || test_opt(sbi, RESERVE_NODE)) >>>> + seq_printf(seq, ",reserve_root=%u,reserve_node=%u,resuid=%u," >>>> + "resgid=%u", >>>> F2FS_OPTION(sbi).root_reserved_blocks, >>>> + F2FS_OPTION(sbi).root_reserved_nodes, >>>> from_kuid_munged(&init_user_ns, >>>> F2FS_OPTION(sbi).s_resuid), >>>> from_kgid_munged(&init_user_ns, >> _______________________________________________ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel