From: Maxim V. Patlasov <mpatla...@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 <khore...@virtuozzo.com>
Signed-off-by: Kirill Tkhai <ktk...@virtuozzo.com>
---
 fs/ext4/ext4.h  |    2 +
 fs/ext4/super.c |   91 +++++++++++++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 87 insertions(+), 6 deletions(-)

diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 3c51e243450d..9b655a94eb16 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -1579,6 +1579,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 befbb0892fdd..3bc2cfb04518 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1682,6 +1682,7 @@ enum {
 #ifdef CONFIG_EXT4_DEBUG
        Opt_fc_debug_max_replay, Opt_fc_debug_force
 #endif
+       Opt_balloon_ino,
 };
 
 static const match_table_t tokens = {
@@ -1786,6 +1787,7 @@ static const match_table_t tokens = {
        {Opt_removed, "reservation"},   /* mount option from ext2/3 */
        {Opt_removed, "noreservation"}, /* mount option from ext2/3 */
        {Opt_removed, "journal=%u"},    /* mount option from ext2/3 */
+       {Opt_balloon_ino, "balloon_ino=%u"},
        {Opt_err, NULL},
 };
 
@@ -2009,6 +2011,7 @@ static const struct mount_opts {
         MOPT_SET | MOPT_2 | MOPT_EXT4_ONLY},
        {Opt_fc_debug_max_replay, 0, MOPT_GTE0},
 #endif
+       {Opt_balloon_ino, 0, 0},
        {Opt_err, 0, 0}
 };
 
@@ -2093,7 +2096,8 @@ struct ext4_parsed_options {
 
 static int handle_mount_opt(struct super_block *sb, char *opt, int token,
                            substring_t *args, struct ext4_parsed_options 
*parsed_opts,
-                           int is_remount)
+
+                           unsigned long *balloon_ino, int is_remount)
 {
        struct ext4_sb_info *sbi = EXT4_SB(sb);
        const struct mount_opts *m;
@@ -2300,6 +2304,8 @@ static int handle_mount_opt(struct super_block *sb, char 
*opt, int token,
        } else if (token == Opt_test_dummy_encryption) {
                return ext4_set_test_dummy_encryption(sb, opt, &args[0],
                                                      is_remount);
+       } else if (token == Opt_balloon_ino) {
+               *balloon_ino = arg;
        } else if (m->flags & MOPT_DATAJ) {
                if (is_remount) {
                        if (!sbi->s_journal)
@@ -2420,6 +2426,7 @@ static int handle_mount_opt(struct super_block *sb, char 
*opt, int token,
 
 static int parse_options(char *options, struct super_block *sb,
                         struct ext4_parsed_options *ret_opts,
+                        unsigned long *balloon_ino,
                         int is_remount)
 {
        struct ext4_sb_info __maybe_unused *sbi = EXT4_SB(sb);
@@ -2440,7 +2447,7 @@ 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, ret_opts,
-                                    is_remount) < 0)
+                                    balloon_ino, is_remount) < 0)
                        return 0;
        }
 #ifdef CONFIG_QUOTA
@@ -2628,6 +2635,10 @@ static int _ext4_show_options(struct seq_file *seq, 
struct super_block *sb,
        } else if (test_opt2(sb, DAX_INODE)) {
                SEQ_OPTS_PUTS("dax=inode");
        }
+
+       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;
 }
@@ -4014,6 +4025,54 @@ static const char *ext4_quota_mode(struct super_block 
*sb)
 #endif
 }
 
+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);
@@ -4036,6 +4095,7 @@ static int ext4_fill_super(struct super_block *sb, void 
*data, int silent)
        int needs_recovery, has_huge_files;
        __u64 blocks_count;
        int err = 0;
+       unsigned long balloon_ino = 0;
        ext4_group_t first_not_zeroed;
        struct ext4_parsed_options parsed_opts;
 
@@ -4288,7 +4348,8 @@ static int ext4_fill_super(struct super_block *sb, void 
*data, int silent)
                                              GFP_KERNEL);
                if (!s_mount_opts)
                        goto failed_mount;
-               if (!parse_options(s_mount_opts, sb, &parsed_opts, 0)) {
+               if (!parse_options(s_mount_opts, sb, &parsed_opts,
+                                  &balloon_ino, 0)) {
                        ext4_msg(sb, KERN_WARNING,
                                 "failed to parse options in superblock: %s",
                                 s_mount_opts);
@@ -4296,7 +4357,8 @@ static int ext4_fill_super(struct super_block *sb, void 
*data, int silent)
                kfree(s_mount_opts);
        }
        sbi->s_def_mount_opt = sbi->s_mount_opt;
-       if (!parse_options((char *) data, sb, &parsed_opts, 0))
+       if (!parse_options((char *) data, sb, &parsed_opts,
+                          &balloon_ino, 0))
                goto failed_mount;
 
 #ifdef CONFIG_UNICODE
@@ -5115,6 +5177,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. Quota mode: %s.", descr,
@@ -5854,6 +5918,7 @@ static int ext4_remount(struct super_block *sb, int 
*flags, char *data)
 #endif
        char *orig_data = kstrdup(data, GFP_KERNEL);
        struct ext4_parsed_options parsed_opts;
+       unsigned long balloon_ino = -1;
 
        parsed_opts.journal_ioprio = DEFAULT_JOURNAL_IOPRIO;
        parsed_opts.journal_devnum = 0;
@@ -5898,7 +5963,7 @@ static int ext4_remount(struct super_block *sb, int 
*flags, char *data)
        vfs_flags = SB_LAZYTIME | SB_I_VERSION;
        sb->s_flags = (sb->s_flags & ~vfs_flags) | (*flags & vfs_flags);
 
-       if (!parse_options(data, sb, &parsed_opts, 1)) {
+       if (!parse_options(data, sb, &parsed_opts, &balloon_ino, 1)) {
                err = -EINVAL;
                goto restore_opts;
        }
@@ -6086,6 +6151,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++)
@@ -6699,11 +6767,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_ALLOW_IDMAP | FS_VIRTUALIZED,
 };
 MODULE_ALIAS_FS("ext4");


_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to