ext3: Remove misplaced BUFFER_TRACE() in ext3_truncate()
[linux-2.6.git] / fs / ext3 / super.c
index 2277b1a..1c68751 100644 (file)
@@ -164,7 +164,7 @@ void ext3_msg(struct super_block *sb, const char *prefix,
  * write out the superblock safely.
  *
  * We'll just use the journal_abort() error code to record an error in
- * the journal instead.  On recovery, the journal will compain about
+ * the journal instead.  On recovery, the journal will complain about
  * that error until we've noted it down and cleared it.
  */
 
@@ -410,6 +410,8 @@ static void ext3_put_super (struct super_block * sb)
        struct ext3_super_block *es = sbi->s_es;
        int i, err;
 
+       dquot_disable(sb, -1, DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED);
+
        lock_kernel();
 
        ext3_xattr_put_super(sb);
@@ -525,17 +527,6 @@ static void destroy_inodecache(void)
        kmem_cache_destroy(ext3_inode_cachep);
 }
 
-static void ext3_clear_inode(struct inode *inode)
-{
-       struct ext3_block_alloc_info *rsv = EXT3_I(inode)->i_block_alloc_info;
-
-       vfs_dq_drop(inode);
-       ext3_discard_reservation(inode);
-       EXT3_I(inode)->i_block_alloc_info = NULL;
-       if (unlikely(rsv))
-               kfree(rsv);
-}
-
 static inline void ext3_show_quota_options(struct seq_file *seq, struct super_block *sb)
 {
 #if defined(CONFIG_QUOTA)
@@ -653,11 +644,12 @@ static int ext3_show_options(struct seq_file *seq, struct vfsmount *vfs)
                seq_printf(seq, ",commit=%u",
                           (unsigned) (sbi->s_commit_interval / HZ));
        }
-       if (test_opt(sb, BARRIER))
-               seq_puts(seq, ",barrier=1");
-       if (test_opt(sb, NOBH))
-               seq_puts(seq, ",nobh");
 
+       /*
+        * Always display barrier state so it's clear what the status is.
+        */
+       seq_puts(seq, ",barrier=");
+       seq_puts(seq, test_opt(sb, BARRIER) ? "1" : "0");
        seq_printf(seq, ",data=%s", data_mode_string(test_opt(sb, DATA_FLAGS)));
        if (test_opt(sb, DATA_ERR_ABORT))
                seq_puts(seq, ",data_err=abort");
@@ -744,7 +736,7 @@ static int ext3_release_dquot(struct dquot *dquot);
 static int ext3_mark_dquot_dirty(struct dquot *dquot);
 static int ext3_write_info(struct super_block *sb, int type);
 static int ext3_quota_on(struct super_block *sb, int type, int format_id,
-                               char *path, int remount);
+                               char *path);
 static int ext3_quota_on_mount(struct super_block *sb, int type);
 static ssize_t ext3_quota_read(struct super_block *sb, int type, char *data,
                               size_t len, loff_t off);
