dquot: move dquot initialization responsibility into the filesystem
[pandora-kernel.git] / fs / quota / dquot.c
index 3fc62b0..6244bca 100644 (file)
  *
  * 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 +229,8 @@ static struct hlist_head *dquot_hash;
 struct dqstats dqstats;
 EXPORT_SYMBOL(dqstats);
 
+static qsize_t inode_get_rsv_space(struct inode *inode);
+
 static inline unsigned int
 hashfn(const struct super_block *sb, unsigned int id, int type)
 {
@@ -564,7 +570,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 +615,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);
@@ -840,11 +873,14 @@ 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;
+       int reserved = 0;
 
        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;
+               if (unlikely(inode_get_rsv_space(inode) > 0))
+                       reserved = 1;
                if (!atomic_read(&inode->i_writecount))
                        continue;
                if (!dqinit_needed(inode, type))
@@ -865,6 +901,12 @@ static void add_dquot_ref(struct super_block *sb, int type)
        }
        spin_unlock(&inode_lock);
        iput(old_inode);
+
+       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);
+       }
 }
 
 /*
@@ -978,10 +1020,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 +1033,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)
@@ -1242,6 +1291,7 @@ 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
@@ -1251,8 +1301,9 @@ int dquot_initialize(struct inode *inode, int type)
 {
        unsigned int id = 0;
        int cnt, ret = 0;
-       struct dquot *got[MAXQUOTAS] = { NULL, NULL };
+       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 */
@@ -1261,6 +1312,7 @@ int dquot_initialize(struct inode *inode, int type)
 
        /* 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 +1327,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,6 +1338,13 @@ 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:
@@ -1300,7 +1358,7 @@ 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 +1370,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 +1408,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 +1463,34 @@ 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 warn, int reserve)
 {
-       int cnt, ret = QUOTA_OK;
+       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)) {
+       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 +1498,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;
+               if (check_bdq(inode->i_dquot[cnt], number, !warn, warntype+cnt)
+                               == NO_QUOTA) {
+                       ret = -EDQUOT;
                        spin_unlock(&dq_data_lock);
                        goto out_flush_warn;
                }
@@ -1466,48 +1521,32 @@ 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 = -EDQUOT;
        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)
+               if (check_idq(inode->i_dquot[cnt], 1, warntype+cnt)
                    == NO_QUOTA)
                        goto warn_put_all;
        }
@@ -1515,12 +1554,12 @@ int dquot_alloc_inode(const struct inode *inode, qsize_t number)
        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;
+       ret = 0;
 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 +1567,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 +1592,26 @@ 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 reserve)
 {
        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)) {
-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 +1631,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,15 +1668,13 @@ 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;
        char warntype_to[MAXQUOTAS];
        char warntype_from_inodes[MAXQUOTAS], warntype_from_space[MAXQUOTAS];
 
@@ -1684,15 +1688,11 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr)
                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;
@@ -1765,19 +1765,31 @@ over_quota:
        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;
+               if (__dquot_transfer(inode, chid, mask) == NO_QUOTA)
+                       return -EDQUOT;
        }
        return 0;
 }
-EXPORT_SYMBOL(vfs_dq_transfer);
+EXPORT_SYMBOL(dquot_transfer);
 
 /*
  * Write info of quota file to disk
@@ -1799,12 +1811,6 @@ EXPORT_SYMBOL(dquot_commit_info);
  */
 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 +1820,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))
+               vfs_dq_init(inode);
+       return error;
+}
+EXPORT_SYMBOL(dquot_file_open);
+
 /*
  * Turn quota off on a device. type == -1 ==> quotaoff for all types (umount)
  */
@@ -1993,11 +2013,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 +2032,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 +2077,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: