Merge to Fedora kernel-2.6.18-1.2239_FC5 patched with stable patch-2.6.18.2-vs2.0...
[linux-2.6.git] / fs / dquot.c
index 70280bc..ad46d25 100644 (file)
@@ -49,7 +49,7 @@
  *             New SMP locking.
  *             Jan Kara, <jack@suse.cz>, 10/2002
  *
- *             Added journalled quota support
+ *             Added journalled quota support, fix lock inversion problems
  *             Jan Kara, <jack@suse.cz>, 2003,2004
  *
  * (C) Copyright 1994 - 1997 Marco van Wieringen 
 #include <linux/proc_fs.h>
 #include <linux/security.h>
 #include <linux/kmod.h>
-#include <linux/pagemap.h>
+#include <linux/namei.h>
+#include <linux/buffer_head.h>
+#include <linux/capability.h>
+#include <linux/quotaops.h>
 
 #include <asm/uaccess.h>
 
  *
  * 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.
- * If operation is holding reference to dquot in other way (e.g. quotactl ops)
- * it must be guarded by dqonoff_sem.
+ * 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).  If operation is holding
+ * reference to dquot in other way (e.g. quotactl ops) it must be guarded by
+ * dqonoff_mutex.
  * This locking assures that:
  *   a) update/access to dquot pointers in inode is serialized
  *   b) everyone is guarded against invalidate_dquots()
  *
- * Each dquot has its dq_lock semaphore. Locked dquots might not be referenced
+ * 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).
  * Currently dquot is locked only when it is being read to memory (or space for
  * it is being allocated) on the first dqget() and when it is being released on
  * operations on dquots don't hold dq_lock as they copy data under dq_data_lock
  * spinlock to internal buffers before writing.
  *
- * Lock ordering (including journal_lock) is following:
- *  dqonoff_sem > journal_lock > dqptr_sem > dquot->dq_lock > dqio_sem
+ * Lock ordering (including related VFS locks) is the following:
+ *   i_mutex > dqonoff_sem > journal_lock > dqptr_sem > dquot->dq_lock >
+ *   dqio_mutex
+ * i_mutex on quota files is special (it's below dqio_mutex)
  */
 
-spinlock_t dq_list_lock = SPIN_LOCK_UNLOCKED;
-spinlock_t dq_data_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(dq_list_lock);
+DEFINE_SPINLOCK(dq_data_lock);
 
 static char *quotatypes[] = INITQFNAMES;
 static struct quota_format_type *quota_formats;        /* List of registered formats */
 static struct quota_module_name module_names[] = INIT_QUOTA_MODULE_NAMES;
 
+/* SLAB cache for dquot structures */
+static kmem_cache_t *dquot_cachep;
+
 int register_quota_format(struct quota_format_type *fmt)
 {
        spin_lock(&dq_list_lock);
@@ -179,8 +189,7 @@ static void put_quota_format(struct quota_format_type *fmt)
  * on all three lists, depending on its current state.
  *
  * All dquots are placed to the end of inuse_list when first created, and this
- * list is used for the sync and invalidate operations, which must look
- * at every dquot.
+ * list is used for invalidate operation, which must look at every dquot.
  *
  * Unused dquots (dq_count == 0) are added to the free_dquots list when freed,
  * and this list is searched whenever we need an available dquot.  Dquots are
@@ -195,16 +204,19 @@ static void put_quota_format(struct quota_format_type *fmt)
 
 static LIST_HEAD(inuse_list);
 static LIST_HEAD(free_dquots);
-unsigned int dq_hash_bits, dq_hash_mask;
+static unsigned int dq_hash_bits, dq_hash_mask;
 static struct hlist_head *dquot_hash;
 
 struct dqstats dqstats;
 
 static void dqput(struct dquot *dquot);
 
-static inline int const hashfn(struct super_block *sb, unsigned int id, int type)
+static inline unsigned int
+hashfn(const struct super_block *sb, unsigned int id, int type)
 {
-       unsigned long tmp = (((unsigned long)sb>>L1_CACHE_SHIFT) ^ id) * (MAXQUOTAS - type);
+       unsigned long tmp;
+
+       tmp = (((unsigned long)sb>>L1_CACHE_SHIFT) ^ id) * (MAXQUOTAS - type);
        return (tmp + (tmp >> dq_hash_bits)) & dq_hash_mask;
 }
 
@@ -238,7 +250,7 @@ static inline struct dquot *find_dquot(unsigned int hashent, struct super_block
 /* Add a dquot to the tail of the free list */
 static inline void put_dquot_last(struct dquot *dquot)
 {
-       list_add(&dquot->dq_free, free_dquots.prev);
+       list_add_tail(&dquot->dq_free, &free_dquots);
        dqstats.free_dquots++;
 }
 
@@ -254,7 +266,7 @@ static inline void put_inuse(struct dquot *dquot)
 {
        /* We add to the back of inuse list so we don't have to restart
         * when traversing this list and we block */
-       list_add(&dquot->dq_inuse, inuse_list.prev);
+       list_add_tail(&dquot->dq_inuse, &inuse_list);
        dqstats.allocated_dquots++;
 }
 
@@ -269,8 +281,8 @@ static inline void remove_inuse(struct dquot *dquot)
 
 static void wait_on_dquot(struct dquot *dquot)
 {
-       down(&dquot->dq_lock);
-       up(&dquot->dq_lock);
+       mutex_lock(&dquot->dq_lock);
+       mutex_unlock(&dquot->dq_lock);
 }
 
 #define mark_dquot_dirty(dquot) ((dquot)->dq_sb->dq_op->mark_dirty(dquot))
@@ -309,8 +321,8 @@ int dquot_acquire(struct dquot *dquot)
        int ret = 0, ret2 = 0;
        struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
 
-       down(&dquot->dq_lock);
-       down(&dqopt->dqio_sem);
+       mutex_lock(&dquot->dq_lock);
+       mutex_lock(&dqopt->dqio_mutex);
        if (!test_bit(DQ_READ_B, &dquot->dq_flags))
                ret = dqopt->ops[dquot->dq_type]->read_dqblk(dquot);
        if (ret < 0)
@@ -331,8 +343,8 @@ int dquot_acquire(struct dquot *dquot)
        }
        set_bit(DQ_ACTIVE_B, &dquot->dq_flags);
 out_iolock:
-       up(&dqopt->dqio_sem);
-       up(&dquot->dq_lock);
+       mutex_unlock(&dqopt->dqio_mutex);
+       mutex_unlock(&dquot->dq_lock);
        return ret;
 }
 
@@ -344,7 +356,7 @@ int dquot_commit(struct dquot *dquot)
        int ret = 0, ret2 = 0;
        struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
 
-       down(&dqopt->dqio_sem);
+       mutex_lock(&dqopt->dqio_mutex);
        spin_lock(&dq_list_lock);
        if (!clear_dquot_dirty(dquot)) {
                spin_unlock(&dq_list_lock);
@@ -361,7 +373,7 @@ int dquot_commit(struct dquot *dquot)
                        ret = ret2;
        }
 out_sem:
-       up(&dqopt->dqio_sem);
+       mutex_unlock(&dqopt->dqio_mutex);
        return ret;
 }
 
