diff options
author | Jaegeuk Kim <jaegeuk@kernel.org> | 2017-12-27 18:05:52 -0500 |
---|---|---|
committer | Jaegeuk Kim <jaegeuk@kernel.org> | 2018-01-16 18:39:58 -0500 |
commit | 7e65be49ed94f89cbf5add7dadf6e338f0cc6e7b (patch) | |
tree | ccea427a00e1202c15bfb7e23b4d0162e47fa233 /fs | |
parent | 2c1905042c8c3da45ec347d5397d1133ff30fce4 (diff) |
f2fs: add reserved blocks for root user
This patch allows root to reserve some blocks via mount option.
"-o reserve_root=N" means N x 4KB-sized blocks for root only.
Reviewed-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/f2fs/f2fs.h | 20 | ||||
-rw-r--r-- | fs/f2fs/super.c | 37 | ||||
-rw-r--r-- | fs/f2fs/sysfs.c | 3 |
3 files changed, 54 insertions, 6 deletions
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 7d3ba65ab638..541709042d53 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h | |||
@@ -95,6 +95,7 @@ extern char *fault_name[FAULT_MAX]; | |||
95 | #define F2FS_MOUNT_PRJQUOTA 0x00200000 | 95 | #define F2FS_MOUNT_PRJQUOTA 0x00200000 |
96 | #define F2FS_MOUNT_QUOTA 0x00400000 | 96 | #define F2FS_MOUNT_QUOTA 0x00400000 |
97 | #define F2FS_MOUNT_INLINE_XATTR_SIZE 0x00800000 | 97 | #define F2FS_MOUNT_INLINE_XATTR_SIZE 0x00800000 |
98 | #define F2FS_MOUNT_RESERVE_ROOT 0x01000000 | ||
98 | 99 | ||
99 | #define clear_opt(sbi, option) ((sbi)->mount_opt.opt &= ~F2FS_MOUNT_##option) | 100 | #define clear_opt(sbi, option) ((sbi)->mount_opt.opt &= ~F2FS_MOUNT_##option) |
100 | #define set_opt(sbi, option) ((sbi)->mount_opt.opt |= F2FS_MOUNT_##option) | 101 | #define set_opt(sbi, option) ((sbi)->mount_opt.opt |= F2FS_MOUNT_##option) |
@@ -1105,6 +1106,7 @@ struct f2fs_sb_info { | |||
1105 | block_t last_valid_block_count; /* for recovery */ | 1106 | block_t last_valid_block_count; /* for recovery */ |
1106 | block_t reserved_blocks; /* configurable reserved blocks */ | 1107 | block_t reserved_blocks; /* configurable reserved blocks */ |
1107 | block_t current_reserved_blocks; /* current reserved blocks */ | 1108 | block_t current_reserved_blocks; /* current reserved blocks */ |
1109 | block_t root_reserved_blocks; /* root reserved blocks */ | ||
1108 | 1110 | ||
1109 | unsigned int nquota_files; /* # of quota sysfile */ | 1111 | unsigned int nquota_files; /* # of quota sysfile */ |
1110 | 1112 | ||
@@ -1583,11 +1585,17 @@ static inline int inc_valid_block_count(struct f2fs_sb_info *sbi, | |||
1583 | sbi->total_valid_block_count += (block_t)(*count); | 1585 | sbi->total_valid_block_count += (block_t)(*count); |
1584 | avail_user_block_count = sbi->user_block_count - | 1586 | avail_user_block_count = sbi->user_block_count - |
1585 | sbi->current_reserved_blocks; | 1587 | sbi->current_reserved_blocks; |
1588 | |||
1589 | if (!(test_opt(sbi, RESERVE_ROOT) && capable(CAP_SYS_RESOURCE))) | ||
1590 | avail_user_block_count -= sbi->root_reserved_blocks; | ||
1591 | |||
1586 | if (unlikely(sbi->total_valid_block_count > avail_user_block_count)) { | 1592 | if (unlikely(sbi->total_valid_block_count > avail_user_block_count)) { |
1587 | diff = sbi->total_valid_block_count - avail_user_block_count; | 1593 | diff = sbi->total_valid_block_count - avail_user_block_count; |
1594 | if (diff > *count) | ||
1595 | diff = *count; | ||
1588 | *count -= diff; | 1596 | *count -= diff; |
1589 | release = diff; | 1597 | release = diff; |
1590 | sbi->total_valid_block_count = avail_user_block_count; | 1598 | sbi->total_valid_block_count -= diff; |
1591 | if (!*count) { | 1599 | if (!*count) { |
1592 | spin_unlock(&sbi->stat_lock); | 1600 | spin_unlock(&sbi->stat_lock); |
1593 | percpu_counter_sub(&sbi->alloc_valid_block_count, diff); | 1601 | percpu_counter_sub(&sbi->alloc_valid_block_count, diff); |
@@ -1776,9 +1784,13 @@ static inline int inc_valid_node_count(struct f2fs_sb_info *sbi, | |||
1776 | 1784 | ||
1777 | spin_lock(&sbi->stat_lock); | 1785 | spin_lock(&sbi->stat_lock); |
1778 | 1786 | ||
1779 | valid_block_count = sbi->total_valid_block_count + 1; | 1787 | valid_block_count = sbi->total_valid_block_count + |
1780 | if (unlikely(valid_block_count + sbi->current_reserved_blocks > | 1788 | sbi->current_reserved_blocks + 1; |
1781 | sbi->user_block_count)) { | 1789 | |
1790 | if (!(test_opt(sbi, RESERVE_ROOT) && capable(CAP_SYS_RESOURCE))) | ||
1791 | valid_block_count += sbi->root_reserved_blocks; | ||
1792 | |||
1793 | if (unlikely(valid_block_count > sbi->user_block_count)) { | ||
1782 | spin_unlock(&sbi->stat_lock); | 1794 | spin_unlock(&sbi->stat_lock); |
1783 | goto enospc; | 1795 | goto enospc; |
1784 | } | 1796 | } |
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index f1300cda6bfd..4904d1644052 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c | |||
@@ -107,6 +107,7 @@ enum { | |||
107 | Opt_noextent_cache, | 107 | Opt_noextent_cache, |
108 | Opt_noinline_data, | 108 | Opt_noinline_data, |
109 | Opt_data_flush, | 109 | Opt_data_flush, |
110 | Opt_reserve_root, | ||
110 | Opt_mode, | 111 | Opt_mode, |
111 | Opt_io_size_bits, | 112 | Opt_io_size_bits, |
112 | Opt_fault_injection, | 113 | Opt_fault_injection, |
@@ -157,6 +158,7 @@ static match_table_t f2fs_tokens = { | |||
157 | {Opt_noextent_cache, "noextent_cache"}, | 158 | {Opt_noextent_cache, "noextent_cache"}, |
158 | {Opt_noinline_data, "noinline_data"}, | 159 | {Opt_noinline_data, "noinline_data"}, |
159 | {Opt_data_flush, "data_flush"}, | 160 | {Opt_data_flush, "data_flush"}, |
161 | {Opt_reserve_root, "reserve_root=%u"}, | ||
160 | {Opt_mode, "mode=%s"}, | 162 | {Opt_mode, "mode=%s"}, |
161 | {Opt_io_size_bits, "io_bits=%u"}, | 163 | {Opt_io_size_bits, "io_bits=%u"}, |
162 | {Opt_fault_injection, "fault_injection=%u"}, | 164 | {Opt_fault_injection, "fault_injection=%u"}, |
@@ -191,6 +193,19 @@ void f2fs_msg(struct super_block *sb, const char *level, const char *fmt, ...) | |||
191 | va_end(args); | 193 | va_end(args); |
192 | } | 194 | } |
193 | 195 | ||
196 | static inline void limit_reserve_root(struct f2fs_sb_info *sbi) | ||
197 | { | ||
198 | block_t limit = (sbi->user_block_count << 1) / 1000; | ||
199 | |||
200 | /* limit is 0.2% */ | ||
201 | if (test_opt(sbi, RESERVE_ROOT) && sbi->root_reserved_blocks > limit) { | ||
202 | sbi->root_reserved_blocks = limit; | ||
203 | f2fs_msg(sbi->sb, KERN_INFO, | ||
204 | "Reduce reserved blocks for root = %u", | ||
205 | sbi->root_reserved_blocks); | ||
206 | } | ||
207 | } | ||
208 | |||
194 | static void init_once(void *foo) | 209 | static void init_once(void *foo) |
195 | { | 210 | { |
196 | struct f2fs_inode_info *fi = (struct f2fs_inode_info *) foo; | 211 | struct f2fs_inode_info *fi = (struct f2fs_inode_info *) foo; |
@@ -488,6 +503,18 @@ static int parse_options(struct super_block *sb, char *options) | |||
488 | case Opt_data_flush: | 503 | case Opt_data_flush: |
489 | set_opt(sbi, DATA_FLUSH); | 504 | set_opt(sbi, DATA_FLUSH); |
490 | break; | 505 | break; |
506 | case Opt_reserve_root: | ||
507 | if (args->from && match_int(args, &arg)) | ||
508 | return -EINVAL; | ||
509 | if (test_opt(sbi, RESERVE_ROOT)) { | ||
510 | f2fs_msg(sb, KERN_INFO, | ||
511 | "Preserve previous reserve_root=%u", | ||
512 | sbi->root_reserved_blocks); | ||
513 | } else { | ||
514 | sbi->root_reserved_blocks = arg; | ||
515 | set_opt(sbi, RESERVE_ROOT); | ||
516 | } | ||
517 | break; | ||
491 | case Opt_mode: | 518 | case Opt_mode: |
492 | name = match_strdup(&args[0]); | 519 | name = match_strdup(&args[0]); |
493 | 520 | ||
@@ -1006,7 +1033,10 @@ static int f2fs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
1006 | buf->f_blocks = total_count - start_count; | 1033 | buf->f_blocks = total_count - start_count; |
1007 | buf->f_bfree = user_block_count - valid_user_blocks(sbi) - | 1034 | buf->f_bfree = user_block_count - valid_user_blocks(sbi) - |
1008 | sbi->current_reserved_blocks; | 1035 | sbi->current_reserved_blocks; |
1009 | buf->f_bavail = buf->f_bfree; | 1036 | if (buf->f_bfree > sbi->root_reserved_blocks) |
1037 | buf->f_bavail = buf->f_bfree - sbi->root_reserved_blocks; | ||
1038 | else | ||
1039 | buf->f_bavail = 0; | ||
1010 | 1040 | ||
1011 | avail_node_count = sbi->total_node_count - sbi->nquota_files - | 1041 | avail_node_count = sbi->total_node_count - sbi->nquota_files - |
1012 | F2FS_RESERVED_NODE_NUM; | 1042 | F2FS_RESERVED_NODE_NUM; |
@@ -1135,6 +1165,9 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) | |||
1135 | else if (test_opt(sbi, LFS)) | 1165 | else if (test_opt(sbi, LFS)) |
1136 | seq_puts(seq, "lfs"); | 1166 | seq_puts(seq, "lfs"); |
1137 | seq_printf(seq, ",active_logs=%u", sbi->active_logs); | 1167 | seq_printf(seq, ",active_logs=%u", sbi->active_logs); |
1168 | if (test_opt(sbi, RESERVE_ROOT)) | ||
1169 | seq_printf(seq, ",reserve_root=%u", | ||
1170 | sbi->root_reserved_blocks); | ||
1138 | if (F2FS_IO_SIZE_BITS(sbi)) | 1171 | if (F2FS_IO_SIZE_BITS(sbi)) |
1139 | seq_printf(seq, ",io_size=%uKB", F2FS_IO_SIZE_KB(sbi)); | 1172 | seq_printf(seq, ",io_size=%uKB", F2FS_IO_SIZE_KB(sbi)); |
1140 | #ifdef CONFIG_F2FS_FAULT_INJECTION | 1173 | #ifdef CONFIG_F2FS_FAULT_INJECTION |
@@ -1333,6 +1366,7 @@ skip: | |||
1333 | sb->s_flags = (sb->s_flags & ~SB_POSIXACL) | | 1366 | sb->s_flags = (sb->s_flags & ~SB_POSIXACL) | |
1334 | (test_opt(sbi, POSIX_ACL) ? SB_POSIXACL : 0); | 1367 | (test_opt(sbi, POSIX_ACL) ? SB_POSIXACL : 0); |
1335 | 1368 | ||
1369 | limit_reserve_root(sbi); | ||
1336 | return 0; | 1370 | return 0; |
1337 | restore_gc: | 1371 | restore_gc: |
1338 | if (need_restart_gc) { | 1372 | if (need_restart_gc) { |
@@ -2569,6 +2603,7 @@ try_onemore: | |||
2569 | sbi->last_valid_block_count = sbi->total_valid_block_count; | 2603 | sbi->last_valid_block_count = sbi->total_valid_block_count; |
2570 | sbi->reserved_blocks = 0; | 2604 | sbi->reserved_blocks = 0; |
2571 | sbi->current_reserved_blocks = 0; | 2605 | sbi->current_reserved_blocks = 0; |
2606 | limit_reserve_root(sbi); | ||
2572 | 2607 | ||
2573 | for (i = 0; i < NR_INODE_TYPE; i++) { | 2608 | for (i = 0; i < NR_INODE_TYPE; i++) { |
2574 | INIT_LIST_HEAD(&sbi->inode_list[i]); | 2609 | INIT_LIST_HEAD(&sbi->inode_list[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, | |||
162 | #endif | 162 | #endif |
163 | if (a->struct_type == RESERVED_BLOCKS) { | 163 | if (a->struct_type == RESERVED_BLOCKS) { |
164 | spin_lock(&sbi->stat_lock); | 164 | spin_lock(&sbi->stat_lock); |
165 | if (t > (unsigned long)sbi->user_block_count) { | 165 | if (t > (unsigned long)(sbi->user_block_count - |
166 | sbi->root_reserved_blocks)) { | ||
166 | spin_unlock(&sbi->stat_lock); | 167 | spin_unlock(&sbi->stat_lock); |
167 | return -EINVAL; | 168 | return -EINVAL; |
168 | } | 169 | } |