+++ /dev/null
-From: Jan Kara <jack@suse.cz>
-
-The four patches in this series fix deadlocks with quotas of pagelock (the
-problem was lock inversion on PageLock and transaction start - quota code
-needed to first start a transaction and then write the data which subsequently
-needed acquisition of PageLock while the standard ordering - PageLock first
-and transaction start later - was used e.g. by pdflush). They implement a
-new way of quota access to disk: Every filesystem that would like to implement
-quotas now has to provide quota_read() and quota_write() functions. These
-functions must obey quota lock ordering (in particular they should not take
-PageLock inside a transaction).
-
-The first patch implements the changes in the quota core, the other three
-patches implement needed functions in ext2, ext3 and reiserfs. The patch for
-reiserfs also fixes several other lock inversion problems (similar as ext3
-had) and implements the journaled quota functionality (which comes almost for
-free after the locking fixes...).
-
-The quota core patch makes quota support in other filesystems (except XFS
-which implements everything on its own ;)) unfunctional (quotaon() will refuse
-to turn on quotas on them). When the patches get reasonable wide testing and
-it will seem that no major changes will be needed I can make fixes also for
-the other filesystems (JFS, UDF, UFS).
-
-This patch:
-
-The patch implements the new way of quota io in the quota core. Every
-filesystem wanting to support quotas has to provide functions quota_read()
-and quota_write() obeying quota locking rules. As the writes and reads
-bypass the pagecache there is some ugly stuff ensuring that userspace can
-see all the data after quotaoff() (or Q_SYNC quotactl). In future I plan
-to make quota files inaccessible from userspace (with the exception of
-quotacheck(8) which will take care about the cache flushing and such stuff
-itself) so that this synchronization stuff can be removed...
-
-The rewrite of the quota core. Quota uses the filesystem read() and write()
-functions no more to avoid possible deadlocks on PageLock. From now on every
-filesystem supporting quotas must provide functions quota_read() and
-quota_write() which obey the quota locking rules (e.g. they cannot acquire the
-PageLock).
-
-Signed-off-by: Jan Kara <jack@suse.cz>
-Signed-off-by: Andrew Morton <akpm@osdl.org>
----
-
- 25-akpm/fs/dquot.c | 162 +++++++++++++--------------
- 25-akpm/fs/quota.c | 45 +++++++
- 25-akpm/fs/quota_v1.c | 62 ++--------
- 25-akpm/fs/quota_v2.c | 227 +++++++++++++++++----------------------
- 25-akpm/include/linux/fs.h | 3
- 25-akpm/include/linux/quota.h | 2
- 25-akpm/include/linux/security.h | 8 -
- 25-akpm/security/dummy.c | 2
- 25-akpm/security/selinux/hooks.c | 4
- 9 files changed, 247 insertions(+), 268 deletions(-)
-
-diff -rup RH_2_6_9_55.orig/fs/dquot.c RH_2_6_9_55/fs/dquot.c
---- RH_2_6_9_55.orig/fs/dquot.c
-+++ RH_2_6_9_55/fs/dquot.c
-@@ -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
-@@ -75,7 +75,8 @@
- #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 <asm/uaccess.h>
-
-@@ -114,7 +115,7 @@
- * 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 related VFS locks) is following:
-+ * Lock ordering (including related VFS locks) is the following:
- * i_sem > dqonoff_sem > journal_lock > dqptr_sem > dquot->dq_lock >
- * dqio_sem
- * i_sem on quota files is special (it's below dqio_sem)
-@@ -183,8 +184,7 @@ static void put_quota_format(struct quot
- * 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
-@@ -1341,10 +1341,12 @@ int vfs_quota_off(struct super_block *sb
- {
- int cnt;
- struct quota_info *dqopt = sb_dqopt(sb);
-+ struct inode *toput[MAXQUOTAS];
-
- /* We need to serialize quota_off() for device */
- down(&dqopt->dqonoff_sem);
- for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-+ toput[cnt] = NULL;
- if (type != -1 && cnt != type)
- continue;
- if (!sb_has_quota_enabled(sb, cnt))
-@@ -1364,7 +1366,7 @@ int vfs_quota_off(struct super_block *sb
- dqopt->ops[cnt]->free_file_info(sb, cnt);
- put_quota_format(dqopt->info[cnt].dqi_format);
-
-- fput(dqopt->files[cnt]);
-+ toput[cnt] = dqopt->files[cnt];
- dqopt->files[cnt] = NULL;
- dqopt->info[cnt].dqi_flags = 0;
- dqopt->info[cnt].dqi_igrace = 0;
-@@ -1372,6 +1374,26 @@ int vfs_quota_off(struct super_block *sb
- dqopt->ops[cnt] = NULL;
- }
- up(&dqopt->dqonoff_sem);
-+ /* 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 (toput[cnt]) {
-+ down(&toput[cnt]->i_sem);
-+ toput[cnt]->i_flags &= ~(S_IMMUTABLE | S_NOATIME | S_NOQUOTA);
-+ truncate_inode_pages(&toput[cnt]->i_data, 0);
-+ up(&toput[cnt]->i_sem);
-+ mark_inode_dirty(toput[cnt]);
-+ iput(toput[cnt]);
-+ }
-+ invalidate_bdev(sb->s_bdev, 0);
- return 0;
- }
-
-@@ -1379,68 +1401,56 @@ int vfs_quota_off(struct super_block *sb
- * 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 = -1;
-+ 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;
-+ }
-
-+ /* 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);
- down(&inode->i_sem);
- down(&dqopt->dqonoff_sem);
- if (sb_has_quota_enabled(sb, type)) {
-- up(&inode->i_sem);
- error = -EBUSY;
- goto out_lock;
- }
- /* 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);
-- oldflags = inode->i_flags & (S_NOATIME | S_NOQUOTA);
-- inode->i_flags |= S_NOQUOTA | S_NOATIME;
-+ oldflags = inode->i_flags & (S_NOATIME | S_IMMUTABLE | S_NOQUOTA);
-+ inode->i_flags |= S_NOQUOTA | S_NOATIME | S_IMMUTABLE;
- up_write(&dqopt->dqptr_sem);
-- up(&inode->i_sem);
-
-- dqopt->files[type] = f;
-+ 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;
-- /*
-- * 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);
--
-- down_write(&dqopt->dqptr_sem);
-- for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-- to_drop[cnt] = inode->i_dquot[cnt];
-- inode->i_dquot[cnt] = NODQUOT;
-- }
-- 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]);
-- }
-
- dqopt->ops[type] = fmt->qf_ops;
- dqopt->info[type].dqi_format = fmt;
-@@ -1451,6 +1461,7 @@ static int vfs_quota_on_file(struct file
- goto out_file_init;
- }
- up(&dqopt->dqio_sem);
-+ up(&inode->i_sem);
- set_enable_flags(dqopt, type);
-
- add_dquot_ref(sb, type);
-@@ -1460,19 +1471,18 @@ static int vfs_quota_on_file(struct file
-
- out_file_init:
- dqopt->files[type] = NULL;
-+ iput(inode);
- out_lock:
- up(&dqopt->dqonoff_sem);
- if (oldflags != -1) {
-- down(&inode->i_sem);
- down_write(&dqopt->dqptr_sem);
-- /* Reset the NOATIME flag back. I know it could change in the
-- * mean time but playing with NOATIME flags on a quota file is
-- * never a good idea */
-- inode->i_flags &= ~(S_NOATIME | S_NOQUOTA);
-+ /* 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);
-- up(&inode->i_sem);
- }
-+ up(&inode->i_sem);
- out_fmt:
- put_quota_format(fmt);
-
-@@ -1482,47 +1492,37 @@ 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)
- {
-- struct file *f;
- 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;
-- }
-- error = vfs_quota_on_file(f, type, format_id);
-- if (!error)
-- return 0;
-- fput(f);
--out_dentry:
-- dput(dentry);
-- return error;
-+ error = security_quota_on(dentry);
-+ if (error)
-+ return error;
-+ return vfs_quota_on_inode(dentry->d_inode, type, format_id);
- }
-
- /* Generic routine for getting common part of quota structure */
-diff -rup RH_2_6_9_55.orig/fs/quota.c RH_2_6_9_55/fs/quota.c
---- RH_2_6_9_55.orig/fs/quota.c
-+++ RH_2_6_9_55/fs/quota.c
-@@ -13,6 +13,8 @@
- #include <linux/kernel.h>
- #include <linux/smp_lock.h>
- #include <linux/security.h>
-+#include <linux/syscalls.h>
-+#include <linux/buffer_head.h>
-
- /* Check validity of quotactl */
- static int check_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id)
-@@ -134,16 +136,54 @@ restart:
- return NULL;
- }
-
-+void quota_sync_sb(struct super_block *sb, int type)
-+{
-+ int cnt;
-+ struct inode *discard[MAXQUOTAS];
-+
-+ sb->s_qcop->quota_sync(sb, type);
-+ /* 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. We need i_sem and so we could
-+ * not do it inside dqonoff_sem. Moreover we need to be carefull
-+ * about races with quotaoff() (that is the reason why we have own
-+ * reference to inode). */
-+ down(&sb_dqopt(sb)->dqonoff_sem);
-+ for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-+ discard[cnt] = NULL;
-+ if (type != -1 && cnt != type)
-+ continue;
-+ if (!sb_has_quota_enabled(sb, cnt))
-+ continue;
-+ discard[cnt] = igrab(sb_dqopt(sb)->files[cnt]);
-+ }
-+ up(&sb_dqopt(sb)->dqonoff_sem);
-+ for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-+ if (discard[cnt]) {
-+ down(&discard[cnt]->i_sem);
-+ truncate_inode_pages(&discard[cnt]->i_data, 0);
-+ up(&discard[cnt]->i_sem);
-+ iput(discard[cnt]);
-+ }
-+ }
-+}
-+
- void sync_dquots(struct super_block *sb, int type)
- {
- if (sb) {
- if (sb->s_qcop->quota_sync)
-- sb->s_qcop->quota_sync(sb, type);
-+ quota_sync_sb(sb, type);
- }
- else {
-- while ((sb = get_super_to_sync(type)) != 0) {
-+ while ((sb = get_super_to_sync(type)) != NULL) {
- if (sb->s_qcop->quota_sync)
-- sb->s_qcop->quota_sync(sb, type);
-+ quota_sync_sb(sb, type);
- drop_super(sb);
- }
- }
-diff -rup RH_2_6_9_55.orig/fs/quota_v1.c RH_2_6_9_55/fs/quota_v1.c
---- RH_2_6_9_55.orig/fs/quota_v1.c
-+++ RH_2_6_9_55/fs/quota_v1.c
-@@ -7,7 +7,6 @@
- #include <linux/init.h>
- #include <linux/module.h>
-
--#include <asm/uaccess.h>
- #include <asm/byteorder.h>
-
- MODULE_AUTHOR("Jan Kara");
-@@ -41,23 +40,14 @@ static void v1_mem2disk_dqblk(struct v1_
- static int v1_read_dqblk(struct dquot *dquot)
- {
- int type = dquot->dq_type;
-- struct file *filp;
-- mm_segment_t fs;
-- loff_t offset;
- struct v1_disk_dqblk dqblk;
-
-- filp = sb_dqopt(dquot->dq_sb)->files[type];
-- if (filp == (struct file *)NULL)
-+ if (!sb_dqopt(dquot->dq_sb)->files[type])
- return -EINVAL;
-
-- /* Now we are sure filp is valid */
-- offset = v1_dqoff(dquot->dq_id);
- /* Set structure to 0s in case read fails/is after end of file */
- memset(&dqblk, 0, sizeof(struct v1_disk_dqblk));
-- fs = get_fs();
-- set_fs(KERNEL_DS);
-- filp->f_op->read(filp, (char *)&dqblk, sizeof(struct v1_disk_dqblk), &offset);
-- set_fs(fs);
-+ dquot->dq_sb->s_op->quota_read(dquot->dq_sb, type, (char *)&dqblk, sizeof(struct v1_disk_dqblk), v1_dqoff(dquot->dq_id));
-
- v1_disk2mem_dqblk(&dquot->dq_dqb, &dqblk);
- if (dquot->dq_dqb.dqb_bhardlimit == 0 && dquot->dq_dqb.dqb_bsoftlimit == 0 &&
-@@ -71,26 +61,18 @@ static int v1_read_dqblk(struct dquot *d
- static int v1_commit_dqblk(struct dquot *dquot)
- {
- short type = dquot->dq_type;
-- struct file *filp;
-- mm_segment_t fs;
-- loff_t offset;
- ssize_t ret;
- struct v1_disk_dqblk dqblk;
-
-- filp = sb_dqopt(dquot->dq_sb)->files[type];
-- offset = v1_dqoff(dquot->dq_id);
-- fs = get_fs();
-- set_fs(KERNEL_DS);
--
- v1_mem2disk_dqblk(&dqblk, &dquot->dq_dqb);
- if (dquot->dq_id == 0) {
- dqblk.dqb_btime = sb_dqopt(dquot->dq_sb)->info[type].dqi_bgrace;
- dqblk.dqb_itime = sb_dqopt(dquot->dq_sb)->info[type].dqi_igrace;
- }
- ret = 0;
-- if (filp)
-- ret = filp->f_op->write(filp, (char *)&dqblk,
-- sizeof(struct v1_disk_dqblk), &offset);
-+ if (sb_dqopt(dquot->dq_sb)->files[type])
-+ ret = dquot->dq_sb->s_op->quota_write(dquot->dq_sb, type, (char *)&dqblk,
-+ sizeof(struct v1_disk_dqblk), v1_dqoff(dquot->dq_id));
- if (ret != sizeof(struct v1_disk_dqblk)) {
- printk(KERN_WARNING "VFS: dquota write failed on dev %s\n",
- dquot->dq_sb->s_id);
-@@ -101,7 +83,6 @@ static int v1_commit_dqblk(struct dquot
- ret = 0;
-
- out:
-- set_fs(fs);
- dqstats.writes++;
-
- return ret;
-@@ -121,14 +102,11 @@ struct v2_disk_dqheader {
-
- static int v1_check_quota_file(struct super_block *sb, int type)
- {
-- struct file *f = sb_dqopt(sb)->files[type];
-- struct inode *inode = f->f_dentry->d_inode;
-+ struct inode *inode = sb_dqopt(sb)->files[type];
- ulong blocks;
- size_t off;
- struct v2_disk_dqheader dqhead;
-- mm_segment_t fs;
- ssize_t size;
-- loff_t offset = 0;
- loff_t isize;
- static const uint quota_magics[] = V2_INITQMAGICS;
-
-@@ -140,10 +118,7 @@ static int v1_check_quota_file(struct su
- if ((blocks % sizeof(struct v1_disk_dqblk) * BLOCK_SIZE + off) % sizeof(struct v1_disk_dqblk))
- return 0;
- /* Doublecheck whether we didn't get file with new format - with old quotactl() this could happen */
-- fs = get_fs();
-- set_fs(KERNEL_DS);
-- size = f->f_op->read(f, (char *)&dqhead, sizeof(struct v2_disk_dqheader), &offset);
-- set_fs(fs);
-+ size = sb->s_op->quota_read(sb, type, (char *)&dqhead, sizeof(struct v2_disk_dqheader), 0);
- if (size != sizeof(struct v2_disk_dqheader))
- return 1; /* Probably not new format */
- if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type])
-@@ -155,16 +130,10 @@ static int v1_check_quota_file(struct su
- static int v1_read_file_info(struct super_block *sb, int type)
- {
- struct quota_info *dqopt = sb_dqopt(sb);
-- mm_segment_t fs;
-- loff_t offset;
-- struct file *filp = dqopt->files[type];
- struct v1_disk_dqblk dqblk;
- int ret;
-
-- offset = v1_dqoff(0);
-- fs = get_fs();
-- set_fs(KERNEL_DS);
-- if ((ret = filp->f_op->read(filp, (char *)&dqblk, sizeof(struct v1_disk_dqblk), &offset)) != sizeof(struct v1_disk_dqblk)) {
-+ if ((ret = sb->s_op->quota_read(sb, type, (char *)&dqblk, sizeof(struct v1_disk_dqblk), v1_dqoff(0))) != sizeof(struct v1_disk_dqblk)) {
- if (ret >= 0)
- ret = -EIO;
- goto out;
-@@ -173,38 +142,31 @@ static int v1_read_file_info(struct supe
- dqopt->info[type].dqi_igrace = dqblk.dqb_itime ? dqblk.dqb_itime : MAX_IQ_TIME;
- dqopt->info[type].dqi_bgrace = dqblk.dqb_btime ? dqblk.dqb_btime : MAX_DQ_TIME;
- out:
-- set_fs(fs);
- return ret;
- }
-
- static int v1_write_file_info(struct super_block *sb, int type)
- {
- struct quota_info *dqopt = sb_dqopt(sb);
-- mm_segment_t fs;
-- struct file *filp = dqopt->files[type];
- struct v1_disk_dqblk dqblk;
-- loff_t offset;
- int ret;
-
- dqopt->info[type].dqi_flags &= ~DQF_INFO_DIRTY;
-- offset = v1_dqoff(0);
-- fs = get_fs();
-- set_fs(KERNEL_DS);
-- if ((ret = filp->f_op->read(filp, (char *)&dqblk, sizeof(struct v1_disk_dqblk), &offset)) != sizeof(struct v1_disk_dqblk)) {
-+ if ((ret = sb->s_op->quota_read(sb, type, (char *)&dqblk,
-+ sizeof(struct v1_disk_dqblk), v1_dqoff(0))) != sizeof(struct v1_disk_dqblk)) {
- if (ret >= 0)
- ret = -EIO;
- goto out;
- }
- dqblk.dqb_itime = dqopt->info[type].dqi_igrace;
- dqblk.dqb_btime = dqopt->info[type].dqi_bgrace;
-- offset = v1_dqoff(0);
-- ret = filp->f_op->write(filp, (char *)&dqblk, sizeof(struct v1_disk_dqblk), &offset);
-+ ret = sb->s_op->quota_write(sb, type, (char *)&dqblk,
-+ sizeof(struct v1_disk_dqblk), v1_dqoff(0));
- if (ret == sizeof(struct v1_disk_dqblk))
- ret = 0;
- else if (ret > 0)
- ret = -EIO;
- out:
-- set_fs(fs);
- return ret;
- }
-
-diff -rup RH_2_6_9_55.orig/fs/quota_v2.c RH_2_6_9_55/fs/quota_v2.c
---- RH_2_6_9_55.orig/fs/quota_v2.c
-+++ RH_2_6_9_55/fs/quota_v2.c
-@@ -13,7 +13,6 @@
- #include <linux/slab.h>
-
- #include <asm/byteorder.h>
--#include <asm/uaccess.h>
-
- MODULE_AUTHOR("Jan Kara");
- MODULE_DESCRIPTION("Quota format v2 support");
-@@ -30,19 +29,15 @@ typedef char *dqbuf_t;
- static int v2_check_quota_file(struct super_block *sb, int type)
- {
- struct v2_disk_dqheader dqhead;
-- struct file *f = sb_dqopt(sb)->files[type];
-- mm_segment_t fs;
- ssize_t size;
-- loff_t offset = 0;
- static const uint quota_magics[] = V2_INITQMAGICS;
- static const uint quota_versions[] = V2_INITQVERSIONS;
-
-- fs = get_fs();
-- set_fs(KERNEL_DS);
-- size = f->f_op->read(f, (char *)&dqhead, sizeof(struct v2_disk_dqheader), &offset);
-- set_fs(fs);
-- if (size != sizeof(struct v2_disk_dqheader))
-+ size = sb->s_op->quota_read(sb, type, (char *)&dqhead, sizeof(struct v2_disk_dqheader), 0);
-+ if (size != sizeof(struct v2_disk_dqheader)) {
-+ printk("failed read\n");
- return 0;
-+ }
- if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type] ||
- le32_to_cpu(dqhead.dqh_version) != quota_versions[type])
- return 0;
-@@ -52,20 +47,15 @@ static int v2_check_quota_file(struct su
- /* Read information header from quota file */
- static int v2_read_file_info(struct super_block *sb, int type)
- {
-- mm_segment_t fs;
- struct v2_disk_dqinfo dinfo;
- struct mem_dqinfo *info = sb_dqopt(sb)->info+type;
-- struct file *f = sb_dqopt(sb)->files[type];
- ssize_t size;
-- loff_t offset = V2_DQINFOOFF;
-
-- fs = get_fs();
-- set_fs(KERNEL_DS);
-- size = f->f_op->read(f, (char *)&dinfo, sizeof(struct v2_disk_dqinfo), &offset);
-- set_fs(fs);
-+ size = sb->s_op->quota_read(sb, type, (char *)&dinfo,
-+ sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF);
- if (size != sizeof(struct v2_disk_dqinfo)) {
- printk(KERN_WARNING "Can't read info structure on device %s.\n",
-- f->f_dentry->d_sb->s_id);
-+ sb->s_id);
- return -1;
- }
- info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace);
-@@ -80,12 +70,9 @@ static int v2_read_file_info(struct supe
- /* Write information header to quota file */
- static int v2_write_file_info(struct super_block *sb, int type)
- {
-- mm_segment_t fs;
- struct v2_disk_dqinfo dinfo;
- struct mem_dqinfo *info = sb_dqopt(sb)->info+type;
-- struct file *f = sb_dqopt(sb)->files[type];
- ssize_t size;
-- loff_t offset = V2_DQINFOOFF;
-
- spin_lock(&dq_data_lock);
- info->dqi_flags &= ~DQF_INFO_DIRTY;
-@@ -96,13 +83,11 @@ static int v2_write_file_info(struct sup
- dinfo.dqi_blocks = cpu_to_le32(info->u.v2_i.dqi_blocks);
- dinfo.dqi_free_blk = cpu_to_le32(info->u.v2_i.dqi_free_blk);
- dinfo.dqi_free_entry = cpu_to_le32(info->u.v2_i.dqi_free_entry);
-- fs = get_fs();
-- set_fs(KERNEL_DS);
-- size = f->f_op->write(f, (char *)&dinfo, sizeof(struct v2_disk_dqinfo), &offset);
-- set_fs(fs);
-+ size = sb->s_op->quota_write(sb, type, (char *)&dinfo,
-+ sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF);
- if (size != sizeof(struct v2_disk_dqinfo)) {
- printk(KERN_WARNING "Can't write info structure on device %s.\n",
-- f->f_dentry->d_sb->s_id);
-+ sb->s_id);
- return -1;
- }
- return 0;
-@@ -146,39 +131,24 @@ static inline void freedqbuf(dqbuf_t buf
- kfree(buf);
- }
-
--static ssize_t read_blk(struct file *filp, uint blk, dqbuf_t buf)
-+static inline ssize_t read_blk(struct super_block *sb, int type, uint blk, dqbuf_t buf)
- {
-- mm_segment_t fs;
-- ssize_t ret;
-- loff_t offset = blk<<V2_DQBLKSIZE_BITS;
--
- memset(buf, 0, V2_DQBLKSIZE);
-- fs = get_fs();
-- set_fs(KERNEL_DS);
-- ret = filp->f_op->read(filp, (char *)buf, V2_DQBLKSIZE, &offset);
-- set_fs(fs);
-- return ret;
-+ return sb->s_op->quota_read(sb, type, (char *)buf,
-+ V2_DQBLKSIZE, blk << V2_DQBLKSIZE_BITS);
- }
-
--static ssize_t write_blk(struct file *filp, uint blk, dqbuf_t buf)
-+static inline ssize_t write_blk(struct super_block *sb, int type, uint blk, dqbuf_t buf)
- {
-- mm_segment_t fs;
-- ssize_t ret;
-- loff_t offset = blk<<V2_DQBLKSIZE_BITS;
--
-- fs = get_fs();
-- set_fs(KERNEL_DS);
-- ret = filp->f_op->write(filp, (char *)buf, V2_DQBLKSIZE, &offset);
-- set_fs(fs);
-- return ret;
--
-+ return sb->s_op->quota_write(sb, type, (char *)buf,
-+ V2_DQBLKSIZE, blk << V2_DQBLKSIZE_BITS);
- }
-
- /* Remove empty block from list and return it */
--static int get_free_dqblk(struct file *filp, int type)
-+static int get_free_dqblk(struct super_block *sb, int type)
- {
- dqbuf_t buf = getdqbuf();
-- struct mem_dqinfo *info = sb_dqinfo(filp->f_dentry->d_sb, type);
-+ struct mem_dqinfo *info = sb_dqinfo(sb, type);
- struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
- int ret, blk;
-
-@@ -186,17 +156,18 @@ static int get_free_dqblk(struct file *f
- return -ENOMEM;
- if (info->u.v2_i.dqi_free_blk) {
- blk = info->u.v2_i.dqi_free_blk;
-- if ((ret = read_blk(filp, blk, buf)) < 0)
-+ if ((ret = read_blk(sb, type, blk, buf)) < 0)
- goto out_buf;
- info->u.v2_i.dqi_free_blk = le32_to_cpu(dh->dqdh_next_free);
- }
- else {
- memset(buf, 0, V2_DQBLKSIZE);
-- if ((ret = write_blk(filp, info->u.v2_i.dqi_blocks, buf)) < 0) /* Assure block allocation... */
-+ /* Assure block allocation... */
-+ if ((ret = write_blk(sb, type, info->u.v2_i.dqi_blocks, buf)) < 0)
- goto out_buf;
- blk = info->u.v2_i.dqi_blocks++;
- }
-- mark_info_dirty(filp->f_dentry->d_sb, type);
-+ mark_info_dirty(sb, type);
- ret = blk;
- out_buf:
- freedqbuf(buf);
-@@ -204,9 +175,9 @@ out_buf:
- }
-
- /* Insert empty block to the list */
--static int put_free_dqblk(struct file *filp, int type, dqbuf_t buf, uint blk)
-+static int put_free_dqblk(struct super_block *sb, int type, dqbuf_t buf, uint blk)
- {
-- struct mem_dqinfo *info = sb_dqinfo(filp->f_dentry->d_sb, type);
-+ struct mem_dqinfo *info = sb_dqinfo(sb, type);
- struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
- int err;
-
-@@ -214,17 +185,18 @@ static int put_free_dqblk(struct file *f
- dh->dqdh_prev_free = cpu_to_le32(0);
- dh->dqdh_entries = cpu_to_le16(0);
- info->u.v2_i.dqi_free_blk = blk;
-- mark_info_dirty(filp->f_dentry->d_sb, type);
-- if ((err = write_blk(filp, blk, buf)) < 0) /* Some strange block. We had better leave it... */
-+ mark_info_dirty(sb, type);
-+ /* Some strange block. We had better leave it... */
-+ if ((err = write_blk(sb, type, blk, buf)) < 0)
- return err;
- return 0;
- }
-
- /* Remove given block from the list of blocks with free entries */
--static int remove_free_dqentry(struct file *filp, int type, dqbuf_t buf, uint blk)
-+static int remove_free_dqentry(struct super_block *sb, int type, dqbuf_t buf, uint blk)
- {
- dqbuf_t tmpbuf = getdqbuf();
-- struct mem_dqinfo *info = sb_dqinfo(filp->f_dentry->d_sb, type);
-+ struct mem_dqinfo *info = sb_dqinfo(sb, type);
- struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
- uint nextblk = le32_to_cpu(dh->dqdh_next_free), prevblk = le32_to_cpu(dh->dqdh_prev_free);
- int err;
-@@ -232,26 +204,27 @@ static int remove_free_dqentry(struct fi
- if (!tmpbuf)
- return -ENOMEM;
- if (nextblk) {
-- if ((err = read_blk(filp, nextblk, tmpbuf)) < 0)
-+ if ((err = read_blk(sb, type, nextblk, tmpbuf)) < 0)
- goto out_buf;
- ((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = dh->dqdh_prev_free;
-- if ((err = write_blk(filp, nextblk, tmpbuf)) < 0)
-+ if ((err = write_blk(sb, type, nextblk, tmpbuf)) < 0)
- goto out_buf;
- }
- if (prevblk) {
-- if ((err = read_blk(filp, prevblk, tmpbuf)) < 0)
-+ if ((err = read_blk(sb, type, prevblk, tmpbuf)) < 0)
- goto out_buf;
- ((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_next_free = dh->dqdh_next_free;
-- if ((err = write_blk(filp, prevblk, tmpbuf)) < 0)
-+ if ((err = write_blk(sb, type, prevblk, tmpbuf)) < 0)
- goto out_buf;
- }
- else {
- info->u.v2_i.dqi_free_entry = nextblk;
-- mark_info_dirty(filp->f_dentry->d_sb, type);
-+ mark_info_dirty(sb, type);
- }
- freedqbuf(tmpbuf);
- dh->dqdh_next_free = dh->dqdh_prev_free = cpu_to_le32(0);
-- if (write_blk(filp, blk, buf) < 0) /* No matter whether write succeeds block is out of list */
-+ /* No matter whether write succeeds block is out of list */
-+ if (write_blk(sb, type, blk, buf) < 0)
- printk(KERN_ERR "VFS: Can't write block (%u) with free entries.\n", blk);
- return 0;
- out_buf:
-@@ -260,10 +233,10 @@ out_buf:
- }
-
- /* Insert given block to the beginning of list with free entries */
--static int insert_free_dqentry(struct file *filp, int type, dqbuf_t buf, uint blk)
-+static int insert_free_dqentry(struct super_block *sb, int type, dqbuf_t buf, uint blk)
- {
- dqbuf_t tmpbuf = getdqbuf();
-- struct mem_dqinfo *info = sb_dqinfo(filp->f_dentry->d_sb, type);
-+ struct mem_dqinfo *info = sb_dqinfo(sb, type);
- struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
- int err;
-
-@@ -271,18 +244,18 @@ static int insert_free_dqentry(struct fi
- return -ENOMEM;
- dh->dqdh_next_free = cpu_to_le32(info->u.v2_i.dqi_free_entry);
- dh->dqdh_prev_free = cpu_to_le32(0);
-- if ((err = write_blk(filp, blk, buf)) < 0)
-+ if ((err = write_blk(sb, type, blk, buf)) < 0)
- goto out_buf;
- if (info->u.v2_i.dqi_free_entry) {
-- if ((err = read_blk(filp, info->u.v2_i.dqi_free_entry, tmpbuf)) < 0)
-+ if ((err = read_blk(sb, type, info->u.v2_i.dqi_free_entry, tmpbuf)) < 0)
- goto out_buf;
- ((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = cpu_to_le32(blk);
-- if ((err = write_blk(filp, info->u.v2_i.dqi_free_entry, tmpbuf)) < 0)
-+ if ((err = write_blk(sb, type, info->u.v2_i.dqi_free_entry, tmpbuf)) < 0)
- goto out_buf;
- }
- freedqbuf(tmpbuf);
- info->u.v2_i.dqi_free_entry = blk;
-- mark_info_dirty(filp->f_dentry->d_sb, type);
-+ mark_info_dirty(sb, type);
- return 0;
- out_buf:
- freedqbuf(tmpbuf);
-@@ -292,8 +265,8 @@ out_buf:
- /* Find space for dquot */
- static uint find_free_dqentry(struct dquot *dquot, int *err)
- {
-- struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
-- struct mem_dqinfo *info = sb_dqopt(dquot->dq_sb)->info+dquot->dq_type;
-+ struct super_block *sb = dquot->dq_sb;
-+ struct mem_dqinfo *info = sb_dqopt(sb)->info+dquot->dq_type;
- uint blk, i;
- struct v2_disk_dqdbheader *dh;
- struct v2_disk_dqblk *ddquot;
-@@ -309,22 +282,23 @@ static uint find_free_dqentry(struct dqu
- ddquot = GETENTRIES(buf);
- if (info->u.v2_i.dqi_free_entry) {
- blk = info->u.v2_i.dqi_free_entry;
-- if ((*err = read_blk(filp, blk, buf)) < 0)
-+ if ((*err = read_blk(sb, dquot->dq_type, blk, buf)) < 0)
- goto out_buf;
- }
- else {
-- blk = get_free_dqblk(filp, dquot->dq_type);
-+ blk = get_free_dqblk(sb, dquot->dq_type);
- if ((int)blk < 0) {
- *err = blk;
- freedqbuf(buf);
- return 0;
- }
- memset(buf, 0, V2_DQBLKSIZE);
-- info->u.v2_i.dqi_free_entry = blk; /* This is enough as block is already zeroed and entry list is empty... */
-- mark_info_dirty(dquot->dq_sb, dquot->dq_type);
-+ /* This is enough as block is already zeroed and entry list is empty... */
-+ info->u.v2_i.dqi_free_entry = blk;
-+ mark_info_dirty(sb, dquot->dq_type);
- }
- if (le16_to_cpu(dh->dqdh_entries)+1 >= V2_DQSTRINBLK) /* Block will be full? */
-- if ((*err = remove_free_dqentry(filp, dquot->dq_type, buf, blk)) < 0) {
-+ if ((*err = remove_free_dqentry(sb, dquot->dq_type, buf, blk)) < 0) {
- printk(KERN_ERR "VFS: find_free_dqentry(): Can't remove block (%u) from entry free list.\n", blk);
- goto out_buf;
- }
-@@ -339,7 +313,7 @@ static uint find_free_dqentry(struct dqu
- goto out_buf;
- }
- #endif
-- if ((*err = write_blk(filp, blk, buf)) < 0) {
-+ if ((*err = write_blk(sb, dquot->dq_type, blk, buf)) < 0) {
- printk(KERN_ERR "VFS: find_free_dqentry(): Can't write quota data block %u.\n", blk);
- goto out_buf;
- }
-@@ -354,7 +328,7 @@ out_buf:
- /* Insert reference to structure into the trie */
- static int do_insert_tree(struct dquot *dquot, uint *treeblk, int depth)
- {
-- struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
-+ struct super_block *sb = dquot->dq_sb;
- dqbuf_t buf;
- int ret = 0, newson = 0, newact = 0;
- __le32 *ref;
-@@ -363,7 +337,7 @@ static int do_insert_tree(struct dquot *
- if (!(buf = getdqbuf()))
- return -ENOMEM;
- if (!*treeblk) {
-- ret = get_free_dqblk(filp, dquot->dq_type);
-+ ret = get_free_dqblk(sb, dquot->dq_type);
- if (ret < 0)
- goto out_buf;
- *treeblk = ret;
-@@ -371,7 +345,7 @@ static int do_insert_tree(struct dquot *
- newact = 1;
- }
- else {
-- if ((ret = read_blk(filp, *treeblk, buf)) < 0) {
-+ if ((ret = read_blk(sb, dquot->dq_type, *treeblk, buf)) < 0) {
- printk(KERN_ERR "VFS: Can't read tree quota block %u.\n", *treeblk);
- goto out_buf;
- }
-@@ -394,10 +368,10 @@ static int do_insert_tree(struct dquot *
- ret = do_insert_tree(dquot, &newblk, depth+1);
- if (newson && ret >= 0) {
- ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(newblk);
-- ret = write_blk(filp, *treeblk, buf);
-+ ret = write_blk(sb, dquot->dq_type, *treeblk, buf);
- }
- else if (newact && ret < 0)
-- put_free_dqblk(filp, dquot->dq_type, buf, *treeblk);
-+ put_free_dqblk(sb, dquot->dq_type, buf, *treeblk);
- out_buf:
- freedqbuf(buf);
- return ret;
-@@ -416,20 +390,15 @@ static inline int dq_insert_tree(struct
- static int v2_write_dquot(struct dquot *dquot)
- {
- int type = dquot->dq_type;
-- struct file *filp;
-- mm_segment_t fs;
-- loff_t offset;
- ssize_t ret;
- struct v2_disk_dqblk ddquot, empty;
-
- /* dq_off is guarded by dqio_sem */
- if (!dquot->dq_off)
- if ((ret = dq_insert_tree(dquot)) < 0) {
-- printk(KERN_ERR "VFS: Error %Zd occurred while creating quota.\n", ret);
-+ printk(KERN_ERR "VFS: Error %d occurred while creating quota.\n", ret);
- return ret;
- }
-- filp = sb_dqopt(dquot->dq_sb)->files[type];
-- offset = dquot->dq_off;
- spin_lock(&dq_data_lock);
- mem2diskdqb(&ddquot, &dquot->dq_dqb, dquot->dq_id);
- /* Argh... We may need to write structure full of zeroes but that would be
-@@ -439,10 +408,8 @@ static int v2_write_dquot(struct dquot *
- if (!memcmp(&empty, &ddquot, sizeof(struct v2_disk_dqblk)))
- ddquot.dqb_itime = cpu_to_le64(1);
- spin_unlock(&dq_data_lock);
-- fs = get_fs();
-- set_fs(KERNEL_DS);
-- ret = filp->f_op->write(filp, (char *)&ddquot, sizeof(struct v2_disk_dqblk), &offset);
-- set_fs(fs);
-+ ret = dquot->dq_sb->s_op->quota_write(dquot->dq_sb, type,
-+ (char *)&ddquot, sizeof(struct v2_disk_dqblk), dquot->dq_off);
- if (ret != sizeof(struct v2_disk_dqblk)) {
- printk(KERN_WARNING "VFS: dquota write failed on dev %s\n", dquot->dq_sb->s_id);
- if (ret >= 0)
-@@ -458,7 +425,8 @@ static int v2_write_dquot(struct dquot *
- /* Free dquot entry in data block */
- static int free_dqentry(struct dquot *dquot, uint blk)
- {
-- struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
-+ struct super_block *sb = dquot->dq_sb;
-+ int type = dquot->dq_type;
- struct v2_disk_dqdbheader *dh;
- dqbuf_t buf = getdqbuf();
- int ret = 0;
-@@ -466,34 +434,39 @@ static int free_dqentry(struct dquot *dq
- if (!buf)
- return -ENOMEM;
- if (dquot->dq_off >> V2_DQBLKSIZE_BITS != blk) {
-- printk(KERN_ERR "VFS: Quota structure has offset to other block (%u) than it should (%u).\n", blk, (uint)(dquot->dq_off >> V2_DQBLKSIZE_BITS));
-+ printk(KERN_ERR "VFS: Quota structure has offset to other "
-+ "block (%u) than it should (%u).\n", blk,
-+ (uint)(dquot->dq_off >> V2_DQBLKSIZE_BITS));
- goto out_buf;
- }
-- if ((ret = read_blk(filp, blk, buf)) < 0) {
-+ if ((ret = read_blk(sb, type, blk, buf)) < 0) {
- printk(KERN_ERR "VFS: Can't read quota data block %u\n", blk);
- goto out_buf;
- }
- dh = (struct v2_disk_dqdbheader *)buf;
- dh->dqdh_entries = cpu_to_le16(le16_to_cpu(dh->dqdh_entries)-1);
- if (!le16_to_cpu(dh->dqdh_entries)) { /* Block got free? */
-- if ((ret = remove_free_dqentry(filp, dquot->dq_type, buf, blk)) < 0 ||
-- (ret = put_free_dqblk(filp, dquot->dq_type, buf, blk)) < 0) {
-- printk(KERN_ERR "VFS: Can't move quota data block (%u) to free list.\n", blk);
-+ if ((ret = remove_free_dqentry(sb, type, buf, blk)) < 0 ||
-+ (ret = put_free_dqblk(sb, type, buf, blk)) < 0) {
-+ printk(KERN_ERR "VFS: Can't move quota data block (%u) "
-+ "to free list.\n", blk);
- goto out_buf;
- }
- }
- else {
-- memset(buf+(dquot->dq_off & ((1 << V2_DQBLKSIZE_BITS)-1)), 0, sizeof(struct v2_disk_dqblk));
-+ memset(buf+(dquot->dq_off & ((1 << V2_DQBLKSIZE_BITS)-1)), 0,
-+ sizeof(struct v2_disk_dqblk));
- if (le16_to_cpu(dh->dqdh_entries) == V2_DQSTRINBLK-1) {
- /* Insert will write block itself */
-- if ((ret = insert_free_dqentry(filp, dquot->dq_type, buf, blk)) < 0) {
-+ if ((ret = insert_free_dqentry(sb, type, buf, blk)) < 0) {
- printk(KERN_ERR "VFS: Can't insert quota data block (%u) to free entry list.\n", blk);
- goto out_buf;
- }
- }
- else
-- if ((ret = write_blk(filp, blk, buf)) < 0) {
-- printk(KERN_ERR "VFS: Can't write quota data block %u\n", blk);
-+ if ((ret = write_blk(sb, type, blk, buf)) < 0) {
-+ printk(KERN_ERR "VFS: Can't write quota data "
-+ "block %u\n", blk);
- goto out_buf;
- }
- }
-@@ -506,7 +479,8 @@ out_buf:
- /* Remove reference to dquot from tree */
- static int remove_tree(struct dquot *dquot, uint *blk, int depth)
- {
-- struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
-+ struct super_block *sb = dquot->dq_sb;
-+ int type = dquot->dq_type;
- dqbuf_t buf = getdqbuf();
- int ret = 0;
- uint newblk;
-@@ -514,7 +488,7 @@ static int remove_tree(struct dquot *dqu
-
- if (!buf)
- return -ENOMEM;
-- if ((ret = read_blk(filp, *blk, buf)) < 0) {
-+ if ((ret = read_blk(sb, type, *blk, buf)) < 0) {
- printk(KERN_ERR "VFS: Can't read quota data block %u\n", *blk);
- goto out_buf;
- }
-@@ -530,12 +504,13 @@ static int remove_tree(struct dquot *dqu
- ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(0);
- for (i = 0; i < V2_DQBLKSIZE && !buf[i]; i++); /* Block got empty? */
- if (i == V2_DQBLKSIZE) {
-- put_free_dqblk(filp, dquot->dq_type, buf, *blk);
-+ put_free_dqblk(sb, type, buf, *blk);
- *blk = 0;
- }
- else
-- if ((ret = write_blk(filp, *blk, buf)) < 0)
-- printk(KERN_ERR "VFS: Can't write quota tree block %u.\n", *blk);
-+ if ((ret = write_blk(sb, type, *blk, buf)) < 0)
-+ printk(KERN_ERR "VFS: Can't write quota tree "
-+ "block %u.\n", *blk);
- }
- out_buf:
- freedqbuf(buf);
-@@ -555,7 +530,6 @@ static int v2_delete_dquot(struct dquot
- /* Find entry in block */
- static loff_t find_block_dqentry(struct dquot *dquot, uint blk)
- {
-- struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
- dqbuf_t buf = getdqbuf();
- loff_t ret = 0;
- int i;
-@@ -563,27 +537,31 @@ static loff_t find_block_dqentry(struct
-
- if (!buf)
- return -ENOMEM;
-- if ((ret = read_blk(filp, blk, buf)) < 0) {
-+ if ((ret = read_blk(dquot->dq_sb, dquot->dq_type, blk, buf)) < 0) {
- printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
- goto out_buf;
- }
- if (dquot->dq_id)
-- for (i = 0; i < V2_DQSTRINBLK && le32_to_cpu(ddquot[i].dqb_id) != dquot->dq_id; i++);
-+ for (i = 0; i < V2_DQSTRINBLK &&
-+ le32_to_cpu(ddquot[i].dqb_id) != dquot->dq_id; i++);
- else { /* ID 0 as a bit more complicated searching... */
- struct v2_disk_dqblk fakedquot;
-
- memset(&fakedquot, 0, sizeof(struct v2_disk_dqblk));
- for (i = 0; i < V2_DQSTRINBLK; i++)
-- if (!le32_to_cpu(ddquot[i].dqb_id) && memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk)))
-+ if (!le32_to_cpu(ddquot[i].dqb_id) &&
-+ memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk)))
- break;
- }
- if (i == V2_DQSTRINBLK) {
-- printk(KERN_ERR "VFS: Quota for id %u referenced but not present.\n", dquot->dq_id);
-+ printk(KERN_ERR "VFS: Quota for id %u referenced "
-+ "but not present.\n", dquot->dq_id);
- ret = -EIO;
- goto out_buf;
- }
- else
-- ret = (blk << V2_DQBLKSIZE_BITS) + sizeof(struct v2_disk_dqdbheader) + i * sizeof(struct v2_disk_dqblk);
-+ ret = (blk << V2_DQBLKSIZE_BITS) + sizeof(struct
-+ v2_disk_dqdbheader) + i * sizeof(struct v2_disk_dqblk);
- out_buf:
- freedqbuf(buf);
- return ret;
-@@ -592,14 +570,13 @@ out_buf:
- /* Find entry for given id in the tree */
- static loff_t find_tree_dqentry(struct dquot *dquot, uint blk, int depth)
- {
-- struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
- dqbuf_t buf = getdqbuf();
- loff_t ret = 0;
- __le32 *ref = (__le32 *)buf;
-
- if (!buf)
- return -ENOMEM;
-- if ((ret = read_blk(filp, blk, buf)) < 0) {
-+ if ((ret = read_blk(dquot->dq_sb, dquot->dq_type, blk, buf)) < 0) {
- printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
- goto out_buf;
- }
-@@ -625,16 +602,13 @@ static inline loff_t find_dqentry(struct
- static int v2_read_dquot(struct dquot *dquot)
- {
- int type = dquot->dq_type;
-- struct file *filp;
-- mm_segment_t fs;
- loff_t offset;
- struct v2_disk_dqblk ddquot, empty;
- int ret = 0;
-
-- filp = sb_dqopt(dquot->dq_sb)->files[type];
--
- #ifdef __QUOTA_V2_PARANOIA
-- if (!filp || !dquot->dq_sb) { /* Invalidated quota? */
-+ /* Invalidated quota? */
-+ if (!dquot->dq_sb || !sb_dqopt(dquot->dq_sb)->files[type]) {
- printk(KERN_ERR "VFS: Quota invalidated while reading!\n");
- return -EIO;
- }
-@@ -642,7 +616,8 @@ static int v2_read_dquot(struct dquot *d
- offset = find_dqentry(dquot);
- if (offset <= 0) { /* Entry not present? */
- if (offset < 0)
-- printk(KERN_ERR "VFS: Can't read quota structure for id %u.\n", dquot->dq_id);
-+ printk(KERN_ERR "VFS: Can't read quota "
-+ "structure for id %u.\n", dquot->dq_id);
- dquot->dq_off = 0;
- set_bit(DQ_FAKE_B, &dquot->dq_flags);
- memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
-@@ -650,12 +625,13 @@ static int v2_read_dquot(struct dquot *d
- }
- else {
- dquot->dq_off = offset;
-- fs = get_fs();
-- set_fs(KERNEL_DS);
-- if ((ret = filp->f_op->read(filp, (char *)&ddquot, sizeof(struct v2_disk_dqblk), &offset)) != sizeof(struct v2_disk_dqblk)) {
-+ if ((ret = dquot->dq_sb->s_op->quota_read(dquot->dq_sb, type,
-+ (char *)&ddquot, sizeof(struct v2_disk_dqblk), offset))
-+ != sizeof(struct v2_disk_dqblk)) {
- if (ret >= 0)
- ret = -EIO;
-- printk(KERN_ERR "VFS: Error while reading quota structure for id %u.\n", dquot->dq_id);
-+ printk(KERN_ERR "VFS: Error while reading quota "
-+ "structure for id %u.\n", dquot->dq_id);
- memset(&ddquot, 0, sizeof(struct v2_disk_dqblk));
- }
- else {
-@@ -666,7 +642,6 @@ static int v2_read_dquot(struct dquot *d
- if (!memcmp(&empty, &ddquot, sizeof(struct v2_disk_dqblk)))
- ddquot.dqb_itime = 0;
- }
-- set_fs(fs);
- disk2memdqb(&dquot->dq_dqb, &ddquot);
- if (!dquot->dq_dqb.dqb_bhardlimit &&
- !dquot->dq_dqb.dqb_bsoftlimit &&
-diff -rup RH_2_6_9_55.orig/include/linux/fs.h RH_2_6_9_55/include/linux/fs.h
---- RH_2_6_9_55.orig/include/linux/fs.h
-+++ RH_2_6_9_55/include/linux/fs.h
-@@ -1042,6 +1042,9 @@ struct super_operations {
- void (*umount_lustre) (struct super_block *);
-
- int (*show_options)(struct seq_file *, struct vfsmount *);
-+
-+ ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t);
-+ ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t);
- };
-
- /* Inode state bits. Protected by inode_lock. */
-diff -rup RH_2_6_9_55.orig/include/linux/quota.h RH_2_6_9_55/include/linux/quota.h
---- RH_2_6_9_55.orig/include/linux/quota.h
-+++ RH_2_6_9_55/include/linux/quota.h
-@@ -285,7 +285,7 @@ struct quota_info {
- struct semaphore dqio_sem; /* lock device while I/O in progress */
- struct semaphore dqonoff_sem; /* Serialize quotaon & quotaoff */
- struct rw_semaphore dqptr_sem; /* serialize ops using quota_info struct, pointers from inode to dquots */
-- struct file *files[MAXQUOTAS]; /* fp's to quotafiles */
-+ struct inode *files[MAXQUOTAS]; /* inodes of quotafiles */
- struct mem_dqinfo info[MAXQUOTAS]; /* Information for each quota type */
- struct quota_format_ops *ops[MAXQUOTAS]; /* Operations for each type */
- };
-diff -rup RH_2_6_9_55.orig/include/linux/security.h RH_2_6_9_55/include/linux/security.h
---- RH_2_6_9_55.orig/include/linux/security.h
-+++ RH_2_6_9_55/include/linux/security.h
-@@ -1033,7 +1033,7 @@ struct security_operations {
- int (*sysctl) (ctl_table * table, int op);
- int (*capable) (struct task_struct * tsk, int cap);
- int (*quotactl) (int cmds, int type, int id, struct super_block * sb);
-- int (*quota_on) (struct file * f);
-+ int (*quota_on) (struct dentry * dentry);
- int (*syslog) (int type);
- int (*vm_enough_memory) (long pages);
-
-@@ -1281,9 +1281,9 @@ static inline int security_quotactl (int
- return security_ops->quotactl (cmds, type, id, sb);
- }
-
--static inline int security_quota_on (struct file * file)
-+static inline int security_quota_on (struct dentry * dentry)
- {
-- return security_ops->quota_on (file);
-+ return security_ops->quota_on (dentry);
- }
-
- static inline int security_syslog(int type)
-@@ -1953,7 +1953,7 @@ static inline int security_quotactl (int
- return 0;
- }
-
--static inline int security_quota_on (struct file * file)
-+static inline int security_quota_on (struct dentry * dentry)
- {
- return 0;
- }
-diff -rup RH_2_6_9_55.orig/security/dummy.c RH_2_6_9_55/security/dummy.c
---- RH_2_6_9_55.orig/security/dummy.c
-+++ RH_2_6_9_55/security/dummy.c
-@@ -92,7 +92,7 @@ static int dummy_quotactl (int cmds, int
- return 0;
- }
-
--static int dummy_quota_on (struct file *f)
-+static int dummy_quota_on (struct dentry *dentry)
- {
- return 0;
- }
-diff -rup RH_2_6_9_55.orig/security/selinux/hooks.c RH_2_6_9_55/security/selinux/hooks.c
---- RH_2_6_9_55.orig/security/selinux/hooks.c
-+++ RH_2_6_9_55/security/selinux/hooks.c
-@@ -1485,9 +1485,9 @@ static int selinux_quotactl(int cmds, in
- return rc;
- }
-
--static int selinux_quota_on(struct file *f)
-+static int selinux_quota_on(struct dentry *dentry)
- {
-- return file_has_perm(current, f, FILE__QUOTAON);
-+ return dentry_has_perm(current, NULL, dentry, FILE__QUOTAON);
- }
-
- static int selinux_syslog(int type)