quota: use flags interface for dquot alloc/free space
[pandora-kernel.git] / fs / quota / dquot.c
index 3fc62b0..8c40c07 100644 (file)
@@ -80,8 +80,6 @@
 
 #include <asm/uaccess.h>
 
-#define __DQUOT_PARANOIA
-
 /*
  * There are three quota SMP locks. dq_list_lock protects all lists with quotas
  * and quota formats, dqstats structure containing statistics about the lists
  *
  * Any operation working on dquots via inode pointers must hold dqptr_sem.  If
  * operation is just reading pointers from inode (or not using them at all) the
- * read lock is enough. If pointers are altered function must hold write lock
- * (these locking rules also apply for S_NOQUOTA flag in the inode - note that
- * for altering the flag i_mutex is also needed).
+ * read lock is enough. If pointers are altered function must hold write lock.
+ * Special care needs to be taken about S_NOQUOTA inode flag (marking that
+ * inode is a quota file). Functions adding pointers from inode to dquots have
+ * to check this flag under dqptr_sem and then (if S_NOQUOTA is not set) they
+ * have to do all pointer modifications before dropping dqptr_sem. This makes
+ * sure they cannot race with quotaon which first sets S_NOQUOTA flag and
+ * then drops all pointers to dquots from an inode.
  *
  * Each dquot has its dq_lock mutex. Locked dquots might not be referenced
  * from inodes (dquot_alloc_space() and such don't check the dq_lock).
@@ -225,6 +227,9 @@ static struct hlist_head *dquot_hash;
 struct dqstats dqstats;
 EXPORT_SYMBOL(dqstats);
 
+static qsize_t inode_get_rsv_space(struct inode *inode);
+static void __dquot_initialize(struct inode *inode, int type);
+
 static inline unsigned int
 hashfn(const struct super_block *sb, unsigned int id, int type)
 {
@@ -564,7 +569,7 @@ out:
 }
 EXPORT_SYMBOL(dquot_scan_active);
 
-int vfs_quota_sync(struct super_block *sb, int type)
+int vfs_quota_sync(struct super_block *sb, int type, int wait)
 {
        struct list_head *dirty;
        struct dquot *dquot;
@@ -609,6 +614,33 @@ int vfs_quota_sync(struct super_block *sb, int type)
        spin_unlock(&dq_list_lock);
        mutex_unlock(&dqopt->dqonoff_mutex);
 
+       if (!wait || (sb_dqopt(sb)->flags & DQUOT_QUOTA_SYS_FILE))
+               return 0;
+
+       /* This is not very clever (and fast) but currently I don't know about
+        * any other simple way of getting quota data to disk and we must get
+        * them there for userspace to be visible... */
+       if (sb->s_op->sync_fs)
+               sb->s_op->sync_fs(sb, 1);
+       sync_blockdev(sb->s_bdev);
+
+       /*
+        * Now when everything is written we can discard the pagecache so
+        * that userspace sees the changes.
+        */
+       mutex_lock(&sb_dqopt(sb)->dqonoff_mutex);
+       for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+               if (type != -1 && cnt != type)
+                       continue;
+               if (!sb_has_quota_active(sb, cnt))
+                       continue;
+               mutex_lock_nested(&sb_dqopt(sb)->files[cnt]->i_mutex,
+                                 I_MUTEX_QUOTA);
+               truncate_inode_pages(&sb_dqopt(sb)->files[cnt]->i_data, 0);
+               mutex_unlock(&sb_dqopt(sb)->files[cnt]->i_mutex);
+       }
+       mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
+
        return 0;
 }
 EXPORT_SYMBOL(vfs_quota_sync);
@@ -661,7 +693,7 @@ void dqput(struct dquot *dquot)
 
        if (!dquot)
                return;
-#ifdef __DQUOT_PARANOIA
+#ifdef CONFIG_QUOTA_DEBUG
        if (!atomic_read(&dquot->dq_count)) {
                printk("VFS: dqput: trying to free free dquot\n");
                printk("VFS: device %s, dquot of %s %d\n",
@@ -714,7 +746,7 @@ we_slept:
                goto we_slept;
        }
        atomic_dec(&dquot->dq_count);
-#ifdef __DQUOT_PARANOIA
+#ifdef CONFIG_QUOTA_DEBUG
        /* sanity check */
        BUG_ON(!list_empty(&dquot->dq_free));
 #endif
@@ -811,7 +843,7 @@ we_slept:
                dquot = NULL;
                goto out;
        }
-#ifdef __DQUOT_PARANOIA
+#ifdef CONFIG_QUOTA_DEBUG
        BUG_ON(!dquot->dq_sb);  /* Has somebody invalidated entry under us? */
 #endif
 out:
