* [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-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-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 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).