@@ -752,8 +744,6 @@ static ssize_t ext3_quota_write(struct super_block *sb, int type,
                                const char *data, size_t len, loff_t off);
 
 static const struct dquot_operations ext3_quota_operations = {
-       .initialize     = dquot_initialize,
-       .drop           = dquot_drop,
        .write_dquot    = ext3_write_dquot,
        .acquire_dquot  = ext3_acquire_dquot,
        .release_dquot  = ext3_release_dquot,
@@ -765,12 +755,12 @@ static const struct dquot_operations ext3_quota_operations = {
 
 static const struct quotactl_ops ext3_qctl_operations = {
        .quota_on       = ext3_quota_on,
-       .quota_off      = vfs_quota_off,
-       .quota_sync     = vfs_quota_sync,
-       .get_info       = vfs_get_dqinfo,
-       .set_info       = vfs_set_dqinfo,
-       .get_dqblk      = vfs_get_dqblk,
-       .set_dqblk      = vfs_set_dqblk
+       .quota_off      = dquot_quota_off,
+       .quota_sync     = dquot_quota_sync,
+       .get_info       = dquot_get_dqinfo,
+       .set_info       = dquot_set_dqinfo,
+       .get_dqblk      = dquot_get_dqblk,
+       .set_dqblk      = dquot_set_dqblk
 };
 #endif
 
@@ -779,14 +769,13 @@ static const struct super_operations ext3_sops = {
        .destroy_inode  = ext3_destroy_inode,
        .write_inode    = ext3_write_inode,
        .dirty_inode    = ext3_dirty_inode,
-       .delete_inode   = ext3_delete_inode,
+       .evict_inode    = ext3_evict_inode,
        .put_super      = ext3_put_super,
        .sync_fs        = ext3_sync_fs,
        .freeze_fs      = ext3_freeze,
        .unfreeze_fs    = ext3_unfreeze,
        .statfs         = ext3_statfs,
        .remount_fs     = ext3_remount,
-       .clear_inode    = ext3_clear_inode,
        .show_options   = ext3_show_options,
 #ifdef CONFIG_QUOTA
        .quota_read     = ext3_quota_read,
@@ -812,8 +801,8 @@ enum {
        Opt_data_err_abort, Opt_data_err_ignore,
        Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
        Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_jqfmt_vfsv1, Opt_quota,
-       Opt_noquota, Opt_ignore, Opt_barrier, Opt_err, Opt_resize,
-       Opt_usrquota, Opt_grpquota
+       Opt_noquota, Opt_ignore, Opt_barrier, Opt_nobarrier, Opt_err,
+       Opt_resize, Opt_usrquota, Opt_grpquota
 };
 
 static const match_table_t tokens = {
@@ -867,6 +856,8 @@ static const match_table_t tokens = {
        {Opt_quota, "quota"},
        {Opt_usrquota, "usrquota"},
        {Opt_barrier, "barrier=%u"},
+       {Opt_barrier, "barrier"},
+       {Opt_nobarrier, "nobarrier"},
        {Opt_resize, "resize"},
        {Opt_err, NULL},
 };
@@ -969,7 +960,11 @@ static int parse_options (char *options, struct super_block *sb,
                int token;
                if (!*p)
                        continue;
-
+               /*
+                * Initialize args struct so we know whether arg was
+                * found; some options take optional arguments.
+                */
+               args[0].to = args[0].from = 0;
                token = match_token(p, tokens, args);
                switch (token) {
                case Opt_bsd_df:
@@ -1217,9 +1212,15 @@ set_qf_format:
                case Opt_abort:
                        set_opt(sbi->s_mount_opt, ABORT);
                        break;
+               case Opt_nobarrier:
+                       clear_opt(sbi->s_mount_opt, BARRIER);
+                       break;
                case Opt_barrier:
-                       if (match_int(&args[0], &option))
-                               return 0;
+                       if (args[0].from) {
+                               if (match_int(&args[0], &option))
+                                       return 0;
+                       } else
+                               option = 1;     /* No argument, default to 1 */
                        if (option)
                                set_opt(sbi->s_mount_opt, BARRIER);
                        else
@@ -1239,10 +1240,12 @@ set_qf_format:
                        *n_blocks_count = option;
                        break;
                case Opt_nobh:
-                       set_opt(sbi->s_mount_opt, NOBH);
+                       ext3_msg(sb, KERN_WARNING,
+                               "warning: ignoring deprecated nobh option");
                        break;
                case Opt_bh:
-                       clear_opt(sbi->s_mount_opt, NOBH);
+                       ext3_msg(sb, KERN_WARNING,
+                               "warning: ignoring deprecated bh option");
                        break;
                default:
                        ext3_msg(sb, KERN_ERR,
@@ -1303,9 +1306,9 @@ static int ext3_setup_super(struct super_block *sb, struct ext3_super_block *es,
                ext3_msg(sb, KERN_WARNING,
                        "warning: mounting fs with errors, "
                        "running e2fsck is recommended");
-       else if ((__s16) le16_to_cpu(es->s_max_mnt_count) >= 0 &&
+       else if ((__s16) le16_to_cpu(es->s_max_mnt_count) > 0 &&
                 le16_to_cpu(es->s_mnt_count) >=
-                (unsigned short) (__s16) le16_to_cpu(es->s_max_mnt_count))
+                       le16_to_cpu(es->s_max_mnt_count))
                ext3_msg(sb, KERN_WARNING,
                        "warning: maximal mount count reached, "
                        "running e2fsck is recommended");
@@ -1322,7 +1325,7 @@ static int ext3_setup_super(struct super_block *sb, struct ext3_super_block *es,
                    valid forever! :) */
        es->s_state &= cpu_to_le16(~EXT3_VALID_FS);
 #endif
-       if (!(__s16) le16_to_cpu(es->s_max_mnt_count))
+       if (!le16_to_cpu(es->s_max_mnt_count))
                es->s_max_mnt_count = cpu_to_le16(EXT3_DFL_MAX_MNT_COUNT);
        le16_add_cpu(&es->s_mnt_count, 1);
        es->s_mtime = cpu_to_le32(get_seconds());
@@ -1481,7 +1484,7 @@ static void ext3_orphan_cleanup (struct super_block * sb,
                }
 
                list_add(&EXT3_I(inode)->i_orphan, &EXT3_SB(sb)->s_orphan);
-               vfs_dq_init(inode);
+               dquot_initialize(inode);
                if (inode->i_nlink) {
                        printk(KERN_DEBUG
                                "%s: truncating inode %lu to %Ld bytes\n",
@@ -1513,7 +1516,7 @@ static void ext3_orphan_cleanup (struct super_block * sb,
        /* Turn quotas off */
        for (i = 0; i < MAXQUOTAS; i++) {
                if (sb_dqopt(sb)->files[i])
-                       vfs_quota_off(sb, i, 0);
+                       dquot_quota_off(sb, i);
        }
 #endif
        sb->s_flags = s_flags; /* Restore MS_RDONLY status */
@@ -1651,7 +1654,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
         * Note: s_es must be initialized as soon as possible because
         *       some ext3 macro-instructions depend on its value
         */
-       es = (struct ext3_super_block *) (((char *)bh->b_data) + offset);
+       es = (struct ext3_super_block *) (bh->b_data + offset);
        sbi->s_es = es;
        sb->s_magic = le16_to_cpu(es->s_magic);
        if (sb->s_magic != EXT3_SUPER_MAGIC)
@@ -1762,7 +1765,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
                               "error: can't read superblock on 2nd try");
                        goto failed_mount;
                }
-               es = (struct ext3_super_block *)(((char *)bh->b_data) + offset);
+               es = (struct ext3_super_block *)(bh->b_data + offset);
                sbi->s_es = es;
                if (es->s_magic != cpu_to_le16(EXT3_SUPER_MAGIC)) {
                        ext3_msg(sb, KERN_ERR,
@@ -1861,13 +1864,13 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
        sbi->s_groups_count = ((le32_to_cpu(es->s_blocks_count) -
                               le32_to_cpu(es->s_first_data_block) - 1)
                                       / EXT3_BLOCKS_PER_GROUP(sb)) + 1;
-       db_count = (sbi->s_groups_count + EXT3_DESC_PER_BLOCK(sb) - 1) /
-                  EXT3_DESC_PER_BLOCK(sb);
+       db_count = DIV_ROUND_UP(sbi->s_groups_count, EXT3_DESC_PER_BLOCK(sb));
        sbi->s_group_desc = kmalloc(db_count * sizeof (struct buffer_head *),
                                    GFP_KERNEL);
        if (sbi->s_group_desc == NULL) {
                ext3_msg(sb, KERN_ERR,
                        "error: not enough memory");
+               ret = -ENOMEM;
                goto failed_mount;
        }
 
@@ -1892,21 +1895,6 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
        get_random_bytes(&sbi->s_next_generation, sizeof(u32));
        spin_lock_init(&sbi->s_next_gen_lock);
 
-       err = percpu_counter_init(&sbi->s_freeblocks_counter,
-                       ext3_count_free_blocks(sb));
-       if (!err) {
-               err = percpu_counter_init(&sbi->s_freeinodes_counter,
-                               ext3_count_free_inodes(sb));
-       }
-       if (!err) {
-               err = percpu_counter_init(&sbi->s_dirs_counter,
-                               ext3_count_dirs(sb));
-       }
-       if (err) {
-               ext3_msg(sb, KERN_ERR, "error: insufficient memory");
-               goto failed_mount3;
-       }
-
        /* per fileystem reservation list head & lock */
        spin_lock_init(&sbi->s_rsv_window_lock);
        sbi->s_rsv_window_root = RB_ROOT;
@@ -1947,15 +1935,30 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
        if (!test_opt(sb, NOLOAD) &&
            EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
                if (ext3_load_journal(sb, es, journal_devnum))
-                       goto failed_mount3;
+                       goto failed_mount2;
        } else if (journal_inum) {
                if (ext3_create_journal(sb, es, journal_inum))
-                       goto failed_mount3;
+                       goto failed_mount2;
        } else {
                if (!silent)
                        ext3_msg(sb, KERN_ERR,
                                "error: no journal found. "
                                "mounting ext3 over ext2?");
+               goto failed_mount2;
+       }
+       err = percpu_counter_init(&sbi->s_freeblocks_counter,
+                       ext3_count_free_blocks(sb));
+       if (!err) {
+               err = percpu_counter_init(&sbi->s_freeinodes_counter,
+                               ext3_count_free_inodes(sb));
+       }
+       if (!err) {
+               err = percpu_counter_init(&sbi->s_dirs_counter,
+                               ext3_count_dirs(sb));
+       }
+       if (err) {
+               ext3_msg(sb, KERN_ERR, "error: insufficient memory");
+               ret = err;
                goto failed_mount3;
        }
 
@@ -1980,20 +1983,12 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
                        ext3_msg(sb, KERN_ERR,
                                "error: journal does not support "
                                "requested data journaling mode");
-                       goto failed_mount4;
+                       goto failed_mount3;
                }
        default:
                break;
        }
 
-       if (test_opt(sb, NOBH)) {
-               if (!(test_opt(sb, DATA_FLAGS) == EXT3_MOUNT_WRITEBACK_DATA)) {
-                       ext3_msg(sb, KERN_WARNING,
-                               "warning: ignoring nobh option - "
-                               "it is supported only with writeback mode");
-                       clear_opt(sbi->s_mount_opt, NOBH);
-               }
-       }
        /*
         * The journal_load will have done any necessary log recovery,
         * so we can safely mount the rest of the filesystem now.
@@ -2003,19 +1998,19 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
        if (IS_ERR(root)) {
                ext3_msg(sb, KERN_ERR, "error: get root inode failed");
                ret = PTR_ERR(root);
-               goto failed_mount4;
+               goto failed_mount3;
        }
        if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) {
                iput(root);
                ext3_msg(sb, KERN_ERR, "error: corrupt root inode, run e2fsck");
-               goto failed_mount4;
+               goto failed_mount3;
        }
        sb->s_root = d_alloc_root(root);
        if (!sb->s_root) {
                ext3_msg(sb, KERN_ERR, "error: get root dentry failed");
                iput(root);
                ret = -ENOMEM;
-               goto failed_mount4;
+               goto failed_mount3;
        }
 
        ext3_setup_super (sb, es, sb->s_flags & MS_RDONLY);
@@ -2041,12 +2036,11 @@ cantfind_ext3:
                       sb->s_id);
        goto failed_mount;
 
-failed_mount4:
-       journal_destroy(sbi->s_journal);
 failed_mount3:
        percpu_counter_destroy(&sbi->s_freeblocks_counter);
        percpu_counter_destroy(&sbi->s_freeinodes_counter);
        percpu_counter_destroy(&sbi->s_dirs_counter);
+       journal_destroy(sbi->s_journal);
 failed_mount2:
        for (i = 0; i < db_count; i++)
                brelse(sbi->s_group_desc[i]);
@@ -2175,7 +2169,7 @@ static journal_t *ext3_get_dev_journal(struct super_block *sb,
                goto out_bdev;
        }
 
-       es = (struct ext3_super_block *) (((char *)bh->b_data) + offset);
+       es = (struct ext3_super_block *) (bh->b_data + offset);
        if ((le16_to_cpu(es->s_magic) != EXT3_SUPER_MAGIC) ||
            !(le32_to_cpu(es->s_feature_incompat) &
              EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) {
@@ -2280,6 +2274,9 @@ static int ext3_load_journal(struct super_block *sb,
                        return -EINVAL;
        }
 
+       if (!(journal->j_flags & JFS_BARRIER))
+               printk(KERN_INFO "EXT3-fs: barriers not enabled\n");
+
        if (!really_read_only && test_opt(sb, UPDATE_JOURNAL)) {
                err = journal_update_format(journal);
                if (err)  {
@@ -2365,6 +2362,21 @@ static int ext3_commit_super(struct super_block *sb,
 
        if (!sbh)
                return error;
+
+       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.
+                */
+               ext3_msg(sb, KERN_ERR, "previous I/O error to "
+                      "superblock detected");
+               clear_buffer_write_io_error(sbh);
+               set_buffer_uptodate(sbh);
+       }
        /*
         * If the file system is mounted read-only, don't update the
         * superblock write time.  This avoids updating the superblock
@@ -2381,8 +2393,15 @@ static int ext3_commit_super(struct super_block *sb,
        es->s_free_inodes_count = cpu_to_le32(ext3_count_free_inodes(sb));
        BUFFER_TRACE(sbh, "marking dirty");
        mark_buffer_dirty(sbh);
-       if (sync)
+       if (sync) {
                error = sync_dirty_buffer(sbh);
+               if (buffer_write_io_error(sbh)) {
+                       ext3_msg(sb, KERN_ERR, "I/O error while writing "
+                              "superblock");
+                       clear_buffer_write_io_error(sbh);
+                       set_buffer_uptodate(sbh);
+               }
+       }
        return error;
 }
 
@@ -2536,6 +2555,7 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
        ext3_fsblk_t n_blocks_count = 0;
        unsigned long old_sb_flags;
        struct ext3_mount_options old_opts;
+       int enable_quota = 0;
        int err;
 #ifdef CONFIG_QUOTA
        int i;
@@ -2582,6 +2602,10 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
                }
 
                if (*flags & MS_RDONLY) {
+                       err = dquot_suspend(sb, -1);
+                       if (err < 0)
+                               goto restore_opts;
+
                        /*
                         * First of all, the unconditional stuff we have to do
                         * to disable replay of the journal when we next remount
@@ -2636,6 +2660,7 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
                                goto restore_opts;
                        if (!ext3_setup_super (sb, es, 0))
                                sb->s_flags &= ~MS_RDONLY;
+                       enable_quota = 1;
                }
        }
 #ifdef CONFIG_QUOTA
@@ -2647,6 +2672,9 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
 #endif
        unlock_super(sb);
        unlock_kernel();
+
+       if (enable_quota)
+               dquot_resume(sb, -1);
        return 0;
 restore_opts:
        sb->s_flags = old_sb_flags;
@@ -2737,7 +2765,7 @@ static int ext3_statfs (struct dentry * dentry, struct kstatfs * buf)
  * Process 1                         Process 2
  * ext3_create()                     quota_sync()
  *   journal_start()                   write_dquot()
- *   vfs_dq_init()                       down(dqio_mutex)
+ *   dquot_initialize()                       down(dqio_mutex)
  *     down(dqio_mutex)                    journal_start()
  *
  */
@@ -2836,24 +2864,21 @@ static int ext3_write_info(struct super_block *sb, int type)
  */
 static int ext3_quota_on_mount(struct super_block *sb, int type)
 {
-       return vfs_quota_on_mount(sb, EXT3_SB(sb)->s_qf_names[type],
-                       EXT3_SB(sb)->s_jquota_fmt, type);
+       return dquot_quota_on_mount(sb, EXT3_SB(sb)->s_qf_names[type],
+                                       EXT3_SB(sb)->s_jquota_fmt, type);
 }
 
 /*
  * Standard function to be called on quota_on
  */
 static int ext3_quota_on(struct super_block *sb, int type, int format_id,
-                        char *name, int remount)
+                        char *name)
 {
        int err;
        struct path path;
 
        if (!test_opt(sb, QUOTA))
                return -EINVAL;
-       /* When remounting, no checks are needed and in fact, name is NULL */
-       if (remount)
-               return vfs_quota_on(sb, type, format_id, name, remount);
 
        err = kern_path(name, LOOKUP_FOLLOW, &path);
        if (err)
@@ -2891,7 +2916,7 @@ static int ext3_quota_on(struct super_block *sb, int type, int format_id,
                }
        }
 
-       err = vfs_quota_on_path(sb, type, format_id, &path);
+       err = dquot_quota_on_path(sb, type, format_id, &path);
        path_put(&path);
        return err;
 }