@@ -840,11 +872,18 @@ static int dqinit_needed(struct inode *inode, int type)
 static void add_dquot_ref(struct super_block *sb, int type)
 {
        struct inode *inode, *old_inode = NULL;
+#ifdef CONFIG_QUOTA_DEBUG
+       int reserved = 0;
+#endif
 
        spin_lock(&inode_lock);
        list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
                if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE|I_NEW))
                        continue;
+#ifdef CONFIG_QUOTA_DEBUG
+               if (unlikely(inode_get_rsv_space(inode) > 0))
+                       reserved = 1;
+#endif
                if (!atomic_read(&inode->i_writecount))
                        continue;
                if (!dqinit_needed(inode, type))
@@ -854,7 +893,7 @@ static void add_dquot_ref(struct super_block *sb, int type)
                spin_unlock(&inode_lock);
 
                iput(old_inode);
-               sb->dq_op->initialize(inode, type);
+               __dquot_initialize(inode, type);
                /* We hold a reference to 'inode' so it couldn't have been
                 * removed from s_inodes list while we dropped the inode_lock.
                 * We cannot iput the inode now as we can be holding the last
@@ -865,6 +904,14 @@ static void add_dquot_ref(struct super_block *sb, int type)
        }
        spin_unlock(&inode_lock);
        iput(old_inode);
+
+#ifdef CONFIG_QUOTA_DEBUG
+       if (reserved) {
+               printk(KERN_WARNING "VFS (%s): Writes happened before quota"
+                       " was turned on thus quota information is probably "
+                       "inconsistent. Please run quotacheck(8).\n", sb->s_id);
+       }
+#endif
 }
 
 /*
@@ -891,7 +938,7 @@ static int remove_inode_dquot_ref(struct inode *inode, int type,
        inode->i_dquot[type] = NULL;
        if (dquot) {
                if (dqput_blocks(dquot)) {
-#ifdef __DQUOT_PARANOIA
+#ifdef CONFIG_QUOTA_DEBUG
                        if (atomic_read(&dquot->dq_count) != 1)
                                printk(KERN_WARNING "VFS: Adding dquot with dq_count %d to dispose list.\n", atomic_read(&dquot->dq_count));
 #endif
@@ -978,10 +1025,12 @@ static inline void dquot_resv_space(struct dquot *dquot, qsize_t number)
 /*
  * Claim reserved quota space
  */
-static void dquot_claim_reserved_space(struct dquot *dquot,
-                                               qsize_t number)
+static void dquot_claim_reserved_space(struct dquot *dquot, qsize_t number)
 {
-       WARN_ON(dquot->dq_dqb.dqb_rsvspace < number);
+       if (dquot->dq_dqb.dqb_rsvspace < number) {
+               WARN_ON_ONCE(1);
+               number = dquot->dq_dqb.dqb_rsvspace;
+       }
        dquot->dq_dqb.dqb_curspace += number;
        dquot->dq_dqb.dqb_rsvspace -= number;
 }
@@ -989,7 +1038,12 @@ static void dquot_claim_reserved_space(struct dquot *dquot,
 static inline
 void dquot_free_reserved_space(struct dquot *dquot, qsize_t number)
 {
-       dquot->dq_dqb.dqb_rsvspace -= number;
+       if (dquot->dq_dqb.dqb_rsvspace >= number)
+               dquot->dq_dqb.dqb_rsvspace -= number;
+       else {
+               WARN_ON_ONCE(1);
+               dquot->dq_dqb.dqb_rsvspace = 0;
+       }
 }
 
 static void dquot_decr_inodes(struct dquot *dquot, qsize_t number)
@@ -1131,13 +1185,13 @@ static int check_idq(struct dquot *dquot, qsize_t inodes, char *warntype)
        *warntype = QUOTA_NL_NOWARN;
        if (!sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_type) ||
            test_bit(DQ_FAKE_B, &dquot->dq_flags))
-               return QUOTA_OK;
+               return 0;
 
        if (dquot->dq_dqb.dqb_ihardlimit &&
            newinodes > dquot->dq_dqb.dqb_ihardlimit &&
             !ignore_hardlimit(dquot)) {
                *warntype = QUOTA_NL_IHARDWARN;
-               return NO_QUOTA;
+               return -EDQUOT;
        }
 
        if (dquot->dq_dqb.dqb_isoftlimit &&
@@ -1146,7 +1200,7 @@ static int check_idq(struct dquot *dquot, qsize_t inodes, char *warntype)
            get_seconds() >= dquot->dq_dqb.dqb_itime &&
             !ignore_hardlimit(dquot)) {
                *warntype = QUOTA_NL_ISOFTLONGWARN;
-               return NO_QUOTA;
+               return -EDQUOT;
        }
 
        if (dquot->dq_dqb.dqb_isoftlimit &&
@@ -1157,7 +1211,7 @@ static int check_idq(struct dquot *dquot, qsize_t inodes, char *warntype)
                    sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_igrace;
        }
 
