Merge branch 'master' into for-2.6.35
[pandora-kernel.git] / fs / ext2 / super.c
index 42e4a30..71e9eb1 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/random.h>
 #include <linux/buffer_head.h>
 #include <linux/exportfs.h>
-#include <linux/smp_lock.h>
 #include <linux/vfs.h>
 #include <linux/seq_file.h>
 #include <linux/mount.h>
@@ -39,7 +38,7 @@
 #include "xip.h"
 
 static void ext2_sync_super(struct super_block *sb,
-                           struct ext2_super_block *es);
+                           struct ext2_super_block *es, int wait);
 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);
@@ -52,9 +51,11 @@ void ext2_error (struct super_block * sb, const char * function,
        struct ext2_super_block *es = sbi->s_es;
 
        if (!(sb->s_flags & MS_RDONLY)) {
+               spin_lock(&sbi->s_lock);
                sbi->s_mount_state |= EXT2_ERROR_FS;
                es->s_state |= cpu_to_le16(EXT2_ERROR_FS);
-               ext2_sync_super(sb, es);
+               spin_unlock(&sbi->s_lock);
+               ext2_sync_super(sb, es, 1);
        }
 
        va_start(args, fmt);
@@ -84,6 +85,9 @@ void ext2_msg(struct super_block *sb, const char *prefix,
        va_end(args);
 }
 
+/*
+ * This must be called with sbi->s_lock held.
+ */
 void ext2_update_dynamic_rev(struct super_block *sb)
 {
        struct ext2_super_block *es = EXT2_SB(sb)->s_es;
@@ -115,8 +119,6 @@ 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);
 
@@ -124,8 +126,10 @@ static void ext2_put_super (struct super_block * sb)
        if (!(sb->s_flags & MS_RDONLY)) {
                struct ext2_super_block *es = sbi->s_es;
 
+               spin_lock(&sbi->s_lock);
                es->s_state = cpu_to_le16(sbi->s_mount_state);
-               ext2_sync_super(sb, es);
+               spin_unlock(&sbi->s_lock);
+               ext2_sync_super(sb, es, 1);
        }
        db_count = sbi->s_gdb_count;
        for (i = 0; i < db_count; i++)
@@ -140,8 +144,6 @@ static void ext2_put_super (struct super_block * sb)
        sb->s_fs_info = NULL;
        kfree(sbi->s_blockgroup_lock);
        kfree(sbi);
-
-       unlock_kernel();
 }
 
 static struct kmem_cache * ext2_inode_cachep;
@@ -209,6 +211,7 @@ static int ext2_show_options(struct seq_file *seq, struct vfsmount *vfs)
        struct ext2_super_block *es = sbi->s_es;
        unsigned long def_mount_opts;
 
+       spin_lock(&sbi->s_lock);
        def_mount_opts = le32_to_cpu(es->s_default_mount_opts);
 
        if (sbi->s_sb_block != 1)
@@ -281,6 +284,7 @@ static int ext2_show_options(struct seq_file *seq, struct vfsmount *vfs)
        if (!test_opt(sb, RESERVATION))
                seq_puts(seq, ",noreservation");
 
+       spin_unlock(&sbi->s_lock);
        return 0;
 }
 
@@ -606,7 +610,6 @@ static int ext2_setup_super (struct super_block * sb,
        if (!le16_to_cpu(es->s_max_mnt_count))
                es->s_max_mnt_count = cpu_to_le16(EXT2_DFL_MAX_MNT_COUNT);
        le16_add_cpu(&es->s_mnt_count, 1);
-       ext2_write_super(sb);
        if (test_opt (sb, DEBUG))
                ext2_msg(sb, KERN_INFO, "%s, %s, bs=%lu, fs=%lu, gc=%lu, "
                        "bpg=%lu, ipg=%lu, mo=%04lx]",
@@ -767,6 +770,8 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_fs_info = sbi;
        sbi->s_sb_block = sb_block;
 
+       spin_lock_init(&sbi->s_lock);
+
        /*
         * See what the current blocksize for the device is, and
         * use that as the blocksize.  Otherwise (or if the blocksize
@@ -1079,7 +1084,9 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
        if (EXT2_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL))
                ext2_msg(sb, KERN_WARNING,
                        "warning: mounting ext3 filesystem as ext2");
-       ext2_setup_super (sb, es, sb->s_flags & MS_RDONLY);
+       if (ext2_setup_super (sb, es, sb->s_flags & MS_RDONLY))
+               sb->s_flags |= MS_RDONLY;
+       ext2_write_super(sb);
        return 0;
 
 cantfind_ext2:
@@ -1120,30 +1127,26 @@ static void ext2_clear_super_error(struct super_block *sb)
                 * be remapped.  Nothing we can do but to retry the
                 * write and hope for the best.
                 */
-               printk(KERN_ERR "EXT2-fs: %s previous I/O error to "
-                      "superblock detected", sb->s_id);
+               ext2_msg(sb, KERN_ERR,
+                      "previous I/O error to superblock detected\n");
                clear_buffer_write_io_error(sbh);
                set_buffer_uptodate(sbh);
        }
 }
 