@@ -373,11 +385,11 @@ int dquot_release(struct dquot *dquot)
        int ret = 0, ret2 = 0;
        struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
 
-       down(&dquot->dq_lock);
+       mutex_lock(&dquot->dq_lock);
        /* Check whether we are not racing with some other dqget() */
        if (atomic_read(&dquot->dq_count) > 1)
                goto out_dqlock;
-       down(&dqopt->dqio_sem);
+       mutex_lock(&dqopt->dqio_mutex);
        if (dqopt->ops[dquot->dq_type]->release_dqblk) {
                ret = dqopt->ops[dquot->dq_type]->release_dqblk(dquot);
                /* Write the info */
@@ -387,34 +399,57 @@ int dquot_release(struct dquot *dquot)
                        ret = ret2;
        }
        clear_bit(DQ_ACTIVE_B, &dquot->dq_flags);
-       up(&dqopt->dqio_sem);
+       mutex_unlock(&dqopt->dqio_mutex);
 out_dqlock:
-       up(&dquot->dq_lock);
+       mutex_unlock(&dquot->dq_lock);
        return ret;
 }
 
 /* Invalidate all dquots on the list. Note that this function is called after
  * quota is disabled and pointers from inodes removed so there cannot be new
- * quota users. Also because we hold dqonoff_sem there can be no quota users
- * for this sb+type at all. */
+ * quota users. There can still be some users of quotas due to inodes being
+ * just deleted or pruned by prune_icache() (those are not attached to any
+ * list). We have to wait for such users.
+ */
 static void invalidate_dquots(struct super_block *sb, int type)
 {
-       struct dquot *dquot;
-       struct list_head *head;
+       struct dquot *dquot, *tmp;
 
+restart:
        spin_lock(&dq_list_lock);
-       for (head = inuse_list.next; head != &inuse_list;) {
-               dquot = list_entry(head, struct dquot, dq_inuse);
-               head = head->next;
+       list_for_each_entry_safe(dquot, tmp, &inuse_list, dq_inuse) {
                if (dquot->dq_sb != sb)
                        continue;
                if (dquot->dq_type != type)
                        continue;
-#ifdef __DQUOT_PARANOIA
-               if (atomic_read(&dquot->dq_count))
-                       BUG();
-#endif
-               /* Quota now has no users and it has been written on last dqput() */
+               /* Wait for dquot users */
+               if (atomic_read(&dquot->dq_count)) {
+                       DEFINE_WAIT(wait);
+
+                       atomic_inc(&dquot->dq_count);
+                       prepare_to_wait(&dquot->dq_wait_unused, &wait,
+                                       TASK_UNINTERRUPTIBLE);
+                       spin_unlock(&dq_list_lock);
+                       /* Once dqput() wakes us up, we know it's time to free
+                        * the dquot.
+                        * IMPORTANT: we rely on the fact that there is always
+                        * at most one process waiting for dquot to free.
+                        * Otherwise dq_count would be > 1 and we would never
+                        * wake up.
+                        */
+                       if (atomic_read(&dquot->dq_count) > 1)
+                               schedule();
+                       finish_wait(&dquot->dq_wait_unused, &wait);
+                       dqput(dquot);
+                       /* At this moment dquot() need not exist (it could be
+                        * reclaimed by prune_dqcache(). Hence we must
+                        * restart. */
+                       goto restart;
+               }
+               /*
+                * Quota now has no users and it has been written on last
+                * dqput()
+                */
                remove_dquot_hash(dquot);
                remove_free_dquot(dquot);
                remove_inuse(dquot);
@@ -430,7 +465,7 @@ int vfs_quota_sync(struct super_block *sb, int type)
        struct quota_info *dqopt = sb_dqopt(sb);
        int cnt;
 
-       down(&dqopt->dqonoff_sem);
+       mutex_lock(&dqopt->dqonoff_mutex);
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
                if (type != -1 && cnt != type)
                        continue;
@@ -465,7 +500,7 @@ int vfs_quota_sync(struct super_block *sb, int type)
        spin_lock(&dq_list_lock);
        dqstats.syncs++;
        spin_unlock(&dq_list_lock);
-       up(&dqopt->dqonoff_sem);
+       mutex_unlock(&dqopt->dqonoff_mutex);
 
        return 0;
 }
@@ -493,22 +528,20 @@ static void prune_dqcache(int count)
  * more memory
  */
 
-static int shrink_dqcache_memory(int nr, unsigned int gfp_mask)
+static int shrink_dqcache_memory(int nr, gfp_t gfp_mask)
 {
-       int ret;
-
-       spin_lock(&dq_list_lock);
-       if (nr)
+       if (nr) {
+               spin_lock(&dq_list_lock);
                prune_dqcache(nr);
-       ret = dqstats.allocated_dquots;
-       spin_unlock(&dq_list_lock);
-       return ret;
+               spin_unlock(&dq_list_lock);
+       }
+       return (dqstats.free_dquots / 100) * sysctl_vfs_cache_pressure;
 }
 
 /*
  * Put reference to dquot
  * NOTE: If you change this function please check whether dqput_blocks() works right...
- * MUST be called with either dqptr_sem or dqonoff_sem held
+ * MUST be called with either dqptr_sem or dqonoff_mutex held
  */
 static void dqput(struct dquot *dquot)
 {
@@ -533,6 +566,10 @@ we_slept:
        if (atomic_read(&dquot->dq_count) > 1) {
                /* We have more than one user... nothing to do */
                atomic_dec(&dquot->dq_count);
+               /* Releasing dquot during quotaoff phase? */
+               if (!sb_has_quota_enabled(dquot->dq_sb, dquot->dq_type) &&
+                   atomic_read(&dquot->dq_count) == 1)
+                       wake_up(&dquot->dq_wait_unused);
                spin_unlock(&dq_list_lock);
                return;
        }
@@ -553,8 +590,7 @@ we_slept:
        atomic_dec(&dquot->dq_count);
 #ifdef __DQUOT_PARANOIA
        /* sanity check */
-       if (!list_empty(&dquot->dq_free))
-               BUG();
+       BUG_ON(!list_empty(&dquot->dq_free));
 #endif
        put_dquot_last(dquot);
        spin_unlock(&dq_list_lock);
@@ -569,11 +605,12 @@ static struct dquot *get_empty_dquot(struct super_block *sb, int type)
                return NODQUOT;
 
        memset((caddr_t)dquot, 0, sizeof(struct dquot));
-       sema_init(&dquot->dq_lock, 1);
+       mutex_init(&dquot->dq_lock);
        INIT_LIST_HEAD(&dquot->dq_free);
        INIT_LIST_HEAD(&dquot->dq_inuse);
        INIT_HLIST_NODE(&dquot->dq_hash);
        INIT_LIST_HEAD(&dquot->dq_dirty);
+       init_waitqueue_head(&dquot->dq_wait_unused);
        dquot->dq_sb = sb;
        dquot->dq_type = type;
        atomic_set(&dquot->dq_count, 1);
@@ -583,7 +620,7 @@ static struct dquot *get_empty_dquot(struct super_block *sb, int type)
 
 /*
  * Get reference to dquot
- * MUST be called with either dqptr_sem or dqonoff_sem held
+ * MUST be called with either dqptr_sem or dqonoff_mutex held
  */
 static struct dquot *dqget(struct super_block *sb, unsigned int id, int type)
 {
@@ -628,8 +665,7 @@ we_slept:
                return NODQUOT;
        }
 #ifdef __DQUOT_PARANOIA
-       if (!dquot->dq_sb)      /* Has somebody invalidated entry under us? */
-               BUG();
+       BUG_ON(!dquot->dq_sb);  /* Has somebody invalidated entry under us? */
 #endif
 
        return dquot;
@@ -649,7 +685,7 @@ static int dqinit_needed(struct inode *inode, int type)
        return 0;
 }
 
-/* This routine is guarded by dqonoff_sem semaphore */
+/* This routine is guarded by dqonoff_mutex mutex */
 static void add_dquot_ref(struct super_block *sb, int type)
 {
        struct list_head *p;
@@ -657,7 +693,7 @@ static void add_dquot_ref(struct super_block *sb, int type)
 restart:
        file_list_lock();
        list_for_each(p, &sb->s_files) {
-               struct file *filp = list_entry(p, struct file, f_list);
+               struct file *filp = list_entry(p, struct file, f_u.fu_list);
                struct inode *inode = filp->f_dentry->d_inode;
                if (filp->f_mode & FMODE_WRITE && dqinit_needed(inode, type)) {
                        struct dentry *dentry = dget(filp->f_dentry);
@@ -684,16 +720,8 @@ static inline int dqput_blocks(struct dquot *dquot)
 int remove_inode_dquot_ref(struct inode *inode, int type, struct list_head *tofree_head)
 {
        struct dquot *dquot = inode->i_dquot[type];
-       int cnt;
 
        inode->i_dquot[type] = NODQUOT;
-       /* any other quota in use? */
-       for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-               if (inode->i_dquot[cnt] != NODQUOT)
-                       goto put_it;
-       }
-       inode->i_flags &= ~S_QUOTA;
-put_it:
        if (dquot != NODQUOT) {
                if (dqput_blocks(dquot)) {
 #ifdef __DQUOT_PARANOIA
@@ -728,9 +756,6 @@ static void put_dquot_list(struct list_head *tofree_head)
        }
 }
 
-/* Function in inode.c - remove pointers to dquots in icache */
-extern void remove_dquot_ref(struct super_block *, int, struct list_head *);
-
 /* Gather all references from inodes and drop them */
 static void drop_dquot_ref(struct super_block *sb, int type)
 {
@@ -758,7 +783,7 @@ static inline void dquot_decr_inodes(struct dquot *dquot, unsigned long number)
                dquot->dq_dqb.dqb_curinodes -= number;
        else
                dquot->dq_dqb.dqb_curinodes = 0;
-       if (dquot->dq_dqb.dqb_curinodes < dquot->dq_dqb.dqb_isoftlimit)
+       if (dquot->dq_dqb.dqb_curinodes <= dquot->dq_dqb.dqb_isoftlimit)
                dquot->dq_dqb.dqb_itime = (time_t) 0;
        clear_bit(DQ_INODES_B, &dquot->dq_flags);
 }
@@ -769,13 +794,18 @@ static inline void dquot_decr_space(struct dquot *dquot, qsize_t number)
                dquot->dq_dqb.dqb_curspace -= number;
        else
                dquot->dq_dqb.dqb_curspace = 0;
-       if (toqb(dquot->dq_dqb.dqb_curspace) < dquot->dq_dqb.dqb_bsoftlimit)
+       if (toqb(dquot->dq_dqb.dqb_curspace) <= dquot->dq_dqb.dqb_bsoftlimit)
                dquot->dq_dqb.dqb_btime = (time_t) 0;
        clear_bit(DQ_BLKS_B, &dquot->dq_flags);
 }
 
+static int flag_print_warnings = 1;
+
 static inline int need_print_warning(struct dquot *dquot)
 {
+       if (!flag_print_warnings)
+               return 0;
+
        switch (dquot->dq_type) {
                case USRQUOTA:
                        return current->fsuid == dquot->dq_id;
@@ -798,38 +828,46 @@ static inline int need_print_warning(struct dquot *dquot)
 static void print_warning(struct dquot *dquot, const char warntype)
 {
        char *msg = NULL;
+       struct tty_struct *tty;
        int flag = (warntype == BHARDWARN || warntype == BSOFTLONGWARN) ? DQ_BLKS_B :
          ((warntype == IHARDWARN || warntype == ISOFTLONGWARN) ? DQ_INODES_B : 0);
 
        if (!need_print_warning(dquot) || (flag && test_and_set_bit(flag, &dquot->dq_flags)))
                return;
-       tty_write_message(current->signal->tty, dquot->dq_sb->s_id);
+
+       mutex_lock(&tty_mutex);
+       tty = get_current_tty();
+       if (!tty)
+               goto out_lock;
+       tty_write_message(tty, dquot->dq_sb->s_id);
        if (warntype == ISOFTWARN || warntype == BSOFTWARN)
-               tty_write_message(current->signal->tty, ": warning, ");
+               tty_write_message(tty, ": warning, ");
        else
-               tty_write_message(current->signal->tty, ": write failed, ");
-       tty_write_message(current->signal->tty, quotatypes[dquot->dq_type]);
+               tty_write_message(tty, ": write failed, ");
+       tty_write_message(tty, quotatypes[dquot->dq_type]);
        switch (warntype) {
                case IHARDWARN:
-                       msg = " file limit reached.\n";
+                       msg = " file limit reached.\r\n";
                        break;
                case ISOFTLONGWARN:
-                       msg = " file quota exceeded too long.\n";
+                       msg = " file quota exceeded too long.\r\n";
                        break;
                case ISOFTWARN:
-                       msg = " file quota exceeded.\n";
+                       msg = " file quota exceeded.\r\n";
                        break;
                case BHARDWARN:
-                       msg = " block limit reached.\n";
+                       msg = " block limit reached.\r\n";
                        break;
                case BSOFTLONGWARN:
-                       msg = " block quota exceeded too long.\n";
+                       msg = " block quota exceeded too long.\r\n";
                        break;
                case BSOFTWARN:
-                       msg = " block quota exceeded.\n";
+                       msg = " block quota exceeded.\r\n";
                        break;
        }
-       tty_write_message(current->signal->tty, msg);
+       tty_write_message(tty, msg);
+out_lock:
+       mutex_unlock(&tty_mutex);
 }
 
 static inline void flush_warnings(struct dquot **dquots, char *warntype)
@@ -932,8 +970,8 @@ int dquot_initialize(struct inode *inode, int type)
        unsigned int id = 0;
        int cnt, ret = 0;
 
-       /* First test before acquiring semaphore - solves deadlocks when we
-         * re-enter the quota code and are already holding the semaphore */
+       /* 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;
        down_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
@@ -953,8 +991,6 @@ int dquot_initialize(struct inode *inode, int type)
                                        break;
                        }
                        inode->i_dquot[cnt] = dqget(inode->i_sb, id, cnt);
-                       if (inode->i_dquot[cnt])
-                               inode->i_flags |= S_QUOTA;
                }
        }
 out_err:
@@ -971,7 +1007,6 @@ int dquot_drop(struct inode *inode)
        int cnt;
 
        down_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
-       inode->i_flags &= ~S_QUOTA;
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
                if (inode->i_dquot[cnt] != NODQUOT) {
                        dqput(inode->i_dquot[cnt]);
@@ -999,8 +1034,8 @@ int dquot_alloc_space(struct inode *inode, qsize_t number, int warn)
        int cnt, ret = NO_QUOTA;
        char warntype[MAXQUOTAS];
 
-       /* First test before acquiring semaphore - solves deadlocks when we
-         * re-enter the quota code and are already holding the semaphore */
+       /* 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_add:
                inode_add_bytes(inode, number);
@@ -1048,8 +1083,8 @@ int dquot_alloc_inode(const struct inode *inode, unsigned long number)
        int cnt, ret = NO_QUOTA;
        char warntype[MAXQUOTAS];
 
-       /* First test before acquiring semaphore - solves deadlocks when we
-         * re-enter the quota code and are already holding the semaphore */
+       /* 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;
        for (cnt = 0; cnt < MAXQUOTAS; cnt++)
@@ -1086,14 +1121,14 @@ warn_put_all:
 }
 
 /*
- * This is a non-blocking operation.
+ * This operation can block, but only after everything is updated
  */
 int dquot_free_space(struct inode *inode, qsize_t number)
 {
        unsigned int cnt;
 
-       /* First test before acquiring semaphore - solves deadlocks when we
-         * re-enter the quota code and are already holding the semaphore */
+       /* 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:
                inode_sub_bytes(inode, number);
@@ -1122,14 +1157,14 @@ out_sub:
 }
 
 /*
- * This is a non-blocking operation.
+ * This operation can block, but only after everything is updated
  */
 int dquot_free_inode(const struct inode *inode, unsigned long number)
 {
        unsigned int cnt;
 
-       /* First test before acquiring semaphore - solves deadlocks when we
-         * re-enter the quota code and are already holding the semaphore */
+       /* 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;
        down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
@@ -1157,6 +1192,7 @@ int dquot_free_inode(const struct inode *inode, unsigned long number)
  * Transfer the number of inode and blocks from one diskquota to an other.
  *
  * 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)
 {
@@ -1167,8 +1203,8 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr)
            chgid = (iattr->ia_valid & ATTR_GID) && inode->i_gid != iattr->ia_gid;
        char warntype[MAXQUOTAS];
 
-       /* First test before acquiring semaphore - solves deadlocks when we
-         * re-enter the quota code and are already holding the semaphore */
+       /* 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;
        /* Clear the arrays */
@@ -1262,9 +1298,9 @@ int dquot_commit_info(struct super_block *sb, int type)
        int ret;
        struct quota_info *dqopt = sb_dqopt(sb);
 
-       down(&dqopt->dqio_sem);
+       mutex_lock(&dqopt->dqio_mutex);
        ret = dqopt->ops[type]->write_file_info(sb, type);
-       up(&dqopt->dqio_sem);
+       mutex_unlock(&dqopt->dqio_mutex);
        return ret;
 }
 
@@ -1317,10 +1353,12 @@ int vfs_quota_off(struct super_block *sb, int type)
 {
        int cnt;
        struct quota_info *dqopt = sb_dqopt(sb);
+       struct inode *toputinode[MAXQUOTAS];
 
        /* We need to serialize quota_off() for device */
-       down(&dqopt->dqonoff_sem);
+       mutex_lock(&dqopt->dqonoff_mutex);
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+               toputinode[cnt] = NULL;
                if (type != -1 && cnt != type)
                        continue;
                if (!sb_has_quota_enabled(sb, cnt))
@@ -1340,14 +1378,42 @@ int vfs_quota_off(struct super_block *sb, int type)
                        dqopt->ops[cnt]->free_file_info(sb, cnt);
                put_quota_format(dqopt->info[cnt].dqi_format);
 
-               fput(dqopt->files[cnt]);
+               toputinode[cnt] = dqopt->files[cnt];
                dqopt->files[cnt] = NULL;
                dqopt->info[cnt].dqi_flags = 0;
                dqopt->info[cnt].dqi_igrace = 0;
                dqopt->info[cnt].dqi_bgrace = 0;
                dqopt->ops[cnt] = NULL;
        }
-       up(&dqopt->dqonoff_sem);
+       mutex_unlock(&dqopt->dqonoff_mutex);
+       /* Sync the superblock so that buffers with quota data are written to
+        * disk (and so userspace sees correct data afterwards). */
+       if (sb->s_op->sync_fs)
+               sb->s_op->sync_fs(sb, 1);
+       sync_blockdev(sb->s_bdev);
+       /* Now the quota files are just ordinary files and we can set the
+        * inode flags back. Moreover we discard the pagecache so that
+        * userspace sees the writes we did bypassing the pagecache. We
+        * must also discard the blockdev buffers so that we see the
+        * changes done by userspace on the next quotaon() */
+       for (cnt = 0; cnt < MAXQUOTAS; cnt++)
+               if (toputinode[cnt]) {
+                       mutex_lock(&dqopt->dqonoff_mutex);
+                       /* If quota was reenabled in the meantime, we have
+                        * nothing to do */
+                       if (!sb_has_quota_enabled(sb, cnt)) {
+                               mutex_lock(&toputinode[cnt]->i_mutex);
+                               toputinode[cnt]->i_flags &= ~(S_IMMUTABLE |
+                                 S_NOATIME | S_NOQUOTA);
+                               truncate_inode_pages(&toputinode[cnt]->i_data, 0);
+                               mutex_unlock(&toputinode[cnt]->i_mutex);
+                               mark_inode_dirty(toputinode[cnt]);
+                               iput(toputinode[cnt]);
+                       }
+                       mutex_unlock(&dqopt->dqonoff_mutex);
+               }
+       if (sb->s_bdev)
+               invalidate_bdev(sb->s_bdev, 0);
        return 0;
 }
 
@@ -1355,87 +1421,89 @@ int vfs_quota_off(struct super_block *sb, int type)
  *     Turn quotas on on a device
  */
 
-/* Helper function when we already have file open */
-static int vfs_quota_on_file(struct file *f, int type, int format_id)
+/* Helper function when we already have the inode */
+static int vfs_quota_on_inode(struct inode *inode, int type, int format_id)
 {
        struct quota_format_type *fmt = find_quota_format(format_id);
-       struct inode *inode;
-       struct super_block *sb = f->f_dentry->d_sb;
+       struct super_block *sb = inode->i_sb;
        struct quota_info *dqopt = sb_dqopt(sb);
-       struct dquot *to_drop[MAXQUOTAS];
-       int error, cnt;
-       unsigned int oldflags;
+       int error;
+       int oldflags = -1;
 
        if (!fmt)
                return -ESRCH;
-       error = -EIO;
-       if (!f->f_op || !f->f_op->read || !f->f_op->write)
+       if (!S_ISREG(inode->i_mode)) {
+               error = -EACCES;
                goto out_fmt;
-       inode = f->f_dentry->d_inode;
-       error = -EACCES;
-       if (!S_ISREG(inode->i_mode))
+       }
+       if (IS_RDONLY(inode)) {
+               error = -EROFS;
+               goto out_fmt;
+       }
+       if (!sb->s_op->quota_write || !sb->s_op->quota_read) {
+               error = -EINVAL;
                goto out_fmt;
+       }
 
-       down(&dqopt->dqonoff_sem);
+       /* 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 */
+       invalidate_bdev(sb->s_bdev, 0);
+       mutex_lock(&inode->i_mutex);
+       mutex_lock(&dqopt->dqonoff_mutex);
        if (sb_has_quota_enabled(sb, type)) {
                error = -EBUSY;
                goto out_lock;
        }
-       oldflags = inode->i_flags;
-       dqopt->files[type] = f;
-       error = -EINVAL;
-       if (!fmt->qf_ops->check_quota_file(sb, type))
-               goto out_file_init;
        /* We don't want quota and atime on quota files (deadlocks possible)
-        * We also need to set GFP mask differently because we cannot recurse
-        * into filesystem when allocating page for quota inode */
+        * Also nobody should write to the file - we use special IO operations
+        * which ignore the immutable bit. */
        down_write(&dqopt->dqptr_sem);
-       inode->i_flags |= S_NOQUOTA | S_NOATIME;
-
-       /*
-        * We write to quota files deep within filesystem code.  We don't want
-        * the VFS to reenter filesystem code when it tries to allocate a
-        * pagecache page for the quota file write.  So clear __GFP_FS in
-        * the quota file's allocation flags.
-        */
-       mapping_set_gfp_mask(inode->i_mapping,
-               mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS);
-
-       for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-               to_drop[cnt] = inode->i_dquot[cnt];
-               inode->i_dquot[cnt] = NODQUOT;
-       }
-       inode->i_flags &= ~S_QUOTA;
+       oldflags = inode->i_flags & (S_NOATIME | S_IMMUTABLE | S_NOQUOTA);
+       inode->i_flags |= S_NOQUOTA | S_NOATIME | S_IMMUTABLE;
        up_write(&dqopt->dqptr_sem);
-       /* We must put dquots outside of dqptr_sem because we may need to
-        * start transaction for dquot_release() */
-       for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-               if (to_drop[cnt])
-                       dqput(to_drop[cnt]);
-       }
+       sb->dq_op->drop(inode);
+
+       error = -EIO;
+       dqopt->files[type] = igrab(inode);
+       if (!dqopt->files[type])
+               goto out_lock;
+       error = -EINVAL;
+       if (!fmt->qf_ops->check_quota_file(sb, type))
+               goto out_file_init;
 
        dqopt->ops[type] = fmt->qf_ops;
        dqopt->info[type].dqi_format = fmt;
        INIT_LIST_HEAD(&dqopt->info[type].dqi_dirty_list);
-       down(&dqopt->dqio_sem);
+       mutex_lock(&dqopt->dqio_mutex);
        if ((error = dqopt->ops[type]->read_file_info(sb, type)) < 0) {
-               up(&dqopt->dqio_sem);
+               mutex_unlock(&dqopt->dqio_mutex);
                goto out_file_init;
        }
-       up(&dqopt->dqio_sem);
+       mutex_unlock(&dqopt->dqio_mutex);
+       mutex_unlock(&inode->i_mutex);
        set_enable_flags(dqopt, type);
 
        add_dquot_ref(sb, type);
-       up(&dqopt->dqonoff_sem);
+       mutex_unlock(&dqopt->dqonoff_mutex);
 
        return 0;
 
 out_file_init:
-       inode->i_flags = oldflags;
        dqopt->files[type] = NULL;
+       iput(inode);
 out_lock:
-       up_write(&dqopt->dqptr_sem);
-       up(&dqopt->dqonoff_sem);
+       mutex_unlock(&dqopt->dqonoff_mutex);
+       if (oldflags != -1) {
+               down_write(&dqopt->dqptr_sem);
+               /* 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;
+               up_write(&dqopt->dqptr_sem);
+       }
+       mutex_unlock(&inode->i_mutex);
 out_fmt:
        put_quota_format(fmt);
 
@@ -1445,45 +1513,49 @@ out_fmt:
 /* Actual function called from quotactl() */
 int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path)
 {
-       struct file *f;
+       struct nameidata nd;
        int error;
 
-       f = filp_open(path, O_RDWR, 0600);
-       if (IS_ERR(f))
-               return PTR_ERR(f);
-       error = security_quota_on(f);
+       error = path_lookup(path, LOOKUP_FOLLOW, &nd);
+       if (error < 0)
+               return error;
+       error = security_quota_on(nd.dentry);
        if (error)
-               goto out_f;
-       error = vfs_quota_on_file(f, type, format_id);
-       if (!error)
-               return 0;
-out_f:
-       filp_close(f, NULL);
+               goto out_path;
+       /* Quota file not on the same filesystem? */
+       if (nd.mnt->mnt_sb != sb)
+               error = -EXDEV;
+       else
+               error = vfs_quota_on_inode(nd.dentry->d_inode, type, format_id);
+out_path:
+       path_release(&nd);
        return error;
 }
 
 /*
- * Function used by filesystems when filp_open() would fail (filesystem is
- * being mounted now). We will use a private file structure. Caller is
- * responsible that it's IO functions won't need vfsmnt structure or
- * some dentry tricks...
+ * This function is used when filesystem needs to initialize quotas
+ * during mount time.
  */
-int vfs_quota_on_mount(int type, int format_id, struct dentry *dentry)
+int vfs_quota_on_mount(struct super_block *sb, char *qf_name,
+               int format_id, int type)
 {
-       struct file *f;
+       struct dentry *dentry;
        int error;
 
-       dget(dentry);   /* Get a reference for struct file */
-       f = dentry_open(dentry, NULL, O_RDWR);
-       if (IS_ERR(f)) {
-               error = PTR_ERR(f);
-               goto out_dentry;
+       dentry = lookup_one_len(qf_name, sb->s_root, strlen(qf_name));
+       if (IS_ERR(dentry))
+               return PTR_ERR(dentry);
+
+       if (!dentry->d_inode) {
+               error = -ENOENT;
+               goto out;
        }
-       error = vfs_quota_on_file(f, type, format_id);
+
+       error = security_quota_on(dentry);
        if (!error)
-               return 0;
-       fput(f);
-out_dentry:
+               error = vfs_quota_on_inode(dentry->d_inode, type, format_id);
+
+out:
        dput(dentry);
        return error;
 }
@@ -1510,14 +1582,14 @@ int vfs_get_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *d
 {
        struct dquot *dquot;
 
-       down(&sb_dqopt(sb)->dqonoff_sem);
+       mutex_lock(&sb_dqopt(sb)->dqonoff_mutex);
        if (!(dquot = dqget(sb, id, type))) {
-               up(&sb_dqopt(sb)->dqonoff_sem);
+               mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
                return -ESRCH;
        }
        do_get_dqblk(dquot, di);
        dqput(dquot);
-       up(&sb_dqopt(sb)->dqonoff_sem);
+       mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
        return 0;
 }
 
@@ -1579,14 +1651,14 @@ int vfs_set_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *d
 {
        struct dquot *dquot;
 
-       down(&sb_dqopt(sb)->dqonoff_sem);
+       mutex_lock(&sb_dqopt(sb)->dqonoff_mutex);
        if (!(dquot = dqget(sb, id, type))) {
-               up(&sb_dqopt(sb)->dqonoff_sem);
+               mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
                return -ESRCH;
        }
        do_set_dqblk(dquot, di);
        dqput(dquot);
-       up(&sb_dqopt(sb)->dqonoff_sem);
+       mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
        return 0;
 }
 
@@ -1595,9 +1667,9 @@ int vfs_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii)
 {
        struct mem_dqinfo *mi;
   
-       down(&sb_dqopt(sb)->dqonoff_sem);
+       mutex_lock(&sb_dqopt(sb)->dqonoff_mutex);
        if (!sb_has_quota_enabled(sb, type)) {
-               up(&sb_dqopt(sb)->dqonoff_sem);
+               mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
                return -ESRCH;
        }
        mi = sb_dqopt(sb)->info + type;
@@ -1607,7 +1679,7 @@ int vfs_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii)
        ii->dqi_flags = mi->dqi_flags & DQF_MASK;
        ii->dqi_valid = IIF_ALL;
        spin_unlock(&dq_data_lock);
-       up(&sb_dqopt(sb)->dqonoff_sem);
+       mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
        return 0;
 }
 
@@ -1616,9 +1688,9 @@ int vfs_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii)
 {
        struct mem_dqinfo *mi;
 
-       down(&sb_dqopt(sb)->dqonoff_sem);
+       mutex_lock(&sb_dqopt(sb)->dqonoff_mutex);
        if (!sb_has_quota_enabled(sb, type)) {
-               up(&sb_dqopt(sb)->dqonoff_sem);
+               mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
                return -ESRCH;
        }
        mi = sb_dqopt(sb)->info + type;
@@ -1633,7 +1705,7 @@ int vfs_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii)
        mark_info_dirty(sb, type);
        /* Force write to disk */
        sb->dq_op->write_info(sb, type);
-       up(&sb_dqopt(sb)->dqonoff_sem);
+       mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
        return 0;
 }
 
@@ -1712,6 +1784,14 @@ static ctl_table fs_dqstats_table[] = {
                .mode           = 0444,
                .proc_handler   = &proc_dointvec,
        },
+       {
+               .ctl_name       = FS_DQ_WARNINGS,
+               .procname       = "warnings",
+               .data           = &flag_print_warnings,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec,
+       },
        { .ctl_name = 0 },
 };
 
@@ -1735,9 +1815,6 @@ static ctl_table sys_table[] = {
        { .ctl_name = 0 },
 };
 
-/* SLAB cache for dquot structures */
-kmem_cache_t *dquot_cachep;
-
 static int __init dquot_init(void)
 {
        int i;
@@ -1749,7 +1826,8 @@ static int __init dquot_init(void)
 
        dquot_cachep = kmem_cache_create("dquot", 
                        sizeof(struct dquot), sizeof(unsigned long) * 4,
-                       SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|SLAB_PANIC,
+                       (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|
+                               SLAB_MEM_SPREAD|SLAB_PANIC),
                        NULL, NULL);
 
        order = 0;
@@ -1782,7 +1860,6 @@ module_init(dquot_init);
 EXPORT_SYMBOL(register_quota_format);
 EXPORT_SYMBOL(unregister_quota_format);
 EXPORT_SYMBOL(dqstats);
-EXPORT_SYMBOL(dq_list_lock);
 EXPORT_SYMBOL(dq_data_lock);
 EXPORT_SYMBOL(vfs_quota_on);
 EXPORT_SYMBOL(vfs_quota_on_mount);