-       return QUOTA_OK;
+       return 0;
 }
 
 /* needs dq_data_lock */
@@ -1169,7 +1223,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *war
        *warntype = QUOTA_NL_NOWARN;
        if (!sb_has_quota_limits_enabled(sb, dquot->dq_type) ||
            test_bit(DQ_FAKE_B, &dquot->dq_flags))
-               return QUOTA_OK;
+               return 0;
 
        tspace = dquot->dq_dqb.dqb_curspace + dquot->dq_dqb.dqb_rsvspace
                + space;
@@ -1179,7 +1233,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *war
             !ignore_hardlimit(dquot)) {
                if (!prealloc)
                        *warntype = QUOTA_NL_BHARDWARN;
-               return NO_QUOTA;
+               return -EDQUOT;
        }
 
        if (dquot->dq_dqb.dqb_bsoftlimit &&
@@ -1189,7 +1243,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *war
             !ignore_hardlimit(dquot)) {
                if (!prealloc)
                        *warntype = QUOTA_NL_BSOFTLONGWARN;
-               return NO_QUOTA;
+               return -EDQUOT;
        }
 
        if (dquot->dq_dqb.dqb_bsoftlimit &&
@@ -1205,10 +1259,10 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *war
                         * We don't allow preallocation to exceed softlimit so exceeding will
                         * be always printed
                         */
-                       return NO_QUOTA;
+                       return -EDQUOT;
        }
 
-       return QUOTA_OK;
+       return 0;
 }
 
 static int info_idq_free(struct dquot *dquot, qsize_t inodes)
@@ -1242,25 +1296,32 @@ static int info_bdq_free(struct dquot *dquot, qsize_t space)
                return QUOTA_NL_BHARDBELOW;
        return QUOTA_NL_NOWARN;
 }
+
 /*
- *     Initialize quota pointers in inode
- *     We do things in a bit complicated way but by that we avoid calling
- *     dqget() and thus filesystem callbacks under dqptr_sem.
+ * Initialize quota pointers in inode
+ *
+ * We do things in a bit complicated way but by that we avoid calling
+ * dqget() and thus filesystem callbacks under dqptr_sem.
+ *
+ * It is better to call this function outside of any transaction as it
+ * might need a lot of space in journal for dquot structure allocation.
  */
-int dquot_initialize(struct inode *inode, int type)
+static void __dquot_initialize(struct inode *inode, int type)
 {
        unsigned int id = 0;
-       int cnt, ret = 0;
-       struct dquot *got[MAXQUOTAS] = { NULL, NULL };
+       int cnt;
+       struct dquot *got[MAXQUOTAS];
        struct super_block *sb = inode->i_sb;
+       qsize_t rsv;
 
        /* First test before acquiring mutex - solves deadlocks when we
          * re-enter the quota code and are already holding the mutex */
-       if (IS_NOQUOTA(inode))
-               return 0;
+       if (!sb_any_quota_active(inode->i_sb) || IS_NOQUOTA(inode))
+               return;
 
        /* First get references to structures we might need. */
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+               got[cnt] = NULL;
                if (type != -1 && cnt != type)
                        continue;
                switch (cnt) {
@@ -1275,7 +1336,6 @@ int dquot_initialize(struct inode *inode, int type)
        }
 
        down_write(&sb_dqopt(sb)->dqptr_sem);
-       /* Having dqptr_sem we know NOQUOTA flags can't be altered... */
        if (IS_NOQUOTA(inode))
                goto out_err;
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
@@ -1287,20 +1347,31 @@ int dquot_initialize(struct inode *inode, int type)
                if (!inode->i_dquot[cnt]) {
                        inode->i_dquot[cnt] = got[cnt];
                        got[cnt] = NULL;
+                       /*
+                        * Make quota reservation system happy if someone
+                        * did a write before quota was turned on
+                        */
+                       rsv = inode_get_rsv_space(inode);
+                       if (unlikely(rsv))
+                               dquot_resv_space(inode->i_dquot[cnt], rsv);
                }
        }
 out_err:
        up_write(&sb_dqopt(sb)->dqptr_sem);
        /* Drop unused references */
        dqput_all(got);
-       return ret;
+}
+
+void dquot_initialize(struct inode *inode)
+{
+       __dquot_initialize(inode, -1);
 }
 EXPORT_SYMBOL(dquot_initialize);
 
 /*
  *     Release all quotas referenced by inode
  */
