nilfs2: fix lock order reversal in chcp operation
[safe/jmp/linux-2.6] / fs / ext2 / super.c
index 1ba18b7..1a9ffee 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/seq_file.h>
 #include <linux/mount.h>
 #include <linux/log2.h>
+#include <linux/quotaops.h>
 #include <asm/uaccess.h>
 #include "ext2.h"
 #include "xattr.h"
@@ -41,6 +42,7 @@ static void ext2_sync_super(struct super_block *sb,
                            struct ext2_super_block *es);
 static int ext2_remount (struct super_block * sb, int * flags, char * data);
 static int ext2_statfs (struct dentry * dentry, struct kstatfs * buf);
+static int ext2_sync_fs(struct super_block *sb, int wait);
 
 void ext2_error (struct super_block * sb, const char * function,
                 const char * fmt, ...)
@@ -51,8 +53,7 @@ void ext2_error (struct super_block * sb, const char * function,
 
        if (!(sb->s_flags & MS_RDONLY)) {
                sbi->s_mount_state |= EXT2_ERROR_FS;
-               es->s_state =
-                       cpu_to_le16(le16_to_cpu(es->s_state) | EXT2_ERROR_FS);
+               es->s_state |= cpu_to_le16(EXT2_ERROR_FS);
                ext2_sync_super(sb, es);
        }
 
@@ -90,7 +91,7 @@ void ext2_update_dynamic_rev(struct super_block *sb)
        if (le32_to_cpu(es->s_rev_level) > EXT2_GOOD_OLD_REV)
                return;
 
-       ext2_warning(sb, __FUNCTION__,
+       ext2_warning(sb, __func__,
                     "updating to rev %d because of new feature flag, "
                     "running e2fsck is recommended",
                     EXT2_DYNAMIC_REV);
@@ -114,6 +115,11 @@ static void ext2_put_super (struct super_block * sb)
        int i;
        struct ext2_sb_info *sbi = EXT2_SB(sb);
 
+       lock_kernel();
+
+       if (sb->s_dirt)
+               ext2_write_super(sb);
+
        ext2_xattr_put_super(sb);
        if (!(sb->s_flags & MS_RDONLY)) {
                struct ext2_super_block *es = sbi->s_es;
@@ -132,9 +138,10 @@ static void ext2_put_super (struct super_block * sb)
        percpu_counter_destroy(&sbi->s_dirs_counter);
        brelse (sbi->s_sbh);
        sb->s_fs_info = NULL;
+       kfree(sbi->s_blockgroup_lock);
        kfree(sbi);
 
-       return;
+       unlock_kernel();
 }
 
 static struct kmem_cache * ext2_inode_cachep;
@@ -145,10 +152,6 @@ static struct inode *ext2_alloc_inode(struct super_block *sb)
        ei = (struct ext2_inode_info *)kmem_cache_alloc(ext2_inode_cachep, GFP_KERNEL);
        if (!ei)
                return NULL;
-#ifdef CONFIG_EXT2_FS_POSIX_ACL
-       ei->i_acl = EXT2_ACL_NOT_CACHED;
-       ei->i_default_acl = EXT2_ACL_NOT_CACHED;
-#endif
        ei->i_block_alloc_info = NULL;
        ei->vfs_inode.i_version = 1;
        return &ei->vfs_inode;
@@ -159,7 +162,7 @@ static void ext2_destroy_inode(struct inode *inode)
        kmem_cache_free(ext2_inode_cachep, EXT2_I(inode));
 }
 
-static void init_once(struct kmem_cache * cachep, void *foo)
+static void init_once(void *foo)
 {
        struct ext2_inode_info *ei = (struct ext2_inode_info *) foo;
 
@@ -191,18 +194,6 @@ static void destroy_inodecache(void)
 static void ext2_clear_inode(struct inode *inode)
 {
        struct ext2_block_alloc_info *rsv = EXT2_I(inode)->i_block_alloc_info;
-#ifdef CONFIG_EXT2_FS_POSIX_ACL
-       struct ext2_inode_info *ei = EXT2_I(inode);
-
-       if (ei->i_acl && ei->i_acl != EXT2_ACL_NOT_CACHED) {
-               posix_acl_release(ei->i_acl);
-               ei->i_acl = EXT2_ACL_NOT_CACHED;
-       }
-       if (ei->i_default_acl && ei->i_default_acl != EXT2_ACL_NOT_CACHED) {
-               posix_acl_release(ei->i_default_acl);
-               ei->i_default_acl = EXT2_ACL_NOT_CACHED;
-       }
-#endif
        ext2_discard_reservation(inode);
        EXT2_I(inode)->i_block_alloc_info = NULL;
        if (unlikely(rsv))
@@ -285,6 +276,9 @@ static int ext2_show_options(struct seq_file *seq, struct vfsmount *vfs)
                seq_puts(seq, ",xip");
 #endif
 
+       if (!test_opt(sb, RESERVATION))
+               seq_puts(seq, ",noreservation");
+
        return 0;
 }
 
@@ -296,11 +290,11 @@ static ssize_t ext2_quota_write(struct super_block *sb, int type, const char *da
 static const struct super_operations ext2_sops = {
        .alloc_inode    = ext2_alloc_inode,
        .destroy_inode  = ext2_destroy_inode,
-       .read_inode     = ext2_read_inode,
        .write_inode    = ext2_write_inode,
        .delete_inode   = ext2_delete_inode,
        .put_super      = ext2_put_super,
        .write_super    = ext2_write_super,
+       .sync_fs        = ext2_sync_fs,
        .statfs         = ext2_statfs,
        .remount_fs     = ext2_remount,
        .clear_inode    = ext2_clear_inode,
@@ -326,11 +320,10 @@ static struct inode *ext2_nfs_get_inode(struct super_block *sb,
         * it might be "neater" to call ext2_get_inode first and check
         * if the inode is valid.....
         */
-       inode = iget(sb, ino);
-       if (inode == NULL)
-               return ERR_PTR(-ENOMEM);
-       if (is_bad_inode(inode) ||
-           (generation && inode->i_generation != generation)) {
+       inode = ext2_iget(sb, ino);
+       if (IS_ERR(inode))
+               return ERR_CAST(inode);
+       if (generation && inode->i_generation != generation) {
                /* we didn't find the right inode.. */
                iput(inode);
                return ERR_PTR(-ESTALE);
@@ -392,7 +385,7 @@ enum {
        Opt_usrquota, Opt_grpquota, Opt_reservation, Opt_noreservation
 };
 
-static match_table_t tokens = {
+static const match_table_t tokens = {
        {Opt_bsd_df, "bsddf"},
        {Opt_minix_df, "minixdf"},
        {Opt_grpid, "grpid"},
@@ -603,7 +596,7 @@ static int ext2_setup_super (struct super_block * sb,
                        "running e2fsck is recommended\n");
        if (!le16_to_cpu(es->s_max_mnt_count))
                es->s_max_mnt_count = cpu_to_le16(EXT2_DFL_MAX_MNT_COUNT);
-       es->s_mnt_count=cpu_to_le16(le16_to_cpu(es->s_mnt_count) + 1);
+       le16_add_cpu(&es->s_mnt_count, 1);
        ext2_write_super(sb);
        if (test_opt (sb, DEBUG))
                printk ("[EXT II FS %s, %s, bs=%lu, fs=%lu, gc=%lu, "
@@ -621,13 +614,13 @@ static int ext2_check_descriptors(struct super_block *sb)
 {
        int i;
        struct ext2_sb_info *sbi = EXT2_SB(sb);
-       unsigned long first_block = le32_to_cpu(sbi->s_es->s_first_data_block);
-       unsigned long last_block;
 
        ext2_debug ("Checking group descriptors");
 
        for (i = 0; i < sbi->s_groups_count; i++) {
                struct ext2_group_desc *gdp = ext2_get_group_desc(sb, i, NULL);
+               ext2_fsblk_t first_block = ext2_group_first_block_no(sb, i);
+               ext2_fsblk_t last_block;
 
                if (i == sbi->s_groups_count - 1)
                        last_block = le32_to_cpu(sbi->s_es->s_blocks_count) - 1;
@@ -663,7 +656,6 @@ static int ext2_check_descriptors(struct super_block *sb)
                                    i, (unsigned long) le32_to_cpu(gdp->bg_inode_table));
                        return 0;
                }
-               first_block += EXT2_BLOCKS_PER_GROUP(sb);
        }
        return 1;
 }
@@ -720,10 +712,9 @@ static unsigned long descriptor_loc(struct super_block *sb,
                                    int nr)
 {
        struct ext2_sb_info *sbi = EXT2_SB(sb);
-       unsigned long bg, first_data_block, first_meta_bg;
+       unsigned long bg, first_meta_bg;
        int has_super = 0;
        
-       first_data_block = le32_to_cpu(sbi->s_es->s_first_data_block);
        first_meta_bg = le32_to_cpu(sbi->s_es->s_first_meta_bg);
 
        if (!EXT2_HAS_INCOMPAT_FEATURE(sb, EXT2_FEATURE_INCOMPAT_META_BG) ||
@@ -732,7 +723,8 @@ static unsigned long descriptor_loc(struct super_block *sb,
        bg = sbi->s_desc_per_block * nr;
        if (ext2_bg_has_super(sb, bg))
                has_super = 1;
-       return (first_data_block + has_super + (bg * sbi->s_blocks_per_group));
+
+       return ext2_group_first_block_no(sb, bg) + has_super;
 }
 
 static int ext2_fill_super(struct super_block *sb, void *data, int silent)
@@ -746,6 +738,7 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
        unsigned long logic_sb_block;
        unsigned long offset = 0;
        unsigned long def_mount_opts;
+       long ret = -EINVAL;
        int blocksize = BLOCK_SIZE;
        int db_count;
        int i, j;
@@ -755,6 +748,13 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
        sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
        if (!sbi)
                return -ENOMEM;
+
+       sbi->s_blockgroup_lock =
+               kzalloc(sizeof(struct blockgroup_lock), GFP_KERNEL);
+       if (!sbi->s_blockgroup_lock) {
+               kfree(sbi);
+               return -ENOMEM;
+       }
        sb->s_fs_info = sbi;
        sbi->s_sb_block = sb_block;
 
@@ -982,7 +982,7 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
                printk ("EXT2-fs: not enough memory\n");
                goto failed_mount;
        }
-       bgl_lock_init(&sbi->s_blockgroup_lock);
+       bgl_lock_init(sbi->s_blockgroup_lock);
        sbi->s_debts = kcalloc(sbi->s_groups_count, sizeof(*sbi->s_debts), GFP_KERNEL);
        if (!sbi->s_debts) {
                printk ("EXT2-fs: not enough memory\n");
@@ -1041,21 +1041,26 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_op = &ext2_sops;
        sb->s_export_op = &ext2_export_ops;
        sb->s_xattr = ext2_xattr_handlers;
-       root = iget(sb, EXT2_ROOT_INO);
-       sb->s_root = d_alloc_root(root);
-       if (!sb->s_root) {
-               iput(root);
-               printk(KERN_ERR "EXT2-fs: get root inode failed\n");
+       root = ext2_iget(sb, EXT2_ROOT_INO);
+       if (IS_ERR(root)) {
+               ret = PTR_ERR(root);
                goto failed_mount3;
        }
        if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) {
-               dput(sb->s_root);
-               sb->s_root = NULL;
+               iput(root);
                printk(KERN_ERR "EXT2-fs: corrupt root inode, run e2fsck\n");
                goto failed_mount3;
        }
+
+       sb->s_root = d_alloc_root(root);
+       if (!sb->s_root) {
+               iput(root);
+               printk(KERN_ERR "EXT2-fs: get root inode failed\n");
+               ret = -ENOMEM;
+               goto failed_mount3;
+       }
        if (EXT2_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL))
-               ext2_warning(sb, __FUNCTION__,
+               ext2_warning(sb, __func__,
                        "mounting ext3 filesystem as ext2");
        ext2_setup_super (sb, es, sb->s_flags & MS_RDONLY);
        return 0;
@@ -1079,8 +1084,9 @@ failed_mount:
        brelse(bh);
 failed_sbi:
        sb->s_fs_info = NULL;
+       kfree(sbi->s_blockgroup_lock);
        kfree(sbi);
-       return -EINVAL;
+       return ret;
 }
 
 static void ext2_commit_super (struct super_block * sb,
@@ -1112,26 +1118,36 @@ static void ext2_sync_super(struct super_block *sb, struct ext2_super_block *es)
  * set s_state to EXT2_VALID_FS after some corrections.
  */
 
-void ext2_write_super (struct super_block * sb)
+static int ext2_sync_fs(struct super_block *sb, int wait)
 {
-       struct ext2_super_block * es;
+       struct ext2_super_block *es = EXT2_SB(sb)->s_es;
+
        lock_kernel();
-       if (!(sb->s_flags & MS_RDONLY)) {
-               es = EXT2_SB(sb)->s_es;
-
-               if (le16_to_cpu(es->s_state) & EXT2_VALID_FS) {
-                       ext2_debug ("setting valid to 0\n");
-                       es->s_state = cpu_to_le16(le16_to_cpu(es->s_state) &
-                                                 ~EXT2_VALID_FS);
-                       es->s_free_blocks_count = cpu_to_le32(ext2_count_free_blocks(sb));
-                       es->s_free_inodes_count = cpu_to_le32(ext2_count_free_inodes(sb));
-                       es->s_mtime = cpu_to_le32(get_seconds());
-                       ext2_sync_super(sb, es);
-               } else
-                       ext2_commit_super (sb, es);
+       if (es->s_state & cpu_to_le16(EXT2_VALID_FS)) {
+               ext2_debug("setting valid to 0\n");
+               es->s_state &= cpu_to_le16(~EXT2_VALID_FS);
+               es->s_free_blocks_count =
+                       cpu_to_le32(ext2_count_free_blocks(sb));
+               es->s_free_inodes_count =
+                       cpu_to_le32(ext2_count_free_inodes(sb));
+               es->s_mtime = cpu_to_le32(get_seconds());
+               ext2_sync_super(sb, es);
+       } else {
+               ext2_commit_super(sb, es);
        }
        sb->s_dirt = 0;
        unlock_kernel();
+
+       return 0;
+}
+
+
+void ext2_write_super(struct super_block *sb)
+{
+       if (!(sb->s_flags & MS_RDONLY))
+               ext2_sync_fs(sb, 1);
+       else
+               sb->s_dirt = 0;
 }
 
 static int ext2_remount (struct super_block * sb, int * flags, char * data)
@@ -1143,6 +1159,8 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data)
        unsigned long old_sb_flags;
        int err;
 
+       lock_kernel();
+
        /* Store the old options */
        old_sb_flags = sb->s_flags;
        old_opts.s_mount_opt = sbi->s_mount_opt;
@@ -1172,15 +1190,22 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data)
        es = sbi->s_es;
        if (((sbi->s_mount_opt & EXT2_MOUNT_XIP) !=
            (old_mount_opt & EXT2_MOUNT_XIP)) &&
-           invalidate_inodes(sb))
-               ext2_warning(sb, __FUNCTION__, "busy inodes while remounting "\
-                            "xip remain in cache (no functional problem)");
-       if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
+           invalidate_inodes(sb)) {
+               ext2_warning(sb, __func__, "refusing change of xip flag "
+                            "with busy inodes while remounting");
+               sbi->s_mount_opt &= ~EXT2_MOUNT_XIP;
+               sbi->s_mount_opt |= old_mount_opt & EXT2_MOUNT_XIP;
+       }
+       if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) {
+               unlock_kernel();
                return 0;
+       }
        if (*flags & MS_RDONLY) {
                if (le16_to_cpu(es->s_state) & EXT2_VALID_FS ||
-                   !(sbi->s_mount_state & EXT2_VALID_FS))
+                   !(sbi->s_mount_state & EXT2_VALID_FS)) {
+                       unlock_kernel();
                        return 0;
+               }
                /*
                 * OK, we are remounting a valid rw partition rdonly, so set
                 * the rdonly flag and then mark the partition as valid again.
@@ -1207,12 +1232,14 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data)
                        sb->s_flags &= ~MS_RDONLY;
        }
        ext2_sync_super(sb, es);
+       unlock_kernel();
        return 0;
 restore_opts:
        sbi->s_mount_opt = old_opts.s_mount_opt;
        sbi->s_resuid = old_opts.s_resuid;
        sbi->s_resgid = old_opts.s_resgid;
        sb->s_flags = old_sb_flags;
+       unlock_kernel();
        return err;
 }
 
@@ -1315,6 +1342,7 @@ static ssize_t ext2_quota_read(struct super_block *sb, int type, char *data,
                                sb->s_blocksize - offset : toread;
 
                tmp_bh.b_state = 0;
+               tmp_bh.b_size = sb->s_blocksize;
                err = ext2_get_block(inode, blk, &tmp_bh, 0);
                if (err < 0)
                        return err;
@@ -1378,8 +1406,10 @@ static ssize_t ext2_quota_write(struct super_block *sb, int type,
                blk++;
        }
 out:
-       if (len == towrite)
+       if (len == towrite) {
+               mutex_unlock(&inode->i_mutex);
                return err;
+       }
        if (inode->i_size < off+len-towrite)
                i_size_write(inode, off+len-towrite);
        inode->i_version++;