在 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

Reply via email to