-static void ext2_commit_super (struct super_block * sb,
-                              struct ext2_super_block * es)
-{
-       ext2_clear_super_error(sb);
-       es->s_wtime = cpu_to_le32(get_seconds());
-       mark_buffer_dirty(EXT2_SB(sb)->s_sbh);
-       sb->s_dirt = 0;
-}
-
-static void ext2_sync_super(struct super_block *sb, struct ext2_super_block *es)
+static void ext2_sync_super(struct super_block *sb, struct ext2_super_block *es,
+                           int wait)
 {
        ext2_clear_super_error(sb);
+       spin_lock(&EXT2_SB(sb)->s_lock);
        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_wtime = cpu_to_le32(get_seconds());
+       /* unlock before we do IO */
+       spin_unlock(&EXT2_SB(sb)->s_lock);
        mark_buffer_dirty(EXT2_SB(sb)->s_sbh);
-       sync_dirty_buffer(EXT2_SB(sb)->s_sbh);
+       if (wait)
+               sync_dirty_buffer(EXT2_SB(sb)->s_sbh);
        sb->s_dirt = 0;
 }
 
@@ -1157,43 +1160,18 @@ static void ext2_sync_super(struct super_block *sb, struct ext2_super_block *es)
  * may have been checked while mounted and e2fsck may have
  * set s_state to EXT2_VALID_FS after some corrections.
  */
-
 static int ext2_sync_fs(struct super_block *sb, int wait)
 {
+       struct ext2_sb_info *sbi = EXT2_SB(sb);
        struct ext2_super_block *es = EXT2_SB(sb)->s_es;
-       struct buffer_head *sbh = EXT2_SB(sb)->s_sbh;
-
-       lock_kernel();
-       if (buffer_write_io_error(sbh)) {
-               /*
-                * Oh, dear.  A previous attempt to write the
-                * superblock failed.  This could happen because the
-                * USB device was yanked out.  Or it could happen to
-                * be a transient write error and maybe the block will
-                * be remapped.  Nothing we can do but to retry the
-                * write and hope for the best.
-                */
-               ext2_msg(sb, KERN_ERR,
-                      "previous I/O error to superblock detected\n");
-               clear_buffer_write_io_error(sbh);
-               set_buffer_uptodate(sbh);
-       }
 
+       spin_lock(&sbi->s_lock);
        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();
-
+       spin_unlock(&sbi->s_lock);
+       ext2_sync_super(sb, es, wait);
        return 0;
 }
 
@@ -1215,7 +1193,7 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data)
        unsigned long old_sb_flags;
        int err;
 
-       lock_kernel();
+       spin_lock(&sbi->s_lock);
 
        /* Store the old options */
        old_sb_flags = sb->s_flags;
@@ -1254,13 +1232,13 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data)
                sbi->s_mount_opt |= old_mount_opt & EXT2_MOUNT_XIP;
        }
        if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) {
-               unlock_kernel();
+               spin_unlock(&sbi->s_lock);
                return 0;
        }
        if (*flags & MS_RDONLY) {
                if (le16_to_cpu(es->s_state) & EXT2_VALID_FS ||
                    !(sbi->s_mount_state & EXT2_VALID_FS)) {
-                       unlock_kernel();
+                       spin_unlock(&sbi->s_lock);
                        return 0;
                }
                /*
@@ -1269,6 +1247,8 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data)
                 */
                es->s_state = cpu_to_le16(sbi->s_mount_state);
                es->s_mtime = cpu_to_le32(get_seconds());
+               spin_unlock(&sbi->s_lock);
+               ext2_sync_super(sb, es, 1);
        } else {
                __le32 ret = EXT2_HAS_RO_COMPAT_FEATURE(sb,
                                               ~EXT2_FEATURE_RO_COMPAT_SUPP);
@@ -1288,16 +1268,16 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data)
                sbi->s_mount_state = le16_to_cpu(es->s_state);
                if (!ext2_setup_super (sb, es, 0))
                        sb->s_flags &= ~MS_RDONLY;
+               spin_unlock(&sbi->s_lock);
+               ext2_write_super(sb);
        }
-       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();
+       spin_unlock(&sbi->s_lock);
        return err;
 }
 
@@ -1308,6 +1288,8 @@ static int ext2_statfs (struct dentry * dentry, struct kstatfs * buf)
        struct ext2_super_block *es = sbi->s_es;
        u64 fsid;
 
+       spin_lock(&sbi->s_lock);
+
        if (test_opt (sb, MINIX_DF))
                sbi->s_overhead_last = 0;
        else if (sbi->s_blocks_last != le32_to_cpu(es->s_blocks_count)) {
@@ -1362,6 +1344,7 @@ static int ext2_statfs (struct dentry * dentry, struct kstatfs * buf)
               le64_to_cpup((void *)es->s_uuid + sizeof(u64));
        buf->f_fsid.val[0] = fsid & 0xFFFFFFFFUL;
        buf->f_fsid.val[1] = (fsid >> 32) & 0xFFFFFFFFUL;
+       spin_unlock(&sbi->s_lock);
        return 0;
 }