Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux...
[safe/jmp/linux-2.6] / fs / reiserfs / super.c
index 5b68dd3..5dbafb7 100644 (file)
 #include <linux/blkdev.h>
 #include <linux/buffer_head.h>
 #include <linux/exportfs.h>
+#include <linux/quotaops.h>
 #include <linux/vfs.h>
 #include <linux/mnt_namespace.h>
 #include <linux/mount.h>
 #include <linux/namei.h>
-#include <linux/quotaops.h>
 
 struct file_system_type reiserfs_fs_type;
 
@@ -83,7 +83,7 @@ static void reiserfs_write_super(struct super_block *s)
        reiserfs_sync_fs(s, 1);
 }
 
-static void reiserfs_write_super_lockfs(struct super_block *s)
+static int reiserfs_freeze(struct super_block *s)
 {
        struct reiserfs_transaction_handle th;
        reiserfs_write_lock(s);
@@ -101,11 +101,13 @@ static void reiserfs_write_super_lockfs(struct super_block *s)
        }
        s->s_dirt = 0;
        reiserfs_write_unlock(s);
+       return 0;
 }
 
-static void reiserfs_unlockfs(struct super_block *s)
+static int reiserfs_unfreeze(struct super_block *s)
 {
        reiserfs_allow_writes(s);
+       return 0;
 }
 
 extern const struct in_core_key MAX_IN_CORE_KEY;
@@ -145,7 +147,7 @@ static int finish_unfinished(struct super_block *s)
 {
        INITIALIZE_PATH(path);
        struct cpu_key max_cpu_key, obj_key;
-       struct reiserfs_key save_link_key;
+       struct reiserfs_key save_link_key, last_inode_key;
        int retval = 0;
        struct item_head *ih;
        struct buffer_head *bh;
@@ -166,6 +168,8 @@ static int finish_unfinished(struct super_block *s)
        set_cpu_key_k_offset(&max_cpu_key, ~0U);
        max_cpu_key.key_length = 3;
 
+       memset(&last_inode_key, 0, sizeof(last_inode_key));
+
 #ifdef CONFIG_QUOTA
        /* Needed for iput() to work correctly and not trash data */
        if (s->s_flags & MS_ACTIVE) {
@@ -180,7 +184,7 @@ static int finish_unfinished(struct super_block *s)
                        int ret = reiserfs_quota_on_mount(s, i);
                        if (ret < 0)
                                reiserfs_warning(s,
-                                                "reiserfs: cannot turn on journalled quota: error %d",
+                                                "reiserfs: cannot turn on journaled quota: error %d",
                                                 ret);
                }
        }
@@ -246,7 +250,7 @@ static int finish_unfinished(struct super_block *s)
                        retval = remove_save_link_only(s, &save_link_key, 0);
                        continue;
                }
-               DQUOT_INIT(inode);
+               vfs_dq_init(inode);
 
                if (truncate && S_ISDIR(inode->i_mode)) {
                        /* We got a truncate request for a dir which is impossible.
@@ -278,8 +282,18 @@ static int finish_unfinished(struct super_block *s)
                        REISERFS_I(inode)->i_flags |= i_link_saved_unlink_mask;
                        /* not completed unlink (rmdir) found */
                        reiserfs_info(s, "Removing %k..", INODE_PKEY(inode));
-                       /* removal gets completed in iput */
-                       retval = 0;
+                       if (memcmp(&last_inode_key, INODE_PKEY(inode),
+                                       sizeof(last_inode_key))){
+                               last_inode_key = *INODE_PKEY(inode);
+                               /* removal gets completed in iput */
+                               retval = 0;
+                       } else {
+                               reiserfs_warning(s, "Dead loop in "
+                                               "finish_unfinished detected, "
+                                               "just remove save link\n");
+                               retval = remove_save_link_only(s,
+                                                       &save_link_key, 0);
+                       }
                }
 
                iput(inode);
