]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - fs/ext4/super.c
filesystem freeze: add error handling of write_super_lockfs/unlockfs
[linux-2.6-omap-h63xx.git] / fs / ext4 / super.c
index 517c90ad25bd793cfa9e965ea1c6a43b1cbab5dc..e5f06a5f045ee72ed825748d760485ec8739240f 100644 (file)
@@ -51,7 +51,7 @@ struct proc_dir_entry *ext4_proc_root;
 
 static int ext4_load_journal(struct super_block *, struct ext4_super_block *,
                             unsigned long journal_devnum);
-static void ext4_commit_super(struct super_block *sb,
+static int ext4_commit_super(struct super_block *sb,
                              struct ext4_super_block *es, int sync);
 static void ext4_mark_recovery_complete(struct super_block *sb,
                                        struct ext4_super_block *es);
@@ -62,9 +62,9 @@ static const char *ext4_decode_error(struct super_block *sb, int errno,
                                     char nbuf[16]);
 static int ext4_remount(struct super_block *sb, int *flags, char *data);
 static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf);
-static void ext4_unlockfs(struct super_block *sb);
+static int ext4_unfreeze(struct super_block *sb);
 static void ext4_write_super(struct super_block *sb);
-static void ext4_write_super_lockfs(struct super_block *sb);
+static int ext4_freeze(struct super_block *sb);
 
 
 ext4_fsblk_t ext4_block_bitmap(struct super_block *sb,
@@ -505,7 +505,7 @@ static struct block_device *ext4_blkdev_get(dev_t dev)
        return bdev;
 
 fail:
-       printk(KERN_ERR "EXT4: failed to open journal device %s: %ld\n",
+       printk(KERN_ERR "EXT4-fs: failed to open journal device %s: %ld\n",
                        __bdevname(dev, b), PTR_ERR(bdev));
        return NULL;
 }
@@ -829,8 +829,6 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs)
                seq_puts(seq, ",journal_async_commit");
        if (test_opt(sb, NOBH))
                seq_puts(seq, ",nobh");
-       if (!test_opt(sb, EXTENTS))
-               seq_puts(seq, ",noextents");
        if (test_opt(sb, I_VERSION))
                seq_puts(seq, ",i_version");
        if (!test_opt(sb, DELALLOC))
