linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v5] f2fs: add reserved nodes for privileged users
@ 2025-08-06  9:19 Chunhai Guo
  2025-08-07  8:25 ` Chao Yu
  2025-08-07 10:55 ` [f2fs-dev] " Zhiguo Niu
  0 siblings, 2 replies; 4+ messages in thread
From: Chunhai Guo @ 2025-08-06  9:19 UTC (permalink / raw)
  To: chao, jaegeuk; +Cc: linux-f2fs-devel, linux-kernel, Chunhai Guo

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 <guochunhai@vivo.com>
---
v4->v5: Apply Chao's suggestion from v4.
v3->v4: Rebase this patch on https://lore.kernel.org/linux-f2fs-devel/20250731060338.1136086-1-chao@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-guochunhai@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 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..a4e4c3931441 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;
 
@@ -2760,15 +2762,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 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,
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH v5] f2fs: add reserved nodes for privileged users
  2025-08-06  9:19 [PATCH v5] f2fs: add reserved nodes for privileged users Chunhai Guo
@ 2025-08-07  8:25 ` Chao Yu
  2025-08-07 10:55 ` [f2fs-dev] " Zhiguo Niu
  1 sibling, 0 replies; 4+ messages in thread
From: Chao Yu @ 2025-08-07  8:25 UTC (permalink / raw)
  To: Chunhai Guo, jaegeuk; +Cc: chao, linux-f2fs-devel, linux-kernel

On 8/6/25 17:19, 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 <guochunhai@vivo.com>

Reviewed-by: Chao Yu <chao@kernel.org>

Thanks,

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [f2fs-dev] [PATCH v5] f2fs: add reserved nodes for privileged users
  2025-08-06  9:19 [PATCH v5] f2fs: add reserved nodes for privileged users Chunhai Guo
  2025-08-07  8:25 ` Chao Yu
@ 2025-08-07 10:55 ` Zhiguo Niu
  2025-08-07 12:24   ` Chunhai Guo
  1 sibling, 1 reply; 4+ messages in thread
From: Zhiguo Niu @ 2025-08-07 10:55 UTC (permalink / raw)
  To: Chunhai Guo; +Cc: chao, jaegeuk, linux-kernel, linux-f2fs-devel

Chunhai Guo via Linux-f2fs-devel
<linux-f2fs-devel@lists.sourceforge.net> 于2025年8月6日周三 17:22写道:
>
> 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 <guochunhai@vivo.com>
> ---
> v4->v5: Apply Chao's suggestion from v4.
> v3->v4: Rebase this patch on https://lore.kernel.org/linux-f2fs-devel/20250731060338.1136086-1-chao@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-guochunhai@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 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..a4e4c3931441 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;
>
> @@ -2760,15 +2762,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 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)
Hi Chunhai,
It seems that this conflicts with commit:1399fd4ff25d (f2fs: add
lookup_mode mount option)
#define F2FS_SPEC_errors (1 << 23)
+#define F2FS_SPEC_lookup_mode (1 << 24)
thanks!
>
>  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,
> --
> 2.34.1
>
>
>
> _______________________________________________
> Linux-f2fs-devel mailing list
> Linux-f2fs-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [f2fs-dev] [PATCH v5] f2fs: add reserved nodes for privileged users
  2025-08-07 10:55 ` [f2fs-dev] " Zhiguo Niu
@ 2025-08-07 12:24   ` Chunhai Guo
  0 siblings, 0 replies; 4+ messages in thread
From: Chunhai Guo @ 2025-08-07 12:24 UTC (permalink / raw)
  To: Zhiguo Niu, Chunhai Guo
  Cc: chao@kernel.org, jaegeuk@kernel.org, linux-kernel@vger.kernel.org,
	linux-f2fs-devel@lists.sourceforge.net

在 8/7/2025 6:55 PM, Zhiguo Niu 写道:
> [You don't often get email from niuzhiguo84@gmail.com. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]
>
> Chunhai Guo via Linux-f2fs-devel
> <linux-f2fs-devel@lists.sourceforge.net> 于2025年8月6日周三 17:22写道:
>> 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 <guochunhai@vivo.com>
>> ---
>> v4->v5: Apply Chao's suggestion from v4.
>> v3->v4: Rebase this patch on https://lore.kernel.org/linux-f2fs-devel/20250731060338.1136086-1-chao@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-guochunhai@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 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..a4e4c3931441 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;
>>
>> @@ -2760,15 +2762,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 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)
> Hi Chunhai,
> It seems that this conflicts with commit:1399fd4ff25d (f2fs: add
> lookup_mode mount option)
> #define F2FS_SPEC_errors (1 << 23)
> +#define F2FS_SPEC_lookup_mode (1 << 24)


Thank you very much for the reminder. I'll send the v6 patch to address
this.


Thanks,


> thanks!
>>   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,
>> --
>> 2.34.1
>>
>>
>>
>> _______________________________________________
>> Linux-f2fs-devel mailing list
>> Linux-f2fs-devel@lists.sourceforge.net
>> https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel



^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2025-08-07 12:24 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-06  9:19 [PATCH v5] f2fs: add reserved nodes for privileged users Chunhai Guo
2025-08-07  8:25 ` Chao Yu
2025-08-07 10:55 ` [f2fs-dev] " Zhiguo Niu
2025-08-07 12:24   ` Chunhai Guo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).