-int dquot_drop(struct inode *inode)
+static void __dquot_drop(struct inode *inode)
 {
        int cnt;
        struct dquot *put[MAXQUOTAS];
@@ -1312,32 +1383,31 @@ int dquot_drop(struct inode *inode)
        }
        up_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
        dqput_all(put);
-       return 0;
 }
-EXPORT_SYMBOL(dquot_drop);
 
-/* Wrapper to remove references to quota structures from inode */
-void vfs_dq_drop(struct inode *inode)
-{
-       /* Here we can get arbitrary inode from clear_inode() so we have
-        * to be careful. OTOH we don't need locking as quota operations
-        * are allowed to change only at mount time */
-       if (!IS_NOQUOTA(inode) && inode->i_sb && inode->i_sb->dq_op
-           && inode->i_sb->dq_op->drop) {
-               int cnt;
-               /* Test before calling to rule out calls from proc and such
-                 * where we are not allowed to block. Note that this is
-                * actually reliable test even without the lock - the caller
-                * must assure that nobody can come after the DQUOT_DROP and
-                * add quota pointers back anyway */
-               for (cnt = 0; cnt < MAXQUOTAS; cnt++)
-                       if (inode->i_dquot[cnt])
-                               break;
-               if (cnt < MAXQUOTAS)
-                       inode->i_sb->dq_op->drop(inode);
-       }
-}
-EXPORT_SYMBOL(vfs_dq_drop);
+void dquot_drop(struct inode *inode)
+{
+       int cnt;
+
+       if (IS_NOQUOTA(inode))
+               return;
+
+       /*
+        * Test before calling to rule out calls from proc and such
+        * where we are not allowed to block. Note that this is
+        * actually reliable test even without the lock - the caller
+        * must assure that nobody can come after the DQUOT_DROP and
+        * add quota pointers back anyway.
+        */
+       for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+               if (inode->i_dquot[cnt])
+                       break;
+       }
+
+       if (cnt < MAXQUOTAS)
+               __dquot_drop(inode);
+}
+EXPORT_SYMBOL(dquot_drop);
 
 /*
  * inode_reserved_space is managed internally by quota, and protected by
@@ -1351,28 +1421,30 @@ static qsize_t *inode_reserved_space(struct inode * inode)
        return inode->i_sb->dq_op->get_reserved_space(inode);
 }
 
-static void inode_add_rsv_space(struct inode *inode, qsize_t number)
+void inode_add_rsv_space(struct inode *inode, qsize_t number)
 {
        spin_lock(&inode->i_lock);
        *inode_reserved_space(inode) += number;
        spin_unlock(&inode->i_lock);
 }
+EXPORT_SYMBOL(inode_add_rsv_space);
 
-
-static void inode_claim_rsv_space(struct inode *inode, qsize_t number)
+void inode_claim_rsv_space(struct inode *inode, qsize_t number)
 {
        spin_lock(&inode->i_lock);
        *inode_reserved_space(inode) -= number;
        __inode_add_bytes(inode, number);
        spin_unlock(&inode->i_lock);
 }
+EXPORT_SYMBOL(inode_claim_rsv_space);
 
-static void inode_sub_rsv_space(struct inode *inode, qsize_t number)
+void inode_sub_rsv_space(struct inode *inode, qsize_t number)
 {
        spin_lock(&inode->i_lock);
        *inode_reserved_space(inode) -= number;
        spin_unlock(&inode->i_lock);
 }
+EXPORT_SYMBOL(inode_sub_rsv_space);
 
 static qsize_t inode_get_rsv_space(struct inode *inode)
 {
@@ -1404,38 +1476,35 @@ static void inode_decr_space(struct inode *inode, qsize_t number, int reserve)
 }
 
 /*
- * Following four functions update i_blocks+i_bytes fields and
- * quota information (together with appropriate checks)
- * NOTE: We absolutely rely on the fact that caller dirties
- * the inode (usually macros in quotaops.h care about this) and
- * holds a handle for the current transaction so that dquot write and
- * inode write go into the same transaction.
+ * This functions updates i_blocks+i_bytes fields and quota information
+ * (together with appropriate checks).
+ *
+ * NOTE: We absolutely rely on the fact that caller dirties the inode
+ * (usually helpers in quotaops.h care about this) and holds a handle for
+ * the current transaction so that dquot write and inode write go into the
+ * same transaction.
  */
 
 /*
  * This operation can block, but only after everything is updated
  */
