This commit was manufactured by cvs2svn to create tag
[linux-2.6.git] / fs / dquot.c
index 6c58af7..df42800 100644 (file)
@@ -75,6 +75,7 @@
 #include <linux/proc_fs.h>
 #include <linux/security.h>
 #include <linux/kmod.h>
+#include <linux/pagemap.h>
 
 #include <asm/uaccess.h>
 
@@ -367,7 +368,8 @@ int dquot_release(struct dquot *dquot)
        if (atomic_read(&dquot->dq_count) > 1)
                goto out_dqlock;
        down(&dqopt->dqio_sem);
-       ret = dqopt->ops[dquot->dq_type]->release_dqblk(dquot);
+       if (dqopt->ops[dquot->dq_type]->release_dqblk)
+               ret = dqopt->ops[dquot->dq_type]->release_dqblk(dquot);
        clear_bit(DQ_ACTIVE_B, &dquot->dq_flags);
        up(&dqopt->dqio_sem);
 out_dqlock:
@@ -529,7 +531,7 @@ we_slept:
        clear_dquot_dirty(dquot);
        if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) {
                spin_unlock(&dq_list_lock);
-               dquot_release(dquot);
+               dquot->dq_sb->dq_op->release_dquot(dquot);
                goto we_slept;
        }
        atomic_dec(&dquot->dq_count);
@@ -546,7 +548,7 @@ static struct dquot *get_empty_dquot(struct super_block *sb, int type)
 {
        struct dquot *dquot;
 
-       dquot = kmem_cache_alloc(dquot_cachep, SLAB_KERNEL);
+       dquot = kmem_cache_alloc(dquot_cachep, SLAB_NOFS);
        if(!dquot)
                return NODQUOT;
 
@@ -605,7 +607,7 @@ we_slept:
         * finished or it will be canceled due to dq_count > 1 test */
        wait_on_dquot(dquot);
        /* Read the dquot and instantiate it (everything done only if needed) */
-       if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags) && dquot_acquire(dquot) < 0) {
+       if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags) && sb->dq_op->acquire_dquot(dquot) < 0) {
                dqput(dquot);
                return NODQUOT;
        }
@@ -1203,8 +1205,11 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr)
                if (transfer_to[cnt] == NODQUOT)
                        continue;
 
-               dquot_decr_inodes(transfer_from[cnt], 1);
-               dquot_decr_space(transfer_from[cnt], space);
+               /* Due to IO error we might not have transfer_from[] structure */
+               if (transfer_from[cnt]) {
+                       dquot_decr_inodes(transfer_from[cnt], 1);
+                       dquot_decr_space(transfer_from[cnt], space);
+               }
 
                dquot_incr_inodes(transfer_to[cnt], 1);
                dquot_incr_space(transfer_to[cnt], space);
@@ -1259,6 +1264,8 @@ struct dquot_operations dquot_operations = {
        .free_inode     = dquot_free_inode,
        .transfer       = dquot_transfer,
        .write_dquot    = dquot_commit,
+       .acquire_dquot  = dquot_acquire,
+       .release_dquot  = dquot_release,
        .mark_dirty     = dquot_mark_dquot_dirty,
        .write_info     = dquot_commit_info
 };
@@ -1363,9 +1370,21 @@ static int vfs_quota_on_file(struct file *f, int type, int format_id)
        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 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 */
        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;
@@ -1714,9 +1733,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, NULL, NULL);
-       if (!dquot_cachep)
-               panic("Cannot create dquot SLAB cache");
+                       SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|SLAB_PANIC,
+                       NULL, NULL);
 
        order = 0;
        dquot_hash = (struct hlist_head *)__get_free_pages(GFP_ATOMIC, order);
@@ -1760,6 +1778,8 @@ EXPORT_SYMBOL(vfs_get_dqblk);
 EXPORT_SYMBOL(vfs_set_dqblk);
 EXPORT_SYMBOL(dquot_commit);
 EXPORT_SYMBOL(dquot_commit_info);
+EXPORT_SYMBOL(dquot_acquire);
+EXPORT_SYMBOL(dquot_release);
 EXPORT_SYMBOL(dquot_mark_dquot_dirty);
 EXPORT_SYMBOL(dquot_initialize);
 EXPORT_SYMBOL(dquot_drop);