[Devel] [PATCH rh8 1/9] ext4: Teach the fs where the balloon inode is
Konstantin Khorenko
khorenko at virtuozzo.com
Wed Mar 3 19:31:10 MSK 2021
From: "Maxim V. Patlasov" <MPatlasov at parallels.com>
This is a port of
da0fae4 ext4: Teach the fs where the balloon inode is
This adds the balloon_ino mount option and stores the inode
pointer on the in-memory super block object.
This is not good solution - in a perfect world the balloon
inode should be hidden (like the journalling one), but this
requires
a) reserve its number in the mainline sources;)
b) teach e2fsprogs not to treat one as orphaned
Until (if) we do this it's better to keep this as a regular
file on the disk.
(cherry picked from vz7 commit 54ac06cf671c68a3778e9f939ba3794fd6a51470)
Signed-off-by: Konstantin Khorenko <khorenko at virtuozzo.com>
---
fs/ext4/ext4.h | 2 ++
fs/ext4/super.c | 89 +++++++++++++++++++++++++++++++++++++++++++++----
2 files changed, 85 insertions(+), 6 deletions(-)
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 053b512397f2..e439695e4b30 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -1474,6 +1474,8 @@ struct ext4_sb_info {
atomic_t s_mb_discarded;
atomic_t s_lock_busy;
+ struct inode *s_balloon_ino;
+
/* locality groups */
struct ext4_locality_group __percpu *s_locality_groups;
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 1bb88cb510d5..db096034e7dc 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1641,6 +1641,7 @@ enum {
Opt_dioread_nolock, Opt_dioread_lock,
Opt_discard, Opt_nodiscard, Opt_init_itable, Opt_noinit_itable,
Opt_max_dir_size_kb, Opt_nojournal_checksum, Opt_nombcache,
+ Opt_balloon_ino,
};
static const match_table_t tokens = {
@@ -1727,6 +1728,7 @@ static const match_table_t tokens = {
{Opt_test_dummy_encryption, "test_dummy_encryption"},
{Opt_nombcache, "nombcache"},
{Opt_nombcache, "no_mbcache"}, /* for backward compatibility */
+ {Opt_balloon_ino, "balloon_ino=%u"},
{Opt_removed, "check=none"}, /* mount option from ext2/3 */
{Opt_removed, "nocheck"}, /* mount option from ext2/3 */
{Opt_removed, "reservation"}, /* mount option from ext2/3 */
@@ -1937,12 +1939,14 @@ static const struct mount_opts {
{Opt_max_dir_size_kb, 0, MOPT_GTE0},
{Opt_test_dummy_encryption, 0, MOPT_GTE0},
{Opt_nombcache, EXT4_MOUNT_NO_MBCACHE, MOPT_SET},
+ {Opt_balloon_ino, 0, 0},
{Opt_err, 0, 0}
};
static int handle_mount_opt(struct super_block *sb, char *opt, int token,
substring_t *args, unsigned long *journal_devnum,
- unsigned int *journal_ioprio, int is_remount)
+ unsigned int *journal_ioprio,
+ unsigned long *balloon_ino, int is_remount)
{
struct ext4_sb_info *sbi = EXT4_SB(sb);
const struct mount_opts *m;
@@ -2144,6 +2148,8 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
ext4_msg(sb, KERN_WARNING,
"Test dummy encryption mount option ignored");
#endif
+ } else if (token == Opt_balloon_ino) {
+ *balloon_ino = arg;
} else if (m->flags & MOPT_DATAJ) {
if (is_remount) {
if (!sbi->s_journal)
@@ -2208,6 +2214,7 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
static int parse_options(char *options, struct super_block *sb,
unsigned long *journal_devnum,
unsigned int *journal_ioprio,
+ unsigned long *balloon_ino,
int is_remount)
{
struct ext4_sb_info *sbi = EXT4_SB(sb);
@@ -2228,7 +2235,8 @@ static int parse_options(char *options, struct super_block *sb,
args[0].to = args[0].from = NULL;
token = match_token(p, tokens, args);
if (handle_mount_opt(sb, p, token, args, journal_devnum,
- journal_ioprio, is_remount) < 0)
+ journal_ioprio, balloon_ino,
+ is_remount) < 0)
return 0;
}
#ifdef CONFIG_QUOTA
@@ -2405,6 +2413,9 @@ static int _ext4_show_options(struct seq_file *seq, struct super_block *sb,
if (DUMMY_ENCRYPTION_ENABLED(sbi))
SEQ_OPTS_PUTS("test_dummy_encryption");
+ if (sbi->s_balloon_ino)
+ SEQ_OPTS_PRINT("balloon_ino=%ld", sbi->s_balloon_ino->i_ino);
+
ext4_show_quota_options(seq, sb);
return 0;
}
@@ -3748,6 +3759,54 @@ static void ext4_set_resv_clusters(struct super_block *sb)
atomic64_set(&sbi->s_resv_clusters, resv_clusters);
}
+static void ext4_load_balloon(struct super_block *sb, unsigned long ino)
+{
+ struct inode *inode;
+ struct ext4_sb_info *sbi;
+
+ sbi = EXT4_SB(sb);
+
+ if (!ino) {
+ /* FIXME locking */
+ if (sbi->s_balloon_ino) {
+ iput(sbi->s_balloon_ino);
+ sbi->s_balloon_ino = NULL;
+ }
+
+ return;
+ }
+
+ if (ino < EXT4_FIRST_INO(sb)) {
+ ext4_msg(sb, KERN_WARNING, "bad balloon inode specified");
+ return;
+ }
+
+ inode = ext4_iget(sb, ino, EXT4_IGET_NORMAL);
+ if (IS_ERR(inode)) {
+ ext4_msg(sb, KERN_WARNING, "can't load balloon inode (%ld)", PTR_ERR(inode));
+ return;
+ }
+
+ if (!S_ISREG(inode->i_mode)) {
+ iput(inode);
+ ext4_msg(sb, KERN_WARNING, "balloon should be regular");
+ return;
+ }
+
+ if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL)) {
+ iput(inode);
+ ext4_msg(sb, KERN_WARNING, "balloon should support extents");
+ return;
+ }
+
+ /* FIXME - locking */
+ if (sbi->s_balloon_ino)
+ iput(sbi->s_balloon_ino);
+ sbi->s_balloon_ino = inode;
+ ext4_msg(sb, KERN_INFO, "loaded balloon from %ld (%llu blocks)",
+ inode->i_ino, inode->i_blocks);
+}
+
static int ext4_fill_super(struct super_block *sb, void *data, int silent)
{
struct dax_device *dax_dev = fs_dax_get_by_bdev(sb->s_bdev);
@@ -3772,6 +3831,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
__u64 blocks_count;
int err = 0;
unsigned int journal_ioprio = DEFAULT_JOURNAL_IOPRIO;
+ unsigned long balloon_ino = 0;
ext4_group_t first_not_zeroed;
if ((data && !orig_data) || !sbi)
@@ -4005,7 +4065,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
if (!s_mount_opts)
goto failed_mount;
if (!parse_options(s_mount_opts, sb, &journal_devnum,
- &journal_ioprio, 0)) {
+ &journal_ioprio, &balloon_ino, 0)) {
ext4_msg(sb, KERN_WARNING,
"failed to parse options in superblock: %s",
s_mount_opts);
@@ -4014,7 +4074,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
}
sbi->s_def_mount_opt = sbi->s_mount_opt;
if (!parse_options((char *) data, sb, &journal_devnum,
- &journal_ioprio, 0))
+ &journal_ioprio, &balloon_ino, 0))
goto failed_mount;
if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) {
@@ -4737,6 +4797,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
"the device does not support discard");
}
+ ext4_load_balloon(sb, balloon_ino);
+
if (___ratelimit(&ext4_mount_msg_ratelimit, "EXT4-fs mount"))
ext4_msg(sb, KERN_INFO, "mounted filesystem with%s. "
"Opts: %.*s%s%s", descr,
@@ -5406,6 +5468,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
char *to_free[EXT4_MAXQUOTAS];
#endif
char *orig_data = kstrdup(data, GFP_KERNEL);
+ unsigned long balloon_ino = -1;
if (data && !orig_data)
return -ENOMEM;
@@ -5438,7 +5501,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
if (sbi->s_journal && sbi->s_journal->j_task->io_context)
journal_ioprio = sbi->s_journal->j_task->io_context->ioprio;
- if (!parse_options(data, sb, NULL, &journal_ioprio, 1)) {
+ if (!parse_options(data, sb, NULL, &journal_ioprio, &balloon_ino, 1)) {
err = -EINVAL;
goto restore_opts;
}
@@ -5622,6 +5685,9 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
goto restore_opts;
}
+ if (balloon_ino != -1)
+ ext4_load_balloon(sb, balloon_ino);
+
#ifdef CONFIG_QUOTA
/* Release old quota file names */
for (i = 0; i < EXT4_MAXQUOTAS; i++)
@@ -6239,11 +6305,22 @@ static inline int ext3_feature_set_ok(struct super_block *sb)
return 1;
}
+static void ext4_kill_sb(struct super_block *sb)
+{
+ struct ext4_sb_info *sbi;
+
+ sbi = EXT4_SB(sb);
+ if (sbi && sbi->s_balloon_ino)
+ iput(sbi->s_balloon_ino);
+
+ kill_block_super(sb);
+}
+
static struct file_system_type ext4_fs_type = {
.owner = THIS_MODULE,
.name = "ext4",
.mount = ext4_mount,
- .kill_sb = kill_block_super,
+ .kill_sb = ext4_kill_sb,
.fs_flags = FS_REQUIRES_DEV | FS_VIRTUALIZED,
};
MODULE_ALIAS_FS("ext4");
--
2.28.0
More information about the Devel
mailing list