-int __dquot_alloc_space(struct inode *inode, qsize_t number,
-                       int warn, int reserve)
+int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags)
 {
-       int cnt, ret = QUOTA_OK;
+       int cnt, ret = 0;
        char warntype[MAXQUOTAS];
+       int warn = flags & DQUOT_SPACE_WARN;
+       int reserve = flags & DQUOT_SPACE_RESERVE;
 
        /*
         * First test before acquiring mutex - solves deadlocks when we
         * re-enter the quota code and are already holding the mutex
         */
-       if (IS_NOQUOTA(inode)) {
+       if (!sb_any_quota_active(inode->i_sb) || IS_NOQUOTA(inode)) {
                inode_incr_space(inode, number, reserve);
                goto out;
        }
 
        down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
-       if (IS_NOQUOTA(inode)) {
-               inode_incr_space(inode, number, reserve);
-               goto out_unlock;
-       }
-
        for (cnt = 0; cnt < MAXQUOTAS; cnt++)
                warntype[cnt] = QUOTA_NL_NOWARN;
 
@@ -1443,9 +1512,9 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number,
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
                if (!inode->i_dquot[cnt])
                        continue;
-               if (check_bdq(inode->i_dquot[cnt], number, warn, warntype+cnt)
-                   == NO_QUOTA) {
-                       ret = NO_QUOTA;
+               ret = check_bdq(inode->i_dquot[cnt], number, !warn,
+                               warntype+cnt);
+               if (ret) {
                        spin_unlock(&dq_data_lock);
                        goto out_flush_warn;
                }
@@ -1466,61 +1535,45 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number,
        mark_all_dquot_dirty(inode->i_dquot);
 out_flush_warn:
        flush_warnings(inode->i_dquot, warntype);
-out_unlock:
        up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
 out:
        return ret;
 }
-
-int dquot_alloc_space(struct inode *inode, qsize_t number, int warn)
-{
-       return __dquot_alloc_space(inode, number, warn, 0);
-}
-EXPORT_SYMBOL(dquot_alloc_space);
-
-int dquot_reserve_space(struct inode *inode, qsize_t number, int warn)
-{
-       return __dquot_alloc_space(inode, number, warn, 1);
-}
-EXPORT_SYMBOL(dquot_reserve_space);
+EXPORT_SYMBOL(__dquot_alloc_space);
 
 /*
  * This operation can block, but only after everything is updated
  */
-int dquot_alloc_inode(const struct inode *inode, qsize_t number)
+int dquot_alloc_inode(const struct inode *inode)
 {
-       int cnt, ret = NO_QUOTA;
+       int cnt, ret = 0;
        char warntype[MAXQUOTAS];
 
        /* First test before acquiring mutex - solves deadlocks when we
          * re-enter the quota code and are already holding the mutex */
-       if (IS_NOQUOTA(inode))
-               return QUOTA_OK;
+       if (!sb_any_quota_active(inode->i_sb) || IS_NOQUOTA(inode))
+               return 0;
        for (cnt = 0; cnt < MAXQUOTAS; cnt++)
                warntype[cnt] = QUOTA_NL_NOWARN;
        down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
-       if (IS_NOQUOTA(inode)) {
-               up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
-               return QUOTA_OK;
-       }
        spin_lock(&dq_data_lock);
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
                if (!inode->i_dquot[cnt])
                        continue;
-               if (check_idq(inode->i_dquot[cnt], number, warntype+cnt)
-                   == NO_QUOTA)
+               ret = check_idq(inode->i_dquot[cnt], 1, warntype + cnt);
+               if (ret)
                        goto warn_put_all;
        }
 
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
                if (!inode->i_dquot[cnt])
                        continue;
-               dquot_incr_inodes(inode->i_dquot[cnt], number);
+               dquot_incr_inodes(inode->i_dquot[cnt], 1);
        }
-       ret = QUOTA_OK;
+
 warn_put_all:
        spin_unlock(&dq_data_lock);
-       if (ret == QUOTA_OK)
+       if (ret == 0)
                mark_all_dquot_dirty(inode->i_dquot);
        flush_warnings(inode->i_dquot, warntype);
        up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
@@ -1528,23 +1581,19 @@ warn_put_all:
 }
 EXPORT_SYMBOL(dquot_alloc_inode);
 
