All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] f2fs: add reserved blocks for root user
@ 2017-12-28  2:19 ` Jaegeuk Kim
  0 siblings, 0 replies; 21+ messages in thread
From: Jaegeuk Kim @ 2017-12-28  2:19 UTC (permalink / raw)
  To: linux-kernel, linux-f2fs-devel; +Cc: Jaegeuk Kim

This patch allows root to reserve some blocks via mount option.

"-o reserve_root=N" means N x 4KB-sized blocks for root only.

Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
---
 fs/f2fs/f2fs.h  | 25 ++++++++++++++++++++-----
 fs/f2fs/super.c | 24 ++++++++++++++++++++++--
 fs/f2fs/sysfs.c |  5 ++++-
 3 files changed, 46 insertions(+), 8 deletions(-)

diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 5bcd530dbae0..e2d859672147 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -95,6 +95,7 @@ extern char *fault_name[FAULT_MAX];
 #define F2FS_MOUNT_PRJQUOTA		0x00200000
 #define F2FS_MOUNT_QUOTA		0x00400000
 #define F2FS_MOUNT_INLINE_XATTR_SIZE	0x00800000
+#define F2FS_MOUNT_RESERVE_ROOT		0x01000000
 
 #define clear_opt(sbi, option)	((sbi)->mount_opt.opt &= ~F2FS_MOUNT_##option)
 #define set_opt(sbi, option)	((sbi)->mount_opt.opt |= F2FS_MOUNT_##option)
@@ -1557,6 +1558,12 @@ static inline bool f2fs_has_xattr_block(unsigned int ofs)
 	return ofs == XATTR_NODE_OFFSET;
 }
 
+static inline block_t reserve_root_limit(struct f2fs_sb_info *sbi)
+{
+	/* limit is 0.2% */
+	return (sbi->user_block_count << 1) / 100;
+}
+
 static inline void f2fs_i_blocks_write(struct inode *, block_t, bool, bool);
 static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
 				 struct inode *inode, blkcnt_t *count)
@@ -1584,13 +1591,18 @@ static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
 
 	spin_lock(&sbi->stat_lock);
 	sbi->total_valid_block_count += (block_t)(*count);
-	avail_user_block_count = sbi->user_block_count -
-					sbi->current_reserved_blocks;
+	avail_user_block_count = sbi->user_block_count;
+
+	if (!(test_opt(sbi, RESERVE_ROOT) && capable(CAP_SYS_RESOURCE)))
+		avail_user_block_count -= sbi->current_reserved_blocks;
+
 	if (unlikely(sbi->total_valid_block_count > avail_user_block_count)) {
 		diff = sbi->total_valid_block_count - avail_user_block_count;
+		if (diff > *count)
+			diff = *count;
 		*count -= diff;
 		release = diff;
-		sbi->total_valid_block_count = avail_user_block_count;
+		sbi->total_valid_block_count -= diff;
 		if (!*count) {
 			spin_unlock(&sbi->stat_lock);
 			percpu_counter_sub(&sbi->alloc_valid_block_count, diff);
@@ -1780,8 +1792,11 @@ 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;
-	if (unlikely(valid_block_count + sbi->current_reserved_blocks >
-						sbi->user_block_count)) {
+
+	if (!(test_opt(sbi, RESERVE_ROOT) && capable(CAP_SYS_RESOURCE)))
+		valid_block_count += sbi->current_reserved_blocks;
+
+	if (unlikely(valid_block_count > sbi->user_block_count)) {
 		spin_unlock(&sbi->stat_lock);
 		goto enospc;
 	}
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index cb876d905ca5..a19e9f7bd908 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -107,6 +107,7 @@ enum {
 	Opt_noextent_cache,
 	Opt_noinline_data,
 	Opt_data_flush,
+	Opt_reserve_root,
 	Opt_mode,
 	Opt_io_size_bits,
 	Opt_fault_injection,
@@ -157,6 +158,7 @@ static match_table_t f2fs_tokens = {
 	{Opt_noextent_cache, "noextent_cache"},
 	{Opt_noinline_data, "noinline_data"},
 	{Opt_data_flush, "data_flush"},
+	{Opt_reserve_root, "reserve_root=%u"},
 	{Opt_mode, "mode=%s"},
 	{Opt_io_size_bits, "io_bits=%u"},
 	{Opt_fault_injection, "fault_injection=%u"},
@@ -488,6 +490,14 @@ static int parse_options(struct super_block *sb, char *options)
 		case Opt_data_flush:
 			set_opt(sbi, DATA_FLUSH);
 			break;
+		case Opt_reserve_root:
+			if (args->from && match_int(args, &arg))
+				return -EINVAL;
+			if (sbi->current_reserved_blocks > arg)
+				return -EINVAL;
+			sbi->current_reserved_blocks = arg;
+			set_opt(sbi, RESERVE_ROOT);
+			break;
 		case Opt_mode:
 			name = match_strdup(&args[0]);
 
@@ -1006,6 +1016,8 @@ static int f2fs_statfs(struct dentry *dentry, struct kstatfs *buf)
 
 	buf->f_blocks = total_count - start_count;
 	buf->f_bfree = user_block_count - valid_user_blocks(sbi) + ovp_count;
+	if (test_opt(sbi, RESERVE_ROOT))
+		buf->f_bfree += sbi->current_reserved_blocks;
 	buf->f_bavail = user_block_count - valid_user_blocks(sbi) -
 						sbi->current_reserved_blocks;
 
@@ -1136,6 +1148,9 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
 	else if (test_opt(sbi, LFS))
 		seq_puts(seq, "lfs");
 	seq_printf(seq, ",active_logs=%u", sbi->active_logs);
+	if (test_opt(sbi, RESERVE_ROOT))
+		seq_printf(seq, ",reserve_root=%u",
+				sbi->current_reserved_blocks);
 	if (F2FS_IO_SIZE_BITS(sbi))
 		seq_printf(seq, ",io_size=%uKB", F2FS_IO_SIZE_KB(sbi));
 #ifdef CONFIG_F2FS_FAULT_INJECTION
@@ -2569,8 +2584,13 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
 				le64_to_cpu(sbi->ckpt->valid_block_count);
 	sbi->last_valid_block_count = sbi->total_valid_block_count;
 	sbi->reserved_blocks = 0;
-	sbi->current_reserved_blocks = 0;
-
+	if (test_opt(sbi, RESERVE_ROOT) &&
+		sbi->current_reserved_blocks > reserve_root_limit(sbi)) {
+		sbi->current_reserved_blocks = reserve_root_limit(sbi);
+		f2fs_msg(sb, KERN_INFO,
+			"Reduce reserved blocks for root = %u\n",
+				sbi->current_reserved_blocks);
+	}
 	for (i = 0; i < NR_INODE_TYPE; i++) {
 		INIT_LIST_HEAD(&sbi->inode_list[i]);
 		spin_lock_init(&sbi->inode_lock[i]);
diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c
index 987b2736348c..33e159491b48 100644
--- a/fs/f2fs/sysfs.c
+++ b/fs/f2fs/sysfs.c
@@ -162,7 +162,10 @@ static ssize_t f2fs_sbi_store(struct f2fs_attr *a,
 #endif
 	if (a->struct_type == RESERVED_BLOCKS) {
 		spin_lock(&sbi->stat_lock);
-		if (t > (unsigned long)sbi->user_block_count) {
+		if (t > (unsigned long)sbi->user_block_count ||
+			(test_opt(sbi, RESERVE_ROOT) &&
+				(t < sbi->current_reserved_blocks ||
+				t > reserve_root_limit(sbi)))) {
 			spin_unlock(&sbi->stat_lock);
 			return -EINVAL;
 		}
-- 
2.15.0.531.g2ccb3012c9-goog

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

* [PATCH] f2fs: add reserved blocks for root user
@ 2017-12-28  2:19 ` Jaegeuk Kim
  0 siblings, 0 replies; 21+ messages in thread
From: Jaegeuk Kim @ 2017-12-28  2:19 UTC (permalink / raw)
  To: linux-kernel, linux-f2fs-devel; +Cc: Jaegeuk Kim

This patch allows root to reserve some blocks via mount option.

"-o reserve_root=N" means N x 4KB-sized blocks for root only.

Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
---
 fs/f2fs/f2fs.h  | 25 ++++++++++++++++++++-----
 fs/f2fs/super.c | 24 ++++++++++++++++++++++--
 fs/f2fs/sysfs.c |  5 ++++-
 3 files changed, 46 insertions(+), 8 deletions(-)

diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 5bcd530dbae0..e2d859672147 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -95,6 +95,7 @@ extern char *fault_name[FAULT_MAX];
 #define F2FS_MOUNT_PRJQUOTA		0x00200000
 #define F2FS_MOUNT_QUOTA		0x00400000
 #define F2FS_MOUNT_INLINE_XATTR_SIZE	0x00800000
+#define F2FS_MOUNT_RESERVE_ROOT		0x01000000
 
 #define clear_opt(sbi, option)	((sbi)->mount_opt.opt &= ~F2FS_MOUNT_##option)
 #define set_opt(sbi, option)	((sbi)->mount_opt.opt |= F2FS_MOUNT_##option)
@@ -1557,6 +1558,12 @@ static inline bool f2fs_has_xattr_block(unsigned int ofs)
 	return ofs == XATTR_NODE_OFFSET;
 }
 
+static inline block_t reserve_root_limit(struct f2fs_sb_info *sbi)
+{
+	/* limit is 0.2% */
+	return (sbi->user_block_count << 1) / 100;
+}
+
 static inline void f2fs_i_blocks_write(struct inode *, block_t, bool, bool);
 static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
 				 struct inode *inode, blkcnt_t *count)
@@ -1584,13 +1591,18 @@ static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
 
 	spin_lock(&sbi->stat_lock);
 	sbi->total_valid_block_count += (block_t)(*count);