@@ -292,7 +306,7 @@ static int finish_unfinished(struct super_block *s)
        /* Turn quotas off */
        for (i = 0; i < MAXQUOTAS; i++) {
                if (sb_dqopt(s)->files[i])
-                       vfs_quota_off_mount(s, i);
+                       vfs_quota_off(s, i, 0);
        }
        if (ms_active_set)
                /* Restore the flag back */
@@ -307,7 +321,7 @@ static int finish_unfinished(struct super_block *s)
 
 /* to protect file being unlinked from getting lost we "safe" link files
    being unlinked. This link will be deleted in the same transaction with last
-   item of file. mounting the filesytem we scan all these links and remove
+   item of file. mounting the filesystem we scan all these links and remove
    files which almost got lost */
 void add_save_link(struct reiserfs_transaction_handle *th,
                   struct inode *inode, int truncate)
@@ -508,7 +522,7 @@ static void reiserfs_destroy_inode(struct inode *inode)
        kmem_cache_free(reiserfs_inode_cachep, REISERFS_I(inode));
 }
 
-static void init_once(void *foo, struct kmem_cache * cachep, unsigned long flags)
+static void init_once(void *foo)
 {
        struct reiserfs_inode_info *ei = (struct reiserfs_inode_info *)foo;
 
@@ -601,10 +615,11 @@ static const struct super_operations reiserfs_sops = {
        .put_super = reiserfs_put_super,
        .write_super = reiserfs_write_super,
        .sync_fs = reiserfs_sync_fs,
-       .write_super_lockfs = reiserfs_write_super_lockfs,
-       .unlockfs = reiserfs_unlockfs,
+       .freeze_fs = reiserfs_freeze,
+       .unfreeze_fs = reiserfs_unfreeze,
        .statfs = reiserfs_statfs,
        .remount_fs = reiserfs_remount,
+       .show_options = generic_show_options,
 #ifdef CONFIG_QUOTA
        .quota_read = reiserfs_quota_read,
        .quota_write = reiserfs_quota_write,
@@ -614,18 +629,16 @@ static const struct super_operations reiserfs_sops = {
 #ifdef CONFIG_QUOTA
 #define QTYPE2NAME(t) ((t)==USRQUOTA?"user":"group")
 
-static int reiserfs_dquot_initialize(struct inode *, int);
-static int reiserfs_dquot_drop(struct inode *);
 static int reiserfs_write_dquot(struct dquot *);
 static int reiserfs_acquire_dquot(struct dquot *);
 static int reiserfs_release_dquot(struct dquot *);
 static int reiserfs_mark_dquot_dirty(struct dquot *);
 static int reiserfs_write_info(struct super_block *, int);
-static int reiserfs_quota_on(struct super_block *, int, int, char *);
+static int reiserfs_quota_on(struct super_block *, int, int, char *, int);
 
 static struct dquot_operations reiserfs_quota_operations = {
-       .initialize = reiserfs_dquot_initialize,
-       .drop = reiserfs_dquot_drop,
+       .initialize = dquot_initialize,
+       .drop = dquot_drop,
        .alloc_space = dquot_alloc_space,
        .alloc_inode = dquot_alloc_inode,
        .free_space = dquot_free_space,
@@ -636,6 +649,8 @@ static struct dquot_operations reiserfs_quota_operations = {
        .release_dquot = reiserfs_release_dquot,
        .mark_dirty = reiserfs_mark_dquot_dirty,
        .write_info = reiserfs_write_info,
+       .alloc_dquot    = dquot_alloc,
+       .destroy_dquot  = dquot_destroy,
 };
 
 static struct quotactl_ops reiserfs_qctl_operations = {
@@ -649,11 +664,11 @@ static struct quotactl_ops reiserfs_qctl_operations = {
 };
 #endif
 
-static struct export_operations reiserfs_export_ops = {
+static const struct export_operations reiserfs_export_ops = {
        .encode_fh = reiserfs_encode_fh,
-       .decode_fh = reiserfs_decode_fh,
+       .fh_to_dentry = reiserfs_fh_to_dentry,
+       .fh_to_parent = reiserfs_fh_to_parent,
        .get_parent = reiserfs_get_parent,
-       .get_dentry = reiserfs_get_dentry,
 };
 
 /* this struct is used in reiserfs_getopt () for containing the value for those
@@ -863,7 +878,9 @@ static int reiserfs_parse_options(struct super_block *s, char *options,     /* strin
                                     mount options were selected. */
                                  unsigned long *blocks,        /* strtol-ed from NNN of resize=NNN */
                                  char **jdev_name,
-                                 unsigned int *commit_max_age)
+                                 unsigned int *commit_max_age,
+                                 char **qf_names,
+                                 unsigned int *qfmt)
 {
        int c;
        char *arg = NULL;
@@ -979,9 +996,10 @@ static int reiserfs_parse_options(struct super_block *s, char *options,    /* strin
                if (c == 'u' || c == 'g') {
                        int qtype = c == 'u' ? USRQUOTA : GRPQUOTA;
 
-                       if (sb_any_quota_enabled(s)) {
+                       if (sb_any_quota_loaded(s) &&
+                           (!*arg != !REISERFS_SB(s)->s_qf_names[qtype])) {
                                reiserfs_warning(s,
-                                                "reiserfs_parse_options: cannot change journalled quota options when quota turned on.");
+                                                "reiserfs_parse_options: cannot change journaled quota options when quota turned on.");
                                return 0;
                        }
                        if (*arg) {     /* Some filename specified? */
@@ -998,51 +1016,58 @@ static int reiserfs_parse_options(struct super_block *s, char *options,  /* strin
                                                         "reiserfs_parse_options: quotafile must be on filesystem root.");
                                        return 0;
                                }
-                               REISERFS_SB(s)->s_qf_names[qtype] =
+                               qf_names[qtype] =
                                    kmalloc(strlen(arg) + 1, GFP_KERNEL);
-                               if (!REISERFS_SB(s)->s_qf_names[qtype]) {
+                               if (!qf_names[qtype]) {
                                        reiserfs_warning(s,
                                                         "reiserfs_parse_options: not enough memory for storing quotafile name.");
                                        return 0;
                                }
-                               strcpy(REISERFS_SB(s)->s_qf_names[qtype], arg);
+                               strcpy(qf_names[qtype], arg);
                                *mount_options |= 1 << REISERFS_QUOTA;
                        } else {
-                               kfree(REISERFS_SB(s)->s_qf_names[qtype]);
-                               REISERFS_SB(s)->s_qf_names[qtype] = NULL;
+                               if (qf_names[qtype] !=
+                                   REISERFS_SB(s)->s_qf_names[qtype])
+                                       kfree(qf_names[qtype]);
+                               qf_names[qtype] = NULL;
                        }
                }
                if (c == 'f') {
                        if (!strcmp(arg, "vfsold"))
-                               REISERFS_SB(s)->s_jquota_fmt = QFMT_VFS_OLD;
+                               *qfmt = QFMT_VFS_OLD;
                        else if (!strcmp(arg, "vfsv0"))
-                               REISERFS_SB(s)->s_jquota_fmt = QFMT_VFS_V0;
+                               *qfmt = QFMT_VFS_V0;
                        else {
                                reiserfs_warning(s,
                                                 "reiserfs_parse_options: unknown quota format specified.");
                                return 0;
                        }
+                       if (sb_any_quota_loaded(s) &&
+                           *qfmt != REISERFS_SB(s)->s_jquota_fmt) {
+                               reiserfs_warning(s,
+                                                "reiserfs_parse_options: cannot change journaled quota options when quota turned on.");
+                               return 0;
+                       }
                }
 #else
                if (c == 'u' || c == 'g' || c == 'f') {
                        reiserfs_warning(s,
-                                        "reiserfs_parse_options: journalled quota options not supported.");
+                                        "reiserfs_parse_options: journaled quota options not supported.");
                        return 0;
                }
 #endif
        }
 
 #ifdef CONFIG_QUOTA
-       if (!REISERFS_SB(s)->s_jquota_fmt
-           && (REISERFS_SB(s)->s_qf_names[USRQUOTA]
-               || REISERFS_SB(s)->s_qf_names[GRPQUOTA])) {
+       if (!REISERFS_SB(s)->s_jquota_fmt && !*qfmt
+           && (qf_names[USRQUOTA] || qf_names[GRPQUOTA])) {
                reiserfs_warning(s,
-                                "reiserfs_parse_options: journalled quota format not specified.");
+                                "reiserfs_parse_options: journaled quota format not specified.");
                return 0;
        }
        /* This checking is not precise wrt the quota type but for our purposes it is sufficient */
        if (!(*mount_options & (1 << REISERFS_QUOTA))
-           && sb_any_quota_enabled(s)) {
+           && sb_any_quota_loaded(s)) {
                reiserfs_warning(s,
                                 "reiserfs_parse_options: quota options must be present when quota is turned on.");
                return 0;
@@ -1117,6 +1142,21 @@ static void handle_attrs(struct super_block *s)
        }
 }
 
+#ifdef CONFIG_QUOTA
+static void handle_quota_files(struct super_block *s, char **qf_names,
+                              unsigned int *qfmt)
+{
+       int i;
+
+       for (i = 0; i < MAXQUOTAS; i++) {
+               if (qf_names[i] != REISERFS_SB(s)->s_qf_names[i])
+                       kfree(REISERFS_SB(s)->s_qf_names[i]);
+               REISERFS_SB(s)->s_qf_names[i] = qf_names[i];
+       }
+       REISERFS_SB(s)->s_jquota_fmt = *qfmt;
+}
+#endif
+
 static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
 {
        struct reiserfs_super_block *rs;
@@ -1126,23 +1166,32 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
        unsigned long safe_mask = 0;
        unsigned int commit_max_age = (unsigned int)-1;
        struct reiserfs_journal *journal = SB_JOURNAL(s);
+       char *new_opts = kstrdup(arg, GFP_KERNEL);
        int err;
+       char *qf_names[MAXQUOTAS];
+       unsigned int qfmt = 0;
 #ifdef CONFIG_QUOTA
        int i;
+
+       memcpy(qf_names, REISERFS_SB(s)->s_qf_names, sizeof(qf_names));
 #endif
 
        rs = SB_DISK_SUPER_BLOCK(s);
 
        if (!reiserfs_parse_options
-           (s, arg, &mount_options, &blocks, NULL, &commit_max_age)) {
+           (s, arg, &mount_options, &blocks, NULL, &commit_max_age,
+           qf_names, &qfmt)) {
 #ifdef CONFIG_QUOTA
-               for (i = 0; i < MAXQUOTAS; i++) {
-                       kfree(REISERFS_SB(s)->s_qf_names[i]);
-                       REISERFS_SB(s)->s_qf_names[i] = NULL;
-               }
+               for (i = 0; i < MAXQUOTAS; i++)
+                       if (qf_names[i] != REISERFS_SB(s)->s_qf_names[i])
+                               kfree(qf_names[i]);
 #endif
-               return -EINVAL;
+               err = -EINVAL;
+               goto out_err;
        }
+#ifdef CONFIG_QUOTA
+       handle_quota_files(s, qf_names, &qfmt);
+#endif
 
        handle_attrs(s);
 
@@ -1179,9 +1228,9 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
        }
 
        if (blocks) {
-               int rc = reiserfs_resize(s, blocks);
-               if (rc != 0)
-                       return rc;
+               err = reiserfs_resize(s, blocks);
+               if (err != 0)
+                       goto out_err;
        }
 
        if (*mount_flags & MS_RDONLY) {
@@ -1189,16 +1238,16 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
                /* remount read-only */
                if (s->s_flags & MS_RDONLY)
                        /* it is read-only already */
-                       return 0;
+                       goto out_ok;
                /* try to remount file system with read-only permissions */
                if (sb_umount_state(rs) == REISERFS_VALID_FS
                    || REISERFS_SB(s)->s_mount_state != REISERFS_VALID_FS) {
-                       return 0;
+                       goto out_ok;
                }
 
                err = journal_begin(&th, s, 10);
                if (err)
-                       return err;
+                       goto out_err;
 
                /* Mounting a rw partition read-only. */
                reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
@@ -1208,11 +1257,13 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
                /* remount read-write */
                if (!(s->s_flags & MS_RDONLY)) {
                        reiserfs_xattr_init(s, *mount_flags);
-                       return 0;       /* We are read-write already */
+                       goto out_ok;    /* We are read-write already */
                }
 
-               if (reiserfs_is_journal_aborted(journal))
-                       return journal->j_errno;
+               if (reiserfs_is_journal_aborted(journal)) {
+                       err = journal->j_errno;
+                       goto out_err;
+               }
 
                handle_data_mode(s, mount_options);
                handle_barrier_mode(s, mount_options);
@@ -1220,7 +1271,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
                s->s_flags &= ~MS_RDONLY;       /* now it is safe to call journal_begin */
                err = journal_begin(&th, s, 10);
                if (err)
-                       return err;
+                       goto out_err;
 
                /* Mount a partition which is read-only, read-write */
                reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
@@ -1235,7 +1286,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
        SB_JOURNAL(s)->j_must_wait = 1;
        err = journal_end(&th, s, 10);
        if (err)
-               return err;
+               goto out_err;
        s->s_dirt = 0;
 
        if (!(*mount_flags & MS_RDONLY)) {
@@ -1243,7 +1294,14 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
                reiserfs_xattr_init(s, *mount_flags);
        }
 
+out_ok:
+       kfree(s->s_options);
+       s->s_options = new_opts;
        return 0;
+
+out_err:
+       kfree(new_opts);
+       return err;
 }
 
 static int read_super_block(struct super_block *s, int offset)
@@ -1546,6 +1604,10 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
        char *jdev_name;
        struct reiserfs_sb_info *sbi;
        int errval = -EINVAL;
+       char *qf_names[MAXQUOTAS] = {};
+       unsigned int qfmt = 0;
+
+       save_mount_options(s, data);
 
        sbi = kzalloc(sizeof(struct reiserfs_sb_info), GFP_KERNEL);
        if (!sbi) {
@@ -1571,9 +1633,12 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
        jdev_name = NULL;
        if (reiserfs_parse_options
            (s, (char *)data, &(sbi->s_mount_opt), &blocks, &jdev_name,
-            &commit_max_age) == 0) {
+            &commit_max_age, qf_names, &qfmt) == 0) {
                goto error;
        }
+#ifdef CONFIG_QUOTA
+       handle_quota_files(s, qf_names, &qfmt);
+#endif
 
        if (blocks) {
                SWARN(silent, s, "jmacd-7: reiserfs_fill_super: resize option "
@@ -1713,6 +1778,21 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
                set_sb_umount_state(rs, REISERFS_ERROR_FS);
                set_sb_fs_state(rs, 0);
 
+               /* Clear out s_bmap_nr if it would wrap. We can handle this
+                * case, but older revisions can't. This will cause the
+                * file system to fail mount on those older implementations,
+                * avoiding corruption. -jeffm */
+               if (bmap_would_wrap(reiserfs_bmap_count(s)) &&
+                   sb_bmap_nr(rs) != 0) {
+                       reiserfs_warning(s, "super-2030: This file system "
+                                       "claims to use %u bitmap blocks in "
+                                       "its super block, but requires %u. "
+                                       "Clearing to zero.", sb_bmap_nr(rs),
+                                       reiserfs_bmap_count(s));
+
+                       set_sb_bmap_nr(rs, 0);
+               }
+
                if (old_format_only(s)) {
                        /* filesystem of format 3.5 either with standard or non-standard
                           journal */
@@ -1778,7 +1858,7 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
 
        return (0);
 
-      error:
+error:
        if (jinit_done) {       /* kill the commit thread, free journal ram */
                journal_release_error(NULL, s);
        }
@@ -1789,10 +1869,8 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
 #ifdef CONFIG_QUOTA
        {
                int j;
-               for (j = 0; j < MAXQUOTAS; j++) {
-                       kfree(sbi->s_qf_names[j]);
-                       sbi->s_qf_names[j] = NULL;
-               }
+               for (j = 0; j < MAXQUOTAS; j++)
+                       kfree(qf_names[j]);
        }
 #endif
        kfree(sbi);
@@ -1816,52 +1894,6 @@ static int reiserfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 }
 
 #ifdef CONFIG_QUOTA
-static int reiserfs_dquot_initialize(struct inode *inode, int type)
-{
-       struct reiserfs_transaction_handle th;
-       int ret, err;
-
-       /* We may create quota structure so we need to reserve enough blocks */
-       reiserfs_write_lock(inode->i_sb);
-       ret =
-           journal_begin(&th, inode->i_sb,
-                         2 * REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb));
-       if (ret)
-               goto out;
-       ret = dquot_initialize(inode, type);
-       err =
-           journal_end(&th, inode->i_sb,
-                       2 * REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb));
-       if (!ret && err)
-               ret = err;
-      out:
-       reiserfs_write_unlock(inode->i_sb);
-       return ret;
-}
-
-static int reiserfs_dquot_drop(struct inode *inode)
-{
-       struct reiserfs_transaction_handle th;
-       int ret, err;
-
-       /* We may delete quota structure so we need to reserve enough blocks */
-       reiserfs_write_lock(inode->i_sb);
-       ret =
-           journal_begin(&th, inode->i_sb,
-                         2 * REISERFS_QUOTA_DEL_BLOCKS(inode->i_sb));
-       if (ret)
-               goto out;
-       ret = dquot_drop(inode);
-       err =
-           journal_end(&th, inode->i_sb,
-                       2 * REISERFS_QUOTA_DEL_BLOCKS(inode->i_sb));
-       if (!ret && err)
-               ret = err;
-      out:
-       reiserfs_write_unlock(inode->i_sb);
-       return ret;
-}
-
 static int reiserfs_write_dquot(struct dquot *dquot)
 {
        struct reiserfs_transaction_handle th;
@@ -1915,8 +1947,11 @@ static int reiserfs_release_dquot(struct dquot *dquot)
        ret =
            journal_begin(&th, dquot->dq_sb,
                          REISERFS_QUOTA_DEL_BLOCKS(dquot->dq_sb));
-       if (ret)
+       if (ret) {
+               /* Release dquot anyway to avoid endless cycle in dqput() */
+               dquot_release(dquot);
                goto out;
+       }
        ret = dquot_release(dquot);
        err =
            journal_end(&th, dquot->dq_sb,
@@ -1930,7 +1965,7 @@ static int reiserfs_release_dquot(struct dquot *dquot)
 
 static int reiserfs_mark_dquot_dirty(struct dquot *dquot)
 {
-       /* Are we journalling quotas? */
+       /* Are we journaling quotas? */
        if (REISERFS_SB(dquot->dq_sb)->s_qf_names[USRQUOTA] ||
            REISERFS_SB(dquot->dq_sb)->s_qf_names[GRPQUOTA]) {
                dquot_mark_dquot_dirty(dquot);
@@ -1971,41 +2006,65 @@ static int reiserfs_quota_on_mount(struct super_block *sb, int type)
  * Standard function to be called on quota_on
  */
 static int reiserfs_quota_on(struct super_block *sb, int type, int format_id,
-                            char *path)
+                            char *name, int remount)
 {
        int err;
-       struct nameidata nd;
+       struct path path;
+       struct inode *inode;
+       struct reiserfs_transaction_handle th;
 
        if (!(REISERFS_SB(sb)->s_mount_opt & (1 << REISERFS_QUOTA)))
                return -EINVAL;
-       err = path_lookup(path, LOOKUP_FOLLOW, &nd);
+       /* No more checks needed? Path and format_id are bogus anyway... */
+       if (remount)
+               return vfs_quota_on(sb, type, format_id, name, 1);
+       err = kern_path(name, LOOKUP_FOLLOW, &path);
        if (err)
                return err;
        /* Quotafile not on the same filesystem? */
-       if (nd.mnt->mnt_sb != sb) {
-               path_release(&nd);
-               return -EXDEV;
+       if (path.mnt->mnt_sb != sb) {
+               err = -EXDEV;
+               goto out;
        }
+       inode = path.dentry->d_inode;
        /* We must not pack tails for quota files on reiserfs for quota IO to work */
-       if (!REISERFS_I(nd.dentry->d_inode)->i_flags & i_nopack_mask) {
-               reiserfs_warning(sb,
-                                "reiserfs: Quota file must have tail packing disabled.");
-               path_release(&nd);
-               return -EINVAL;
-       }
-       /* Not journalling quota? No more tests needed... */
-       if (!REISERFS_SB(sb)->s_qf_names[USRQUOTA] &&
-           !REISERFS_SB(sb)->s_qf_names[GRPQUOTA]) {
-               path_release(&nd);
-               return vfs_quota_on(sb, type, format_id, path);
+       if (!(REISERFS_I(inode)->i_flags & i_nopack_mask)) {
+               err = reiserfs_unpack(inode, NULL);
+               if (err) {
+                       reiserfs_warning(sb,
+                               "reiserfs: Unpacking tail of quota file failed"
+                               " (%d). Cannot turn on quotas.", err);
+                       err = -EINVAL;
+                       goto out;
+               }
+               mark_inode_dirty(inode);
        }
-       /* Quotafile not of fs root? */
-       if (nd.dentry->d_parent->d_inode != sb->s_root->d_inode)
-               reiserfs_warning(sb,
+       /* Journaling quota? */
+       if (REISERFS_SB(sb)->s_qf_names[type]) {
+               /* Quotafile not of fs root? */
+               if (path.dentry->d_parent != sb->s_root)
+                       reiserfs_warning(sb,
                                 "reiserfs: Quota file not on filesystem root. "
                                 "Journalled quota will not work.");
-       path_release(&nd);
-       return vfs_quota_on(sb, type, format_id, path);
+       }
+
+       /*
+        * When we journal data on quota file, we have to flush journal to see
+        * all updates to the file when we bypass pagecache...
+        */
+       if (reiserfs_file_data_log(inode)) {
+               /* Just start temporary transaction and finish it */
+               err = journal_begin(&th, sb, 1);
+               if (err)
+                       goto out;
+               err = journal_end_sync(&th, sb, 1);
+               if (err)
+                       goto out;
+       }
+       err = vfs_quota_on_path(sb, type, format_id, &path);
+out:
+       path_put(&path);
+       return err;
 }
 
 /* Read data from quotafile - avoid pagecache and such because we cannot afford
@@ -2067,6 +2126,12 @@ static ssize_t reiserfs_quota_write(struct super_block *sb, int type,
        size_t towrite = len;
        struct buffer_head tmp_bh, *bh;
 
+       if (!current->journal_info) {
+               printk(KERN_WARNING "reiserfs: Quota write (off=%Lu, len=%Lu)"
+                       " cancelled because transaction is not started.\n",
+                       (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 ?
@@ -2098,9 +2163,11 @@ static ssize_t reiserfs_quota_write(struct super_block *sb, int type,
                data += tocopy;
                blk++;
        }
-      out:
-       if (len == towrite)
+out:
+       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++;