-int dquot_claim_space(struct inode *inode, qsize_t number)
+/*
+ * Convert in-memory reserved quotas to real consumed quotas
+ */
+int dquot_claim_space_nodirty(struct inode *inode, qsize_t number)
 {
        int cnt;
-       int ret = QUOTA_OK;
 
-       if (IS_NOQUOTA(inode)) {
+       if (!sb_any_quota_active(inode->i_sb) || IS_NOQUOTA(inode)) {
                inode_claim_rsv_space(inode, number);
-               goto out;
+               return 0;
        }
 
        down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
-       if (IS_NOQUOTA(inode))  {
-               up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
-               inode_claim_rsv_space(inode, number);
-               goto out;
-       }
-
        spin_lock(&dq_data_lock);
        /* Claim reserved quotas to allocated quotas */
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
@@ -1557,33 +1606,27 @@ int dquot_claim_space(struct inode *inode, qsize_t number)
        spin_unlock(&dq_data_lock);
        mark_all_dquot_dirty(inode->i_dquot);
        up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
-out:
-       return ret;
+       return 0;
 }
-EXPORT_SYMBOL(dquot_claim_space);
+EXPORT_SYMBOL(dquot_claim_space_nodirty);
 
 /*
  * This operation can block, but only after everything is updated
  */
-int __dquot_free_space(struct inode *inode, qsize_t number, int reserve)
+void __dquot_free_space(struct inode *inode, qsize_t number, int flags)
 {
        unsigned int cnt;
        char warntype[MAXQUOTAS];
+       int reserve = flags & DQUOT_SPACE_RESERVE;
 
        /* First test before acquiring mutex - solves deadlocks when we
          * re-enter the quota code and are already holding the mutex */
-       if (IS_NOQUOTA(inode)) {
-out_sub:
+       if (!sb_any_quota_active(inode->i_sb) || IS_NOQUOTA(inode)) {
                inode_decr_space(inode, number, reserve);
-               return QUOTA_OK;
+               return;
        }
 
        down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
-       /* Now recheck reliably when holding dqptr_sem */
-       if (IS_NOQUOTA(inode)) {
-               up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
-               goto out_sub;
-       }
        spin_lock(&dq_data_lock);
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
                if (!inode->i_dquot[cnt])
@@ -1603,56 +1646,34 @@ out_sub:
 out_unlock:
        flush_warnings(inode->i_dquot, warntype);
        up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
-       return QUOTA_OK;
-}
-
-int dquot_free_space(struct inode *inode, qsize_t number)
-{
-       return  __dquot_free_space(inode, number, 0);
 }
-EXPORT_SYMBOL(dquot_free_space);
-
-/*
- * Release reserved quota space
- */
-void dquot_release_reserved_space(struct inode *inode, qsize_t number)
-{
-       __dquot_free_space(inode, number, 1);
-
-}
-EXPORT_SYMBOL(dquot_release_reserved_space);
+EXPORT_SYMBOL(__dquot_free_space);
 
 /*
  * This operation can block, but only after everything is updated
  */
-int dquot_free_inode(const struct inode *inode, qsize_t number)
+void dquot_free_inode(const struct inode *inode)
 {
        unsigned int cnt;
        char warntype[MAXQUOTAS];
 
        /* First test before acquiring mutex - solves deadlocks when we
          * re-enter the quota code and are already holding the mutex */
-       if (IS_NOQUOTA(inode))
-               return QUOTA_OK;
+       if (!sb_any_quota_active(inode->i_sb) || IS_NOQUOTA(inode))
+               return;
 
        down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
-       /* Now recheck reliably when holding dqptr_sem */
-       if (IS_NOQUOTA(inode)) {
-               up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
-               return QUOTA_OK;
-       }
        spin_lock(&dq_data_lock);
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
                if (!inode->i_dquot[cnt])
                        continue;
-               warntype[cnt] = info_idq_free(inode->i_dquot[cnt], number);
-               dquot_decr_inodes(inode->i_dquot[cnt], number);
+               warntype[cnt] = info_idq_free(inode->i_dquot[cnt], 1);
+               dquot_decr_inodes(inode->i_dquot[cnt], 1);
        }
        spin_unlock(&dq_data_lock);
        mark_all_dquot_dirty(inode->i_dquot);
        flush_warnings(inode->i_dquot, warntype);
        up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
-       return QUOTA_OK;
 }
 EXPORT_SYMBOL(dquot_free_inode);
 
@@ -1662,37 +1683,31 @@ EXPORT_SYMBOL(dquot_free_inode);
  * This operation can block, but only after everything is updated
  * A transaction must be started when entering this function.
  */
-int dquot_transfer(struct inode *inode, struct iattr *iattr)
+static int __dquot_transfer(struct inode *inode, qid_t *chid, unsigned long mask)
 {
        qsize_t space, cur_space;
        qsize_t rsv_space = 0;
        struct dquot *transfer_from[MAXQUOTAS];
        struct dquot *transfer_to[MAXQUOTAS];
-       int cnt, ret = QUOTA_OK;
-       int chuid = iattr->ia_valid & ATTR_UID && inode->i_uid != iattr->ia_uid,
-           chgid = iattr->ia_valid & ATTR_GID && inode->i_gid != iattr->ia_gid;
+       int cnt, ret = 0;
        char warntype_to[MAXQUOTAS];
        char warntype_from_inodes[MAXQUOTAS], warntype_from_space[MAXQUOTAS];
 
        /* First test before acquiring mutex - solves deadlocks when we
          * re-enter the quota code and are already holding the mutex */
        if (IS_NOQUOTA(inode))
-               return QUOTA_OK;
+               return 0;
        /* Initialize the arrays */
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
                transfer_from[cnt] = NULL;
                transfer_to[cnt] = NULL;
                warntype_to[cnt] = QUOTA_NL_NOWARN;
        }
-       if (chuid)
-               transfer_to[USRQUOTA] = dqget(inode->i_sb, iattr->ia_uid,
-                                             USRQUOTA);
-       if (chgid)
-               transfer_to[GRPQUOTA] = dqget(inode->i_sb, iattr->ia_gid,
-                                             GRPQUOTA);
-
+       for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+               if (mask & (1 << cnt))
+                       transfer_to[cnt] = dqget(inode->i_sb, chid[cnt], cnt);
+       }
        down_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
