exec: replace call_usermodehelper_pipe with use of umh init function and resolve...
[safe/jmp/linux-2.6] / fs / ext3 / super.c
index 7ad1e8c..0fc1293 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.
  */
 
@@ -181,7 +181,7 @@ static void ext3_handle_error(struct super_block *sb)
        if (!test_opt (sb, ERRORS_CONT)) {
                journal_t *journal = EXT3_SB(sb)->s_journal;
 
-               EXT3_SB(sb)->s_mount_opt |= EXT3_MOUNT_ABORT;
+               set_opt(EXT3_SB(sb)->s_mount_opt, ABORT);
                if (journal)
                        journal_abort(journal, -EIO);
        }
@@ -296,7 +296,7 @@ void ext3_abort (struct super_block * sb, const char * function,
                "error: remounting filesystem read-only");
        EXT3_SB(sb)->s_mount_state |= EXT3_ERROR_FS;
        sb->s_flags |= MS_RDONLY;
-       EXT3_SB(sb)->s_mount_opt |= EXT3_MOUNT_ABORT;
+       set_opt(EXT3_SB(sb)->s_mount_opt, ABORT);
        if (EXT3_SB(sb)->s_journal)
                journal_abort(EXT3_SB(sb)->s_journal, -EIO);
 }
@@ -528,6 +528,8 @@ static void destroy_inodecache(void)
 static void ext3_clear_inode(struct inode *inode)
 {
        struct ext3_block_alloc_info *rsv = EXT3_I(inode)->i_block_alloc_info;
+
+       dquot_drop(inode);
        ext3_discard_reservation(inode);
        EXT3_I(inode)->i_block_alloc_info = NULL;
        if (unlikely(rsv))
@@ -562,10 +564,10 @@ static inline void ext3_show_quota_options(struct seq_file *seq, struct super_bl
        if (sbi->s_qf_names[GRPQUOTA])
                seq_printf(seq, ",grpjquota=%s", sbi->s_qf_names[GRPQUOTA]);
 
-       if (sbi->s_mount_opt & EXT3_MOUNT_USRQUOTA)
+       if (test_opt(sb, USRQUOTA))
                seq_puts(seq, ",usrquota");
 
-       if (sbi->s_mount_opt & EXT3_MOUNT_GRPQUOTA)
+       if (test_opt(sb, GRPQUOTA))
                seq_puts(seq, ",grpquota");
 #endif
 }
@@ -651,13 +653,16 @@ 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");
+
+       /*
+        * 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");
        if (test_opt(sb, NOBH))
                seq_puts(seq, ",nobh");
 
-       seq_printf(seq, ",data=%s", data_mode_string(sbi->s_mount_opt &
-                                                    EXT3_MOUNT_DATA_FLAGS));
+       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");
 
@@ -751,13 +756,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,
-       .alloc_space    = dquot_alloc_space,
-       .alloc_inode    = dquot_alloc_inode,
-       .free_space     = dquot_free_space,
-       .free_inode     = dquot_free_inode,
-       .transfer       = dquot_transfer,
        .write_dquot    = ext3_write_dquot,
        .acquire_dquot  = ext3_acquire_dquot,
        .release_dquot  = ext3_release_dquot,
@@ -816,8 +814,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 = {
@@ -871,6 +869,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},
 };
@@ -896,6 +896,63 @@ static ext3_fsblk_t get_sb_block(void **data, struct super_block *sb)
        return sb_block;
 }
 
+#ifdef CONFIG_QUOTA
+static int set_qf_name(struct super_block *sb, int qtype, substring_t *args)
+{
+       struct ext3_sb_info *sbi = EXT3_SB(sb);
+       char *qname;
+
+       if (sb_any_quota_loaded(sb) &&
+               !sbi->s_qf_names[qtype]) {
+               ext3_msg(sb, KERN_ERR,
+                       "Cannot change journaled "
+                       "quota options when quota turned on");
+               return 0;
+       }
+       qname = match_strdup(args);
+       if (!qname) {
+               ext3_msg(sb, KERN_ERR,
+                       "Not enough memory for storing quotafile name");
+               return 0;
+       }
+       if (sbi->s_qf_names[qtype] &&
+               strcmp(sbi->s_qf_names[qtype], qname)) {
+               ext3_msg(sb, KERN_ERR,
+                       "%s quota file already specified", QTYPE2NAME(qtype));
+               kfree(qname);
+               return 0;
+       }
+       sbi->s_qf_names[qtype] = qname;
+       if (strchr(sbi->s_qf_names[qtype], '/')) {
+               ext3_msg(sb, KERN_ERR,
+                       "quotafile must be on filesystem root");
+               kfree(sbi->s_qf_names[qtype]);
+               sbi->s_qf_names[qtype] = NULL;
+               return 0;
+       }
+       set_opt(sbi->s_mount_opt, QUOTA);
+       return 1;
+}
+
+static int clear_qf_name(struct super_block *sb, int qtype) {
+
+       struct ext3_sb_info *sbi = EXT3_SB(sb);
+
+       if (sb_any_quota_loaded(sb) &&
+               sbi->s_qf_names[qtype]) {
+               ext3_msg(sb, KERN_ERR, "Cannot change journaled quota options"
+                       " when quota turned on");
+               return 0;
+       }
+       /*
+        * The space will be released later when all options are confirmed
+        * to be correct
+        */
+       sbi->s_qf_names[qtype] = NULL;
+       return 1;
+}
+#endif
+
 static int parse_options (char *options, struct super_block *sb,
                          unsigned int *inum, unsigned long *journal_devnum,
                          ext3_fsblk_t *n_blocks_count, int is_remount)