@@ -955,7 +953,9 @@ static struct dquot_operations ext4_quota_operations = {
        .acquire_dquot  = ext4_acquire_dquot,
        .release_dquot  = ext4_release_dquot,
        .mark_dirty     = ext4_mark_dquot_dirty,
-       .write_info     = ext4_write_info
+       .write_info     = ext4_write_info,
+       .alloc_dquot    = dquot_alloc,
+       .destroy_dquot  = dquot_destroy,
 };
 
 static struct quotactl_ops ext4_qctl_operations = {
@@ -978,8 +978,8 @@ static const struct super_operations ext4_sops = {
        .put_super      = ext4_put_super,
        .write_super    = ext4_write_super,
        .sync_fs        = ext4_sync_fs,
-       .write_super_lockfs = ext4_write_super_lockfs,
-       .unlockfs       = ext4_unlockfs,
+       .freeze_fs      = ext4_freeze,
+       .unfreeze_fs    = ext4_unfreeze,
        .statfs         = ext4_statfs,
        .remount_fs     = ext4_remount,
        .clear_inode    = ext4_clear_inode,
@@ -1011,7 +1011,7 @@ enum {
        Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
        Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_quota, Opt_noquota,
        Opt_ignore, Opt_barrier, Opt_err, Opt_resize, Opt_usrquota,
-       Opt_grpquota, Opt_extents, Opt_noextents, Opt_i_version,
+       Opt_grpquota, Opt_i_version,
        Opt_stripe, Opt_delalloc, Opt_nodelalloc,
        Opt_inode_readahead_blks, Opt_journal_ioprio
 };
@@ -1066,8 +1066,6 @@ static const match_table_t tokens = {
        {Opt_quota, "quota"},
        {Opt_usrquota, "usrquota"},
        {Opt_barrier, "barrier=%u"},
-       {Opt_extents, "extents"},
-       {Opt_noextents, "noextents"},
        {Opt_i_version, "i_version"},
        {Opt_stripe, "stripe=%u"},
        {Opt_resize, "resize"},
@@ -1115,7 +1113,6 @@ static int parse_options(char *options, struct super_block *sb,
        int qtype, qfmt;
        char *qname;
 #endif
-       ext4_fsblk_t last_block;
 
        if (!options)
                return 1;
@@ -1307,8 +1304,7 @@ static int parse_options(char *options, struct super_block *sb,
                case Opt_grpjquota:
                        qtype = GRPQUOTA;
 set_qf_name:
-                       if ((sb_any_quota_enabled(sb) ||
-                            sb_any_quota_suspended(sb)) &&
+                       if (sb_any_quota_loaded(sb) &&
                            !sbi->s_qf_names[qtype]) {
                                printk(KERN_ERR
                                       "EXT4-fs: Cannot change journaled "
@@ -1347,8 +1343,7 @@ set_qf_name:
                case Opt_offgrpjquota:
                        qtype = GRPQUOTA;
 clear_qf_name:
-                       if ((sb_any_quota_enabled(sb) ||
-                            sb_any_quota_suspended(sb)) &&
+                       if (sb_any_quota_loaded(sb) &&
                            sbi->s_qf_names[qtype]) {
                                printk(KERN_ERR "EXT4-fs: Cannot change "
                                        "journaled quota options when "
@@ -1367,8 +1362,7 @@ clear_qf_name:
                case Opt_jqfmt_vfsv0:
                        qfmt = QFMT_VFS_V0;
 set_qf_format:
-                       if ((sb_any_quota_enabled(sb) ||
-                            sb_any_quota_suspended(sb)) &&
+                       if (sb_any_quota_loaded(sb) &&
                            sbi->s_jquota_fmt != qfmt) {
                                printk(KERN_ERR "EXT4-fs: Cannot change "
                                        "journaled quota options when "
@@ -1387,7 +1381,7 @@ set_qf_format:
                        set_opt(sbi->s_mount_opt, GRPQUOTA);
                        break;
                case Opt_noquota:
-                       if (sb_any_quota_enabled(sb)) {
+                       if (sb_any_quota_loaded(sb)) {
                                printk(KERN_ERR "EXT4-fs: Cannot change quota "
                                        "options when quota turned on.\n");
                                return 0;
@@ -1445,33 +1439,6 @@ set_qf_format:
                case Opt_bh:
                        clear_opt(sbi->s_mount_opt, NOBH);
                        break;
-               case Opt_extents:
-                       if (!EXT4_HAS_INCOMPAT_FEATURE(sb,
-                                       EXT4_FEATURE_INCOMPAT_EXTENTS)) {
-                               ext4_warning(sb, __func__,
-                                       "extents feature not enabled "
-                                       "on this filesystem, use tune2fs");
-                               return 0;
-                       }
-                       set_opt(sbi->s_mount_opt, EXTENTS);
-                       break;
-               case Opt_noextents:
-                       /*
-                        * When e2fsprogs support resizing an already existing
-                        * ext3 file system to greater than 2**32 we need to
-                        * add support to block allocator to handle growing
-                        * already existing block  mapped inode so that blocks
-                        * allocated for them fall within 2**32
-                        */
-                       last_block = ext4_blocks_count(sbi->s_es) - 1;
-                       if (last_block  > 0xffffffffULL) {
-                               printk(KERN_ERR "EXT4-fs: Filesystem too "
-                                               "large to mount with "
-                                               "-o noextents options\n");
-                               return 0;
-                       }
-                       clear_opt(sbi->s_mount_opt, EXTENTS);
-                       break;
                case Opt_i_version:
                        set_opt(sbi->s_mount_opt, I_VERSION);
                        sb->s_flags |= MS_I_VERSION;
@@ -2135,18 +2102,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        set_opt(sbi->s_mount_opt, RESERVATION);
        set_opt(sbi->s_mount_opt, BARRIER);
 
-       /*
-        * turn on extents feature by default in ext4 filesystem
-        * only if feature flag already set by mkfs or tune2fs.
-        * Use -o noextents to turn it off
-        */
-       if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_EXTENTS))
-               set_opt(sbi->s_mount_opt, EXTENTS);
-       else
-               ext4_warning(sb, __func__,
-                       "extents feature not enabled on this filesystem, "
-                       "use tune2fs.");
-
        /*
         * enable delayed allocation by default
         * Use -o nodelalloc to turn it off
@@ -2485,7 +2440,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        if (ext4_blocks_count(es) > 0xffffffffULL &&
            !jbd2_journal_set_features(EXT4_SB(sb)->s_journal, 0, 0,
                                       JBD2_FEATURE_INCOMPAT_64BIT)) {
-               printk(KERN_ERR "ext4: Failed to set 64-bit journal feature\n");
+               printk(KERN_ERR "EXT4-fs: Failed to set 64-bit journal feature\n");
                goto failed_mount4;
        }
 
@@ -2766,7 +2721,7 @@ static journal_t *ext4_get_dev_journal(struct super_block *sb,
 
        if (bd_claim(bdev, sb)) {
                printk(KERN_ERR
-                       "EXT4: failed to claim external journal device.\n");
+                       "EXT4-fs: failed to claim external journal device.\n");
                blkdev_put(bdev, FMODE_READ|FMODE_WRITE);
                return NULL;
        }
@@ -2933,13 +2888,14 @@ static int ext4_load_journal(struct super_block *sb,
        return 0;
 }
 
-static void ext4_commit_super(struct super_block *sb,
+static int ext4_commit_super(struct super_block *sb,
                              struct ext4_super_block *es, int sync)
 {
        struct buffer_head *sbh = EXT4_SB(sb)->s_sbh;
+       int error = 0;
 
        if (!sbh)
-               return;
+               return error;
        if (buffer_write_io_error(sbh)) {
                /*
                 * Oh, dear.  A previous attempt to write the
@@ -2949,7 +2905,7 @@ static void ext4_commit_super(struct super_block *sb,
                 * be remapped.  Nothing we can do but to retry the
                 * write and hope for the best.
                 */
-               printk(KERN_ERR "ext4: previous I/O error to "
+               printk(KERN_ERR "EXT4-fs: previous I/O error to "
                       "superblock detected for %s.\n", sb->s_id);
                clear_buffer_write_io_error(sbh);
                set_buffer_uptodate(sbh);
@@ -2963,14 +2919,19 @@ static void ext4_commit_super(struct super_block *sb,
        BUFFER_TRACE(sbh, "marking dirty");
        mark_buffer_dirty(sbh);
        if (sync) {
-               sync_dirty_buffer(sbh);
-               if (buffer_write_io_error(sbh)) {
-                       printk(KERN_ERR "ext4: I/O error while writing "
+               error = sync_dirty_buffer(sbh);
+               if (error)
+                       return error;
+
+               error = buffer_write_io_error(sbh);
+               if (error) {
+                       printk(KERN_ERR "EXT4-fs: I/O error while writing "
                               "superblock for %s.\n", sb->s_id);
                        clear_buffer_write_io_error(sbh);
                        set_buffer_uptodate(sbh);
                }
        }
+       return error;
 }
 
 
@@ -3103,12 +3064,14 @@ static int ext4_sync_fs(struct super_block *sb, int wait)
  * LVM calls this function before a (read-only) snapshot is created.  This
  * gives us a chance to flush the journal completely and mark the fs clean.
  */
-static void ext4_write_super_lockfs(struct super_block *sb)
+static int ext4_freeze(struct super_block *sb)
 {
+       int error = 0;
+       journal_t *journal;
        sb->s_dirt = 0;
 
        if (!(sb->s_flags & MS_RDONLY)) {
-               journal_t *journal = EXT4_SB(sb)->s_journal;
+               journal = EXT4_SB(sb)->s_journal;
 
                if (journal) {
                        /* Now we set up the journal barrier. */
@@ -3118,21 +3081,29 @@ static void ext4_write_super_lockfs(struct super_block *sb)
                         * We don't want to clear needs_recovery flag when we
                         * failed to flush the journal.
                         */
-                       if (jbd2_journal_flush(journal) < 0)
-                               return;
+                       error = jbd2_journal_flush(journal);
+                       if (error < 0)
+                               goto out;
                }
 
                /* Journal blocked and flushed, clear needs_recovery flag. */
                EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
                ext4_commit_super(sb, EXT4_SB(sb)->s_es, 1);
+               error = ext4_commit_super(sb, EXT4_SB(sb)->s_es, 1);
+               if (error)
+                       goto out;
        }
+       return 0;
+out:
+       jbd2_journal_unlock_updates(journal);
+       return error;
 }
 
 /*
  * Called by LVM after the snapshot is done.  We need to reset the RECOVER
  * flag here, even though the filesystem is not technically dirty yet.
  */
-static void ext4_unlockfs(struct super_block *sb)
+static int ext4_unfreeze(struct super_block *sb)
 {
        if (EXT4_SB(sb)->s_journal && !(sb->s_flags & MS_RDONLY)) {
                lock_super(sb);
@@ -3142,6 +3113,7 @@ static void ext4_unlockfs(struct super_block *sb)
                unlock_super(sb);
                jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
        }
+       return 0;
 }
 
 static int ext4_remount(struct super_block *sb, int *flags, char *data)
@@ -3825,7 +3797,7 @@ static void __exit exit_ext4_fs(void)
 }
 
 MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others");
-MODULE_DESCRIPTION("Fourth Extended Filesystem with extents");
+MODULE_DESCRIPTION("Fourth Extended Filesystem");
 MODULE_LICENSE("GPL");
 module_init(init_ext4_fs)
 module_exit(exit_ext4_fs)