-       /* Now recheck reliably when holding dqptr_sem */
        if (IS_NOQUOTA(inode)) {        /* File without quota accounting? */
                up_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
                goto put_all;
@@ -1706,9 +1721,11 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr)
                if (!transfer_to[cnt])
                        continue;
                transfer_from[cnt] = inode->i_dquot[cnt];
-               if (check_idq(transfer_to[cnt], 1, warntype_to + cnt) ==
-                   NO_QUOTA || check_bdq(transfer_to[cnt], space, 0,
-                   warntype_to + cnt) == NO_QUOTA)
+               ret = check_idq(transfer_to[cnt], 1, warntype_to + cnt);
+               if (ret)
+                       goto over_quota;
+               ret = check_bdq(transfer_to[cnt], space, 0, warntype_to + cnt);
+               if (ret)
                        goto over_quota;
        }
 
@@ -1762,22 +1779,32 @@ over_quota:
        /* Clear dquot pointers we don't want to dqput() */
        for (cnt = 0; cnt < MAXQUOTAS; cnt++)
                transfer_from[cnt] = NULL;
-       ret = NO_QUOTA;
        goto warn_put_all;
 }
-EXPORT_SYMBOL(dquot_transfer);
 
-/* Wrapper for transferring ownership of an inode */
-int vfs_dq_transfer(struct inode *inode, struct iattr *iattr)
+/* Wrapper for transferring ownership of an inode for uid/gid only
+ * Called from FSXXX_setattr()
+ */
+int dquot_transfer(struct inode *inode, struct iattr *iattr)
 {
+       qid_t chid[MAXQUOTAS];
+       unsigned long mask = 0;
+
+       if (iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid) {
+               mask |= 1 << USRQUOTA;
+               chid[USRQUOTA] = iattr->ia_uid;
+       }
+       if (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid) {
+               mask |= 1 << GRPQUOTA;
+               chid[GRPQUOTA] = iattr->ia_gid;
+       }
        if (sb_any_quota_active(inode->i_sb) && !IS_NOQUOTA(inode)) {
-               vfs_dq_init(inode);
-               if (inode->i_sb->dq_op->transfer(inode, iattr) == NO_QUOTA)
-                       return 1;
+               dquot_initialize(inode);
+               return __dquot_transfer(inode, chid, mask);
        }
        return 0;
 }
-EXPORT_SYMBOL(vfs_dq_transfer);
+EXPORT_SYMBOL(dquot_transfer);
 
 /*
  * Write info of quota file to disk
@@ -1798,13 +1825,6 @@ EXPORT_SYMBOL(dquot_commit_info);
  * Definitions of diskquota operations.
  */
 const struct dquot_operations dquot_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    = dquot_commit,
        .acquire_dquot  = dquot_acquire,
        .release_dquot  = dquot_release,
@@ -1814,6 +1834,20 @@ const struct dquot_operations dquot_operations = {
        .destroy_dquot  = dquot_destroy,
 };
 
+/*
+ * Generic helper for ->open on filesystems supporting disk quotas.
+ */
+int dquot_file_open(struct inode *inode, struct file *file)
+{
+       int error;
+
+       error = generic_file_open(inode, file);
+       if (!error && (file->f_mode & FMODE_WRITE))
+               dquot_initialize(inode);
+       return error;
+}
+EXPORT_SYMBOL(dquot_file_open);
+
 /*
  * Turn quota off on a device. type == -1 ==> quotaoff for all types (umount)
  */