@@ -906,8 +963,7 @@ static int parse_options (char *options, struct super_block *sb,
        int data_opt = 0;
        int option;
 #ifdef CONFIG_QUOTA
-       int qtype, qfmt;
-       char *qname;
+       int qfmt;
 #endif
 
        if (!options)
@@ -917,7 +973,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:
@@ -1065,20 +1125,19 @@ static int parse_options (char *options, struct super_block *sb,
                        data_opt = EXT3_MOUNT_WRITEBACK_DATA;
                datacheck:
                        if (is_remount) {
-                               if ((sbi->s_mount_opt & EXT3_MOUNT_DATA_FLAGS)
-                                               == data_opt)
+                               if (test_opt(sb, DATA_FLAGS) == data_opt)
                                        break;
                                ext3_msg(sb, KERN_ERR,
                                        "error: cannot change "
                                        "data mode on remount. The filesystem "
                                        "is mounted in data=%s mode and you "
                                        "try to remount it in data=%s mode.",
-                                       data_mode_string(sbi->s_mount_opt &
-                                                       EXT3_MOUNT_DATA_FLAGS),
+                                       data_mode_string(test_opt(sb,
+                                                       DATA_FLAGS)),
                                        data_mode_string(data_opt));
                                return 0;
                        } else {
-                               sbi->s_mount_opt &= ~EXT3_MOUNT_DATA_FLAGS;
+                               clear_opt(sbi->s_mount_opt, DATA_FLAGS);
                                sbi->s_mount_opt |= data_opt;
                        }
                        break;
@@ -1090,62 +1149,20 @@ static int parse_options (char *options, struct super_block *sb,
                        break;
 #ifdef CONFIG_QUOTA
                case Opt_usrjquota:
-                       qtype = USRQUOTA;
-                       goto set_qf_name;
-               case Opt_grpjquota:
-                       qtype = GRPQUOTA;
-set_qf_name:
-                       if (sb_any_quota_loaded(sb) &&
-                           !sbi->s_qf_names[qtype]) {
-                               ext3_msg(sb, KERN_ERR,
-                                       "error: cannot change journaled "
-                                       "quota options when quota turned on.");
+                       if (!set_qf_name(sb, USRQUOTA, &args[0]))
                                return 0;
-                       }
-                       qname = match_strdup(&args[0]);
-                       if (!qname) {
-                               ext3_msg(sb, KERN_ERR,
-                                       "error: not enough memory for "
-                                       "storing quotafile name.");
-                               return 0;
-                       }
-                       if (sbi->s_qf_names[qtype] &&
-                           strcmp(sbi->s_qf_names[qtype], qname)) {
-                               ext3_msg(sb, KERN_ERR,
-                                       "error: %s quota file already "
-                                       "specified.", QTYPE2NAME(qtype));
-                               kfree(qname);
-                               return 0;
-                       }
-                       sbi->s_qf_names[qtype] = qname;
-                       if (strchr(sbi->s_qf_names[qtype], '/')) {
-                               ext3_msg(sb, KERN_ERR,
-                                       "error: quotafile must be on "
-                                       "filesystem root.");
-                               kfree(sbi->s_qf_names[qtype]);
-                               sbi->s_qf_names[qtype] = NULL;
+                       break;
+               case Opt_grpjquota:
+                       if (!set_qf_name(sb, GRPQUOTA, &args[0]))
                                return 0;
-                       }
-                       set_opt(sbi->s_mount_opt, QUOTA);
                        break;
                case Opt_offusrjquota:
-                       qtype = USRQUOTA;
-                       goto clear_qf_name;
+                       if (!clear_qf_name(sb, USRQUOTA))
+                               return 0;
+                       break;
                case Opt_offgrpjquota:
-                       qtype = GRPQUOTA;
-clear_qf_name:
-                       if (sb_any_quota_loaded(sb) &&
-                           sbi->s_qf_names[qtype]) {
-                               ext3_msg(sb, KERN_ERR, "error: cannot change "
-                                       "journaled quota options when "
-                                       "quota turned on.");
+                       if (!clear_qf_name(sb, GRPQUOTA))
                                return 0;
-                       }
-                       /*
-                        * The space will be released later when all options
-                        * are confirmed to be correct
-                        */
-                       sbi->s_qf_names[qtype] = NULL;
                        break;
                case Opt_jqfmt_vfsold:
                        qfmt = QFMT_VFS_OLD;
@@ -1208,9 +1225,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
@@ -1244,18 +1267,12 @@ set_qf_format:
        }
 #ifdef CONFIG_QUOTA
        if (sbi->s_qf_names[USRQUOTA] || sbi->s_qf_names[GRPQUOTA]) {
-               if ((sbi->s_mount_opt & EXT3_MOUNT_USRQUOTA) &&
-                    sbi->s_qf_names[USRQUOTA])
+               if (test_opt(sb, USRQUOTA) && sbi->s_qf_names[USRQUOTA])
                        clear_opt(sbi->s_mount_opt, USRQUOTA);
-
-               if ((sbi->s_mount_opt & EXT3_MOUNT_GRPQUOTA) &&
-                    sbi->s_qf_names[GRPQUOTA])
+               if (test_opt(sb, GRPQUOTA) && sbi->s_qf_names[GRPQUOTA])
                        clear_opt(sbi->s_mount_opt, GRPQUOTA);
 
-               if ((sbi->s_qf_names[USRQUOTA] &&
-                               (sbi->s_mount_opt & EXT3_MOUNT_GRPQUOTA)) ||
-                   (sbi->s_qf_names[GRPQUOTA] &&
-                               (sbi->s_mount_opt & EXT3_MOUNT_USRQUOTA))) {
+               if (test_opt(sb, GRPQUOTA) || test_opt(sb, USRQUOTA)) {
                        ext3_msg(sb, KERN_ERR, "error: old and new quota "
                                        "format mixing.");
                        return 0;
@@ -1478,7 +1495,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",
@@ -1671,11 +1688,11 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
                set_opt(sbi->s_mount_opt, POSIX_ACL);
 #endif
        if ((def_mount_opts & EXT3_DEFM_JMODE) == EXT3_DEFM_JMODE_DATA)
-               sbi->s_mount_opt |= EXT3_MOUNT_JOURNAL_DATA;
+               set_opt(sbi->s_mount_opt, JOURNAL_DATA);
        else if ((def_mount_opts & EXT3_DEFM_JMODE) == EXT3_DEFM_JMODE_ORDERED)
-               sbi->s_mount_opt |= EXT3_MOUNT_ORDERED_DATA;
+               set_opt(sbi->s_mount_opt, ORDERED_DATA);
        else if ((def_mount_opts & EXT3_DEFM_JMODE) == EXT3_DEFM_JMODE_WBACK)
-               sbi->s_mount_opt |= EXT3_MOUNT_WRITEBACK_DATA;
+               set_opt(sbi->s_mount_opt, WRITEBACK_DATA);
 
        if (le16_to_cpu(sbi->s_es->s_errors) == EXT3_ERRORS_PANIC)
                set_opt(sbi->s_mount_opt, ERRORS_PANIC);
@@ -1694,7 +1711,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
                goto failed_mount;
 
        sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
-               ((sbi->s_mount_opt & EXT3_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0);
+               (test_opt(sb, POSIX_ACL) ? MS_POSIXACL : 0);
 
        if (le32_to_cpu(es->s_rev_level) == EXT3_GOOD_OLD_REV &&
            (EXT3_HAS_COMPAT_FEATURE(sb, ~0U) ||
@@ -1889,21 +1906,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;
@@ -1928,6 +1930,8 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
        sb->dq_op = &ext3_quota_operations;
 #endif
        INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */
+       mutex_init(&sbi->s_orphan_lock);
+       mutex_init(&sbi->s_resize_lock);
 
        sb->s_root = NULL;
 
@@ -1942,15 +1946,29 @@ 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");
                goto failed_mount3;
        }
 
@@ -1975,7 +1993,7 @@ 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;
@@ -1998,30 +2016,23 @@ 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);
-       /*
-        * akpm: core read_super() calls in here with the superblock locked.
-        * That deadlocks, because orphan cleanup needs to lock the superblock
-        * in numerous places.  Here we just pop the lock - it's relatively
-        * harmless, because we are now ready to accept write_super() requests,
-        * and aviro says that's the only reason for hanging onto the
-        * superblock lock.
-        */
+
        EXT3_SB(sb)->s_mount_state |= EXT3_ORPHAN_FS;
        ext3_orphan_cleanup(sb, es);
        EXT3_SB(sb)->s_mount_state &= ~EXT3_ORPHAN_FS;
@@ -2043,12 +2054,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]);
@@ -2282,6 +2292,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)  {
@@ -2403,13 +2416,11 @@ static void ext3_mark_recovery_complete(struct super_block * sb,
        if (journal_flush(journal) < 0)
                goto out;
 
-       lock_super(sb);
        if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER) &&
            sb->s_flags & MS_RDONLY) {
                EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER);
                ext3_commit_super(sb, es, 1);
        }
-       unlock_super(sb);
 
 out:
        journal_unlock_updates(journal);
@@ -2568,11 +2579,11 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
                goto restore_opts;
        }
 
-       if (sbi->s_mount_opt & EXT3_MOUNT_ABORT)
+       if (test_opt(sb, ABORT))
                ext3_abort(sb, __func__, "Abort forced by user");
 
        sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
-               ((sbi->s_mount_opt & EXT3_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0);
+               (test_opt(sb, POSIX_ACL) ? MS_POSIXACL : 0);
 
        es = sbi->s_es;
 
@@ -2580,7 +2591,7 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
 
        if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY) ||
                n_blocks_count > le32_to_cpu(es->s_blocks_count)) {
-               if (sbi->s_mount_opt & EXT3_MOUNT_ABORT) {
+               if (test_opt(sb, ABORT)) {
                        err = -EROFS;
                        goto restore_opts;
                }
@@ -2601,13 +2612,7 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
                            (sbi->s_mount_state & EXT3_VALID_FS))
                                es->s_state = cpu_to_le16(sbi->s_mount_state);
 
-                       /*
-                        * We have to unlock super so that we can wait for
-                        * transactions.
-                        */
-                       unlock_super(sb);
                        ext3_mark_recovery_complete(sb, es);
-                       lock_super(sb);
                } else {
                        __le32 ret;
                        if ((ret = EXT3_HAS_RO_COMPAT_FEATURE(sb,
@@ -2747,7 +2752,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()
  *
  */
@@ -2955,9 +2960,7 @@ static ssize_t ext3_quota_write(struct super_block *sb, int type,
        sector_t blk = off >> EXT3_BLOCK_SIZE_BITS(sb);
        int err = 0;
        int offset = off & (sb->s_blocksize - 1);
-       int tocopy;
        int journal_quota = EXT3_SB(sb)->s_qf_names[type] != NULL;
-       size_t towrite = len;
        struct buffer_head *bh;
        handle_t *handle = journal_current_handle();
 
@@ -2968,53 +2971,54 @@ static ssize_t ext3_quota_write(struct super_block *sb, int type,
                        (unsigned long long)off, (unsigned long long)len);
                return -EIO;
        }
+
+       /*
+        * Since we account only one data block in transaction credits,
+        * then it is impossible to cross a block boundary.
+        */
+       if (sb->s_blocksize - offset < len) {
+               ext3_msg(sb, KERN_WARNING, "Quota write (off=%llu, len=%llu)"
+                       " cancelled because not block aligned",
+                       (unsigned long long)off, (unsigned long long)len);
+               return -EIO;
+       }
        mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA);
-       while (towrite > 0) {
-               tocopy = sb->s_blocksize - offset < towrite ?
-                               sb->s_blocksize - offset : towrite;
-               bh = ext3_bread(handle, inode, blk, 1, &err);
-               if (!bh)
+       bh = ext3_bread(handle, inode, blk, 1, &err);
+       if (!bh)
+               goto out;
+       if (journal_quota) {
+               err = ext3_journal_get_write_access(handle, bh);
+               if (err) {
+                       brelse(bh);
                        goto out;
-               if (journal_quota) {
-                       err = ext3_journal_get_write_access(handle, bh);
-                       if (err) {
-                               brelse(bh);
-                               goto out;
-                       }
-               }
-               lock_buffer(bh);
-               memcpy(bh->b_data+offset, data, tocopy);
-               flush_dcache_page(bh->b_page);
-               unlock_buffer(bh);
-               if (journal_quota)
-                       err = ext3_journal_dirty_metadata(handle, bh);
-               else {
-                       /* Always do at least ordered writes for quotas */
-                       err = ext3_journal_dirty_data(handle, bh);
-                       mark_buffer_dirty(bh);
                }
-               brelse(bh);
-               if (err)
-                       goto out;
-               offset = 0;
-               towrite -= tocopy;
-               data += tocopy;
-               blk++;
        }
+       lock_buffer(bh);
+       memcpy(bh->b_data+offset, data, len);
+       flush_dcache_page(bh->b_page);
+       unlock_buffer(bh);
+       if (journal_quota)
+               err = ext3_journal_dirty_metadata(handle, bh);
+       else {
+               /* Always do at least ordered writes for quotas */
+               err = ext3_journal_dirty_data(handle, bh);
+               mark_buffer_dirty(bh);
+       }
+       brelse(bh);
 out:
-       if (len == towrite) {
+       if (err) {
                mutex_unlock(&inode->i_mutex);
                return err;
        }
-       if (inode->i_size < off+len-towrite) {
-               i_size_write(inode, off+len-towrite);
+       if (inode->i_size < off + len) {
+               i_size_write(inode, off + len);
                EXT3_I(inode)->i_disksize = inode->i_size;
        }
        inode->i_version++;
        inode->i_mtime = inode->i_ctime = CURRENT_TIME;
        ext3_mark_inode_dirty(handle, inode);
        mutex_unlock(&inode->i_mutex);
-       return len - towrite;
+       return len;
 }
 
 #endif