linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4] f2fs: add reserved nodes for privileged users
@ 2025-07-31  7:57 Chunhai Guo
  2025-07-31  8:46 ` Chao Yu
  0 siblings, 1 reply; 7+ messages in thread
From: Chunhai Guo @ 2025-07-31  7:57 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>
---
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                     | 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))
+		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] 7+ messages in thread

* Re: [PATCH v4] f2fs: add reserved nodes for privileged users
  2025-07-31  7:57 [PATCH v4] f2fs: add reserved nodes for privileged users Chunhai Guo
@ 2025-07-31  8:46 ` Chao Yu
  2025-07-31 10:53   ` Chunhai Guo
  2025-08-05  8:56   ` Chao Yu
  0 siblings, 2 replies; 7+ messages in thread
From: Chao Yu @ 2025-07-31  8:46 UTC (permalink / raw)
  To: Chunhai Guo, jaegeuk; +Cc: chao, linux-f2fs-devel, linux-kernel

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 <guochunhai@vivo.com>
> ---
> 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                     | 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);

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,


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

* Re: [PATCH v4] f2fs: add reserved nodes for privileged users
  2025-07-31  8:46 ` Chao Yu
@ 2025-07-31 10:53   ` Chunhai Guo
  2025-08-05  2:38     ` Jaegeuk Kim
  2025-08-05  8:56   ` Chao Yu
  1 sibling, 1 reply; 7+ messages in thread
From: Chunhai Guo @ 2025-07-31 10:53 UTC (permalink / raw)
  To: Chao Yu, Chunhai Guo, jaegeuk@kernel.org
  Cc: linux-f2fs-devel@lists.sourceforge.net,
	linux-kernel@vger.kernel.org

在 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 <guochunhai@vivo.com>
>> ---
>> 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                     | 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?


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,



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

* Re: [PATCH v4] f2fs: add reserved nodes for privileged users
  2025-07-31 10:53   ` Chunhai Guo
@ 2025-08-05  2:38     ` Jaegeuk Kim
  2025-08-06  8:56       ` Chunhai Guo
  0 siblings, 1 reply; 7+ messages in thread
From: Jaegeuk Kim @ 2025-08-05  2:38 UTC (permalink / raw)
  To: Chunhai Guo
  Cc: Chao Yu, linux-f2fs-devel@lists.sourceforge.net,
	linux-kernel@vger.kernel.org

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 <guochunhai@vivo.com>
> >> ---
> >> 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                     | 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.

> 
> 
> 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,
> 
> 

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

* Re: [PATCH v4] f2fs: add reserved nodes for privileged users
  2025-07-31  8:46 ` Chao Yu
  2025-07-31 10:53   ` Chunhai Guo
@ 2025-08-05  8:56   ` Chao Yu
  2025-08-06  8:56     ` Chunhai Guo
  1 sibling, 1 reply; 7+ messages in thread
From: Chao Yu @ 2025-08-05  8:56 UTC (permalink / raw)
  To: Chunhai Guo, jaegeuk; +Cc: chao, linux-f2fs-devel, linux-kernel

On 7/31/25 16:46, Chao Yu wrote:
> 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 <guochunhai@vivo.com>
>> ---
>> 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                     | 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);

I meant something like this? not sure.

---
 fs/f2fs/f2fs.h | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 3804b70e5a28..d0aa5766ea66 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -2805,7 +2805,8 @@ 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);
@@ -2814,7 +2815,7 @@ static inline int inc_valid_node_count(struct f2fs_sb_info *sbi,

 	avail_user_node_count = sbi->total_node_count - F2FS_RESERVED_NODE_NUM;
 	if (test_opt(sbi, RESERVE_NODE) &&
-			!__allow_reserved_root(sbi, inode, false))
+			!__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 > avail_user_node_count)) {
-- 
2.49.0

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,
> 


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

* Re: [PATCH v4] f2fs: add reserved nodes for privileged users
  2025-08-05  2:38     ` Jaegeuk Kim
@ 2025-08-06  8:56       ` Chunhai Guo
  0 siblings, 0 replies; 7+ messages in thread
From: Chunhai Guo @ 2025-08-06  8:56 UTC (permalink / raw)
  To: Jaegeuk Kim, Chunhai Guo
  Cc: Chao Yu, linux-f2fs-devel@lists.sourceforge.net,
	linux-kernel@vger.kernel.org

在 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 <guochunhai@vivo.com>
>>>> ---
>>>> 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                     | 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,
>>


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

* Re: [PATCH v4] f2fs: add reserved nodes for privileged users
  2025-08-05  8:56   ` Chao Yu
@ 2025-08-06  8:56     ` Chunhai Guo
  0 siblings, 0 replies; 7+ messages in thread
From: Chunhai Guo @ 2025-08-06  8:56 UTC (permalink / raw)
  To: Chao Yu, Chunhai Guo, jaegeuk@kernel.org
  Cc: linux-f2fs-devel@lists.sourceforge.net,
	linux-kernel@vger.kernel.org

在 8/5/2025 4:56 PM, Chao Yu 写道:
> On 7/31/25 16:46, Chao Yu wrote:
>> 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 <guochunhai@vivo.com>
>>> ---
>>> 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                     | 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);
> I meant something like this? not sure.


I think this is fine. I have tested with your modifications on an
Android device and no selinx issue has been found. I will send the v5
patch with your modifications.

Thanks,


>
> ---
>   fs/f2fs/f2fs.h | 5 +++--
>   1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> index 3804b70e5a28..d0aa5766ea66 100644
> --- a/fs/f2fs/f2fs.h
> +++ b/fs/f2fs/f2fs.h
> @@ -2805,7 +2805,8 @@ 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);
> @@ -2814,7 +2815,7 @@ static inline int inc_valid_node_count(struct f2fs_sb_info *sbi,
>
>       avail_user_node_count = sbi->total_node_count - F2FS_RESERVED_NODE_NUM;
>       if (test_opt(sbi, RESERVE_NODE) &&
> -                     !__allow_reserved_root(sbi, inode, false))
> +                     !__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 > avail_user_node_count)) {



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

end of thread, other threads:[~2025-08-06  8:56 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-07-31  7:57 [PATCH v4] f2fs: add reserved nodes for privileged users Chunhai Guo
2025-07-31  8:46 ` Chao Yu
2025-07-31 10:53   ` Chunhai Guo
2025-08-05  2:38     ` Jaegeuk Kim
2025-08-06  8:56       ` Chunhai Guo
2025-08-05  8:56   ` Chao Yu
2025-08-06  8:56     ` 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).