-	avail_user_block_count = sbi->user_block_count -
-					sbi->current_reserved_blocks;
+	avail_user_block_count = sbi->user_block_count;
+
+	if (!(test_opt(sbi, RESERVE_ROOT) && capable(CAP_SYS_RESOURCE)))
+		avail_user_block_count -= sbi->current_reserved_blocks;
+
 	if (unlikely(sbi->total_valid_block_count > avail_user_block_count)) {
 		diff = sbi->total_valid_block_count - avail_user_block_count;
+		if (diff > *count)
+			diff = *count;
 		*count -= diff;
 		release = diff;
-		sbi->total_valid_block_count = avail_user_block_count;
+		sbi->total_valid_block_count -= diff;
 		if (!*count) {
 			spin_unlock(&sbi->stat_lock);
 			percpu_counter_sub(&sbi->alloc_valid_block_count, diff);
@@ -1780,8 +1792,11 @@ 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;
-	if (unlikely(valid_block_count + sbi->current_reserved_blocks >
-						sbi->user_block_count)) {
+
+	if (!(test_opt(sbi, RESERVE_ROOT) && capable(CAP_SYS_RESOURCE)))
+		valid_block_count += sbi->current_reserved_blocks;
+
+	if (unlikely(valid_block_count > sbi->user_block_count)) {
 		spin_unlock(&sbi->stat_lock);
 		goto enospc;
 	}
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index cb876d905ca5..a19e9f7bd908 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -107,6 +107,7 @@ enum {
 	Opt_noextent_cache,
 	Opt_noinline_data,
 	Opt_data_flush,
+	Opt_reserve_root,
 	Opt_mode,
 	Opt_io_size_bits,
 	Opt_fault_injection,
@@ -157,6 +158,7 @@ static match_table_t f2fs_tokens = {
 	{Opt_noextent_cache, "noextent_cache"},
 	{Opt_noinline_data, "noinline_data"},
 	{Opt_data_flush, "data_flush"},
+	{Opt_reserve_root, "reserve_root=%u"},
 	{Opt_mode, "mode=%s"},
 	{Opt_io_size_bits, "io_bits=%u"},
 	{Opt_fault_injection, "fault_injection=%u"},
@@ -488,6 +490,14 @@ static int parse_options(struct super_block *sb, char *options)
 		case Opt_data_flush:
 			set_opt(sbi, DATA_FLUSH);
 			break;
+		case Opt_reserve_root:
+			if (args->from && match_int(args, &arg))
+				return -EINVAL;
+			if (sbi->current_reserved_blocks > arg)
+				return -EINVAL;
+			sbi->current_reserved_blocks = arg;
+			set_opt(sbi, RESERVE_ROOT);
+			break;
 		case Opt_mode:
 			name = match_strdup(&args[0]);
 
@@ -1006,6 +1016,8 @@ static int f2fs_statfs(struct dentry *dentry, struct kstatfs *buf)
 
 	buf->f_blocks = total_count - start_count;
 	buf->f_bfree = user_block_count - valid_user_blocks(sbi) + ovp_count;
+	if (test_opt(sbi, RESERVE_ROOT))
+		buf->f_bfree += sbi->current_reserved_blocks;
 	buf->f_bavail = user_block_count - valid_user_blocks(sbi) -
 						sbi->current_reserved_blocks;
 
@@ -1136,6 +1148,9 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
 	else if (test_opt(sbi, LFS))
 		seq_puts(seq, "lfs");
 	seq_printf(seq, ",active_logs=%u", sbi->active_logs);
+	if (test_opt(sbi, RESERVE_ROOT))
+		seq_printf(seq, ",reserve_root=%u",
+				sbi->current_reserved_blocks);
 	if (F2FS_IO_SIZE_BITS(sbi))
 		seq_printf(seq, ",io_size=%uKB", F2FS_IO_SIZE_KB(sbi));
 #ifdef CONFIG_F2FS_FAULT_INJECTION
@@ -2569,8 +2584,13 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
 				le64_to_cpu(sbi->ckpt->valid_block_count);
 	sbi->last_valid_block_count = sbi->total_valid_block_count;
 	sbi->reserved_blocks = 0;
-	sbi->current_reserved_blocks = 0;
-
+	if (test_opt(sbi, RESERVE_ROOT) &&
+		sbi->current_reserved_blocks > reserve_root_limit(sbi)) {
+		sbi->current_reserved_blocks = reserve_root_limit(sbi);
+		f2fs_msg(sb, KERN_INFO,
+			"Reduce reserved blocks for root = %u\n",
+				sbi->current_reserved_blocks);
+	}
 	for (i = 0; i < NR_INODE_TYPE; i++) {
 		INIT_LIST_HEAD(&sbi->inode_list[i]);
 		spin_lock_init(&sbi->inode_lock[i]);
diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c
index 987b2736348c..33e159491b48 100644
--- a/fs/f2fs/sysfs.c
+++ b/fs/f2fs/sysfs.c
@@ -162,7 +162,10 @@ static ssize_t f2fs_sbi_store(struct f2fs_attr *a,
 #endif
 	if (a->struct_type == RESERVED_BLOCKS) {
 		spin_lock(&sbi->stat_lock);
-		if (t > (unsigned long)sbi->user_block_count) {
+		if (t > (unsigned long)sbi->user_block_count ||
+			(test_opt(sbi, RESERVE_ROOT) &&
+				(t < sbi->current_reserved_blocks ||
+				t > reserve_root_limit(sbi)))) {
 			spin_unlock(&sbi->stat_lock);
 			return -EINVAL;
 		}
-- 
2.15.0.531.g2ccb3012c9-goog


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot

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

* Re: [PATCH] f2fs: add reserved blocks for root user
  2017-12-28  2:19 ` Jaegeuk Kim
@ 2017-12-29  7:55   ` Chao Yu
  -1 siblings, 0 replies; 21+ messages in thread
From: Chao Yu @ 2017-12-29  7:55 UTC (permalink / raw)
  To: Jaegeuk Kim, linux-kernel, linux-f2fs-devel

On 2017/12/28 10:19, Jaegeuk Kim wrote:
> This patch allows root to reserve some blocks via mount option.
> 
> "-o reserve_root=N" means N x 4KB-sized blocks for root only.
> 
> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
> ---
>  fs/f2fs/f2fs.h  | 25 ++++++++++++++++++++-----
>  fs/f2fs/super.c | 24 ++++++++++++++++++++++--
>  fs/f2fs/sysfs.c |  5 ++++-
>  3 files changed, 46 insertions(+), 8 deletions(-)
> 
> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> index 5bcd530dbae0..e2d859672147 100644
> --- a/fs/f2fs/f2fs.h
> +++ b/fs/f2fs/f2fs.h
> @@ -95,6 +95,7 @@ extern char *fault_name[FAULT_MAX];
>  #define F2FS_MOUNT_PRJQUOTA		0x00200000
>  #define F2FS_MOUNT_QUOTA		0x00400000
>  #define F2FS_MOUNT_INLINE_XATTR_SIZE	0x00800000
> +#define F2FS_MOUNT_RESERVE_ROOT		0x01000000
>  
>  #define clear_opt(sbi, option)	((sbi)->mount_opt.opt &= ~F2FS_MOUNT_##option)
>  #define set_opt(sbi, option)	((sbi)->mount_opt.opt |= F2FS_MOUNT_##option)
> @@ -1557,6 +1558,12 @@ static inline bool f2fs_has_xattr_block(unsigned int ofs)
>  	return ofs == XATTR_NODE_OFFSET;
>  }
>  
> +static inline block_t reserve_root_limit(struct f2fs_sb_info *sbi)
> +{
> +	/* limit is 0.2% */
> +	return (sbi->user_block_count << 1) / 100;
> +}
> +
>  static inline void f2fs_i_blocks_write(struct inode *, block_t, bool, bool);
>  static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
>  				 struct inode *inode, blkcnt_t *count)
> @@ -1584,13 +1591,18 @@ static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
>  
>  	spin_lock(&sbi->stat_lock);
>  	sbi->total_valid_block_count += (block_t)(*count);
> -	avail_user_block_count = sbi->user_block_count -
> -					sbi->current_reserved_blocks;
> +	avail_user_block_count = sbi->user_block_count;
> +
> +	if (!(test_opt(sbi, RESERVE_ROOT) && capable(CAP_SYS_RESOURCE)))

How about adding uid & gid verification also like ext4?

> +		avail_user_block_count -= sbi->current_reserved_blocks;
> +
>  	if (unlikely(sbi->total_valid_block_count > avail_user_block_count)) {
>  		diff = sbi->total_valid_block_count - avail_user_block_count;
> +		if (diff > *count)
> +			diff = *count;
>  		*count -= diff;
>  		release = diff;
> -		sbi->total_valid_block_count = avail_user_block_count;
> +		sbi->total_valid_block_count -= diff;
>  		if (!*count) {
>  			spin_unlock(&sbi->stat_lock);
>  			percpu_counter_sub(&sbi->alloc_valid_block_count, diff);
> @@ -1780,8 +1792,11 @@ 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;
> -	if (unlikely(valid_block_count + sbi->current_reserved_blocks >
> -						sbi->user_block_count)) {
> +
> +	if (!(test_opt(sbi, RESERVE_ROOT) && capable(CAP_SYS_RESOURCE)))
> +		valid_block_count += sbi->current_reserved_blocks;
> +
> +	if (unlikely(valid_block_count > sbi->user_block_count)) {
>  		spin_unlock(&sbi->stat_lock);
>  		goto enospc;
>  	}
> diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
> index cb876d905ca5..a19e9f7bd908 100644
> --- a/fs/f2fs/super.c
> +++ b/fs/f2fs/super.c
> @@ -107,6 +107,7 @@ enum {
>  	Opt_noextent_cache,
>  	Opt_noinline_data,
>  	Opt_data_flush,
> +	Opt_reserve_root,
>  	Opt_mode,
>  	Opt_io_size_bits,
>  	Opt_fault_injection,
> @@ -157,6 +158,7 @@ static match_table_t f2fs_tokens = {
>  	{Opt_noextent_cache, "noextent_cache"},
>  	{Opt_noinline_data, "noinline_data"},
>  	{Opt_data_flush, "data_flush"},
> +	{Opt_reserve_root, "reserve_root=%u"},
>  	{Opt_mode, "mode=%s"},
>  	{Opt_io_size_bits, "io_bits=%u"},
>  	{Opt_fault_injection, "fault_injection=%u"},
> @@ -488,6 +490,14 @@ static int parse_options(struct super_block *sb, char *options)
>  		case Opt_data_flush:
>  			set_opt(sbi, DATA_FLUSH);
>  			break;
> +		case Opt_reserve_root:
> +			if (args->from && match_int(args, &arg))
> +				return -EINVAL;
> +			if (sbi->current_reserved_blocks > arg)
> +				return -EINVAL;
> +			sbi->current_reserved_blocks = arg;

Previously, we have supported to reserve blocks in fs layer to adjust
over-provision ratio dynamically by configuring sysfs interface, which can
be used for reserving space of low level storage device for performance or
flash lifetime.

I think reserve blocks for root user is another requirement which is
different from above one, so I hope we can keep both of these two features
available and usable, in order to keep previous one's backward
compatibility and also try to support more various features in f2fs.

Thanks,

> +			set_opt(sbi, RESERVE_ROOT);
> +			break;
>  		case Opt_mode:
>  			name = match_strdup(&args[0]);
>  
> @@ -1006,6 +1016,8 @@ static int f2fs_statfs(struct dentry *dentry, struct kstatfs *buf)
>  
>  	buf->f_blocks = total_count - start_count;
>  	buf->f_bfree = user_block_count - valid_user_blocks(sbi) + ovp_count;
> +	if (test_opt(sbi, RESERVE_ROOT))
> +		buf->f_bfree += sbi->current_reserved_blocks;
>  	buf->f_bavail = user_block_count - valid_user_blocks(sbi) -
>  						sbi->current_reserved_blocks;
>  
> @@ -1136,6 +1148,9 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
>  	else if (test_opt(sbi, LFS))
>  		seq_puts(seq, "lfs");
>  	seq_printf(seq, ",active_logs=%u", sbi->active_logs);
> +	if (test_opt(sbi, RESERVE_ROOT))
> +		seq_printf(seq, ",reserve_root=%u",
> +				sbi->current_reserved_blocks);
>  	if (F2FS_IO_SIZE_BITS(sbi))
>  		seq_printf(seq, ",io_size=%uKB", F2FS_IO_SIZE_KB(sbi));
>  #ifdef CONFIG_F2FS_FAULT_INJECTION
> @@ -2569,8 +2584,13 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
>  				le64_to_cpu(sbi->ckpt->valid_block_count);
>  	sbi->last_valid_block_count = sbi->total_valid_block_count;
>  	sbi->reserved_blocks = 0;
> -	sbi->current_reserved_blocks = 0;
> -
> +	if (test_opt(sbi, RESERVE_ROOT) &&
> +		sbi->current_reserved_blocks > reserve_root_limit(sbi)) {
> +		sbi->current_reserved_blocks = reserve_root_limit(sbi);
> +		f2fs_msg(sb, KERN_INFO,
> +			"Reduce reserved blocks for root = %u\n",
> +				sbi->current_reserved_blocks);
> +	}
>  	for (i = 0; i < NR_INODE_TYPE; i++) {
>  		INIT_LIST_HEAD(&sbi->inode_list[i]);
>  		spin_lock_init(&sbi->inode_lock[i]);
> diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c
> index 987b2736348c..33e159491b48 100644
> --- a/fs/f2fs/sysfs.c
> +++ b/fs/f2fs/sysfs.c
> @@ -162,7 +162,10 @@ static ssize_t f2fs_sbi_store(struct f2fs_attr *a,
>  #endif
>  	if (a->struct_type == RESERVED_BLOCKS) {
>  		spin_lock(&sbi->stat_lock);
> -		if (t > (unsigned long)sbi->user_block_count) {
> +		if (t > (unsigned long)sbi->user_block_count ||
> +			(test_opt(sbi, RESERVE_ROOT) &&
> +				(t < sbi->current_reserved_blocks ||
> +				t > reserve_root_limit(sbi)))) {
>  			spin_unlock(&sbi->stat_lock);
>  			return -EINVAL;
>  		}
> 

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

* Re: [PATCH] f2fs: add reserved blocks for root user
@ 2017-12-29  7:55   ` Chao Yu
  0 siblings, 0 replies; 21+ messages in thread
From: Chao Yu @ 2017-12-29  7:55 UTC (permalink / raw)
  To: Jaegeuk Kim, linux-kernel, linux-f2fs-devel

On 2017/12/28 10:19, Jaegeuk Kim wrote:
> This patch allows root to reserve some blocks via mount option.
> 
> "-o reserve_root=N" means N x 4KB-sized blocks for root only.
> 
> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
> ---
>  fs/f2fs/f2fs.h  | 25 ++++++++++++++++++++-----
>  fs/f2fs/super.c | 24 ++++++++++++++++++++++--
>  fs/f2fs/sysfs.c |  5 ++++-
>  3 files changed, 46 insertions(+), 8 deletions(-)
> 
> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> index 5bcd530dbae0..e2d859672147 100644
> --- a/fs/f2fs/f2fs.h
> +++ b/fs/f2fs/f2fs.h
> @@ -95,6 +95,7 @@ extern char *fault_name[FAULT_MAX];
>  #define F2FS_MOUNT_PRJQUOTA		0x00200000
>  #define F2FS_MOUNT_QUOTA		0x00400000
>  #define F2FS_MOUNT_INLINE_XATTR_SIZE	0x00800000
> +#define F2FS_MOUNT_RESERVE_ROOT		0x01000000
>  
>  #define clear_opt(sbi, option)	((sbi)->mount_opt.opt &= ~F2FS_MOUNT_##option)
>  #define set_opt(sbi, option)	((sbi)->mount_opt.opt |= F2FS_MOUNT_##option)
> @@ -1557,6 +1558,12 @@ static inline bool f2fs_has_xattr_block(unsigned int ofs)
>  	return ofs == XATTR_NODE_OFFSET;
>  }
>  
> +static inline block_t reserve_root_limit(struct f2fs_sb_info *sbi)
> +{
> +	/* limit is 0.2% */
> +	return (sbi->user_block_count << 1) / 100;
> +}
> +
>  static inline void f2fs_i_blocks_write(struct inode *, block_t, bool, bool);
>  static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
>  				 struct inode *inode, blkcnt_t *count)
> @@ -1584,13 +1591,18 @@ static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
>  
>  	spin_lock(&sbi->stat_lock);
>  	sbi->total_valid_block_count += (block_t)(*count);
> -	avail_user_block_count = sbi->user_block_count -
> -					sbi->current_reserved_blocks;
> +	avail_user_block_count = sbi->user_block_count;
> +
> +	if (!(test_opt(sbi, RESERVE_ROOT) && capable(CAP_SYS_RESOURCE)))

How about adding uid & gid verification also like ext4?

> +		avail_user_block_count -= sbi->current_reserved_blocks;
> +
>  	if (unlikely(sbi->total_valid_block_count > avail_user_block_count)) {
>  		diff = sbi->total_valid_block_count - avail_user_block_count;
> +		if (diff > *count)
> +			diff = *count;
>  		*count -= diff;
>  		release = diff;
> -		sbi->total_valid_block_count = avail_user_block_count;
> +		sbi->total_valid_block_count -= diff;
>  		if (!*count) {
>  			spin_unlock(&sbi->stat_lock);
>  			percpu_counter_sub(&sbi->alloc_valid_block_count, diff);
> @@ -1780,8 +1792,11 @@ 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;
> -	if (unlikely(valid_block_count + sbi->current_reserved_blocks >
> -						sbi->user_block_count)) {
> +
> +	if (!(test_opt(sbi, RESERVE_ROOT) && capable(CAP_SYS_RESOURCE)))
> +		valid_block_count += sbi->current_reserved_blocks;
> +
> +	if (unlikely(valid_block_count > sbi->user_block_count)) {
>  		spin_unlock(&sbi->stat_lock);
>  		goto enospc;
>  	}
> diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
> index cb876d905ca5..a19e9f7bd908 100644
> --- a/fs/f2fs/super.c
> +++ b/fs/f2fs/super.c
> @@ -107,6 +107,7 @@ enum {
>  	Opt_noextent_cache,
>  	Opt_noinline_data,
>  	Opt_data_flush,
> +	Opt_reserve_root,
>  	Opt_mode,
>  	Opt_io_size_bits,
>  	Opt_fault_injection,
> @@ -157,6 +158,7 @@ static match_table_t f2fs_tokens = {
>  	{Opt_noextent_cache, "noextent_cache"},
>  	{Opt_noinline_data, "noinline_data"},
>  	{Opt_data_flush, "data_flush"},
> +	{Opt_reserve_root, "reserve_root=%u"},
>  	{Opt_mode, "mode=%s"},
>  	{Opt_io_size_bits, "io_bits=%u"},
>  	{Opt_fault_injection, "fault_injection=%u"},
> @@ -488,6 +490,14 @@ static int parse_options(struct super_block *sb, char *options)
>  		case Opt_data_flush:
>  			set_opt(sbi, DATA_FLUSH);
>  			break;
> +		case Opt_reserve_root:
> +			if (args->from && match_int(args, &arg))
> +				return -EINVAL;
> +			if (sbi->current_reserved_blocks > arg)
> +				return -EINVAL;
> +			sbi->current_reserved_blocks = arg;

Previously, we have supported to reserve blocks in fs layer to adjust
over-provision ratio dynamically by configuring sysfs interface, which can
be used for reserving space of low level storage device for performance or
flash lifetime.

I think reserve blocks for root user is another requirement which is
different from above one, so I hope we can keep both of these two features
available and usable, in order to keep previous one's backward
compatibility and also try to support more various features in f2fs.

Thanks,

> +			set_opt(sbi, RESERVE_ROOT);
> +			break;
>  		case Opt_mode:
>  			name = match_strdup(&args[0]);
>  
> @@ -1006,6 +1016,8 @@ static int f2fs_statfs(struct dentry *dentry, struct kstatfs *buf)
>  
>  	buf->f_blocks = total_count - start_count;
>  	buf->f_bfree = user_block_count - valid_user_blocks(sbi) + ovp_count;
> +	if (test_opt(sbi, RESERVE_ROOT))
> +		buf->f_bfree += sbi->current_reserved_blocks;
>  	buf->f_bavail = user_block_count - valid_user_blocks(sbi) -
>  						sbi->current_reserved_blocks;
>  
> @@ -1136,6 +1148,9 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
>  	else if (test_opt(sbi, LFS))
>  		seq_puts(seq, "lfs");
>  	seq_printf(seq, ",active_logs=%u", sbi->active_logs);
> +	if (test_opt(sbi, RESERVE_ROOT))
> +		seq_printf(seq, ",reserve_root=%u",
> +				sbi->current_reserved_blocks);
>  	if (F2FS_IO_SIZE_BITS(sbi))
>  		seq_printf(seq, ",io_size=%uKB", F2FS_IO_SIZE_KB(sbi));
>  #ifdef CONFIG_F2FS_FAULT_INJECTION
> @@ -2569,8 +2584,13 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
>  				le64_to_cpu(sbi->ckpt->valid_block_count);
>  	sbi->last_valid_block_count = sbi->total_valid_block_count;
>  	sbi->reserved_blocks = 0;
> -	sbi->current_reserved_blocks = 0;
> -
> +	if (test_opt(sbi, RESERVE_ROOT) &&
> +		sbi->current_reserved_blocks > reserve_root_limit(sbi)) {
> +		sbi->current_reserved_blocks = reserve_root_limit(sbi);
> +		f2fs_msg(sb, KERN_INFO,
> +			"Reduce reserved blocks for root = %u\n",
> +				sbi->current_reserved_blocks);
> +	}
>  	for (i = 0; i < NR_INODE_TYPE; i++) {
>  		INIT_LIST_HEAD(&sbi->inode_list[i]);
>  		spin_lock_init(&sbi->inode_lock[i]);
> diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c
> index 987b2736348c..33e159491b48 100644
> --- a/fs/f2fs/sysfs.c
> +++ b/fs/f2fs/sysfs.c
> @@ -162,7 +162,10 @@ static ssize_t f2fs_sbi_store(struct f2fs_attr *a,
>  #endif
>  	if (a->struct_type == RESERVED_BLOCKS) {
>  		spin_lock(&sbi->stat_lock);
> -		if (t > (unsigned long)sbi->user_block_count) {
> +		if (t > (unsigned long)sbi->user_block_count ||
> +			(test_opt(sbi, RESERVE_ROOT) &&
> +				(t < sbi->current_reserved_blocks ||
> +				t > reserve_root_limit(sbi)))) {
>  			spin_unlock(&sbi->stat_lock);
>  			return -EINVAL;
>  		}
> 

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

* Re: [PATCH v2] f2fs: add reserved blocks for root user
  2017-12-28  2:19 ` Jaegeuk Kim
@ 2018-01-01  1:24   ` Jaegeuk Kim
  -1 siblings, 0 replies; 21+ messages in thread
From: Jaegeuk Kim @ 2018-01-01  1:24 UTC (permalink / raw)
  To: linux-kernel, linux-f2fs-devel

We can give another chance to write user data, which can resolve
generic/441.

Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
---

Change log from v1:
 - skip stop_checkpoint for normal user data

 fs/f2fs/data.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index b9fab6186f28..45f65a5b9871 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -111,7 +111,8 @@ static void f2fs_write_end_io(struct bio *bio)
 
 		if (unlikely(bio->bi_status)) {
 			mapping_set_error(page->mapping, -EIO);
-			f2fs_stop_checkpoint(sbi, true);
+			if (type == F2FS_WB_CP_DATA)
+				f2fs_stop_checkpoint(sbi, true);
 		}
 		dec_page_count(sbi, type);
 		clear_cold_data(page);
-- 
2.15.0.531.g2ccb3012c9-goog

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

* Re: [PATCH v2] f2fs: add reserved blocks for root user
@ 2018-01-01  1:24   ` Jaegeuk Kim
  0 siblings, 0 replies; 21+ messages in thread
From: Jaegeuk Kim @ 2018-01-01  1:24 UTC (permalink / raw)
  To: linux-kernel, linux-f2fs-devel

We can give another chance to write user data, which can resolve
generic/441.

Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
---

Change log from v1:
 - skip stop_checkpoint for normal user data

 fs/f2fs/data.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index b9fab6186f28..45f65a5b9871 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -111,7 +111,8 @@ static void f2fs_write_end_io(struct bio *bio)
 
 		if (unlikely(bio->bi_status)) {
 			mapping_set_error(page->mapping, -EIO);
-			f2fs_stop_checkpoint(sbi, true);
+			if (type == F2FS_WB_CP_DATA)
+				f2fs_stop_checkpoint(sbi, true);
 		}
 		dec_page_count(sbi, type);
 		clear_cold_data(page);
-- 
2.15.0.531.g2ccb3012c9-goog


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot

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

* Re: [PATCH v3] f2fs: add reserved blocks for root user
  2017-12-28  2:19 ` Jaegeuk Kim
@ 2018-01-01  1:29   ` Jaegeuk Kim
  -1 siblings, 0 replies; 21+ messages in thread
From: Jaegeuk Kim @ 2018-01-01  1:29 UTC (permalink / raw)
  To: linux-kernel, linux-f2fs-devel

This patch allows root to reserve some blocks via mount option.

"-o reserve_root=N" means N x 4KB-sized blocks for root only.

Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
---

Change log from v2:
 - wrong submission. :P

 fs/f2fs/f2fs.h  | 26 ++++++++++++++++++++++----
 fs/f2fs/super.c | 26 +++++++++++++++++++++++---
 fs/f2fs/sysfs.c |  3 ++-
 3 files changed, 47 insertions(+), 8 deletions(-)

diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 5f7f42267221..123d875f7293 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -95,6 +95,7 @@ extern char *fault_name[FAULT_MAX];
 #define F2FS_MOUNT_PRJQUOTA		0x00200000
 #define F2FS_MOUNT_QUOTA		0x00400000
 #define F2FS_MOUNT_INLINE_XATTR_SIZE	0x00800000
+#define F2FS_MOUNT_RESERVE_ROOT		0x01000000
 
 #define clear_opt(sbi, option)	((sbi)->mount_opt.opt &= ~F2FS_MOUNT_##option)
 #define set_opt(sbi, option)	((sbi)->mount_opt.opt |= F2FS_MOUNT_##option)
@@ -1110,6 +1111,7 @@ struct f2fs_sb_info {
 	block_t last_valid_block_count;		/* for recovery */
 	block_t reserved_blocks;		/* configurable reserved blocks */
 	block_t current_reserved_blocks;	/* current reserved blocks */
+	block_t root_reserved_blocks;		/* root reserved blocks */
 
 	unsigned int nquota_files;		/* # of quota sysfile */
 
@@ -1562,6 +1564,12 @@ static inline bool f2fs_has_xattr_block(unsigned int ofs)
 	return ofs == XATTR_NODE_OFFSET;
 }
 
+static inline block_t reserve_root_limit(struct f2fs_sb_info *sbi)
+{
+	/* limit is 0.2% */
+	return (sbi->user_block_count << 1) / 100;
+}
+
 static inline void f2fs_i_blocks_write(struct inode *, block_t, bool, bool);
 static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
 				 struct inode *inode, blkcnt_t *count)
@@ -1591,11 +1599,17 @@ static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
 	sbi->total_valid_block_count += (block_t)(*count);
 	avail_user_block_count = sbi->user_block_count -
 					sbi->current_reserved_blocks;
+
+	if (!(test_opt(sbi, RESERVE_ROOT) && capable(CAP_SYS_RESOURCE)))
+		avail_user_block_count -= sbi->root_reserved_blocks;
+
 	if (unlikely(sbi->total_valid_block_count > avail_user_block_count)) {
 		diff = sbi->total_valid_block_count - avail_user_block_count;
+		if (diff > *count)
+			diff = *count;
 		*count -= diff;
 		release = diff;
-		sbi->total_valid_block_count = avail_user_block_count;
+		sbi->total_valid_block_count -= diff;
 		if (!*count) {
 			spin_unlock(&sbi->stat_lock);
 			percpu_counter_sub(&sbi->alloc_valid_block_count, diff);
@@ -1784,9 +1798,13 @@ 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;
-	if (unlikely(valid_block_count + sbi->current_reserved_blocks >
-						sbi->user_block_count)) {
+	valid_block_count = sbi->total_valid_block_count +
+					sbi->current_reserved_blocks + 1;
+
+	if (!(test_opt(sbi, RESERVE_ROOT) && capable(CAP_SYS_RESOURCE)))
+		valid_block_count += sbi->root_reserved_blocks;
+
+	if (unlikely(valid_block_count > sbi->user_block_count)) {
 		spin_unlock(&sbi->stat_lock);
 		goto enospc;
 	}
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index cb876d905ca5..9221b013db98 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -107,6 +107,7 @@ enum {
 	Opt_noextent_cache,
 	Opt_noinline_data,
 	Opt_data_flush,
+	Opt_reserve_root,
 	Opt_mode,
 	Opt_io_size_bits,
 	Opt_fault_injection,
@@ -157,6 +158,7 @@ static match_table_t f2fs_tokens = {
 	{Opt_noextent_cache, "noextent_cache"},
 	{Opt_noinline_data, "noinline_data"},
 	{Opt_data_flush, "data_flush"},
+	{Opt_reserve_root, "reserve_root=%u"},
 	{Opt_mode, "mode=%s"},
 	{Opt_io_size_bits, "io_bits=%u"},
 	{Opt_fault_injection, "fault_injection=%u"},
@@ -488,6 +490,12 @@ static int parse_options(struct super_block *sb, char *options)
 		case Opt_data_flush:
 			set_opt(sbi, DATA_FLUSH);
 			break;
+		case Opt_reserve_root:
+			if (args->from && match_int(args, &arg))
+				return -EINVAL;
+			sbi->root_reserved_blocks = arg;
+			set_opt(sbi, RESERVE_ROOT);
+			break;
 		case Opt_mode:
 			name = match_strdup(&args[0]);
 
@@ -1005,10 +1013,12 @@ static int f2fs_statfs(struct dentry *dentry, struct kstatfs *buf)
 	buf->f_bsize = sbi->blocksize;
 
 	buf->f_blocks = total_count - start_count;
-	buf->f_bfree = user_block_count - valid_user_blocks(sbi) + ovp_count;
+	buf->f_bfree = user_block_count - valid_user_blocks(sbi) -
+						sbi->current_reserved_blocks +
+						sbi->root_reserved_blocks;
 	buf->f_bavail = user_block_count - valid_user_blocks(sbi) -
-						sbi->current_reserved_blocks;
-
+						sbi->current_reserved_blocks -
+						sbi->root_reserved_blocks;
 	avail_node_count = sbi->total_node_count - sbi->nquota_files -
 						F2FS_RESERVED_NODE_NUM;
 
@@ -1136,6 +1146,9 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
 	else if (test_opt(sbi, LFS))
 		seq_puts(seq, "lfs");
 	seq_printf(seq, ",active_logs=%u", sbi->active_logs);
+	if (test_opt(sbi, RESERVE_ROOT))
+		seq_printf(seq, ",reserve_root=%u",
+				sbi->root_reserved_blocks);
 	if (F2FS_IO_SIZE_BITS(sbi))
 		seq_printf(seq, ",io_size=%uKB", F2FS_IO_SIZE_KB(sbi));
 #ifdef CONFIG_F2FS_FAULT_INJECTION
@@ -2571,6 +2584,13 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
 	sbi->reserved_blocks = 0;
 	sbi->current_reserved_blocks = 0;
 
+	if (test_opt(sbi, RESERVE_ROOT) &&
+		sbi->root_reserved_blocks > reserve_root_limit(sbi)) {
+		sbi->root_reserved_blocks = reserve_root_limit(sbi);
+		f2fs_msg(sb, KERN_INFO,
+			"Reduce reserved blocks for root = %u\n",
+				sbi->root_reserved_blocks);
+	}
 	for (i = 0; i < NR_INODE_TYPE; i++) {
 		INIT_LIST_HEAD(&sbi->inode_list[i]);
 		spin_lock_init(&sbi->inode_lock[i]);
diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c
index 7e15cbc5b8e1..41887e6ec1b3 100644
--- a/fs/f2fs/sysfs.c
+++ b/fs/f2fs/sysfs.c
@@ -162,7 +162,8 @@ static ssize_t f2fs_sbi_store(struct f2fs_attr *a,
 #endif
 	if (a->struct_type == RESERVED_BLOCKS) {
 		spin_lock(&sbi->stat_lock);
-		if (t > (unsigned long)sbi->user_block_count) {
+		if (t > (unsigned long)(sbi->user_block_count -
+					sbi->root_reserved_blocks)) {
 			spin_unlock(&sbi->stat_lock);
 			return -EINVAL;
 		}
-- 
2.15.0.531.g2ccb3012c9-goog

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

* Re: [PATCH v3] f2fs: add reserved blocks for root user
@ 2018-01-01  1:29   ` Jaegeuk Kim
  0 siblings, 0 replies; 21+ messages in thread
From: Jaegeuk Kim @ 2018-01-01  1:29 UTC (permalink / raw)
  To: linux-kernel, linux-f2fs-devel

This patch allows root to reserve some blocks via mount option.

"-o reserve_root=N" means N x 4KB-sized blocks for root only.

Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
---

Change log from v2:
 - wrong submission. :P

 fs/f2fs/f2fs.h  | 26 ++++++++++++++++++++++----
 fs/f2fs/super.c | 26 +++++++++++++++++++++++---
 fs/f2fs/sysfs.c |  3 ++-
 3 files changed, 47 insertions(+), 8 deletions(-)

diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 5f7f42267221..123d875f7293 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -95,6 +95,7 @@ extern char *fault_name[FAULT_MAX];
 #define F2FS_MOUNT_PRJQUOTA		0x00200000
 #define F2FS_MOUNT_QUOTA		0x00400000
 #define F2FS_MOUNT_INLINE_XATTR_SIZE	0x00800000
+#define F2FS_MOUNT_RESERVE_ROOT		0x01000000
 
 #define clear_opt(sbi, option)	((sbi)->mount_opt.opt &= ~F2FS_MOUNT_##option)
 #define set_opt(sbi, option)	((sbi)->mount_opt.opt |= F2FS_MOUNT_##option)
@@ -1110,6 +1111,7 @@ struct f2fs_sb_info {
 	block_t last_valid_block_count;		/* for recovery */
 	block_t reserved_blocks;		/* configurable reserved blocks */
 	block_t current_reserved_blocks;	/* current reserved blocks */
+	block_t root_reserved_blocks;		/* root reserved blocks */
 
 	unsigned int nquota_files;		/* # of quota sysfile */
 
@@ -1562,6 +1564,12 @@ static inline bool f2fs_has_xattr_block(unsigned int ofs)
 	return ofs == XATTR_NODE_OFFSET;
 }
 
+static inline block_t reserve_root_limit(struct f2fs_sb_info *sbi)
+{
+	/* limit is 0.2% */
+	return (sbi->user_block_count << 1) / 100;
+}
+
 static inline void f2fs_i_blocks_write(struct inode *, block_t, bool, bool);
 static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
 				 struct inode *inode, blkcnt_t *count)
@@ -1591,11 +1599,17 @@ static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
 	sbi->total_valid_block_count += (block_t)(*count);
 	avail_user_block_count = sbi->user_block_count -
 					sbi->current_reserved_blocks;
+
+	if (!(test_opt(sbi, RESERVE_ROOT) && capable(CAP_SYS_RESOURCE)))
+		avail_user_block_count -= sbi->root_reserved_blocks;
+
 	if (unlikely(sbi->total_valid_block_count > avail_user_block_count)) {
 		diff = sbi->total_valid_block_count - avail_user_block_count;
+		if (diff > *count)
+			diff = *count;
 		*count -= diff;
 		release = diff;
-		sbi->total_valid_block_count = avail_user_block_count;
+		sbi->total_valid_block_count -= diff;
 		if (!*count) {
 			spin_unlock(&sbi->stat_lock);
 			percpu_counter_sub(&sbi->alloc_valid_block_count, diff);
@@ -1784,9 +1798,13 @@ 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;
-	if (unlikely(valid_block_count + sbi->current_reserved_blocks >
-						sbi->user_block_count)) {
+	valid_block_count = sbi->total_valid_block_count +
+					sbi->current_reserved_blocks + 1;
+
+	if (!(test_opt(sbi, RESERVE_ROOT) && capable(CAP_SYS_RESOURCE)))
+		valid_block_count += sbi->root_reserved_blocks;
+
+	if (unlikely(valid_block_count > sbi->user_block_count)) {
 		spin_unlock(&sbi->stat_lock);
 		goto enospc;
 	}
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index cb876d905ca5..9221b013db98 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -107,6 +107,7 @@ enum {
 	Opt_noextent_cache,
 	Opt_noinline_data,
 	Opt_data_flush,
+	Opt_reserve_root,
 	Opt_mode,
 	Opt_io_size_bits,
 	Opt_fault_injection,
@@ -157,6 +158,7 @@ static match_table_t f2fs_tokens = {
 	{Opt_noextent_cache, "noextent_cache"},
 	{Opt_noinline_data, "noinline_data"},
 	{Opt_data_flush, "data_flush"},
+	{Opt_reserve_root, "reserve_root=%u"},
 	{Opt_mode, "mode=%s"},
 	{Opt_io_size_bits, "io_bits=%u"},
 	{Opt_fault_injection, "fault_injection=%u"},
@@ -488,6 +490,12 @@ static int parse_options(struct super_block *sb, char *options)
 		case Opt_data_flush:
 			set_opt(sbi, DATA_FLUSH);
 			break;
+		case Opt_reserve_root:
+			if (args->from && match_int(args, &arg))
+				return -EINVAL;
+			sbi->root_reserved_blocks = arg;
+			set_opt(sbi, RESERVE_ROOT);
+			break;
 		case Opt_mode:
 			name = match_strdup(&args[0]);
 
@@ -1005,10 +1013,12 @@ static int f2fs_statfs(struct dentry *dentry, struct kstatfs *buf)
 	buf->f_bsize = sbi->blocksize;
 
 	buf->f_blocks = total_count - start_count;
-	buf->f_bfree = user_block_count - valid_user_blocks(sbi) + ovp_count;
+	buf->f_bfree = user_block_count - valid_user_blocks(sbi) -
+						sbi->current_reserved_blocks +
+						sbi->root_reserved_blocks;
 	buf->f_bavail = user_block_count - valid_user_blocks(sbi) -
-						sbi->current_reserved_blocks;
-
+						sbi->current_reserved_blocks -
+						sbi->root_reserved_blocks;
 	avail_node_count = sbi->total_node_count - sbi->nquota_files -
 						F2FS_RESERVED_NODE_NUM;
 
@@ -1136,6 +1146,9 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
 	else if (test_opt(sbi, LFS))
 		seq_puts(seq, "lfs");
 	seq_printf(seq, ",active_logs=%u", sbi->active_logs);
+	if (test_opt(sbi, RESERVE_ROOT))
+		seq_printf(seq, ",reserve_root=%u",
+				sbi->root_reserved_blocks);
 	if (F2FS_IO_SIZE_BITS(sbi))
 		seq_printf(seq, ",io_size=%uKB", F2FS_IO_SIZE_KB(sbi));
 #ifdef CONFIG_F2FS_FAULT_INJECTION
@@ -2571,6 +2584,13 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
 	sbi->reserved_blocks = 0;
 	sbi->current_reserved_blocks = 0;
 
+	if (test_opt(sbi, RESERVE_ROOT) &&
+		sbi->root_reserved_blocks > reserve_root_limit(sbi)) {
+		sbi->root_reserved_blocks = reserve_root_limit(sbi);
+		f2fs_msg(sb, KERN_INFO,
+			"Reduce reserved blocks for root = %u\n",
+				sbi->root_reserved_blocks);
+	}
 	for (i = 0; i < NR_INODE_TYPE; i++) {
 		INIT_LIST_HEAD(&sbi->inode_list[i]);
 		spin_lock_init(&sbi->inode_lock[i]);
diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c
index 7e15cbc5b8e1..41887e6ec1b3 100644
--- a/fs/f2fs/sysfs.c
+++ b/fs/f2fs/sysfs.c
@@ -162,7 +162,8 @@ static ssize_t f2fs_sbi_store(struct f2fs_attr *a,
 #endif
 	if (a->struct_type == RESERVED_BLOCKS) {
 		spin_lock(&sbi->stat_lock);
-		if (t > (unsigned long)sbi->user_block_count) {
+		if (t > (unsigned long)(sbi->user_block_count -
+					sbi->root_reserved_blocks)) {
 			spin_unlock(&sbi->stat_lock);
 			return -EINVAL;
 		}
-- 
2.15.0.531.g2ccb3012c9-goog


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot

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

* Re: [f2fs-dev] [PATCH v3] f2fs: add reserved blocks for root user
  2018-01-01  1:29   ` Jaegeuk Kim
@ 2018-01-02  6:25     ` Chao Yu
  -1 siblings, 0 replies; 21+ messages in thread
From: Chao Yu @ 2018-01-02  6:25 UTC (permalink / raw)
  To: Jaegeuk Kim, linux-kernel, linux-f2fs-devel

On 2018/1/1 9:29, Jaegeuk Kim wrote:
> This patch allows root to reserve some blocks via mount option.
> 
> "-o reserve_root=N" means N x 4KB-sized blocks for root only.
> 
> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
> ---
> 
> Change log from v2:
>  - wrong submission. :P
> 
>  fs/f2fs/f2fs.h  | 26 ++++++++++++++++++++++----
>  fs/f2fs/super.c | 26 +++++++++++++++++++++++---
>  fs/f2fs/sysfs.c |  3 ++-
>  3 files changed, 47 insertions(+), 8 deletions(-)
> 
> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> index 5f7f42267221..123d875f7293 100644
> --- a/fs/f2fs/f2fs.h
> +++ b/fs/f2fs/f2fs.h
> @@ -95,6 +95,7 @@ extern char *fault_name[FAULT_MAX];
>  #define F2FS_MOUNT_PRJQUOTA		0x00200000
>  #define F2FS_MOUNT_QUOTA		0x00400000
>  #define F2FS_MOUNT_INLINE_XATTR_SIZE	0x00800000
> +#define F2FS_MOUNT_RESERVE_ROOT		0x01000000
>  
>  #define clear_opt(sbi, option)	((sbi)->mount_opt.opt &= ~F2FS_MOUNT_##option)
>  #define set_opt(sbi, option)	((sbi)->mount_opt.opt |= F2FS_MOUNT_##option)
> @@ -1110,6 +1111,7 @@ struct f2fs_sb_info {
>  	block_t last_valid_block_count;		/* for recovery */
>  	block_t reserved_blocks;		/* configurable reserved blocks */
>  	block_t current_reserved_blocks;	/* current reserved blocks */
> +	block_t root_reserved_blocks;		/* root reserved blocks */
>  
>  	unsigned int nquota_files;		/* # of quota sysfile */
>  
> @@ -1562,6 +1564,12 @@ static inline bool f2fs_has_xattr_block(unsigned int ofs)
>  	return ofs == XATTR_NODE_OFFSET;
>  }
>  
> +static inline block_t reserve_root_limit(struct f2fs_sb_info *sbi)
> +{
> +	/* limit is 0.2% */

Should be 2% according to below calculation?

> +	return (sbi->user_block_count << 1) / 100;
> +}
> +
>  static inline void f2fs_i_blocks_write(struct inode *, block_t, bool, bool);
>  static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
>  				 struct inode *inode, blkcnt_t *count)
> @@ -1591,11 +1599,17 @@ static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
>  	sbi->total_valid_block_count += (block_t)(*count);
>  	avail_user_block_count = sbi->user_block_count -
>  					sbi->current_reserved_blocks;
> +
> +	if (!(test_opt(sbi, RESERVE_ROOT) && capable(CAP_SYS_RESOURCE)))

How about adding uid & gid verification also like ext4?

As this is a mount option, in ->remount_fs, we should consider to recover
original reserved block number if we encounter some error during remount.

Thanks,

> +		avail_user_block_count -= sbi->root_reserved_blocks;
> +
>  	if (unlikely(sbi->total_valid_block_count > avail_user_block_count)) {
>  		diff = sbi->total_valid_block_count - avail_user_block_count;
> +		if (diff > *count)
> +			diff = *count;
>  		*count -= diff;
>  		release = diff;
> -		sbi->total_valid_block_count = avail_user_block_count;
> +		sbi->total_valid_block_count -= diff;
>  		if (!*count) {
>  			spin_unlock(&sbi->stat_lock);
>  			percpu_counter_sub(&sbi->alloc_valid_block_count, diff);
> @@ -1784,9 +1798,13 @@ 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;
> -	if (unlikely(valid_block_count + sbi->current_reserved_blocks >
> -						sbi->user_block_count)) {
> +	valid_block_count = sbi->total_valid_block_count +
> +					sbi->current_reserved_blocks + 1;
> +
> +	if (!(test_opt(sbi, RESERVE_ROOT) && capable(CAP_SYS_RESOURCE)))
> +		valid_block_count += sbi->root_reserved_blocks;
> +
> +	if (unlikely(valid_block_count > sbi->user_block_count)) {
>  		spin_unlock(&sbi->stat_lock);
>  		goto enospc;
>  	}
> diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
> index cb876d905ca5..9221b013db98 100644
> --- a/fs/f2fs/super.c
> +++ b/fs/f2fs/super.c
> @@ -107,6 +107,7 @@ enum {
>  	Opt_noextent_cache,
>  	Opt_noinline_data,
>  	Opt_data_flush,
> +	Opt_reserve_root,
>  	Opt_mode,
>  	Opt_io_size_bits,
>  	Opt_fault_injection,
> @@ -157,6 +158,7 @@ static match_table_t f2fs_tokens = {
>  	{Opt_noextent_cache, "noextent_cache"},
>  	{Opt_noinline_data, "noinline_data"},
>  	{Opt_data_flush, "data_flush"},
> +	{Opt_reserve_root, "reserve_root=%u"},
>  	{Opt_mode, "mode=%s"},
>  	{Opt_io_size_bits, "io_bits=%u"},
>  	{Opt_fault_injection, "fault_injection=%u"},
> @@ -488,6 +490,12 @@ static int parse_options(struct super_block *sb, char *options)
>  		case Opt_data_flush:
>  			set_opt(sbi, DATA_FLUSH);
>  			break;
> +		case Opt_reserve_root:
> +			if (args->from && match_int(args, &arg))
> +				return -EINVAL;
> +			sbi->root_reserved_blocks = arg;
> +			set_opt(sbi, RESERVE_ROOT);
> +			break;
>  		case Opt_mode:
>  			name = match_strdup(&args[0]);
>  
> @@ -1005,10 +1013,12 @@ static int f2fs_statfs(struct dentry *dentry, struct kstatfs *buf)
>  	buf->f_bsize = sbi->blocksize;
>  
>  	buf->f_blocks = total_count - start_count;
> -	buf->f_bfree = user_block_count - valid_user_blocks(sbi) + ovp_count;
> +	buf->f_bfree = user_block_count - valid_user_blocks(sbi) -
> +						sbi->current_reserved_blocks +
> +						sbi->root_reserved_blocks;
>  	buf->f_bavail = user_block_count - valid_user_blocks(sbi) -
> -						sbi->current_reserved_blocks;
> -
> +						sbi->current_reserved_blocks -
> +						sbi->root_reserved_blocks;
>  	avail_node_count = sbi->total_node_count - sbi->nquota_files -
>  						F2FS_RESERVED_NODE_NUM;
>  
> @@ -1136,6 +1146,9 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
>  	else if (test_opt(sbi, LFS))
>  		seq_puts(seq, "lfs");
>  	seq_printf(seq, ",active_logs=%u", sbi->active_logs);
> +	if (test_opt(sbi, RESERVE_ROOT))
> +		seq_printf(seq, ",reserve_root=%u",
> +				sbi->root_reserved_blocks);
>  	if (F2FS_IO_SIZE_BITS(sbi))
>  		seq_printf(seq, ",io_size=%uKB", F2FS_IO_SIZE_KB(sbi));
>  #ifdef CONFIG_F2FS_FAULT_INJECTION
> @@ -2571,6 +2584,13 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
>  	sbi->reserved_blocks = 0;
>  	sbi->current_reserved_blocks = 0;
>  
> +	if (test_opt(sbi, RESERVE_ROOT) &&
> +		sbi->root_reserved_blocks > reserve_root_limit(sbi)) {
> +		sbi->root_reserved_blocks = reserve_root_limit(sbi);
> +		f2fs_msg(sb, KERN_INFO,
> +			"Reduce reserved blocks for root = %u\n",
> +				sbi->root_reserved_blocks);
> +	}
>  	for (i = 0; i < NR_INODE_TYPE; i++) {
>  		INIT_LIST_HEAD(&sbi->inode_list[i]);
>  		spin_lock_init(&sbi->inode_lock[i]);
> diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c
> index 7e15cbc5b8e1..41887e6ec1b3 100644
> --- a/fs/f2fs/sysfs.c
> +++ b/fs/f2fs/sysfs.c
> @@ -162,7 +162,8 @@ static ssize_t f2fs_sbi_store(struct f2fs_attr *a,
>  #endif
>  	if (a->struct_type == RESERVED_BLOCKS) {
>  		spin_lock(&sbi->stat_lock);
> -		if (t > (unsigned long)sbi->user_block_count) {
> +		if (t > (unsigned long)(sbi->user_block_count -
> +					sbi->root_reserved_blocks)) {
>  			spin_unlock(&sbi->stat_lock);
>  			return -EINVAL;
>  		}
> 

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

* Re: [PATCH v3] f2fs: add reserved blocks for root user
@ 2018-01-02  6:25     ` Chao Yu
  0 siblings, 0 replies; 21+ messages in thread
From: Chao Yu @ 2018-01-02  6:25 UTC (permalink / raw)
  To: Jaegeuk Kim, linux-kernel, linux-f2fs-devel

On 2018/1/1 9:29, Jaegeuk Kim wrote:
> This patch allows root to reserve some blocks via mount option.
> 
> "-o reserve_root=N" means N x 4KB-sized blocks for root only.
> 
> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
> ---
> 
> Change log from v2:
>  - wrong submission. :P
> 
>  fs/f2fs/f2fs.h  | 26 ++++++++++++++++++++++----
>  fs/f2fs/super.c | 26 +++++++++++++++++++++++---
>  fs/f2fs/sysfs.c |  3 ++-
>  3 files changed, 47 insertions(+), 8 deletions(-)
> 
> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> index 5f7f42267221..123d875f7293 100644
> --- a/fs/f2fs/f2fs.h
> +++ b/fs/f2fs/f2fs.h
> @@ -95,6 +95,7 @@ extern char *fault_name[FAULT_MAX];
>  #define F2FS_MOUNT_PRJQUOTA		0x00200000
>  #define F2FS_MOUNT_QUOTA		0x00400000
>  #define F2FS_MOUNT_INLINE_XATTR_SIZE	0x00800000
> +#define F2FS_MOUNT_RESERVE_ROOT		0x01000000
>  
>  #define clear_opt(sbi, option)	((sbi)->mount_opt.opt &= ~F2FS_MOUNT_##option)
>  #define set_opt(sbi, option)	((sbi)->mount_opt.opt |= F2FS_MOUNT_##option)
> @@ -1110,6 +1111,7 @@ struct f2fs_sb_info {
>  	block_t last_valid_block_count;		/* for recovery */
>  	block_t reserved_blocks;		/* configurable reserved blocks */
>  	block_t current_reserved_blocks;	/* current reserved blocks */
> +	block_t root_reserved_blocks;		/* root reserved blocks */
>  
>  	unsigned int nquota_files;		/* # of quota sysfile */
>  
> @@ -1562,6 +1564,12 @@ static inline bool f2fs_has_xattr_block(unsigned int ofs)
>  	return ofs == XATTR_NODE_OFFSET;
>  }
>  
> +static inline block_t reserve_root_limit(struct f2fs_sb_info *sbi)
> +{
> +	/* limit is 0.2% */

Should be 2% according to below calculation?

> +	return (sbi->user_block_count << 1) / 100;
> +}
> +
>  static inline void f2fs_i_blocks_write(struct inode *, block_t, bool, bool);
>  static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
>  				 struct inode *inode, blkcnt_t *count)
> @@ -1591,11 +1599,17 @@ static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
>  	sbi->total_valid_block_count += (block_t)(*count);
>  	avail_user_block_count = sbi->user_block_count -
>  					sbi->current_reserved_blocks;
> +
> +	if (!(test_opt(sbi, RESERVE_ROOT) && capable(CAP_SYS_RESOURCE)))

How about adding uid & gid verification also like ext4?

As this is a mount option, in ->remount_fs, we should consider to recover
original reserved block number if we encounter some error during remount.

Thanks,

> +		avail_user_block_count -= sbi->root_reserved_blocks;
> +
>  	if (unlikely(sbi->total_valid_block_count > avail_user_block_count)) {
>  		diff = sbi->total_valid_block_count - avail_user_block_count;
> +		if (diff > *count)
> +			diff = *count;
>  		*count -= diff;
>  		release = diff;
> -		sbi->total_valid_block_count = avail_user_block_count;
> +		sbi->total_valid_block_count -= diff;
>  		if (!*count) {
>  			spin_unlock(&sbi->stat_lock);
>  			percpu_counter_sub(&sbi->alloc_valid_block_count, diff);
> @@ -1784,9 +1798,13 @@ 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;
> -	if (unlikely(valid_block_count + sbi->current_reserved_blocks >
> -						sbi->user_block_count)) {
> +	valid_block_count = sbi->total_valid_block_count +
> +					sbi->current_reserved_blocks + 1;
> +
> +	if (!(test_opt(sbi, RESERVE_ROOT) && capable(CAP_SYS_RESOURCE)))
> +		valid_block_count += sbi->root_reserved_blocks;
> +
> +	if (unlikely(valid_block_count > sbi->user_block_count)) {
>  		spin_unlock(&sbi->stat_lock);
>  		goto enospc;
>  	}
> diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
> index cb876d905ca5..9221b013db98 100644
> --- a/fs/f2fs/super.c
> +++ b/fs/f2fs/super.c
> @@ -107,6 +107,7 @@ enum {
>  	Opt_noextent_cache,
>  	Opt_noinline_data,
>  	Opt_data_flush,
> +	Opt_reserve_root,
>  	Opt_mode,
>  	Opt_io_size_bits,
>  	Opt_fault_injection,
> @@ -157,6 +158,7 @@ static match_table_t f2fs_tokens = {
>  	{Opt_noextent_cache, "noextent_cache"},
>  	{Opt_noinline_data, "noinline_data"},
>  	{Opt_data_flush, "data_flush"},
> +	{Opt_reserve_root, "reserve_root=%u"},
>  	{Opt_mode, "mode=%s"},
>  	{Opt_io_size_bits, "io_bits=%u"},
>  	{Opt_fault_injection, "fault_injection=%u"},
> @@ -488,6 +490,12 @@ static int parse_options(struct super_block *sb, char *options)
>  		case Opt_data_flush:
>  			set_opt(sbi, DATA_FLUSH);
>  			break;
> +		case Opt_reserve_root:
> +			if (args->from && match_int(args, &arg))
> +				return -EINVAL;
> +			sbi->root_reserved_blocks = arg;
> +			set_opt(sbi, RESERVE_ROOT);
> +			break;
>  		case Opt_mode:
>  			name = match_strdup(&args[0]);
>  
> @@ -1005,10 +1013,12 @@ static int f2fs_statfs(struct dentry *dentry, struct kstatfs *buf)
>  	buf->f_bsize = sbi->blocksize;
>  
>  	buf->f_blocks = total_count - start_count;
> -	buf->f_bfree = user_block_count - valid_user_blocks(sbi) + ovp_count;
> +	buf->f_bfree = user_block_count - valid_user_blocks(sbi) -
> +						sbi->current_reserved_blocks +
> +						sbi->root_reserved_blocks;
>  	buf->f_bavail = user_block_count - valid_user_blocks(sbi) -
> -						sbi->current_reserved_blocks;
> -
> +						sbi->current_reserved_blocks -
> +						sbi->root_reserved_blocks;
>  	avail_node_count = sbi->total_node_count - sbi->nquota_files -
>  						F2FS_RESERVED_NODE_NUM;
>  
> @@ -1136,6 +1146,9 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
>  	else if (test_opt(sbi, LFS))
>  		seq_puts(seq, "lfs");
>  	seq_printf(seq, ",active_logs=%u", sbi->active_logs);
> +	if (test_opt(sbi, RESERVE_ROOT))
> +		seq_printf(seq, ",reserve_root=%u",
> +				sbi->root_reserved_blocks);
>  	if (F2FS_IO_SIZE_BITS(sbi))
>  		seq_printf(seq, ",io_size=%uKB", F2FS_IO_SIZE_KB(sbi));
>  #ifdef CONFIG_F2FS_FAULT_INJECTION
> @@ -2571,6 +2584,13 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
>  	sbi->reserved_blocks = 0;
>  	sbi->current_reserved_blocks = 0;
>  
> +	if (test_opt(sbi, RESERVE_ROOT) &&
> +		sbi->root_reserved_blocks > reserve_root_limit(sbi)) {
> +		sbi->root_reserved_blocks = reserve_root_limit(sbi);
> +		f2fs_msg(sb, KERN_INFO,
> +			"Reduce reserved blocks for root = %u\n",
> +				sbi->root_reserved_blocks);
> +	}
>  	for (i = 0; i < NR_INODE_TYPE; i++) {
>  		INIT_LIST_HEAD(&sbi->inode_list[i]);
>  		spin_lock_init(&sbi->inode_lock[i]);
> diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c
> index 7e15cbc5b8e1..41887e6ec1b3 100644
> --- a/fs/f2fs/sysfs.c
> +++ b/fs/f2fs/sysfs.c
> @@ -162,7 +162,8 @@ static ssize_t f2fs_sbi_store(struct f2fs_attr *a,
>  #endif
>  	if (a->struct_type == RESERVED_BLOCKS) {
>  		spin_lock(&sbi->stat_lock);
> -		if (t > (unsigned long)sbi->user_block_count) {
> +		if (t > (unsigned long)(sbi->user_block_count -
> +					sbi->root_reserved_blocks)) {
>  			spin_unlock(&sbi->stat_lock);
>  			return -EINVAL;
>  		}
> 


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot

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

* Re: [f2fs-dev] [PATCH v3] f2fs: add reserved blocks for root user
  2018-01-02  6:25     ` Chao Yu
  (?)
@ 2018-01-02 19:24     ` Jaegeuk Kim
  2018-01-03  6:46         ` Chao Yu
  -1 siblings, 1 reply; 21+ messages in thread
From: Jaegeuk Kim @ 2018-01-02 19:24 UTC (permalink / raw)
  To: Chao Yu; +Cc: linux-kernel, linux-f2fs-devel

On 01/02, Chao Yu wrote:
> On 2018/1/1 9:29, Jaegeuk Kim wrote:
> > This patch allows root to reserve some blocks via mount option.
> > 
> > "-o reserve_root=N" means N x 4KB-sized blocks for root only.
> > 
> > Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
> > ---
> > 
> > Change log from v2:
> >  - wrong submission. :P
> > 
> >  fs/f2fs/f2fs.h  | 26 ++++++++++++++++++++++----
> >  fs/f2fs/super.c | 26 +++++++++++++++++++++++---
> >  fs/f2fs/sysfs.c |  3 ++-
> >  3 files changed, 47 insertions(+), 8 deletions(-)
> > 
> > diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> > index 5f7f42267221..123d875f7293 100644
> > --- a/fs/f2fs/f2fs.h
> > +++ b/fs/f2fs/f2fs.h
> > @@ -95,6 +95,7 @@ extern char *fault_name[FAULT_MAX];
> >  #define F2FS_MOUNT_PRJQUOTA		0x00200000
> >  #define F2FS_MOUNT_QUOTA		0x00400000
> >  #define F2FS_MOUNT_INLINE_XATTR_SIZE	0x00800000
> > +#define F2FS_MOUNT_RESERVE_ROOT		0x01000000
> >  
> >  #define clear_opt(sbi, option)	((sbi)->mount_opt.opt &= ~F2FS_MOUNT_##option)
> >  #define set_opt(sbi, option)	((sbi)->mount_opt.opt |= F2FS_MOUNT_##option)
> > @@ -1110,6 +1111,7 @@ struct f2fs_sb_info {
> >  	block_t last_valid_block_count;		/* for recovery */
> >  	block_t reserved_blocks;		/* configurable reserved blocks */
> >  	block_t current_reserved_blocks;	/* current reserved blocks */
> > +	block_t root_reserved_blocks;		/* root reserved blocks */
> >  
> >  	unsigned int nquota_files;		/* # of quota sysfile */
> >  
> > @@ -1562,6 +1564,12 @@ static inline bool f2fs_has_xattr_block(unsigned int ofs)
> >  	return ofs == XATTR_NODE_OFFSET;
> >  }
> >  
> > +static inline block_t reserve_root_limit(struct f2fs_sb_info *sbi)
> > +{
> > +	/* limit is 0.2% */
> 
> Should be 2% according to below calculation?

Oh, right. Fixed.

> 
> > +	return (sbi->user_block_count << 1) / 100;
> > +}
> > +
> >  static inline void f2fs_i_blocks_write(struct inode *, block_t, bool, bool);
> >  static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
> >  				 struct inode *inode, blkcnt_t *count)
> > @@ -1591,11 +1599,17 @@ static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
> >  	sbi->total_valid_block_count += (block_t)(*count);
> >  	avail_user_block_count = sbi->user_block_count -
> >  					sbi->current_reserved_blocks;
> > +
> > +	if (!(test_opt(sbi, RESERVE_ROOT) && capable(CAP_SYS_RESOURCE)))
> 
> How about adding uid & gid verification also like ext4?

Again, that's another feature which requires a mount option. I think it'd be
better to add that, once we have a use-case.

> As this is a mount option, in ->remount_fs, we should consider to recover
> original reserved block number if we encounter some error during remount.

Yup, agreed.

Thanks,

> 
> Thanks,
> 
> > +		avail_user_block_count -= sbi->root_reserved_blocks;
> > +
> >  	if (unlikely(sbi->total_valid_block_count > avail_user_block_count)) {
> >  		diff = sbi->total_valid_block_count - avail_user_block_count;
> > +		if (diff > *count)
> > +			diff = *count;
> >  		*count -= diff;
> >  		release = diff;
> > -		sbi->total_valid_block_count = avail_user_block_count;
> > +		sbi->total_valid_block_count -= diff;
> >  		if (!*count) {
> >  			spin_unlock(&sbi->stat_lock);
> >  			percpu_counter_sub(&sbi->alloc_valid_block_count, diff);
> > @@ -1784,9 +1798,13 @@ 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;
> > -	if (unlikely(valid_block_count + sbi->current_reserved_blocks >
> > -						sbi->user_block_count)) {
> > +	valid_block_count = sbi->total_valid_block_count +
> > +					sbi->current_reserved_blocks + 1;
> > +
> > +	if (!(test_opt(sbi, RESERVE_ROOT) && capable(CAP_SYS_RESOURCE)))
> > +		valid_block_count += sbi->root_reserved_blocks;
> > +
> > +	if (unlikely(valid_block_count > sbi->user_block_count)) {
> >  		spin_unlock(&sbi->stat_lock);
> >  		goto enospc;
> >  	}
> > diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
> > index cb876d905ca5..9221b013db98 100644
> > --- a/fs/f2fs/super.c
> > +++ b/fs/f2fs/super.c
> > @@ -107,6 +107,7 @@ enum {
> >  	Opt_noextent_cache,
> >  	Opt_noinline_data,
> >  	Opt_data_flush,
> > +	Opt_reserve_root,
> >  	Opt_mode,
> >  	Opt_io_size_bits,
> >  	Opt_fault_injection,
> > @@ -157,6 +158,7 @@ static match_table_t f2fs_tokens = {
> >  	{Opt_noextent_cache, "noextent_cache"},
> >  	{Opt_noinline_data, "noinline_data"},
> >  	{Opt_data_flush, "data_flush"},
> > +	{Opt_reserve_root, "reserve_root=%u"},
> >  	{Opt_mode, "mode=%s"},
> >  	{Opt_io_size_bits, "io_bits=%u"},
> >  	{Opt_fault_injection, "fault_injection=%u"},
> > @@ -488,6 +490,12 @@ static int parse_options(struct super_block *sb, char *options)
> >  		case Opt_data_flush:
> >  			set_opt(sbi, DATA_FLUSH);
> >  			break;
> > +		case Opt_reserve_root:
> > +			if (args->from && match_int(args, &arg))
> > +				return -EINVAL;
> > +			sbi->root_reserved_blocks = arg;
> > +			set_opt(sbi, RESERVE_ROOT);
> > +			break;
> >  		case Opt_mode:
> >  			name = match_strdup(&args[0]);
> >  
> > @@ -1005,10 +1013,12 @@ static int f2fs_statfs(struct dentry *dentry, struct kstatfs *buf)
> >  	buf->f_bsize = sbi->blocksize;
> >  
> >  	buf->f_blocks = total_count - start_count;
> > -	buf->f_bfree = user_block_count - valid_user_blocks(sbi) + ovp_count;
> > +	buf->f_bfree = user_block_count - valid_user_blocks(sbi) -
> > +						sbi->current_reserved_blocks +
> > +						sbi->root_reserved_blocks;
> >  	buf->f_bavail = user_block_count - valid_user_blocks(sbi) -
> > -						sbi->current_reserved_blocks;
> > -
> > +						sbi->current_reserved_blocks -
> > +						sbi->root_reserved_blocks;
> >  	avail_node_count = sbi->total_node_count - sbi->nquota_files -
> >  						F2FS_RESERVED_NODE_NUM;
> >  
> > @@ -1136,6 +1146,9 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
> >  	else if (test_opt(sbi, LFS))
> >  		seq_puts(seq, "lfs");
> >  	seq_printf(seq, ",active_logs=%u", sbi->active_logs);
> > +	if (test_opt(sbi, RESERVE_ROOT))
> > +		seq_printf(seq, ",reserve_root=%u",
> > +				sbi->root_reserved_blocks);
> >  	if (F2FS_IO_SIZE_BITS(sbi))
> >  		seq_printf(seq, ",io_size=%uKB", F2FS_IO_SIZE_KB(sbi));
> >  #ifdef CONFIG_F2FS_FAULT_INJECTION
> > @@ -2571,6 +2584,13 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
> >  	sbi->reserved_blocks = 0;
> >  	sbi->current_reserved_blocks = 0;
> >  
> > +	if (test_opt(sbi, RESERVE_ROOT) &&
> > +		sbi->root_reserved_blocks > reserve_root_limit(sbi)) {
> > +		sbi->root_reserved_blocks = reserve_root_limit(sbi);
> > +		f2fs_msg(sb, KERN_INFO,
> > +			"Reduce reserved blocks for root = %u\n",
> > +				sbi->root_reserved_blocks);
> > +	}
> >  	for (i = 0; i < NR_INODE_TYPE; i++) {
> >  		INIT_LIST_HEAD(&sbi->inode_list[i]);
> >  		spin_lock_init(&sbi->inode_lock[i]);
> > diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c
> > index 7e15cbc5b8e1..41887e6ec1b3 100644
> > --- a/fs/f2fs/sysfs.c
> > +++ b/fs/f2fs/sysfs.c
> > @@ -162,7 +162,8 @@ static ssize_t f2fs_sbi_store(struct f2fs_attr *a,
> >  #endif
> >  	if (a->struct_type == RESERVED_BLOCKS) {
> >  		spin_lock(&sbi->stat_lock);
> > -		if (t > (unsigned long)sbi->user_block_count) {
> > +		if (t > (unsigned long)(sbi->user_block_count -
> > +					sbi->root_reserved_blocks)) {
> >  			spin_unlock(&sbi->stat_lock);
> >  			return -EINVAL;
> >  		}
> > 

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

* Re: [PATCH v4] f2fs: add reserved blocks for root user
  2018-01-01  1:29   ` Jaegeuk Kim
  (?)
  (?)
@ 2018-01-02 19:27   ` Jaegeuk Kim
  2018-01-03  2:21     ` [PATCH v5] " Jaegeuk Kim
  -1 siblings, 1 reply; 21+ messages in thread
From: Jaegeuk Kim @ 2018-01-02 19:27 UTC (permalink / raw)
  To: linux-kernel, linux-f2fs-devel

This patch allows root to reserve some blocks via mount option.

"-o reserve_root=N" means N x 4KB-sized blocks for root only.

Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
---

Change log from v3:
 - fix 0.2% calculation
 - preserve reserve_root=%u from remount_fs

 fs/f2fs/f2fs.h  | 26 ++++++++++++++++++++++----
 fs/f2fs/super.c | 35 ++++++++++++++++++++++++++++++-----
 fs/f2fs/sysfs.c |  3 ++-
 3 files changed, 54 insertions(+), 10 deletions(-)

diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 5f7f42267221..9dde05c62b1c 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -95,6 +95,7 @@ extern char *fault_name[FAULT_MAX];
 #define F2FS_MOUNT_PRJQUOTA		0x00200000
 #define F2FS_MOUNT_QUOTA		0x00400000
 #define F2FS_MOUNT_INLINE_XATTR_SIZE	0x00800000
+#define F2FS_MOUNT_RESERVE_ROOT		0x01000000
 
 #define clear_opt(sbi, option)	((sbi)->mount_opt.opt &= ~F2FS_MOUNT_##option)
 #define set_opt(sbi, option)	((sbi)->mount_opt.opt |= F2FS_MOUNT_##option)
@@ -1110,6 +1111,7 @@ struct f2fs_sb_info {
 	block_t last_valid_block_count;		/* for recovery */
 	block_t reserved_blocks;		/* configurable reserved blocks */
 	block_t current_reserved_blocks;	/* current reserved blocks */
+	block_t root_reserved_blocks;		/* root reserved blocks */
 
 	unsigned int nquota_files;		/* # of quota sysfile */
 
@@ -1562,6 +1564,12 @@ static inline bool f2fs_has_xattr_block(unsigned int ofs)
 	return ofs == XATTR_NODE_OFFSET;
 }
 
+static inline block_t reserve_root_limit(struct f2fs_sb_info *sbi)
+{
+	/* limit is 0.2% */
+	return (sbi->user_block_count << 1) / 1000;
+}
+
 static inline void f2fs_i_blocks_write(struct inode *, block_t, bool, bool);
 static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
 				 struct inode *inode, blkcnt_t *count)
@@ -1591,11 +1599,17 @@ static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
 	sbi->total_valid_block_count += (block_t)(*count);
 	avail_user_block_count = sbi->user_block_count -
 					sbi->current_reserved_blocks;
+
+	if (!(test_opt(sbi, RESERVE_ROOT) && capable(CAP_SYS_RESOURCE)))
+		avail_user_block_count -= sbi->root_reserved_blocks;
+
 	if (unlikely(sbi->total_valid_block_count > avail_user_block_count)) {
 		diff = sbi->total_valid_block_count - avail_user_block_count;
+		if (diff > *count)
+			diff = *count;
 		*count -= diff;
 		release = diff;
-		sbi->total_valid_block_count = avail_user_block_count;
+		sbi->total_valid_block_count -= diff;
 		if (!*count) {
 			spin_unlock(&sbi->stat_lock);
 			percpu_counter_sub(&sbi->alloc_valid_block_count, diff);
@@ -1784,9 +1798,13 @@ 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;
-	if (unlikely(valid_block_count + sbi->current_reserved_blocks >
-						sbi->user_block_count)) {
+	valid_block_count = sbi->total_valid_block_count +
+					sbi->current_reserved_blocks + 1;
+
+	if (!(test_opt(sbi, RESERVE_ROOT) && capable(CAP_SYS_RESOURCE)))
+		valid_block_count += sbi->root_reserved_blocks;
+
+	if (unlikely(valid_block_count > sbi->user_block_count)) {
 		spin_unlock(&sbi->stat_lock);
 		goto enospc;
 	}
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index cb876d905ca5..3c62492b6a0d 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -107,6 +107,7 @@ enum {
 	Opt_noextent_cache,
 	Opt_noinline_data,
 	Opt_data_flush,
+	Opt_reserve_root,
 	Opt_mode,
 	Opt_io_size_bits,
 	Opt_fault_injection,
@@ -157,6 +158,7 @@ static match_table_t f2fs_tokens = {
 	{Opt_noextent_cache, "noextent_cache"},
 	{Opt_noinline_data, "noinline_data"},
 	{Opt_data_flush, "data_flush"},
+	{Opt_reserve_root, "reserve_root=%u"},
 	{Opt_mode, "mode=%s"},
 	{Opt_io_size_bits, "io_bits=%u"},
 	{Opt_fault_injection, "fault_injection=%u"},
@@ -488,6 +490,18 @@ static int parse_options(struct super_block *sb, char *options)
 		case Opt_data_flush:
 			set_opt(sbi, DATA_FLUSH);
 			break;
+		case Opt_reserve_root:
+			if (args->from && match_int(args, &arg))
+				return -EINVAL;
+			if (test_opt(sbi, RESERVE_ROOT)) {
+				f2fs_msg(sb, KERN_INFO,
+					"Preserve previous reserve_root=%u",
+					sbi->root_reserved_blocks);
+			} else {
+				sbi->root_reserved_blocks = arg;
+				set_opt(sbi, RESERVE_ROOT);
+			}
+			break;
 		case Opt_mode:
 			name = match_strdup(&args[0]);
 
@@ -994,21 +1008,22 @@ static int f2fs_statfs(struct dentry *dentry, struct kstatfs *buf)
 	struct super_block *sb = dentry->d_sb;
 	struct f2fs_sb_info *sbi = F2FS_SB(sb);
 	u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
-	block_t total_count, user_block_count, start_count, ovp_count;
+	block_t total_count, user_block_count, start_count;
 	u64 avail_node_count;
 
 	total_count = le64_to_cpu(sbi->raw_super->block_count);
 	user_block_count = sbi->user_block_count;
 	start_count = le32_to_cpu(sbi->raw_super->segment0_blkaddr);
-	ovp_count = SM_I(sbi)->ovp_segments << sbi->log_blocks_per_seg;
 	buf->f_type = F2FS_SUPER_MAGIC;
 	buf->f_bsize = sbi->blocksize;
 
 	buf->f_blocks = total_count - start_count;
-	buf->f_bfree = user_block_count - valid_user_blocks(sbi) + ovp_count;
+	buf->f_bfree = user_block_count - valid_user_blocks(sbi) -
+						sbi->current_reserved_blocks +
+						sbi->root_reserved_blocks;
 	buf->f_bavail = user_block_count - valid_user_blocks(sbi) -
-						sbi->current_reserved_blocks;
-
+						sbi->current_reserved_blocks -
+						sbi->root_reserved_blocks;
 	avail_node_count = sbi->total_node_count - sbi->nquota_files -
 						F2FS_RESERVED_NODE_NUM;
 
@@ -1136,6 +1151,9 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
 	else if (test_opt(sbi, LFS))
 		seq_puts(seq, "lfs");
 	seq_printf(seq, ",active_logs=%u", sbi->active_logs);
+	if (test_opt(sbi, RESERVE_ROOT))
+		seq_printf(seq, ",reserve_root=%u",
+				sbi->root_reserved_blocks);
 	if (F2FS_IO_SIZE_BITS(sbi))
 		seq_printf(seq, ",io_size=%uKB", F2FS_IO_SIZE_KB(sbi));
 #ifdef CONFIG_F2FS_FAULT_INJECTION
@@ -2571,6 +2589,13 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
 	sbi->reserved_blocks = 0;
 	sbi->current_reserved_blocks = 0;
 
+	if (test_opt(sbi, RESERVE_ROOT) &&
+		sbi->root_reserved_blocks > reserve_root_limit(sbi)) {
+		sbi->root_reserved_blocks = reserve_root_limit(sbi);
+		f2fs_msg(sb, KERN_INFO,
+			"Reduce reserved blocks for root = %u\n",
+				sbi->root_reserved_blocks);
+	}
 	for (i = 0; i < NR_INODE_TYPE; i++) {
 		INIT_LIST_HEAD(&sbi->inode_list[i]);
 		spin_lock_init(&sbi->inode_lock[i]);
diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c
index 7e15cbc5b8e1..41887e6ec1b3 100644
--- a/fs/f2fs/sysfs.c
+++ b/fs/f2fs/sysfs.c
@@ -162,7 +162,8 @@ static ssize_t f2fs_sbi_store(struct f2fs_attr *a,
 #endif
 	if (a->struct_type == RESERVED_BLOCKS) {
 		spin_lock(&sbi->stat_lock);
-		if (t > (unsigned long)sbi->user_block_count) {
+		if (t > (unsigned long)(sbi->user_block_count -
+					sbi->root_reserved_blocks)) {
 			spin_unlock(&sbi->stat_lock);
 			return -EINVAL;
 		}
-- 
2.15.0.531.g2ccb3012c9-goog

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

* Re: [PATCH v5] f2fs: add reserved blocks for root user
  2018-01-02 19:27   ` [PATCH v4] " Jaegeuk Kim
@ 2018-01-03  2:21     ` Jaegeuk Kim
  2018-01-03  6:45         ` Chao Yu
  0 siblings, 1 reply; 21+ messages in thread
From: Jaegeuk Kim @ 2018-01-03  2:21 UTC (permalink / raw)
  To: linux-kernel, linux-f2fs-devel

This patch allows root to reserve some blocks via mount option.

"-o reserve_root=N" means N x 4KB-sized blocks for root only.

Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
---

Change log from v4:
 - fix f_bfree in statfs

 fs/f2fs/f2fs.h  | 26 ++++++++++++++++++++++----
 fs/f2fs/super.c | 34 +++++++++++++++++++++++++++++-----
 fs/f2fs/sysfs.c |  3 ++-
 3 files changed, 53 insertions(+), 10 deletions(-)

diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 07e03990420b..a0e8eec23125 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -95,6 +95,7 @@ extern char *fault_name[FAULT_MAX];
 #define F2FS_MOUNT_PRJQUOTA		0x00200000
 #define F2FS_MOUNT_QUOTA		0x00400000
 #define F2FS_MOUNT_INLINE_XATTR_SIZE	0x00800000
+#define F2FS_MOUNT_RESERVE_ROOT		0x01000000
 
 #define clear_opt(sbi, option)	((sbi)->mount_opt.opt &= ~F2FS_MOUNT_##option)
 #define set_opt(sbi, option)	((sbi)->mount_opt.opt |= F2FS_MOUNT_##option)
@@ -1105,6 +1106,7 @@ struct f2fs_sb_info {
 	block_t last_valid_block_count;		/* for recovery */
 	block_t reserved_blocks;		/* configurable reserved blocks */
 	block_t current_reserved_blocks;	/* current reserved blocks */
+	block_t root_reserved_blocks;		/* root reserved blocks */
 
 	unsigned int nquota_files;		/* # of quota sysfile */
 
@@ -1554,6 +1556,12 @@ static inline bool f2fs_has_xattr_block(unsigned int ofs)
 	return ofs == XATTR_NODE_OFFSET;
 }
 
+static inline block_t reserve_root_limit(struct f2fs_sb_info *sbi)
+{
+	/* limit is 0.2% */
+	return (sbi->user_block_count << 1) / 1000;
+}
+
 static inline void f2fs_i_blocks_write(struct inode *, block_t, bool, bool);
 static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
 				 struct inode *inode, blkcnt_t *count)
@@ -1583,11 +1591,17 @@ static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
 	sbi->total_valid_block_count += (block_t)(*count);
 	avail_user_block_count = sbi->user_block_count -
 					sbi->current_reserved_blocks;
+
+	if (!(test_opt(sbi, RESERVE_ROOT) && capable(CAP_SYS_RESOURCE)))
+		avail_user_block_count -= sbi->root_reserved_blocks;
+
 	if (unlikely(sbi->total_valid_block_count > avail_user_block_count)) {
 		diff = sbi->total_valid_block_count - avail_user_block_count;
+		if (diff > *count)
+			diff = *count;
 		*count -= diff;
 		release = diff;
-		sbi->total_valid_block_count = avail_user_block_count;
+		sbi->total_valid_block_count -= diff;
 		if (!*count) {
 			spin_unlock(&sbi->stat_lock);
 			percpu_counter_sub(&sbi->alloc_valid_block_count, diff);
@@ -1776,9 +1790,13 @@ 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;
-	if (unlikely(valid_block_count + sbi->current_reserved_blocks >
-						sbi->user_block_count)) {
+	valid_block_count = sbi->total_valid_block_count +
+					sbi->current_reserved_blocks + 1;
+
+	if (!(test_opt(sbi, RESERVE_ROOT) && capable(CAP_SYS_RESOURCE)))
+		valid_block_count += sbi->root_reserved_blocks;
+
+	if (unlikely(valid_block_count > sbi->user_block_count)) {
 		spin_unlock(&sbi->stat_lock);
 		goto enospc;
 	}
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index 5c6a02b558f0..e814340bc2f0 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -107,6 +107,7 @@ enum {
 	Opt_noextent_cache,
 	Opt_noinline_data,
 	Opt_data_flush,
+	Opt_reserve_root,
 	Opt_mode,
 	Opt_io_size_bits,
 	Opt_fault_injection,
@@ -157,6 +158,7 @@ static match_table_t f2fs_tokens = {
 	{Opt_noextent_cache, "noextent_cache"},
 	{Opt_noinline_data, "noinline_data"},
 	{Opt_data_flush, "data_flush"},
+	{Opt_reserve_root, "reserve_root=%u"},
 	{Opt_mode, "mode=%s"},
 	{Opt_io_size_bits, "io_bits=%u"},
 	{Opt_fault_injection, "fault_injection=%u"},
@@ -488,6 +490,18 @@ static int parse_options(struct super_block *sb, char *options)
 		case Opt_data_flush:
 			set_opt(sbi, DATA_FLUSH);
 			break;
+		case Opt_reserve_root:
+			if (args->from && match_int(args, &arg))
+				return -EINVAL;
+			if (test_opt(sbi, RESERVE_ROOT)) {
+				f2fs_msg(sb, KERN_INFO,
+					"Preserve previous reserve_root=%u",
+					sbi->root_reserved_blocks);
+			} else {
+				sbi->root_reserved_blocks = arg;
+				set_opt(sbi, RESERVE_ROOT);
+			}
+			break;
 		case Opt_mode:
 			name = match_strdup(&args[0]);
 
@@ -994,21 +1008,21 @@ static int f2fs_statfs(struct dentry *dentry, struct kstatfs *buf)
 	struct super_block *sb = dentry->d_sb;
 	struct f2fs_sb_info *sbi = F2FS_SB(sb);
 	u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
-	block_t total_count, user_block_count, start_count, ovp_count;
+	block_t total_count, user_block_count, start_count;
 	u64 avail_node_count;
 
 	total_count = le64_to_cpu(sbi->raw_super->block_count);
 	user_block_count = sbi->user_block_count;
 	start_count = le32_to_cpu(sbi->raw_super->segment0_blkaddr);
-	ovp_count = SM_I(sbi)->ovp_segments << sbi->log_blocks_per_seg;
 	buf->f_type = F2FS_SUPER_MAGIC;
 	buf->f_bsize = sbi->blocksize;
 
 	buf->f_blocks = total_count - start_count;
-	buf->f_bfree = user_block_count - valid_user_blocks(sbi) + ovp_count;
-	buf->f_bavail = user_block_count - valid_user_blocks(sbi) -
+	buf->f_bfree = user_block_count - valid_user_blocks(sbi) -
 						sbi->current_reserved_blocks;
-
+	buf->f_bavail = user_block_count - valid_user_blocks(sbi) -
+						sbi->current_reserved_blocks -
+						sbi->root_reserved_blocks;
 	avail_node_count = sbi->total_node_count - sbi->nquota_files -
 						F2FS_RESERVED_NODE_NUM;
 
@@ -1136,6 +1150,9 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
 	else if (test_opt(sbi, LFS))
 		seq_puts(seq, "lfs");
 	seq_printf(seq, ",active_logs=%u", sbi->active_logs);
+	if (test_opt(sbi, RESERVE_ROOT))
+		seq_printf(seq, ",reserve_root=%u",
+				sbi->root_reserved_blocks);
 	if (F2FS_IO_SIZE_BITS(sbi))
 		seq_printf(seq, ",io_size=%uKB", F2FS_IO_SIZE_KB(sbi));
 #ifdef CONFIG_F2FS_FAULT_INJECTION
@@ -2571,6 +2588,13 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
 	sbi->reserved_blocks = 0;
 	sbi->current_reserved_blocks = 0;
 
+	if (test_opt(sbi, RESERVE_ROOT) &&
+		sbi->root_reserved_blocks > reserve_root_limit(sbi)) {
+		sbi->root_reserved_blocks = reserve_root_limit(sbi);
+		f2fs_msg(sb, KERN_INFO,
+			"Reduce reserved blocks for root = %u\n",
+				sbi->root_reserved_blocks);
+	}
 	for (i = 0; i < NR_INODE_TYPE; i++) {
 		INIT_LIST_HEAD(&sbi->inode_list[i]);
 		spin_lock_init(&sbi->inode_lock[i]);
diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c
index 93c3364250dd..ab6028c332aa 100644
--- a/fs/f2fs/sysfs.c
+++ b/fs/f2fs/sysfs.c
@@ -162,7 +162,8 @@ static ssize_t f2fs_sbi_store(struct f2fs_attr *a,
 #endif
 	if (a->struct_type == RESERVED_BLOCKS) {
 		spin_lock(&sbi->stat_lock);
-		if (t > (unsigned long)sbi->user_block_count) {
+		if (t > (unsigned long)(sbi->user_block_count -
+					sbi->root_reserved_blocks)) {
 			spin_unlock(&sbi->stat_lock);
 			return -EINVAL;
 		}
-- 
2.15.0.531.g2ccb3012c9-goog

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

* Re: [f2fs-dev] [PATCH v5] f2fs: add reserved blocks for root user
  2018-01-03  2:21     ` [PATCH v5] " Jaegeuk Kim
@ 2018-01-03  6:45         ` Chao Yu
  0 siblings, 0 replies; 21+ messages in thread
From: Chao Yu @ 2018-01-03  6:45 UTC (permalink / raw)
  To: Jaegeuk Kim, linux-kernel, linux-f2fs-devel

On 2018/1/3 10:21, Jaegeuk Kim wrote:
> This patch allows root to reserve some blocks via mount option.
> 
> "-o reserve_root=N" means N x 4KB-sized blocks for root only.
> 
> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
> ---
> 
> Change log from v4:
>  - fix f_bfree in statfs

Could you fix f_bfree calculation issue in another patch prior to this
patch? That will be better for history tracking of patches or git bisect
when backtracking issues.

One more thing, should we move reserve_root_limit check to parse_option?
now, it looks that during remount we can set root_reserved_blocks exceeding
our defined limitation.

Thanks,

> 
>  fs/f2fs/f2fs.h  | 26 ++++++++++++++++++++++----
>  fs/f2fs/super.c | 34 +++++++++++++++++++++++++++++-----
>  fs/f2fs/sysfs.c |  3 ++-
>  3 files changed, 53 insertions(+), 10 deletions(-)
> 
> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> index 07e03990420b..a0e8eec23125 100644
> --- a/fs/f2fs/f2fs.h
> +++ b/fs/f2fs/f2fs.h
> @@ -95,6 +95,7 @@ extern char *fault_name[FAULT_MAX];
>  #define F2FS_MOUNT_PRJQUOTA		0x00200000
>  #define F2FS_MOUNT_QUOTA		0x00400000
>  #define F2FS_MOUNT_INLINE_XATTR_SIZE	0x00800000
> +#define F2FS_MOUNT_RESERVE_ROOT		0x01000000
>  
>  #define clear_opt(sbi, option)	((sbi)->mount_opt.opt &= ~F2FS_MOUNT_##option)
>  #define set_opt(sbi, option)	((sbi)->mount_opt.opt |= F2FS_MOUNT_##option)
> @@ -1105,6 +1106,7 @@ struct f2fs_sb_info {
>  	block_t last_valid_block_count;		/* for recovery */
>  	block_t reserved_blocks;		/* configurable reserved blocks */
>  	block_t current_reserved_blocks;	/* current reserved blocks */
> +	block_t root_reserved_blocks;		/* root reserved blocks */
>  
>  	unsigned int nquota_files;		/* # of quota sysfile */
>  
> @@ -1554,6 +1556,12 @@ static inline bool f2fs_has_xattr_block(unsigned int ofs)
>  	return ofs == XATTR_NODE_OFFSET;
>  }
>  
> +static inline block_t reserve_root_limit(struct f2fs_sb_info *sbi)
> +{
> +	/* limit is 0.2% */
> +	return (sbi->user_block_count << 1) / 1000;
> +}
> +
>  static inline void f2fs_i_blocks_write(struct inode *, block_t, bool, bool);
>  static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
>  				 struct inode *inode, blkcnt_t *count)
> @@ -1583,11 +1591,17 @@ static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
>  	sbi->total_valid_block_count += (block_t)(*count);
>  	avail_user_block_count = sbi->user_block_count -
>  					sbi->current_reserved_blocks;
> +
> +	if (!(test_opt(sbi, RESERVE_ROOT) && capable(CAP_SYS_RESOURCE)))
> +		avail_user_block_count -= sbi->root_reserved_blocks;
> +
>  	if (unlikely(sbi->total_valid_block_count > avail_user_block_count)) {
>  		diff = sbi->total_valid_block_count - avail_user_block_count;
> +		if (diff > *count)
> +			diff = *count;
>  		*count -= diff;
>  		release = diff;
> -		sbi->total_valid_block_count = avail_user_block_count;
> +		sbi->total_valid_block_count -= diff;
>  		if (!*count) {
>  			spin_unlock(&sbi->stat_lock);
>  			percpu_counter_sub(&sbi->alloc_valid_block_count, diff);
> @@ -1776,9 +1790,13 @@ 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;
> -	if (unlikely(valid_block_count + sbi->current_reserved_blocks >
> -						sbi->user_block_count)) {
> +	valid_block_count = sbi->total_valid_block_count +
> +					sbi->current_reserved_blocks + 1;
> +
> +	if (!(test_opt(sbi, RESERVE_ROOT) && capable(CAP_SYS_RESOURCE)))
> +		valid_block_count += sbi->root_reserved_blocks;
> +
> +	if (unlikely(valid_block_count > sbi->user_block_count)) {
>  		spin_unlock(&sbi->stat_lock);
>  		goto enospc;
>  	}
> diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
> index 5c6a02b558f0..e814340bc2f0 100644
> --- a/fs/f2fs/super.c
> +++ b/fs/f2fs/super.c
> @@ -107,6 +107,7 @@ enum {
>  	Opt_noextent_cache,
>  	Opt_noinline_data,
>  	Opt_data_flush,
> +	Opt_reserve_root,
>  	Opt_mode,
>  	Opt_io_size_bits,
>  	Opt_fault_injection,
> @@ -157,6 +158,7 @@ static match_table_t f2fs_tokens = {
>  	{Opt_noextent_cache, "noextent_cache"},
>  	{Opt_noinline_data, "noinline_data"},
>  	{Opt_data_flush, "data_flush"},
> +	{Opt_reserve_root, "reserve_root=%u"},
>  	{Opt_mode, "mode=%s"},
>  	{Opt_io_size_bits, "io_bits=%u"},
>  	{Opt_fault_injection, "fault_injection=%u"},
> @@ -488,6 +490,18 @@ static int parse_options(struct super_block *sb, char *options)
>  		case Opt_data_flush:
>  			set_opt(sbi, DATA_FLUSH);
>  			break;
> +		case Opt_reserve_root:
> +			if (args->from && match_int(args, &arg))
> +				return -EINVAL;
> +			if (test_opt(sbi, RESERVE_ROOT)) {
> +				f2fs_msg(sb, KERN_INFO,
> +					"Preserve previous reserve_root=%u",
> +					sbi->root_reserved_blocks);
> +			} else {
> +				sbi->root_reserved_blocks = arg;
> +				set_opt(sbi, RESERVE_ROOT);
> +			}
> +			break;
>  		case Opt_mode:
>  			name = match_strdup(&args[0]);
>  
> @@ -994,21 +1008,21 @@ static int f2fs_statfs(struct dentry *dentry, struct kstatfs *buf)
>  	struct super_block *sb = dentry->d_sb;
>  	struct f2fs_sb_info *sbi = F2FS_SB(sb);
>  	u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
> -	block_t total_count, user_block_count, start_count, ovp_count;
> +	block_t total_count, user_block_count, start_count;
>  	u64 avail_node_count;
>  
>  	total_count = le64_to_cpu(sbi->raw_super->block_count);
>  	user_block_count = sbi->user_block_count;
>  	start_count = le32_to_cpu(sbi->raw_super->segment0_blkaddr);
> -	ovp_count = SM_I(sbi)->ovp_segments << sbi->log_blocks_per_seg;
>  	buf->f_type = F2FS_SUPER_MAGIC;
>  	buf->f_bsize = sbi->blocksize;
>  
>  	buf->f_blocks = total_count - start_count;
> -	buf->f_bfree = user_block_count - valid_user_blocks(sbi) + ovp_count;
> -	buf->f_bavail = user_block_count - valid_user_blocks(sbi) -
> +	buf->f_bfree = user_block_count - valid_user_blocks(sbi) -
>  						sbi->current_reserved_blocks;
> -
> +	buf->f_bavail = user_block_count - valid_user_blocks(sbi) -
> +						sbi->current_reserved_blocks -
> +						sbi->root_reserved_blocks;
>  	avail_node_count = sbi->total_node_count - sbi->nquota_files -
>  						F2FS_RESERVED_NODE_NUM;
>  
> @@ -1136,6 +1150,9 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
>  	else if (test_opt(sbi, LFS))
>  		seq_puts(seq, "lfs");
>  	seq_printf(seq, ",active_logs=%u", sbi->active_logs);
> +	if (test_opt(sbi, RESERVE_ROOT))
> +		seq_printf(seq, ",reserve_root=%u",
> +				sbi->root_reserved_blocks);
>  	if (F2FS_IO_SIZE_BITS(sbi))
>  		seq_printf(seq, ",io_size=%uKB", F2FS_IO_SIZE_KB(sbi));
>  #ifdef CONFIG_F2FS_FAULT_INJECTION
> @@ -2571,6 +2588,13 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
>  	sbi->reserved_blocks = 0;
>  	sbi->current_reserved_blocks = 0;
>  
> +	if (test_opt(sbi, RESERVE_ROOT) &&
> +		sbi->root_reserved_blocks > reserve_root_limit(sbi)) {
> +		sbi->root_reserved_blocks = reserve_root_limit(sbi);
> +		f2fs_msg(sb, KERN_INFO,
> +			"Reduce reserved blocks for root = %u\n",
> +				sbi->root_reserved_blocks);
> +	}
>  	for (i = 0; i < NR_INODE_TYPE; i++) {
>  		INIT_LIST_HEAD(&sbi->inode_list[i]);
>  		spin_lock_init(&sbi->inode_lock[i]);
> diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c
> index 93c3364250dd..ab6028c332aa 100644
> --- a/fs/f2fs/sysfs.c
> +++ b/fs/f2fs/sysfs.c
> @@ -162,7 +162,8 @@ static ssize_t f2fs_sbi_store(struct f2fs_attr *a,
>  #endif
>  	if (a->struct_type == RESERVED_BLOCKS) {
>  		spin_lock(&sbi->stat_lock);
> -		if (t > (unsigned long)sbi->user_block_count) {
> +		if (t > (unsigned long)(sbi->user_block_count -
> +					sbi->root_reserved_blocks)) {
>  			spin_unlock(&sbi->stat_lock);
>  			return -EINVAL;
>  		}
> 

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

* Re: [PATCH v5] f2fs: add reserved blocks for root user
@ 2018-01-03  6:45         ` Chao Yu
  0 siblings, 0 replies; 21+ messages in thread
From: Chao Yu @ 2018-01-03  6:45 UTC (permalink / raw)
  To: Jaegeuk Kim, linux-kernel, linux-f2fs-devel

On 2018/1/3 10:21, Jaegeuk Kim wrote:
> This patch allows root to reserve some blocks via mount option.
> 
> "-o reserve_root=N" means N x 4KB-sized blocks for root only.
> 
> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
> ---
> 
> Change log from v4:
>  - fix f_bfree in statfs

Could you fix f_bfree calculation issue in another patch prior to this
patch? That will be better for history tracking of patches or git bisect
when backtracking issues.

One more thing, should we move reserve_root_limit check to parse_option?
now, it looks that during remount we can set root_reserved_blocks exceeding
our defined limitation.

Thanks,

> 
>  fs/f2fs/f2fs.h  | 26 ++++++++++++++++++++++----
>  fs/f2fs/super.c | 34 +++++++++++++++++++++++++++++-----
>  fs/f2fs/sysfs.c |  3 ++-
>  3 files changed, 53 insertions(+), 10 deletions(-)
> 
> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> index 07e03990420b..a0e8eec23125 100644
> --- a/fs/f2fs/f2fs.h
> +++ b/fs/f2fs/f2fs.h
> @@ -95,6 +95,7 @@ extern char *fault_name[FAULT_MAX];
>  #define F2FS_MOUNT_PRJQUOTA		0x00200000
>  #define F2FS_MOUNT_QUOTA		0x00400000
>  #define F2FS_MOUNT_INLINE_XATTR_SIZE	0x00800000
> +#define F2FS_MOUNT_RESERVE_ROOT		0x01000000
>  
>  #define clear_opt(sbi, option)	((sbi)->mount_opt.opt &= ~F2FS_MOUNT_##option)
>  #define set_opt(sbi, option)	((sbi)->mount_opt.opt |= F2FS_MOUNT_##option)
> @@ -1105,6 +1106,7 @@ struct f2fs_sb_info {
>  	block_t last_valid_block_count;		/* for recovery */
>  	block_t reserved_blocks;		/* configurable reserved blocks */
>  	block_t current_reserved_blocks;	/* current reserved blocks */
> +	block_t root_reserved_blocks;		/* root reserved blocks */
>  
>  	unsigned int nquota_files;		/* # of quota sysfile */
>  
> @@ -1554,6 +1556,12 @@ static inline bool f2fs_has_xattr_block(unsigned int ofs)
>  	return ofs == XATTR_NODE_OFFSET;
>  }
>  
> +static inline block_t reserve_root_limit(struct f2fs_sb_info *sbi)
> +{
> +	/* limit is 0.2% */
> +	return (sbi->user_block_count << 1) / 1000;
> +}
> +
>  static inline void f2fs_i_blocks_write(struct inode *, block_t, bool, bool);
>  static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
>  				 struct inode *inode, blkcnt_t *count)
> @@ -1583,11 +1591,17 @@ static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
>  	sbi->total_valid_block_count += (block_t)(*count);
>  	avail_user_block_count = sbi->user_block_count -
>  					sbi->current_reserved_blocks;
> +
> +	if (!(test_opt(sbi, RESERVE_ROOT) && capable(CAP_SYS_RESOURCE)))
> +		avail_user_block_count -= sbi->root_reserved_blocks;
> +
>  	if (unlikely(sbi->total_valid_block_count > avail_user_block_count)) {
>  		diff = sbi->total_valid_block_count - avail_user_block_count;
> +		if (diff > *count)
> +			diff = *count;
>  		*count -= diff;
>  		release = diff;
> -		sbi->total_valid_block_count = avail_user_block_count;
> +		sbi->total_valid_block_count -= diff;
>  		if (!*count) {
>  			spin_unlock(&sbi->stat_lock);
>  			percpu_counter_sub(&sbi->alloc_valid_block_count, diff);
> @@ -1776,9 +1790,13 @@ 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;
> -	if (unlikely(valid_block_count + sbi->current_reserved_blocks >
> -						sbi->user_block_count)) {
> +	valid_block_count = sbi->total_valid_block_count +
> +					sbi->current_reserved_blocks + 1;
> +
> +	if (!(test_opt(sbi, RESERVE_ROOT) && capable(CAP_SYS_RESOURCE)))
> +		valid_block_count += sbi->root_reserved_blocks;
> +
> +	if (unlikely(valid_block_count > sbi->user_block_count)) {
>  		spin_unlock(&sbi->stat_lock);
>  		goto enospc;
>  	}
> diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
> index 5c6a02b558f0..e814340bc2f0 100644
> --- a/fs/f2fs/super.c
> +++ b/fs/f2fs/super.c
> @@ -107,6 +107,7 @@ enum {
>  	Opt_noextent_cache,
>  	Opt_noinline_data,
>  	Opt_data_flush,
> +	Opt_reserve_root,
>  	Opt_mode,
>  	Opt_io_size_bits,
>  	Opt_fault_injection,
> @@ -157,6 +158,7 @@ static match_table_t f2fs_tokens = {
>  	{Opt_noextent_cache, "noextent_cache"},
>  	{Opt_noinline_data, "noinline_data"},
>  	{Opt_data_flush, "data_flush"},
> +	{Opt_reserve_root, "reserve_root=%u"},
>  	{Opt_mode, "mode=%s"},
>  	{Opt_io_size_bits, "io_bits=%u"},
>  	{Opt_fault_injection, "fault_injection=%u"},
> @@ -488,6 +490,18 @@ static int parse_options(struct super_block *sb, char *options)
>  		case Opt_data_flush:
>  			set_opt(sbi, DATA_FLUSH);
>  			break;
> +		case Opt_reserve_root:
> +			if (args->from && match_int(args, &arg))
> +				return -EINVAL;
> +			if (test_opt(sbi, RESERVE_ROOT)) {
> +				f2fs_msg(sb, KERN_INFO,
> +					"Preserve previous reserve_root=%u",
> +					sbi->root_reserved_blocks);
> +			} else {
> +				sbi->root_reserved_blocks = arg;
> +				set_opt(sbi, RESERVE_ROOT);
> +			}
> +			break;
>  		case Opt_mode:
>  			name = match_strdup(&args[0]);
>  
> @@ -994,21 +1008,21 @@ static int f2fs_statfs(struct dentry *dentry, struct kstatfs *buf)
>  	struct super_block *sb = dentry->d_sb;
>  	struct f2fs_sb_info *sbi = F2FS_SB(sb);
>  	u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
> -	block_t total_count, user_block_count, start_count, ovp_count;
> +	block_t total_count, user_block_count, start_count;
>  	u64 avail_node_count;
>  
>  	total_count = le64_to_cpu(sbi->raw_super->block_count);
>  	user_block_count = sbi->user_block_count;
>  	start_count = le32_to_cpu(sbi->raw_super->segment0_blkaddr);
> -	ovp_count = SM_I(sbi)->ovp_segments << sbi->log_blocks_per_seg;
>  	buf->f_type = F2FS_SUPER_MAGIC;
>  	buf->f_bsize = sbi->blocksize;
>  
>  	buf->f_blocks = total_count - start_count;
> -	buf->f_bfree = user_block_count - valid_user_blocks(sbi) + ovp_count;
> -	buf->f_bavail = user_block_count - valid_user_blocks(sbi) -
> +	buf->f_bfree = user_block_count - valid_user_blocks(sbi) -
>  						sbi->current_reserved_blocks;
> -
> +	buf->f_bavail = user_block_count - valid_user_blocks(sbi) -
> +						sbi->current_reserved_blocks -
> +						sbi->root_reserved_blocks;
>  	avail_node_count = sbi->total_node_count - sbi->nquota_files -
>  						F2FS_RESERVED_NODE_NUM;
>  
> @@ -1136,6 +1150,9 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
>  	else if (test_opt(sbi, LFS))
>  		seq_puts(seq, "lfs");
>  	seq_printf(seq, ",active_logs=%u", sbi->active_logs);
> +	if (test_opt(sbi, RESERVE_ROOT))
> +		seq_printf(seq, ",reserve_root=%u",
> +				sbi->root_reserved_blocks);
>  	if (F2FS_IO_SIZE_BITS(sbi))
>  		seq_printf(seq, ",io_size=%uKB", F2FS_IO_SIZE_KB(sbi));
>  #ifdef CONFIG_F2FS_FAULT_INJECTION
> @@ -2571,6 +2588,13 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
>  	sbi->reserved_blocks = 0;
>  	sbi->current_reserved_blocks = 0;
>  
> +	if (test_opt(sbi, RESERVE_ROOT) &&
> +		sbi->root_reserved_blocks > reserve_root_limit(sbi)) {
> +		sbi->root_reserved_blocks = reserve_root_limit(sbi);
> +		f2fs_msg(sb, KERN_INFO,
> +			"Reduce reserved blocks for root = %u\n",
> +				sbi->root_reserved_blocks);
> +	}
>  	for (i = 0; i < NR_INODE_TYPE; i++) {
>  		INIT_LIST_HEAD(&sbi->inode_list[i]);
>  		spin_lock_init(&sbi->inode_lock[i]);
> diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c
> index 93c3364250dd..ab6028c332aa 100644
> --- a/fs/f2fs/sysfs.c
> +++ b/fs/f2fs/sysfs.c
> @@ -162,7 +162,8 @@ static ssize_t f2fs_sbi_store(struct f2fs_attr *a,
>  #endif
>  	if (a->struct_type == RESERVED_BLOCKS) {
>  		spin_lock(&sbi->stat_lock);
> -		if (t > (unsigned long)sbi->user_block_count) {
> +		if (t > (unsigned long)(sbi->user_block_count -
> +					sbi->root_reserved_blocks)) {
>  			spin_unlock(&sbi->stat_lock);
>  			return -EINVAL;
>  		}
> 


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot

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

* Re: [f2fs-dev] [PATCH v3] f2fs: add reserved blocks for root user
  2018-01-02 19:24     ` [f2fs-dev] " Jaegeuk Kim
@ 2018-01-03  6:46         ` Chao Yu
  0 siblings, 0 replies; 21+ messages in thread
From: Chao Yu @ 2018-01-03  6:46 UTC (permalink / raw)
  To: Jaegeuk Kim; +Cc: linux-kernel, linux-f2fs-devel

On 2018/1/3 3:24, Jaegeuk Kim wrote:
>> How about adding uid & gid verification also like ext4?
> 
> Again, that's another feature which requires a mount option. I think it'd be
> better to add that, once we have a use-case.

That's OK. ;)

Thanks,

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

* Re: [f2fs-dev] [PATCH v3] f2fs: add reserved blocks for root user
@ 2018-01-03  6:46         ` Chao Yu
  0 siblings, 0 replies; 21+ messages in thread
From: Chao Yu @ 2018-01-03  6:46 UTC (permalink / raw)
  To: Jaegeuk Kim; +Cc: linux-kernel, linux-f2fs-devel

On 2018/1/3 3:24, Jaegeuk Kim wrote:
>> How about adding uid & gid verification also like ext4?
> 
> Again, that's another feature which requires a mount option. I think it'd be
> better to add that, once we have a use-case.

That's OK. ;)

Thanks,

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

* Re: [f2fs-dev] [PATCH v5] f2fs: add reserved blocks for root user
  2018-01-03  6:45         ` Chao Yu
  (?)
@ 2018-01-03 19:06         ` Jaegeuk Kim
  2018-01-04  1:16             ` Chao Yu
  -1 siblings, 1 reply; 21+ messages in thread
From: Jaegeuk Kim @ 2018-01-03 19:06 UTC (permalink / raw)
  To: Chao Yu; +Cc: linux-kernel, linux-f2fs-devel

On 01/03, Chao Yu wrote:
> On 2018/1/3 10:21, Jaegeuk Kim wrote:
> > This patch allows root to reserve some blocks via mount option.
> > 
> > "-o reserve_root=N" means N x 4KB-sized blocks for root only.
> > 
> > Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
> > ---
> > 
> > Change log from v4:
> >  - fix f_bfree in statfs
> 
> Could you fix f_bfree calculation issue in another patch prior to this
> patch? That will be better for history tracking of patches or git bisect
> when backtracking issues.

I've sent out a new series for this.

> 
> One more thing, should we move reserve_root_limit check to parse_option?

No, since we don't have sbi yet.

> now, it looks that during remount we can set root_reserved_blocks exceeding
> our defined limitation.

Oh, I missed the changelog that it won't be changed once getting the flag set.

Thanks,

> 
> Thanks,
> 
> > 
> >  fs/f2fs/f2fs.h  | 26 ++++++++++++++++++++++----
> >  fs/f2fs/super.c | 34 +++++++++++++++++++++++++++++-----
> >  fs/f2fs/sysfs.c |  3 ++-
> >  3 files changed, 53 insertions(+), 10 deletions(-)
> > 
> > diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> > index 07e03990420b..a0e8eec23125 100644
> > --- a/fs/f2fs/f2fs.h
> > +++ b/fs/f2fs/f2fs.h
> > @@ -95,6 +95,7 @@ extern char *fault_name[FAULT_MAX];
> >  #define F2FS_MOUNT_PRJQUOTA		0x00200000
> >  #define F2FS_MOUNT_QUOTA		0x00400000
> >  #define F2FS_MOUNT_INLINE_XATTR_SIZE	0x00800000
> > +#define F2FS_MOUNT_RESERVE_ROOT		0x01000000
> >  
> >  #define clear_opt(sbi, option)	((sbi)->mount_opt.opt &= ~F2FS_MOUNT_##option)
> >  #define set_opt(sbi, option)	((sbi)->mount_opt.opt |= F2FS_MOUNT_##option)
> > @@ -1105,6 +1106,7 @@ struct f2fs_sb_info {
> >  	block_t last_valid_block_count;		/* for recovery */
> >  	block_t reserved_blocks;		/* configurable reserved blocks */
> >  	block_t current_reserved_blocks;	/* current reserved blocks */
> > +	block_t root_reserved_blocks;		/* root reserved blocks */
> >  
> >  	unsigned int nquota_files;		/* # of quota sysfile */
> >  
> > @@ -1554,6 +1556,12 @@ static inline bool f2fs_has_xattr_block(unsigned int ofs)
> >  	return ofs == XATTR_NODE_OFFSET;
> >  }
> >  
> > +static inline block_t reserve_root_limit(struct f2fs_sb_info *sbi)
> > +{
> > +	/* limit is 0.2% */
> > +	return (sbi->user_block_count << 1) / 1000;
> > +}
> > +
> >  static inline void f2fs_i_blocks_write(struct inode *, block_t, bool, bool);
> >  static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
> >  				 struct inode *inode, blkcnt_t *count)
> > @@ -1583,11 +1591,17 @@ static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
> >  	sbi->total_valid_block_count += (block_t)(*count);
> >  	avail_user_block_count = sbi->user_block_count -
> >  					sbi->current_reserved_blocks;
> > +
> > +	if (!(test_opt(sbi, RESERVE_ROOT) && capable(CAP_SYS_RESOURCE)))
> > +		avail_user_block_count -= sbi->root_reserved_blocks;
> > +
> >  	if (unlikely(sbi->total_valid_block_count > avail_user_block_count)) {
> >  		diff = sbi->total_valid_block_count - avail_user_block_count;
> > +		if (diff > *count)
> > +			diff = *count;
> >  		*count -= diff;
> >  		release = diff;
> > -		sbi->total_valid_block_count = avail_user_block_count;
> > +		sbi->total_valid_block_count -= diff;
> >  		if (!*count) {
> >  			spin_unlock(&sbi->stat_lock);
> >  			percpu_counter_sub(&sbi->alloc_valid_block_count, diff);
> > @@ -1776,9 +1790,13 @@ 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;
> > -	if (unlikely(valid_block_count + sbi->current_reserved_blocks >
> > -						sbi->user_block_count)) {
> > +	valid_block_count = sbi->total_valid_block_count +
> > +					sbi->current_reserved_blocks + 1;
> > +
> > +	if (!(test_opt(sbi, RESERVE_ROOT) && capable(CAP_SYS_RESOURCE)))
> > +		valid_block_count += sbi->root_reserved_blocks;
> > +
> > +	if (unlikely(valid_block_count > sbi->user_block_count)) {
> >  		spin_unlock(&sbi->stat_lock);
> >  		goto enospc;
> >  	}
> > diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
> > index 5c6a02b558f0..e814340bc2f0 100644
> > --- a/fs/f2fs/super.c
> > +++ b/fs/f2fs/super.c
> > @@ -107,6 +107,7 @@ enum {
> >  	Opt_noextent_cache,
> >  	Opt_noinline_data,
> >  	Opt_data_flush,
> > +	Opt_reserve_root,
> >  	Opt_mode,
> >  	Opt_io_size_bits,
> >  	Opt_fault_injection,
> > @@ -157,6 +158,7 @@ static match_table_t f2fs_tokens = {
> >  	{Opt_noextent_cache, "noextent_cache"},
> >  	{Opt_noinline_data, "noinline_data"},
> >  	{Opt_data_flush, "data_flush"},
> > +	{Opt_reserve_root, "reserve_root=%u"},
> >  	{Opt_mode, "mode=%s"},
> >  	{Opt_io_size_bits, "io_bits=%u"},
> >  	{Opt_fault_injection, "fault_injection=%u"},
> > @@ -488,6 +490,18 @@ static int parse_options(struct super_block *sb, char *options)
> >  		case Opt_data_flush:
> >  			set_opt(sbi, DATA_FLUSH);
> >  			break;
> > +		case Opt_reserve_root:
> > +			if (args->from && match_int(args, &arg))
> > +				return -EINVAL;
> > +			if (test_opt(sbi, RESERVE_ROOT)) {
> > +				f2fs_msg(sb, KERN_INFO,
> > +					"Preserve previous reserve_root=%u",
> > +					sbi->root_reserved_blocks);
> > +			} else {
> > +				sbi->root_reserved_blocks = arg;
> > +				set_opt(sbi, RESERVE_ROOT);
> > +			}
> > +			break;
> >  		case Opt_mode:
> >  			name = match_strdup(&args[0]);
> >  
> > @@ -994,21 +1008,21 @@ static int f2fs_statfs(struct dentry *dentry, struct kstatfs *buf)
> >  	struct super_block *sb = dentry->d_sb;
> >  	struct f2fs_sb_info *sbi = F2FS_SB(sb);
> >  	u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
> > -	block_t total_count, user_block_count, start_count, ovp_count;
> > +	block_t total_count, user_block_count, start_count;
> >  	u64 avail_node_count;
> >  
> >  	total_count = le64_to_cpu(sbi->raw_super->block_count);
> >  	user_block_count = sbi->user_block_count;
> >  	start_count = le32_to_cpu(sbi->raw_super->segment0_blkaddr);
> > -	ovp_count = SM_I(sbi)->ovp_segments << sbi->log_blocks_per_seg;
> >  	buf->f_type = F2FS_SUPER_MAGIC;
> >  	buf->f_bsize = sbi->blocksize;
> >  
> >  	buf->f_blocks = total_count - start_count;
> > -	buf->f_bfree = user_block_count - valid_user_blocks(sbi) + ovp_count;
> > -	buf->f_bavail = user_block_count - valid_user_blocks(sbi) -
> > +	buf->f_bfree = user_block_count - valid_user_blocks(sbi) -
> >  						sbi->current_reserved_blocks;
> > -
> > +	buf->f_bavail = user_block_count - valid_user_blocks(sbi) -
> > +						sbi->current_reserved_blocks -
> > +						sbi->root_reserved_blocks;
> >  	avail_node_count = sbi->total_node_count - sbi->nquota_files -
> >  						F2FS_RESERVED_NODE_NUM;
> >  
> > @@ -1136,6 +1150,9 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
> >  	else if (test_opt(sbi, LFS))
> >  		seq_puts(seq, "lfs");
> >  	seq_printf(seq, ",active_logs=%u", sbi->active_logs);
> > +	if (test_opt(sbi, RESERVE_ROOT))
> > +		seq_printf(seq, ",reserve_root=%u",
> > +				sbi->root_reserved_blocks);
> >  	if (F2FS_IO_SIZE_BITS(sbi))
> >  		seq_printf(seq, ",io_size=%uKB", F2FS_IO_SIZE_KB(sbi));
> >  #ifdef CONFIG_F2FS_FAULT_INJECTION
> > @@ -2571,6 +2588,13 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
> >  	sbi->reserved_blocks = 0;
> >  	sbi->current_reserved_blocks = 0;
> >  
> > +	if (test_opt(sbi, RESERVE_ROOT) &&
> > +		sbi->root_reserved_blocks > reserve_root_limit(sbi)) {
> > +		sbi->root_reserved_blocks = reserve_root_limit(sbi);
> > +		f2fs_msg(sb, KERN_INFO,
> > +			"Reduce reserved blocks for root = %u\n",
> > +				sbi->root_reserved_blocks);
> > +	}
> >  	for (i = 0; i < NR_INODE_TYPE; i++) {
> >  		INIT_LIST_HEAD(&sbi->inode_list[i]);
> >  		spin_lock_init(&sbi->inode_lock[i]);
> > diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c
> > index 93c3364250dd..ab6028c332aa 100644
> > --- a/fs/f2fs/sysfs.c
> > +++ b/fs/f2fs/sysfs.c
> > @@ -162,7 +162,8 @@ static ssize_t f2fs_sbi_store(struct f2fs_attr *a,
> >  #endif
> >  	if (a->struct_type == RESERVED_BLOCKS) {
> >  		spin_lock(&sbi->stat_lock);
> > -		if (t > (unsigned long)sbi->user_block_count) {
> > +		if (t > (unsigned long)(sbi->user_block_count -
> > +					sbi->root_reserved_blocks)) {
> >  			spin_unlock(&sbi->stat_lock);
> >  			return -EINVAL;
> >  		}
> > 

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

* Re: [f2fs-dev] [PATCH v5] f2fs: add reserved blocks for root user
  2018-01-03 19:06         ` [f2fs-dev] " Jaegeuk Kim
@ 2018-01-04  1:16             ` Chao Yu
  0 siblings, 0 replies; 21+ messages in thread
From: Chao Yu @ 2018-01-04  1:16 UTC (permalink / raw)
  To: Jaegeuk Kim; +Cc: linux-kernel, linux-f2fs-devel

On 2018/1/4 3:06, Jaegeuk Kim wrote:
> On 01/03, Chao Yu wrote:
>> On 2018/1/3 10:21, Jaegeuk Kim wrote:
>>> This patch allows root to reserve some blocks via mount option.
>>>
>>> "-o reserve_root=N" means N x 4KB-sized blocks for root only.
>>>
>>> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
>>> ---
>>>
>>> Change log from v4:
>>>  - fix f_bfree in statfs
>>
>> Could you fix f_bfree calculation issue in another patch prior to this
>> patch? That will be better for history tracking of patches or git bisect
>> when backtracking issues.
> 
> I've sent out a new series for this.
> 
>>
>> One more thing, should we move reserve_root_limit check to parse_option?
> 
> No, since we don't have sbi yet.
> 
>> now, it looks that during remount we can set root_reserved_blocks exceeding
>> our defined limitation.
> 
> Oh, I missed the changelog that it won't be changed once getting the flag set.

If the flag is not set previously, and then we remount with that flag being
set?

Like:

mount -t f2fs /dev/xxx /mnt/
mount -t f2fs -o remount,reserve_root=xxx /dev/xxx /mnt/

Thanks,

> 
> Thanks,
> 
>>
>> Thanks,
>>
>>>
>>>  fs/f2fs/f2fs.h  | 26 ++++++++++++++++++++++----
>>>  fs/f2fs/super.c | 34 +++++++++++++++++++++++++++++-----
>>>  fs/f2fs/sysfs.c |  3 ++-
>>>  3 files changed, 53 insertions(+), 10 deletions(-)
>>>
>>> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
>>> index 07e03990420b..a0e8eec23125 100644
>>> --- a/fs/f2fs/f2fs.h
>>> +++ b/fs/f2fs/f2fs.h
>>> @@ -95,6 +95,7 @@ extern char *fault_name[FAULT_MAX];
>>>  #define F2FS_MOUNT_PRJQUOTA		0x00200000
>>>  #define F2FS_MOUNT_QUOTA		0x00400000
>>>  #define F2FS_MOUNT_INLINE_XATTR_SIZE	0x00800000
>>> +#define F2FS_MOUNT_RESERVE_ROOT		0x01000000
>>>  
>>>  #define clear_opt(sbi, option)	((sbi)->mount_opt.opt &= ~F2FS_MOUNT_##option)
>>>  #define set_opt(sbi, option)	((sbi)->mount_opt.opt |= F2FS_MOUNT_##option)
>>> @@ -1105,6 +1106,7 @@ struct f2fs_sb_info {
>>>  	block_t last_valid_block_count;		/* for recovery */
>>>  	block_t reserved_blocks;		/* configurable reserved blocks */
>>>  	block_t current_reserved_blocks;	/* current reserved blocks */
>>> +	block_t root_reserved_blocks;		/* root reserved blocks */
>>>  
>>>  	unsigned int nquota_files;		/* # of quota sysfile */
>>>  
>>> @@ -1554,6 +1556,12 @@ static inline bool f2fs_has_xattr_block(unsigned int ofs)
>>>  	return ofs == XATTR_NODE_OFFSET;
>>>  }
>>>  
>>> +static inline block_t reserve_root_limit(struct f2fs_sb_info *sbi)
>>> +{
>>> +	/* limit is 0.2% */
>>> +	return (sbi->user_block_count << 1) / 1000;
>>> +}
>>> +
>>>  static inline void f2fs_i_blocks_write(struct inode *, block_t, bool, bool);
>>>  static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
>>>  				 struct inode *inode, blkcnt_t *count)
>>> @@ -1583,11 +1591,17 @@ static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
>>>  	sbi->total_valid_block_count += (block_t)(*count);
>>>  	avail_user_block_count = sbi->user_block_count -
>>>  					sbi->current_reserved_blocks;
>>> +
>>> +	if (!(test_opt(sbi, RESERVE_ROOT) && capable(CAP_SYS_RESOURCE)))
>>> +		avail_user_block_count -= sbi->root_reserved_blocks;
>>> +
>>>  	if (unlikely(sbi->total_valid_block_count > avail_user_block_count)) {
>>>  		diff = sbi->total_valid_block_count - avail_user_block_count;
>>> +		if (diff > *count)
>>> +			diff = *count;
>>>  		*count -= diff;
>>>  		release = diff;
>>> -		sbi->total_valid_block_count = avail_user_block_count;
>>> +		sbi->total_valid_block_count -= diff;
>>>  		if (!*count) {
>>>  			spin_unlock(&sbi->stat_lock);
>>>  			percpu_counter_sub(&sbi->alloc_valid_block_count, diff);
>>> @@ -1776,9 +1790,13 @@ 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;
>>> -	if (unlikely(valid_block_count + sbi->current_reserved_blocks >
>>> -						sbi->user_block_count)) {
>>> +	valid_block_count = sbi->total_valid_block_count +
>>> +					sbi->current_reserved_blocks + 1;
>>> +
>>> +	if (!(test_opt(sbi, RESERVE_ROOT) && capable(CAP_SYS_RESOURCE)))
>>> +		valid_block_count += sbi->root_reserved_blocks;
>>> +
>>> +	if (unlikely(valid_block_count > sbi->user_block_count)) {
>>>  		spin_unlock(&sbi->stat_lock);
>>>  		goto enospc;
>>>  	}
>>> diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
>>> index 5c6a02b558f0..e814340bc2f0 100644
>>> --- a/fs/f2fs/super.c
>>> +++ b/fs/f2fs/super.c
>>> @@ -107,6 +107,7 @@ enum {
>>>  	Opt_noextent_cache,
>>>  	Opt_noinline_data,
>>>  	Opt_data_flush,
>>> +	Opt_reserve_root,
>>>  	Opt_mode,
>>>  	Opt_io_size_bits,
>>>  	Opt_fault_injection,
>>> @@ -157,6 +158,7 @@ static match_table_t f2fs_tokens = {
>>>  	{Opt_noextent_cache, "noextent_cache"},
>>>  	{Opt_noinline_data, "noinline_data"},
>>>  	{Opt_data_flush, "data_flush"},
>>> +	{Opt_reserve_root, "reserve_root=%u"},
>>>  	{Opt_mode, "mode=%s"},
>>>  	{Opt_io_size_bits, "io_bits=%u"},
>>>  	{Opt_fault_injection, "fault_injection=%u"},
>>> @@ -488,6 +490,18 @@ static int parse_options(struct super_block *sb, char *options)
>>>  		case Opt_data_flush:
>>>  			set_opt(sbi, DATA_FLUSH);
>>>  			break;
>>> +		case Opt_reserve_root:
>>> +			if (args->from && match_int(args, &arg))
>>> +				return -EINVAL;
>>> +			if (test_opt(sbi, RESERVE_ROOT)) {
>>> +				f2fs_msg(sb, KERN_INFO,
>>> +					"Preserve previous reserve_root=%u",
>>> +					sbi->root_reserved_blocks);
>>> +			} else {
>>> +				sbi->root_reserved_blocks = arg;
>>> +				set_opt(sbi, RESERVE_ROOT);
>>> +			}
>>> +			break;
>>>  		case Opt_mode:
>>>  			name = match_strdup(&args[0]);
>>>  
>>> @@ -994,21 +1008,21 @@ static int f2fs_statfs(struct dentry *dentry, struct kstatfs *buf)
>>>  	struct super_block *sb = dentry->d_sb;
>>>  	struct f2fs_sb_info *sbi = F2FS_SB(sb);
>>>  	u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
>>> -	block_t total_count, user_block_count, start_count, ovp_count;
>>> +	block_t total_count, user_block_count, start_count;
>>>  	u64 avail_node_count;
>>>  
>>>  	total_count = le64_to_cpu(sbi->raw_super->block_count);
>>>  	user_block_count = sbi->user_block_count;
>>>  	start_count = le32_to_cpu(sbi->raw_super->segment0_blkaddr);
>>> -	ovp_count = SM_I(sbi)->ovp_segments << sbi->log_blocks_per_seg;
>>>  	buf->f_type = F2FS_SUPER_MAGIC;
>>>  	buf->f_bsize = sbi->blocksize;
>>>  
>>>  	buf->f_blocks = total_count - start_count;
>>> -	buf->f_bfree = user_block_count - valid_user_blocks(sbi) + ovp_count;
>>> -	buf->f_bavail = user_block_count - valid_user_blocks(sbi) -
>>> +	buf->f_bfree = user_block_count - valid_user_blocks(sbi) -
>>>  						sbi->current_reserved_blocks;
>>> -
>>> +	buf->f_bavail = user_block_count - valid_user_blocks(sbi) -
>>> +						sbi->current_reserved_blocks -
>>> +						sbi->root_reserved_blocks;
>>>  	avail_node_count = sbi->total_node_count - sbi->nquota_files -
>>>  						F2FS_RESERVED_NODE_NUM;
>>>  
>>> @@ -1136,6 +1150,9 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
>>>  	else if (test_opt(sbi, LFS))
>>>  		seq_puts(seq, "lfs");
>>>  	seq_printf(seq, ",active_logs=%u", sbi->active_logs);
>>> +	if (test_opt(sbi, RESERVE_ROOT))
>>> +		seq_printf(seq, ",reserve_root=%u",
>>> +				sbi->root_reserved_blocks);
>>>  	if (F2FS_IO_SIZE_BITS(sbi))
>>>  		seq_printf(seq, ",io_size=%uKB", F2FS_IO_SIZE_KB(sbi));
>>>  #ifdef CONFIG_F2FS_FAULT_INJECTION
>>> @@ -2571,6 +2588,13 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
>>>  	sbi->reserved_blocks = 0;
>>>  	sbi->current_reserved_blocks = 0;
>>>  
>>> +	if (test_opt(sbi, RESERVE_ROOT) &&
>>> +		sbi->root_reserved_blocks > reserve_root_limit(sbi)) {
>>> +		sbi->root_reserved_blocks = reserve_root_limit(sbi);
>>> +		f2fs_msg(sb, KERN_INFO,
>>> +			"Reduce reserved blocks for root = %u\n",
>>> +				sbi->root_reserved_blocks);
>>> +	}
>>>  	for (i = 0; i < NR_INODE_TYPE; i++) {
>>>  		INIT_LIST_HEAD(&sbi->inode_list[i]);
>>>  		spin_lock_init(&sbi->inode_lock[i]);
>>> diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c
>>> index 93c3364250dd..ab6028c332aa 100644
>>> --- a/fs/f2fs/sysfs.c
>>> +++ b/fs/f2fs/sysfs.c
>>> @@ -162,7 +162,8 @@ static ssize_t f2fs_sbi_store(struct f2fs_attr *a,
>>>  #endif
>>>  	if (a->struct_type == RESERVED_BLOCKS) {
>>>  		spin_lock(&sbi->stat_lock);
>>> -		if (t > (unsigned long)sbi->user_block_count) {
>>> +		if (t > (unsigned long)(sbi->user_block_count -
>>> +					sbi->root_reserved_blocks)) {
>>>  			spin_unlock(&sbi->stat_lock);
>>>  			return -EINVAL;
>>>  		}
>>>
> 
> .
> 

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

* Re: [PATCH v5] f2fs: add reserved blocks for root user
@ 2018-01-04  1:16             ` Chao Yu
  0 siblings, 0 replies; 21+ messages in thread
From: Chao Yu @ 2018-01-04  1:16 UTC (permalink / raw)
  To: Jaegeuk Kim; +Cc: linux-kernel, linux-f2fs-devel

On 2018/1/4 3:06, Jaegeuk Kim wrote:
> On 01/03, Chao Yu wrote:
>> On 2018/1/3 10:21, Jaegeuk Kim wrote:
>>> This patch allows root to reserve some blocks via mount option.
>>>
>>> "-o reserve_root=N" means N x 4KB-sized blocks for root only.
>>>
>>> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
>>> ---
>>>
>>> Change log from v4:
>>>  - fix f_bfree in statfs
>>
>> Could you fix f_bfree calculation issue in another patch prior to this
>> patch? That will be better for history tracking of patches or git bisect
>> when backtracking issues.
> 
> I've sent out a new series for this.
> 
>>
>> One more thing, should we move reserve_root_limit check to parse_option?
> 
> No, since we don't have sbi yet.
> 
>> now, it looks that during remount we can set root_reserved_blocks exceeding
>> our defined limitation.
> 
> Oh, I missed the changelog that it won't be changed once getting the flag set.

If the flag is not set previously, and then we remount with that flag being
set?

Like:

mount -t f2fs /dev/xxx /mnt/
mount -t f2fs -o remount,reserve_root=xxx /dev/xxx /mnt/

Thanks,

> 
> Thanks,
> 
>>
>> Thanks,
>>
>>>
>>>  fs/f2fs/f2fs.h  | 26 ++++++++++++++++++++++----
>>>  fs/f2fs/super.c | 34 +++++++++++++++++++++++++++++-----
>>>  fs/f2fs/sysfs.c |  3 ++-
>>>  3 files changed, 53 insertions(+), 10 deletions(-)
>>>
>>> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
>>> index 07e03990420b..a0e8eec23125 100644
>>> --- a/fs/f2fs/f2fs.h
>>> +++ b/fs/f2fs/f2fs.h
>>> @@ -95,6 +95,7 @@ extern char *fault_name[FAULT_MAX];
>>>  #define F2FS_MOUNT_PRJQUOTA		0x00200000
>>>  #define F2FS_MOUNT_QUOTA		0x00400000
>>>  #define F2FS_MOUNT_INLINE_XATTR_SIZE	0x00800000
>>> +#define F2FS_MOUNT_RESERVE_ROOT		0x01000000
>>>  
>>>  #define clear_opt(sbi, option)	((sbi)->mount_opt.opt &= ~F2FS_MOUNT_##option)
>>>  #define set_opt(sbi, option)	((sbi)->mount_opt.opt |= F2FS_MOUNT_##option)
>>> @@ -1105,6 +1106,7 @@ struct f2fs_sb_info {
>>>  	block_t last_valid_block_count;		/* for recovery */
>>>  	block_t reserved_blocks;		/* configurable reserved blocks */
>>>  	block_t current_reserved_blocks;	/* current reserved blocks */
>>> +	block_t root_reserved_blocks;		/* root reserved blocks */
>>>  
>>>  	unsigned int nquota_files;		/* # of quota sysfile */
>>>  
>>> @@ -1554,6 +1556,12 @@ static inline bool f2fs_has_xattr_block(unsigned int ofs)
>>>  	return ofs == XATTR_NODE_OFFSET;
>>>  }
>>>  
>>> +static inline block_t reserve_root_limit(struct f2fs_sb_info *sbi)
>>> +{
>>> +	/* limit is 0.2% */
>>> +	return (sbi->user_block_count << 1) / 1000;
>>> +}
>>> +
>>>  static inline void f2fs_i_blocks_write(struct inode *, block_t, bool, bool);
>>>  static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
>>>  				 struct inode *inode, blkcnt_t *count)
>>> @@ -1583,11 +1591,17 @@ static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
>>>  	sbi->total_valid_block_count += (block_t)(*count);
>>>  	avail_user_block_count = sbi->user_block_count -
>>>  					sbi->current_reserved_blocks;
>>> +
>>> +	if (!(test_opt(sbi, RESERVE_ROOT) && capable(CAP_SYS_RESOURCE)))
>>> +		avail_user_block_count -= sbi->root_reserved_blocks;
>>> +
>>>  	if (unlikely(sbi->total_valid_block_count > avail_user_block_count)) {
>>>  		diff = sbi->total_valid_block_count - avail_user_block_count;
>>> +		if (diff > *count)
>>> +			diff = *count;
>>>  		*count -= diff;
>>>  		release = diff;
>>> -		sbi->total_valid_block_count = avail_user_block_count;
>>> +		sbi->total_valid_block_count -= diff;
>>>  		if (!*count) {
>>>  			spin_unlock(&sbi->stat_lock);
>>>  			percpu_counter_sub(&sbi->alloc_valid_block_count, diff);
>>> @@ -1776,9 +1790,13 @@ 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;
>>> -	if (unlikely(valid_block_count + sbi->current_reserved_blocks >
>>> -						sbi->user_block_count)) {
>>> +	valid_block_count = sbi->total_valid_block_count +
>>> +					sbi->current_reserved_blocks + 1;
>>> +
>>> +	if (!(test_opt(sbi, RESERVE_ROOT) && capable(CAP_SYS_RESOURCE)))
>>> +		valid_block_count += sbi->root_reserved_blocks;
>>> +
>>> +	if (unlikely(valid_block_count > sbi->user_block_count)) {
>>>  		spin_unlock(&sbi->stat_lock);
>>>  		goto enospc;
>>>  	}
>>> diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
>>> index 5c6a02b558f0..e814340bc2f0 100644
>>> --- a/fs/f2fs/super.c
>>> +++ b/fs/f2fs/super.c
>>> @@ -107,6 +107,7 @@ enum {
>>>  	Opt_noextent_cache,
>>>  	Opt_noinline_data,
>>>  	Opt_data_flush,
>>> +	Opt_reserve_root,
>>>  	Opt_mode,
>>>  	Opt_io_size_bits,
>>>  	Opt_fault_injection,
>>> @@ -157,6 +158,7 @@ static match_table_t f2fs_tokens = {
>>>  	{Opt_noextent_cache, "noextent_cache"},
>>>  	{Opt_noinline_data, "noinline_data"},
>>>  	{Opt_data_flush, "data_flush"},
>>> +	{Opt_reserve_root, "reserve_root=%u"},
>>>  	{Opt_mode, "mode=%s"},
>>>  	{Opt_io_size_bits, "io_bits=%u"},
>>>  	{Opt_fault_injection, "fault_injection=%u"},
>>> @@ -488,6 +490,18 @@ static int parse_options(struct super_block *sb, char *options)
>>>  		case Opt_data_flush:
>>>  			set_opt(sbi, DATA_FLUSH);
>>>  			break;
>>> +		case Opt_reserve_root:
>>> +			if (args->from && match_int(args, &arg))
>>> +				return -EINVAL;
>>> +			if (test_opt(sbi, RESERVE_ROOT)) {
>>> +				f2fs_msg(sb, KERN_INFO,
>>> +					"Preserve previous reserve_root=%u",
>>> +					sbi->root_reserved_blocks);
>>> +			} else {
>>> +				sbi->root_reserved_blocks = arg;
>>> +				set_opt(sbi, RESERVE_ROOT);
>>> +			}
>>> +			break;
>>>  		case Opt_mode:
>>>  			name = match_strdup(&args[0]);
>>>  
>>> @@ -994,21 +1008,21 @@ static int f2fs_statfs(struct dentry *dentry, struct kstatfs *buf)
>>>  	struct super_block *sb = dentry->d_sb;
>>>  	struct f2fs_sb_info *sbi = F2FS_SB(sb);
>>>  	u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
>>> -	block_t total_count, user_block_count, start_count, ovp_count;
>>> +	block_t total_count, user_block_count, start_count;
>>>  	u64 avail_node_count;
>>>  
>>>  	total_count = le64_to_cpu(sbi->raw_super->block_count);
>>>  	user_block_count = sbi->user_block_count;
>>>  	start_count = le32_to_cpu(sbi->raw_super->segment0_blkaddr);
>>> -	ovp_count = SM_I(sbi)->ovp_segments << sbi->log_blocks_per_seg;
>>>  	buf->f_type = F2FS_SUPER_MAGIC;
>>>  	buf->f_bsize = sbi->blocksize;
>>>  
>>>  	buf->f_blocks = total_count - start_count;
>>> -	buf->f_bfree = user_block_count - valid_user_blocks(sbi) + ovp_count;
>>> -	buf->f_bavail = user_block_count - valid_user_blocks(sbi) -
>>> +	buf->f_bfree = user_block_count - valid_user_blocks(sbi) -
>>>  						sbi->current_reserved_blocks;
>>> -
>>> +	buf->f_bavail = user_block_count - valid_user_blocks(sbi) -
>>> +						sbi->current_reserved_blocks -
>>> +						sbi->root_reserved_blocks;
>>>  	avail_node_count = sbi->total_node_count - sbi->nquota_files -
>>>  						F2FS_RESERVED_NODE_NUM;
>>>  
>>> @@ -1136,6 +1150,9 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
>>>  	else if (test_opt(sbi, LFS))
>>>  		seq_puts(seq, "lfs");
>>>  	seq_printf(seq, ",active_logs=%u", sbi->active_logs);
>>> +	if (test_opt(sbi, RESERVE_ROOT))
>>> +		seq_printf(seq, ",reserve_root=%u",
>>> +				sbi->root_reserved_blocks);
>>>  	if (F2FS_IO_SIZE_BITS(sbi))
>>>  		seq_printf(seq, ",io_size=%uKB", F2FS_IO_SIZE_KB(sbi));
>>>  #ifdef CONFIG_F2FS_FAULT_INJECTION
>>> @@ -2571,6 +2588,13 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
>>>  	sbi->reserved_blocks = 0;
>>>  	sbi->current_reserved_blocks = 0;
>>>  
>>> +	if (test_opt(sbi, RESERVE_ROOT) &&
>>> +		sbi->root_reserved_blocks > reserve_root_limit(sbi)) {
>>> +		sbi->root_reserved_blocks = reserve_root_limit(sbi);
>>> +		f2fs_msg(sb, KERN_INFO,
>>> +			"Reduce reserved blocks for root = %u\n",
>>> +				sbi->root_reserved_blocks);
>>> +	}
>>>  	for (i = 0; i < NR_INODE_TYPE; i++) {
>>>  		INIT_LIST_HEAD(&sbi->inode_list[i]);
>>>  		spin_lock_init(&sbi->inode_lock[i]);
>>> diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c
>>> index 93c3364250dd..ab6028c332aa 100644
>>> --- a/fs/f2fs/sysfs.c
>>> +++ b/fs/f2fs/sysfs.c
>>> @@ -162,7 +162,8 @@ static ssize_t f2fs_sbi_store(struct f2fs_attr *a,
>>>  #endif
>>>  	if (a->struct_type == RESERVED_BLOCKS) {
>>>  		spin_lock(&sbi->stat_lock);
>>> -		if (t > (unsigned long)sbi->user_block_count) {
>>> +		if (t > (unsigned long)(sbi->user_block_count -
>>> +					sbi->root_reserved_blocks)) {
>>>  			spin_unlock(&sbi->stat_lock);
>>>  			return -EINVAL;
>>>  		}
>>>
> 
> .
> 


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot

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

* Re: [f2fs-dev] [PATCH v5] f2fs: add reserved blocks for root user
  2018-01-04  1:16             ` Chao Yu
  (?)
@ 2018-01-04  6:02             ` Jaegeuk Kim
  -1 siblings, 0 replies; 21+ messages in thread
From: Jaegeuk Kim @ 2018-01-04  6:02 UTC (permalink / raw)
  To: Chao Yu; +Cc: linux-kernel, linux-f2fs-devel

On 01/04, Chao Yu wrote:
> On 2018/1/4 3:06, Jaegeuk Kim wrote:
> > On 01/03, Chao Yu wrote:
> >> On 2018/1/3 10:21, Jaegeuk Kim wrote:
> >>> This patch allows root to reserve some blocks via mount option.
> >>>
> >>> "-o reserve_root=N" means N x 4KB-sized blocks for root only.
> >>>
> >>> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
> >>> ---
> >>>
> >>> Change log from v4:
> >>>  - fix f_bfree in statfs
> >>
> >> Could you fix f_bfree calculation issue in another patch prior to this
> >> patch? That will be better for history tracking of patches or git bisect
> >> when backtracking issues.
> > 
> > I've sent out a new series for this.
> > 
> >>
> >> One more thing, should we move reserve_root_limit check to parse_option?
> > 
> > No, since we don't have sbi yet.
> > 
> >> now, it looks that during remount we can set root_reserved_blocks exceeding
> >> our defined limitation.
> > 
> > Oh, I missed the changelog that it won't be changed once getting the flag set.
> 
> If the flag is not set previously, and then we remount with that flag being
> set?

Right. Will fix.

> 
> Like:
> 
> mount -t f2fs /dev/xxx /mnt/
> mount -t f2fs -o remount,reserve_root=xxx /dev/xxx /mnt/
> 
> Thanks,
> 
> > 
> > Thanks,
> > 
> >>
> >> Thanks,
> >>
> >>>
> >>>  fs/f2fs/f2fs.h  | 26 ++++++++++++++++++++++----
> >>>  fs/f2fs/super.c | 34 +++++++++++++++++++++++++++++-----
> >>>  fs/f2fs/sysfs.c |  3 ++-
> >>>  3 files changed, 53 insertions(+), 10 deletions(-)
> >>>
> >>> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> >>> index 07e03990420b..a0e8eec23125 100644
> >>> --- a/fs/f2fs/f2fs.h
> >>> +++ b/fs/f2fs/f2fs.h
> >>> @@ -95,6 +95,7 @@ extern char *fault_name[FAULT_MAX];
> >>>  #define F2FS_MOUNT_PRJQUOTA		0x00200000
> >>>  #define F2FS_MOUNT_QUOTA		0x00400000
> >>>  #define F2FS_MOUNT_INLINE_XATTR_SIZE	0x00800000
> >>> +#define F2FS_MOUNT_RESERVE_ROOT		0x01000000
> >>>  
> >>>  #define clear_opt(sbi, option)	((sbi)->mount_opt.opt &= ~F2FS_MOUNT_##option)
> >>>  #define set_opt(sbi, option)	((sbi)->mount_opt.opt |= F2FS_MOUNT_##option)
> >>> @@ -1105,6 +1106,7 @@ struct f2fs_sb_info {
> >>>  	block_t last_valid_block_count;		/* for recovery */
> >>>  	block_t reserved_blocks;		/* configurable reserved blocks */
> >>>  	block_t current_reserved_blocks;	/* current reserved blocks */
> >>> +	block_t root_reserved_blocks;		/* root reserved blocks */
> >>>  
> >>>  	unsigned int nquota_files;		/* # of quota sysfile */
> >>>  
> >>> @@ -1554,6 +1556,12 @@ static inline bool f2fs_has_xattr_block(unsigned int ofs)
> >>>  	return ofs == XATTR_NODE_OFFSET;
> >>>  }
> >>>  
> >>> +static inline block_t reserve_root_limit(struct f2fs_sb_info *sbi)
> >>> +{
> >>> +	/* limit is 0.2% */
> >>> +	return (sbi->user_block_count << 1) / 1000;
> >>> +}
> >>> +
> >>>  static inline void f2fs_i_blocks_write(struct inode *, block_t, bool, bool);
> >>>  static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
> >>>  				 struct inode *inode, blkcnt_t *count)
> >>> @@ -1583,11 +1591,17 @@ static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
> >>>  	sbi->total_valid_block_count += (block_t)(*count);
> >>>  	avail_user_block_count = sbi->user_block_count -
> >>>  					sbi->current_reserved_blocks;
> >>> +
> >>> +	if (!(test_opt(sbi, RESERVE_ROOT) && capable(CAP_SYS_RESOURCE)))
> >>> +		avail_user_block_count -= sbi->root_reserved_blocks;
> >>> +
> >>>  	if (unlikely(sbi->total_valid_block_count > avail_user_block_count)) {
> >>>  		diff = sbi->total_valid_block_count - avail_user_block_count;
> >>> +		if (diff > *count)
> >>> +			diff = *count;
> >>>  		*count -= diff;
> >>>  		release = diff;
> >>> -		sbi->total_valid_block_count = avail_user_block_count;
> >>> +		sbi->total_valid_block_count -= diff;
> >>>  		if (!*count) {
> >>>  			spin_unlock(&sbi->stat_lock);
> >>>  			percpu_counter_sub(&sbi->alloc_valid_block_count, diff);
> >>> @@ -1776,9 +1790,13 @@ 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;
> >>> -	if (unlikely(valid_block_count + sbi->current_reserved_blocks >
> >>> -						sbi->user_block_count)) {
> >>> +	valid_block_count = sbi->total_valid_block_count +
> >>> +					sbi->current_reserved_blocks + 1;
> >>> +
> >>> +	if (!(test_opt(sbi, RESERVE_ROOT) && capable(CAP_SYS_RESOURCE)))
> >>> +		valid_block_count += sbi->root_reserved_blocks;
> >>> +
> >>> +	if (unlikely(valid_block_count > sbi->user_block_count)) {
> >>>  		spin_unlock(&sbi->stat_lock);
> >>>  		goto enospc;
> >>>  	}
> >>> diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
> >>> index 5c6a02b558f0..e814340bc2f0 100644
> >>> --- a/fs/f2fs/super.c
> >>> +++ b/fs/f2fs/super.c
> >>> @@ -107,6 +107,7 @@ enum {
> >>>  	Opt_noextent_cache,
> >>>  	Opt_noinline_data,
> >>>  	Opt_data_flush,
> >>> +	Opt_reserve_root,
> >>>  	Opt_mode,
> >>>  	Opt_io_size_bits,
> >>>  	Opt_fault_injection,
> >>> @@ -157,6 +158,7 @@ static match_table_t f2fs_tokens = {
> >>>  	{Opt_noextent_cache, "noextent_cache"},
> >>>  	{Opt_noinline_data, "noinline_data"},
> >>>  	{Opt_data_flush, "data_flush"},
> >>> +	{Opt_reserve_root, "reserve_root=%u"},
> >>>  	{Opt_mode, "mode=%s"},
> >>>  	{Opt_io_size_bits, "io_bits=%u"},
> >>>  	{Opt_fault_injection, "fault_injection=%u"},
> >>> @@ -488,6 +490,18 @@ static int parse_options(struct super_block *sb, char *options)
> >>>  		case Opt_data_flush:
> >>>  			set_opt(sbi, DATA_FLUSH);
> >>>  			break;
> >>> +		case Opt_reserve_root:
> >>> +			if (args->from && match_int(args, &arg))
> >>> +				return -EINVAL;
> >>> +			if (test_opt(sbi, RESERVE_ROOT)) {
> >>> +				f2fs_msg(sb, KERN_INFO,
> >>> +					"Preserve previous reserve_root=%u",
> >>> +					sbi->root_reserved_blocks);
> >>> +			} else {
> >>> +				sbi->root_reserved_blocks = arg;
> >>> +				set_opt(sbi, RESERVE_ROOT);
> >>> +			}
> >>> +			break;
> >>>  		case Opt_mode:
> >>>  			name = match_strdup(&args[0]);
> >>>  
> >>> @@ -994,21 +1008,21 @@ static int f2fs_statfs(struct dentry *dentry, struct kstatfs *buf)
> >>>  	struct super_block *sb = dentry->d_sb;
> >>>  	struct f2fs_sb_info *sbi = F2FS_SB(sb);
> >>>  	u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
> >>> -	block_t total_count, user_block_count, start_count, ovp_count;
> >>> +	block_t total_count, user_block_count, start_count;
> >>>  	u64 avail_node_count;
> >>>  
> >>>  	total_count = le64_to_cpu(sbi->raw_super->block_count);
> >>>  	user_block_count = sbi->user_block_count;
> >>>  	start_count = le32_to_cpu(sbi->raw_super->segment0_blkaddr);
> >>> -	ovp_count = SM_I(sbi)->ovp_segments << sbi->log_blocks_per_seg;
> >>>  	buf->f_type = F2FS_SUPER_MAGIC;
> >>>  	buf->f_bsize = sbi->blocksize;
> >>>  
> >>>  	buf->f_blocks = total_count - start_count;
> >>> -	buf->f_bfree = user_block_count - valid_user_blocks(sbi) + ovp_count;
> >>> -	buf->f_bavail = user_block_count - valid_user_blocks(sbi) -
> >>> +	buf->f_bfree = user_block_count - valid_user_blocks(sbi) -
> >>>  						sbi->current_reserved_blocks;
> >>> -
> >>> +	buf->f_bavail = user_block_count - valid_user_blocks(sbi) -
> >>> +						sbi->current_reserved_blocks -
> >>> +						sbi->root_reserved_blocks;
> >>>  	avail_node_count = sbi->total_node_count - sbi->nquota_files -
> >>>  						F2FS_RESERVED_NODE_NUM;
> >>>  
> >>> @@ -1136,6 +1150,9 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
> >>>  	else if (test_opt(sbi, LFS))
> >>>  		seq_puts(seq, "lfs");
> >>>  	seq_printf(seq, ",active_logs=%u", sbi->active_logs);
> >>> +	if (test_opt(sbi, RESERVE_ROOT))
> >>> +		seq_printf(seq, ",reserve_root=%u",
> >>> +				sbi->root_reserved_blocks);
> >>>  	if (F2FS_IO_SIZE_BITS(sbi))
> >>>  		seq_printf(seq, ",io_size=%uKB", F2FS_IO_SIZE_KB(sbi));
> >>>  #ifdef CONFIG_F2FS_FAULT_INJECTION
> >>> @@ -2571,6 +2588,13 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
> >>>  	sbi->reserved_blocks = 0;
> >>>  	sbi->current_reserved_blocks = 0;
> >>>  
> >>> +	if (test_opt(sbi, RESERVE_ROOT) &&
> >>> +		sbi->root_reserved_blocks > reserve_root_limit(sbi)) {
> >>> +		sbi->root_reserved_blocks = reserve_root_limit(sbi);
> >>> +		f2fs_msg(sb, KERN_INFO,
> >>> +			"Reduce reserved blocks for root = %u\n",
> >>> +				sbi->root_reserved_blocks);
> >>> +	}
> >>>  	for (i = 0; i < NR_INODE_TYPE; i++) {
> >>>  		INIT_LIST_HEAD(&sbi->inode_list[i]);
> >>>  		spin_lock_init(&sbi->inode_lock[i]);
> >>> diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c
> >>> index 93c3364250dd..ab6028c332aa 100644
> >>> --- a/fs/f2fs/sysfs.c
> >>> +++ b/fs/f2fs/sysfs.c
> >>> @@ -162,7 +162,8 @@ static ssize_t f2fs_sbi_store(struct f2fs_attr *a,
> >>>  #endif
> >>>  	if (a->struct_type == RESERVED_BLOCKS) {
> >>>  		spin_lock(&sbi->stat_lock);
> >>> -		if (t > (unsigned long)sbi->user_block_count) {
> >>> +		if (t > (unsigned long)(sbi->user_block_count -
> >>> +					sbi->root_reserved_blocks)) {
> >>>  			spin_unlock(&sbi->stat_lock);
> >>>  			return -EINVAL;
> >>>  		}
> >>>
> > 
> > .
> > 

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

end of thread, other threads:[~2018-01-04  6:02 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-12-28  2:19 [PATCH] f2fs: add reserved blocks for root user Jaegeuk Kim
2017-12-28  2:19 ` Jaegeuk Kim
2017-12-29  7:55 ` Chao Yu
2017-12-29  7:55   ` Chao Yu
2018-01-01  1:24 ` [PATCH v2] " Jaegeuk Kim
2018-01-01  1:24   ` Jaegeuk Kim
2018-01-01  1:29 ` [PATCH v3] " Jaegeuk Kim
2018-01-01  1:29   ` Jaegeuk Kim
2018-01-02  6:25   ` [f2fs-dev] " Chao Yu
2018-01-02  6:25     ` Chao Yu
2018-01-02 19:24     ` [f2fs-dev] " Jaegeuk Kim
2018-01-03  6:46       ` Chao Yu
2018-01-03  6:46         ` Chao Yu
2018-01-02 19:27   ` [PATCH v4] " Jaegeuk Kim
2018-01-03  2:21     ` [PATCH v5] " Jaegeuk Kim
2018-01-03  6:45       ` [f2fs-dev] " Chao Yu
2018-01-03  6:45         ` Chao Yu
2018-01-03 19:06         ` [f2fs-dev] " Jaegeuk Kim
2018-01-04  1:16           ` Chao Yu
2018-01-04  1:16             ` Chao Yu
2018-01-04  6:02             ` [f2fs-dev] " Jaegeuk Kim

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.