By the way, can we also add some testcases in xfstests to check all this
works as intended?

On 08/07, 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>
> ---
> v5->v6: Modified F2FS_SPEC_reserve_node from (1<<24) to (1<<25) following 
> Zhiguo's suggestion in v5.
> v4->v5: Apply Chao's suggestion from v4.
> 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                     | 17 ++++++++----
>  fs/f2fs/super.c                    | 43 +++++++++++++++++++++++++-----
>  3 files changed, 54 insertions(+), 15 deletions(-)
> 
> diff --git a/Documentation/filesystems/f2fs.rst 
> b/Documentation/filesystems/f2fs.rst
> index 5cad369ceb92..e06cbb823bb7 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 f19472eb2789..047964d66736 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)
> @@ -178,6 +179,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 */
> @@ -2407,7 +2409,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)
> @@ -2432,7 +2434,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))) {
> @@ -2790,7 +2792,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;
>  
> @@ -2812,15 +2814,20 @@ static inline int inc_valid_node_count(struct 
> f2fs_sb_info *sbi,
>       spin_lock(&sbi->stat_lock);
>  
>       valid_block_count = sbi->total_valid_block_count + 1;
> -     avail_user_block_count = get_available_block_count(sbi, inode, false);
> +     avail_user_block_count = get_available_block_count(sbi, inode,
> +                     test_opt(sbi, RESERVE_NODE));
>  
>       if (unlikely(valid_block_count > avail_user_block_count)) {
>               spin_unlock(&sbi->stat_lock);
>               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, true))
> +             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 3f8bc42e0968..f37004780ce0 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,
> @@ -273,6 +274,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),
> @@ -346,6 +348,7 @@ static match_table_t f2fs_checkpoint_tokens = {
>  #define F2FS_SPEC_memory_mode                        (1 << 22)
>  #define F2FS_SPEC_errors                     (1 << 23)
>  #define F2FS_SPEC_lookup_mode                        (1 << 24)
> +#define F2FS_SPEC_reserve_node                       (1 << 25)
>  
>  struct f2fs_fs_context {
>       struct f2fs_mount_info info;
> @@ -447,22 +450,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,
> @@ -851,6 +862,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;
> @@ -1438,6 +1454,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)
> @@ -1637,6 +1661,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)
> @@ -2359,9 +2386,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,
> -- 
> 2.34.1


_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

Reply via email to