@@ -1993,11 +2027,13 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
        }
 
        if (!(dqopt->flags & DQUOT_QUOTA_SYS_FILE)) {
-               /* As we bypass the pagecache we must now flush the inode so
-                * that we see all the changes from userspace... */
-               write_inode_now(inode, 1);
-               /* And now flush the block cache so that kernel sees the
-                * changes */
+               /* As we bypass the pagecache we must now flush all the
+                * dirty data and invalidate caches so that kernel sees
+                * changes from userspace. It is not enough to just flush
+                * the quota file since if blocksize < pagesize, invalidation
+                * of the cache could fail because of other unrelated dirty
+                * data */
+               sync_filesystem(sb);
                invalidate_bdev(sb->s_bdev);
        }
        mutex_lock(&dqopt->dqonoff_mutex);
@@ -2010,14 +2046,16 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
                /* We don't want quota and atime on quota files (deadlocks
                 * possible) Also nobody should write to the file - we use
                 * special IO operations which ignore the immutable bit. */
-               down_write(&dqopt->dqptr_sem);
                mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA);
                oldflags = inode->i_flags & (S_NOATIME | S_IMMUTABLE |
                                             S_NOQUOTA);
                inode->i_flags |= S_NOQUOTA | S_NOATIME | S_IMMUTABLE;
                mutex_unlock(&inode->i_mutex);
-               up_write(&dqopt->dqptr_sem);
-               sb->dq_op->drop(inode);
+               /*
+                * When S_NOQUOTA is set, remove dquot references as no more
+                * references can be added
+                */
+               __dquot_drop(inode);
        }
 
        error = -EIO;
@@ -2053,14 +2091,12 @@ out_file_init:
        iput(inode);
 out_lock:
        if (oldflags != -1) {
-               down_write(&dqopt->dqptr_sem);
                mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA);
                /* Set the flags back (in the case of accidental quotaon()
                 * on a wrong file we don't want to mess up the flags) */
                inode->i_flags &= ~(S_NOATIME | S_NOQUOTA | S_IMMUTABLE);
                inode->i_flags |= oldflags;
                mutex_unlock(&inode->i_mutex);
-               up_write(&dqopt->dqptr_sem);
        }
        mutex_unlock(&dqopt->dqonoff_mutex);
 out_fmt:
@@ -2292,34 +2328,34 @@ static int do_set_dqblk(struct dquot *dquot, struct if_dqblk *di)
        if (di->dqb_valid & QIF_SPACE) {
                dm->dqb_curspace = di->dqb_curspace - dm->dqb_rsvspace;
                check_blim = 1;
-               __set_bit(DQ_LASTSET_B + QIF_SPACE_B, &dquot->dq_flags);
+               set_bit(DQ_LASTSET_B + QIF_SPACE_B, &dquot->dq_flags);
        }
        if (di->dqb_valid & QIF_BLIMITS) {
                dm->dqb_bsoftlimit = qbtos(di->dqb_bsoftlimit);
                dm->dqb_bhardlimit = qbtos(di->dqb_bhardlimit);
                check_blim = 1;
-               __set_bit(DQ_LASTSET_B + QIF_BLIMITS_B, &dquot->dq_flags);
+               set_bit(DQ_LASTSET_B + QIF_BLIMITS_B, &dquot->dq_flags);
        }
        if (di->dqb_valid & QIF_INODES) {
                dm->dqb_curinodes = di->dqb_curinodes;
                check_ilim = 1;
-               __set_bit(DQ_LASTSET_B + QIF_INODES_B, &dquot->dq_flags);
+               set_bit(DQ_LASTSET_B + QIF_INODES_B, &dquot->dq_flags);
        }
        if (di->dqb_valid & QIF_ILIMITS) {
                dm->dqb_isoftlimit = di->dqb_isoftlimit;
                dm->dqb_ihardlimit = di->dqb_ihardlimit;
                check_ilim = 1;
-               __set_bit(DQ_LASTSET_B + QIF_ILIMITS_B, &dquot->dq_flags);
+               set_bit(DQ_LASTSET_B + QIF_ILIMITS_B, &dquot->dq_flags);
        }
        if (di->dqb_valid & QIF_BTIME) {
                dm->dqb_btime = di->dqb_btime;
                check_blim = 1;
-               __set_bit(DQ_LASTSET_B + QIF_BTIME_B, &dquot->dq_flags);
+               set_bit(DQ_LASTSET_B + QIF_BTIME_B, &dquot->dq_flags);
        }
        if (di->dqb_valid & QIF_ITIME) {
                dm->dqb_itime = di->dqb_itime;
                check_ilim = 1;
-               __set_bit(DQ_LASTSET_B + QIF_ITIME_B, &dquot->dq_flags);
+               set_bit(DQ_LASTSET_B + QIF_ITIME_B, &dquot->dq_flags);
        }
 
        if (check_blim) {