Whamcloud - gitweb
Branch HEAD
[fs/lustre-release.git] / lustre / kernel_patches / patches / quota-deadlock-on-pagelock-core.patch
1 From: Jan Kara <jack@suse.cz>
2
3 The four patches in this series fix deadlocks with quotas of pagelock (the
4 problem was lock inversion on PageLock and transaction start - quota code
5 needed to first start a transaction and then write the data which subsequently
6 needed acquisition of PageLock while the standard ordering - PageLock first
7 and transaction start later - was used e.g.  by pdflush).  They implement a
8 new way of quota access to disk: Every filesystem that would like to implement
9 quotas now has to provide quota_read() and quota_write() functions.  These
10 functions must obey quota lock ordering (in particular they should not take
11 PageLock inside a transaction).
12
13 The first patch implements the changes in the quota core, the other three
14 patches implement needed functions in ext2, ext3 and reiserfs.  The patch for
15 reiserfs also fixes several other lock inversion problems (similar as ext3
16 had) and implements the journaled quota functionality (which comes almost for
17 free after the locking fixes...).
18
19 The quota core patch makes quota support in other filesystems (except XFS
20 which implements everything on its own ;)) unfunctional (quotaon() will refuse
21 to turn on quotas on them).  When the patches get reasonable wide testing and
22 it will seem that no major changes will be needed I can make fixes also for
23 the other filesystems (JFS, UDF, UFS).
24
25 This patch:
26
27 The patch implements the new way of quota io in the quota core.  Every
28 filesystem wanting to support quotas has to provide functions quota_read()
29 and quota_write() obeying quota locking rules.  As the writes and reads
30 bypass the pagecache there is some ugly stuff ensuring that userspace can
31 see all the data after quotaoff() (or Q_SYNC quotactl).  In future I plan
32 to make quota files inaccessible from userspace (with the exception of
33 quotacheck(8) which will take care about the cache flushing and such stuff
34 itself) so that this synchronization stuff can be removed...
35
36 The rewrite of the quota core. Quota uses the filesystem read() and write()
37 functions no more to avoid possible deadlocks on PageLock. From now on every
38 filesystem supporting quotas must provide functions quota_read() and
39 quota_write() which obey the quota locking rules (e.g. they cannot acquire the
40 PageLock).
41
42 Signed-off-by: Jan Kara <jack@suse.cz>
43 Signed-off-by: Andrew Morton <akpm@osdl.org>
44 ---
45
46  25-akpm/fs/dquot.c               |  162 +++++++++++++--------------
47  25-akpm/fs/quota.c               |   45 +++++++
48  25-akpm/fs/quota_v1.c            |   62 ++--------
49  25-akpm/fs/quota_v2.c            |  227 +++++++++++++++++----------------------
50  25-akpm/include/linux/fs.h       |    3 
51  25-akpm/include/linux/quota.h    |    2 
52  25-akpm/include/linux/security.h |    8 -
53  25-akpm/security/dummy.c         |    2 
54  25-akpm/security/selinux/hooks.c |    4 
55  9 files changed, 247 insertions(+), 268 deletions(-)
56
57 diff -rup RH_2_6_9_55.orig/fs/dquot.c RH_2_6_9_55/fs/dquot.c
58 --- RH_2_6_9_55.orig/fs/dquot.c
59 +++ RH_2_6_9_55/fs/dquot.c
60 @@ -49,7 +49,7 @@
61   *             New SMP locking.
62   *             Jan Kara, <jack@suse.cz>, 10/2002
63   *
64 - *             Added journalled quota support
65 + *             Added journalled quota support, fix lock inversion problems
66   *             Jan Kara, <jack@suse.cz>, 2003,2004
67   *
68   * (C) Copyright 1994 - 1997 Marco van Wieringen 
69 @@ -75,7 +75,8 @@
70  #include <linux/proc_fs.h>
71  #include <linux/security.h>
72  #include <linux/kmod.h>
73 -#include <linux/pagemap.h>
74 +#include <linux/namei.h>
75 +#include <linux/buffer_head.h>
76  
77  #include <asm/uaccess.h>
78  
79 @@ -114,7 +115,7 @@
80   * operations on dquots don't hold dq_lock as they copy data under dq_data_lock
81   * spinlock to internal buffers before writing.
82   *
83 - * Lock ordering (including related VFS locks) is following:
84 + * Lock ordering (including related VFS locks) is the following:
85   *   i_sem > dqonoff_sem > journal_lock > dqptr_sem > dquot->dq_lock > 
86   *   dqio_sem
87   * i_sem on quota files is special (it's below dqio_sem)
88 @@ -183,8 +184,7 @@ static void put_quota_format(struct quot
89   * on all three lists, depending on its current state.
90   *
91   * All dquots are placed to the end of inuse_list when first created, and this
92 - * list is used for the sync and invalidate operations, which must look
93 - * at every dquot.
94 + * list is used for invalidate operation, which must look at every dquot.
95   *
96   * Unused dquots (dq_count == 0) are added to the free_dquots list when freed,
97   * and this list is searched whenever we need an available dquot.  Dquots are
98 @@ -1341,10 +1341,12 @@ int vfs_quota_off(struct super_block *sb
99  {
100         int cnt;
101         struct quota_info *dqopt = sb_dqopt(sb);
102 +       struct inode *toput[MAXQUOTAS];
103  
104         /* We need to serialize quota_off() for device */
105         down(&dqopt->dqonoff_sem);
106         for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
107 +               toput[cnt] = NULL;
108                 if (type != -1 && cnt != type)
109                         continue;
110                 if (!sb_has_quota_enabled(sb, cnt))
111 @@ -1364,7 +1366,7 @@ int vfs_quota_off(struct super_block *sb
112                         dqopt->ops[cnt]->free_file_info(sb, cnt);
113                 put_quota_format(dqopt->info[cnt].dqi_format);
114  
115 -               fput(dqopt->files[cnt]);
116 +               toput[cnt] = dqopt->files[cnt];
117                 dqopt->files[cnt] = NULL;
118                 dqopt->info[cnt].dqi_flags = 0;
119                 dqopt->info[cnt].dqi_igrace = 0;
120 @@ -1372,6 +1374,26 @@ int vfs_quota_off(struct super_block *sb
121                 dqopt->ops[cnt] = NULL;
122         }
123         up(&dqopt->dqonoff_sem);
124 +       /* Sync the superblock so that buffers with quota data are written to
125 +         * disk (and so userspace sees correct data afterwards) */
126 +       if (sb->s_op->sync_fs)
127 +               sb->s_op->sync_fs(sb, 1);
128 +       sync_blockdev(sb->s_bdev);
129 +       /* Now the quota files are just ordinary files and we can set the
130 +        * inode flags back. Moreover we discard the pagecache so that
131 +        * userspace sees the writes we did bypassing the pagecache. We
132 +        * must also discard the blockdev buffers so that we see the
133 +        * changes done by userspace on the next quotaon() */
134 +       for (cnt = 0; cnt < MAXQUOTAS; cnt++)
135 +               if (toput[cnt]) {
136 +                       down(&toput[cnt]->i_sem);
137 +                       toput[cnt]->i_flags &= ~(S_IMMUTABLE | S_NOATIME | S_NOQUOTA);
138 +                       truncate_inode_pages(&toput[cnt]->i_data, 0);
139 +                       up(&toput[cnt]->i_sem);
140 +                       mark_inode_dirty(toput[cnt]);
141 +                       iput(toput[cnt]);
142 +               }
143 +       invalidate_bdev(sb->s_bdev, 0);
144         return 0;
145  }
146  
147 @@ -1379,68 +1401,56 @@ int vfs_quota_off(struct super_block *sb
148   *     Turn quotas on on a device
149   */
150  
151 -/* Helper function when we already have file open */
152 -static int vfs_quota_on_file(struct file *f, int type, int format_id)
153 +/* Helper function when we already have the inode */
154 +static int vfs_quota_on_inode(struct inode *inode, int type, int format_id)
155  {
156         struct quota_format_type *fmt = find_quota_format(format_id);
157 -       struct inode *inode;
158 -       struct super_block *sb = f->f_dentry->d_sb;
159 +       struct super_block *sb = inode->i_sb;
160         struct quota_info *dqopt = sb_dqopt(sb);
161 -       struct dquot *to_drop[MAXQUOTAS];
162 -       int error, cnt;
163 -       unsigned int oldflags = -1;
164 +       int error;
165 +       int oldflags = -1;
166  
167         if (!fmt)
168                 return -ESRCH;
169 -       error = -EIO;
170 -       if (!f->f_op || !f->f_op->read || !f->f_op->write)
171 +       if (!S_ISREG(inode->i_mode)) {
172 +               error = -EACCES;
173                 goto out_fmt;
174 -       inode = f->f_dentry->d_inode;
175 -       error = -EACCES;
176 -       if (!S_ISREG(inode->i_mode))
177 +       }
178 +       if (IS_RDONLY(inode)) {
179 +               error = -EROFS;
180 +               goto out_fmt;
181 +       }
182 +       if (!sb->s_op->quota_write || !sb->s_op->quota_read) {
183 +               error = -EINVAL;
184                 goto out_fmt;
185 +       }
186  
187 +       /* As we bypass the pagecache we must now flush the inode so that
188 +        * we see all the changes from userspace... */
189 +       write_inode_now(inode, 1);
190 +       /* And now flush the block cache so that kernel sees the changes */
191 +       invalidate_bdev(sb->s_bdev, 0);
192         down(&inode->i_sem);
193         down(&dqopt->dqonoff_sem);
194         if (sb_has_quota_enabled(sb, type)) {
195 -               up(&inode->i_sem);
196                 error = -EBUSY;
197                 goto out_lock;
198         }
199         /* We don't want quota and atime on quota files (deadlocks possible)
200 -        * We also need to set GFP mask differently because we cannot recurse
201 -        * into filesystem when allocating page for quota inode */
202 +        * Also nobody should write to the file - we use special IO operations
203 +        * which ignore the immutable bit. */
204         down_write(&dqopt->dqptr_sem);
205 -       oldflags = inode->i_flags & (S_NOATIME | S_NOQUOTA);
206 -       inode->i_flags |= S_NOQUOTA | S_NOATIME;
207 +       oldflags = inode->i_flags & (S_NOATIME | S_IMMUTABLE | S_NOQUOTA);
208 +       inode->i_flags |= S_NOQUOTA | S_NOATIME | S_IMMUTABLE;
209         up_write(&dqopt->dqptr_sem);
210 -       up(&inode->i_sem);
211  
212 -       dqopt->files[type] = f;
213 +       error = -EIO;
214 +       dqopt->files[type] = igrab(inode);
215 +       if (!dqopt->files[type])
216 +               goto out_lock;
217         error = -EINVAL;
218         if (!fmt->qf_ops->check_quota_file(sb, type))
219                 goto out_file_init;
220 -       /*
221 -        * We write to quota files deep within filesystem code.  We don't want
222 -        * the VFS to reenter filesystem code when it tries to allocate a
223 -        * pagecache page for the quota file write.  So clear __GFP_FS in
224 -        * the quota file's allocation flags.
225 -        */
226 -       mapping_set_gfp_mask(inode->i_mapping,
227 -               mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS);
228 -
229 -       down_write(&dqopt->dqptr_sem);
230 -       for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
231 -               to_drop[cnt] = inode->i_dquot[cnt];
232 -               inode->i_dquot[cnt] = NODQUOT;
233 -       }
234 -       up_write(&dqopt->dqptr_sem);
235 -       /* We must put dquots outside of dqptr_sem because we may need to
236 -        * start transaction for dquot_release() */
237 -       for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
238 -               if (to_drop[cnt])
239 -                       dqput(to_drop[cnt]);
240 -       }
241  
242         dqopt->ops[type] = fmt->qf_ops;
243         dqopt->info[type].dqi_format = fmt;
244 @@ -1451,6 +1461,7 @@ static int vfs_quota_on_file(struct file
245                 goto out_file_init;
246         }
247         up(&dqopt->dqio_sem);
248 +       up(&inode->i_sem);
249         set_enable_flags(dqopt, type);
250  
251         add_dquot_ref(sb, type);
252 @@ -1460,19 +1471,18 @@ static int vfs_quota_on_file(struct file
253  
254  out_file_init:
255         dqopt->files[type] = NULL;
256 +       iput(inode);
257  out_lock:
258         up(&dqopt->dqonoff_sem);
259         if (oldflags != -1) {
260 -               down(&inode->i_sem);
261                 down_write(&dqopt->dqptr_sem);
262 -               /* Reset the NOATIME flag back. I know it could change in the
263 -                * mean time but playing with NOATIME flags on a quota file is
264 -                * never a good idea */
265 -               inode->i_flags &= ~(S_NOATIME | S_NOQUOTA);
266 +               /* Set the flags back (in the case of accidental quotaon()
267 +                * on a wrong file we don't want to mess up the flags) */
268 +               inode->i_flags &= ~(S_NOATIME | S_NOQUOTA | S_IMMUTABLE);
269                 inode->i_flags |= oldflags;
270                 up_write(&dqopt->dqptr_sem);
271 -               up(&inode->i_sem);
272         }
273 +       up(&inode->i_sem);
274  out_fmt:
275         put_quota_format(fmt);
276  
277 @@ -1482,47 +1492,37 @@ out_fmt:
278  /* Actual function called from quotactl() */
279  int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path)
280  {
281 -       struct file *f;
282 +       struct nameidata nd;
283         int error;
284  
285 -       f = filp_open(path, O_RDWR, 0600);
286 -       if (IS_ERR(f))
287 -               return PTR_ERR(f);
288 -       error = security_quota_on(f);
289 +       error = path_lookup(path, LOOKUP_FOLLOW, &nd);
290 +       if (error < 0)
291 +               return error;
292 +       error = security_quota_on(nd.dentry);
293         if (error)
294 -               goto out_f;
295 -       error = vfs_quota_on_file(f, type, format_id);
296 -       if (!error)
297 -               return 0;
298 -out_f:
299 -       filp_close(f, NULL);
300 +               goto out_path;
301 +       /* Quota file not on the same filesystem? */
302 +       if (nd.mnt->mnt_sb != sb)
303 +               error = -EXDEV;
304 +       else
305 +               error = vfs_quota_on_inode(nd.dentry->d_inode, type, format_id);
306 +out_path:
307 +       path_release(&nd);
308         return error;
309  }
310  
311  /*
312 - * Function used by filesystems when filp_open() would fail (filesystem is
313 - * being mounted now). We will use a private file structure. Caller is
314 - * responsible that it's IO functions won't need vfsmnt structure or
315 - * some dentry tricks...
316 + * This function is used when filesystem needs to initialize quotas
317 + * during mount time.
318   */
319  int vfs_quota_on_mount(int type, int format_id, struct dentry *dentry)
320  {
321 -       struct file *f;
322         int error;
323  
324 -       dget(dentry);   /* Get a reference for struct file */
325 -       f = dentry_open(dentry, NULL, O_RDWR);
326 -       if (IS_ERR(f)) {
327 -               error = PTR_ERR(f);
328 -               goto out_dentry;
329 -       }
330 -       error = vfs_quota_on_file(f, type, format_id);
331 -       if (!error)
332 -               return 0;
333 -       fput(f);
334 -out_dentry:
335 -       dput(dentry);
336 -       return error;
337 +       error = security_quota_on(dentry);
338 +       if (error)
339 +               return error;
340 +       return vfs_quota_on_inode(dentry->d_inode, type, format_id);
341  }
342  
343  /* Generic routine for getting common part of quota structure */
344 diff -rup RH_2_6_9_55.orig/fs/quota.c RH_2_6_9_55/fs/quota.c
345 --- RH_2_6_9_55.orig/fs/quota.c
346 +++ RH_2_6_9_55/fs/quota.c
347 @@ -13,6 +13,8 @@
348  #include <linux/kernel.h>
349  #include <linux/smp_lock.h>
350  #include <linux/security.h>
351 +#include <linux/syscalls.h>
352 +#include <linux/buffer_head.h>
353
354  /* Check validity of quotactl */
355  static int check_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id)
356 @@ -134,16 +136,54 @@ restart:
357         return NULL;
358  }
359  
360 +void quota_sync_sb(struct super_block *sb, int type)
361 +{
362 +       int cnt;
363 +       struct inode *discard[MAXQUOTAS];
364 +
365 +       sb->s_qcop->quota_sync(sb, type);
366 +       /* This is not very clever (and fast) but currently I don't know about
367 +        * any other simple way of getting quota data to disk and we must get
368 +        * them there for userspace to be visible... */
369 +       if (sb->s_op->sync_fs)
370 +               sb->s_op->sync_fs(sb, 1);
371 +       sync_blockdev(sb->s_bdev);
372 +
373 +       /* Now when everything is written we can discard the pagecache so
374 +        * that userspace sees the changes. We need i_sem and so we could
375 +        * not do it inside dqonoff_sem. Moreover we need to be carefull
376 +        * about races with quotaoff() (that is the reason why we have own
377 +        * reference to inode). */
378 +       down(&sb_dqopt(sb)->dqonoff_sem);
379 +       for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
380 +               discard[cnt] = NULL;
381 +               if (type != -1 && cnt != type)
382 +                       continue;
383 +               if (!sb_has_quota_enabled(sb, cnt))
384 +                       continue;
385 +               discard[cnt] = igrab(sb_dqopt(sb)->files[cnt]);
386 +       }
387 +       up(&sb_dqopt(sb)->dqonoff_sem);
388 +       for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
389 +               if (discard[cnt]) {
390 +                       down(&discard[cnt]->i_sem);
391 +                       truncate_inode_pages(&discard[cnt]->i_data, 0);
392 +                       up(&discard[cnt]->i_sem);
393 +                       iput(discard[cnt]);
394 +               }
395 +       }
396 +}
397 +
398  void sync_dquots(struct super_block *sb, int type)
399  {
400         if (sb) {
401                 if (sb->s_qcop->quota_sync)
402 -                       sb->s_qcop->quota_sync(sb, type);
403 +                       quota_sync_sb(sb, type);
404         }
405         else {
406 -               while ((sb = get_super_to_sync(type)) != 0) {
407 +               while ((sb = get_super_to_sync(type)) != NULL) {
408                         if (sb->s_qcop->quota_sync)
409 -                               sb->s_qcop->quota_sync(sb, type);
410 +                               quota_sync_sb(sb, type);
411                         drop_super(sb);
412                 }
413         }
414 diff -rup RH_2_6_9_55.orig/fs/quota_v1.c RH_2_6_9_55/fs/quota_v1.c
415 --- RH_2_6_9_55.orig/fs/quota_v1.c
416 +++ RH_2_6_9_55/fs/quota_v1.c
417 @@ -7,7 +7,6 @@
418  #include <linux/init.h>
419  #include <linux/module.h>
420  
421 -#include <asm/uaccess.h>
422  #include <asm/byteorder.h>
423  
424  MODULE_AUTHOR("Jan Kara");
425 @@ -41,23 +40,14 @@ static void v1_mem2disk_dqblk(struct v1_
426  static int v1_read_dqblk(struct dquot *dquot)
427  {
428         int type = dquot->dq_type;
429 -       struct file *filp;
430 -       mm_segment_t fs;
431 -       loff_t offset;
432         struct v1_disk_dqblk dqblk;
433  
434 -       filp = sb_dqopt(dquot->dq_sb)->files[type];
435 -       if (filp == (struct file *)NULL)
436 +       if (!sb_dqopt(dquot->dq_sb)->files[type])
437                 return -EINVAL;
438  
439 -       /* Now we are sure filp is valid */
440 -       offset = v1_dqoff(dquot->dq_id);
441         /* Set structure to 0s in case read fails/is after end of file */
442         memset(&dqblk, 0, sizeof(struct v1_disk_dqblk));
443 -       fs = get_fs();
444 -       set_fs(KERNEL_DS);
445 -       filp->f_op->read(filp, (char *)&dqblk, sizeof(struct v1_disk_dqblk), &offset);
446 -       set_fs(fs);
447 +       dquot->dq_sb->s_op->quota_read(dquot->dq_sb, type, (char *)&dqblk, sizeof(struct v1_disk_dqblk), v1_dqoff(dquot->dq_id));
448  
449         v1_disk2mem_dqblk(&dquot->dq_dqb, &dqblk);
450         if (dquot->dq_dqb.dqb_bhardlimit == 0 && dquot->dq_dqb.dqb_bsoftlimit == 0 &&
451 @@ -71,26 +61,18 @@ static int v1_read_dqblk(struct dquot *d
452  static int v1_commit_dqblk(struct dquot *dquot)
453  {
454         short type = dquot->dq_type;
455 -       struct file *filp;
456 -       mm_segment_t fs;
457 -       loff_t offset;
458         ssize_t ret;
459         struct v1_disk_dqblk dqblk;
460  
461 -       filp = sb_dqopt(dquot->dq_sb)->files[type];
462 -       offset = v1_dqoff(dquot->dq_id);
463 -       fs = get_fs();
464 -       set_fs(KERNEL_DS);
465 -
466         v1_mem2disk_dqblk(&dqblk, &dquot->dq_dqb);
467         if (dquot->dq_id == 0) {
468                 dqblk.dqb_btime = sb_dqopt(dquot->dq_sb)->info[type].dqi_bgrace;
469                 dqblk.dqb_itime = sb_dqopt(dquot->dq_sb)->info[type].dqi_igrace;
470         }
471         ret = 0;
472 -       if (filp)
473 -               ret = filp->f_op->write(filp, (char *)&dqblk,
474 -                                       sizeof(struct v1_disk_dqblk), &offset);
475 +       if (sb_dqopt(dquot->dq_sb)->files[type])
476 +               ret = dquot->dq_sb->s_op->quota_write(dquot->dq_sb, type, (char *)&dqblk,
477 +                                       sizeof(struct v1_disk_dqblk), v1_dqoff(dquot->dq_id));
478         if (ret != sizeof(struct v1_disk_dqblk)) {
479                 printk(KERN_WARNING "VFS: dquota write failed on dev %s\n",
480                         dquot->dq_sb->s_id);
481 @@ -101,7 +83,6 @@ static int v1_commit_dqblk(struct dquot 
482         ret = 0;
483  
484  out:
485 -       set_fs(fs);
486         dqstats.writes++;
487  
488         return ret;
489 @@ -121,14 +102,11 @@ struct v2_disk_dqheader {
490  
491  static int v1_check_quota_file(struct super_block *sb, int type)
492  {
493 -       struct file *f = sb_dqopt(sb)->files[type];
494 -       struct inode *inode = f->f_dentry->d_inode;
495 +       struct inode *inode = sb_dqopt(sb)->files[type];
496         ulong blocks;
497         size_t off; 
498         struct v2_disk_dqheader dqhead;
499 -       mm_segment_t fs;
500         ssize_t size;
501 -       loff_t offset = 0;
502         loff_t isize;
503         static const uint quota_magics[] = V2_INITQMAGICS;
504  
505 @@ -140,10 +118,7 @@ static int v1_check_quota_file(struct su
506         if ((blocks % sizeof(struct v1_disk_dqblk) * BLOCK_SIZE + off) % sizeof(struct v1_disk_dqblk))
507                 return 0;
508         /* Doublecheck whether we didn't get file with new format - with old quotactl() this could happen */
509 -       fs = get_fs();
510 -       set_fs(KERNEL_DS);
511 -       size = f->f_op->read(f, (char *)&dqhead, sizeof(struct v2_disk_dqheader), &offset);
512 -       set_fs(fs);
513 +       size = sb->s_op->quota_read(sb, type, (char *)&dqhead, sizeof(struct v2_disk_dqheader), 0);
514         if (size != sizeof(struct v2_disk_dqheader))
515                 return 1;       /* Probably not new format */
516         if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type])
517 @@ -155,16 +130,10 @@ static int v1_check_quota_file(struct su
518  static int v1_read_file_info(struct super_block *sb, int type)
519  {
520         struct quota_info *dqopt = sb_dqopt(sb);
521 -       mm_segment_t fs;
522 -       loff_t offset;
523 -       struct file *filp = dqopt->files[type];
524         struct v1_disk_dqblk dqblk;
525         int ret;
526  
527 -       offset = v1_dqoff(0);
528 -       fs = get_fs();
529 -       set_fs(KERNEL_DS);
530 -       if ((ret = filp->f_op->read(filp, (char *)&dqblk, sizeof(struct v1_disk_dqblk), &offset)) != sizeof(struct v1_disk_dqblk)) {
531 +       if ((ret = sb->s_op->quota_read(sb, type, (char *)&dqblk, sizeof(struct v1_disk_dqblk), v1_dqoff(0))) != sizeof(struct v1_disk_dqblk)) {
532                 if (ret >= 0)
533                         ret = -EIO;
534                 goto out;
535 @@ -173,38 +142,31 @@ static int v1_read_file_info(struct supe
536         dqopt->info[type].dqi_igrace = dqblk.dqb_itime ? dqblk.dqb_itime : MAX_IQ_TIME;
537         dqopt->info[type].dqi_bgrace = dqblk.dqb_btime ? dqblk.dqb_btime : MAX_DQ_TIME;
538  out:
539 -       set_fs(fs);
540         return ret;
541  }
542  
543  static int v1_write_file_info(struct super_block *sb, int type)
544  {
545         struct quota_info *dqopt = sb_dqopt(sb);
546 -       mm_segment_t fs;
547 -       struct file *filp = dqopt->files[type];
548         struct v1_disk_dqblk dqblk;
549 -       loff_t offset;
550         int ret;
551  
552         dqopt->info[type].dqi_flags &= ~DQF_INFO_DIRTY;
553 -       offset = v1_dqoff(0);
554 -       fs = get_fs();
555 -       set_fs(KERNEL_DS);
556 -       if ((ret = filp->f_op->read(filp, (char *)&dqblk, sizeof(struct v1_disk_dqblk), &offset)) != sizeof(struct v1_disk_dqblk)) {
557 +       if ((ret = sb->s_op->quota_read(sb, type, (char *)&dqblk,
558 +           sizeof(struct v1_disk_dqblk), v1_dqoff(0))) != sizeof(struct v1_disk_dqblk)) {
559                 if (ret >= 0)
560                         ret = -EIO;
561                 goto out;
562         }
563         dqblk.dqb_itime = dqopt->info[type].dqi_igrace;
564         dqblk.dqb_btime = dqopt->info[type].dqi_bgrace;
565 -       offset = v1_dqoff(0);
566 -       ret = filp->f_op->write(filp, (char *)&dqblk, sizeof(struct v1_disk_dqblk), &offset);
567 +       ret = sb->s_op->quota_write(sb, type, (char *)&dqblk,
568 +             sizeof(struct v1_disk_dqblk), v1_dqoff(0));
569         if (ret == sizeof(struct v1_disk_dqblk))
570                 ret = 0;
571         else if (ret > 0)
572                 ret = -EIO;
573  out:
574 -       set_fs(fs);
575         return ret;
576  }
577  
578 diff -rup RH_2_6_9_55.orig/fs/quota_v2.c RH_2_6_9_55/fs/quota_v2.c
579 --- RH_2_6_9_55.orig/fs/quota_v2.c
580 +++ RH_2_6_9_55/fs/quota_v2.c
581 @@ -13,7 +13,6 @@
582  #include <linux/slab.h>
583  
584  #include <asm/byteorder.h>
585 -#include <asm/uaccess.h>
586  
587  MODULE_AUTHOR("Jan Kara");
588  MODULE_DESCRIPTION("Quota format v2 support");
589 @@ -30,19 +29,15 @@ typedef char *dqbuf_t;
590  static int v2_check_quota_file(struct super_block *sb, int type)
591  {
592         struct v2_disk_dqheader dqhead;
593 -       struct file *f = sb_dqopt(sb)->files[type];
594 -       mm_segment_t fs;
595         ssize_t size;
596 -       loff_t offset = 0;
597         static const uint quota_magics[] = V2_INITQMAGICS;
598         static const uint quota_versions[] = V2_INITQVERSIONS;
599   
600 -       fs = get_fs();
601 -       set_fs(KERNEL_DS);
602 -       size = f->f_op->read(f, (char *)&dqhead, sizeof(struct v2_disk_dqheader), &offset);
603 -       set_fs(fs);
604 -       if (size != sizeof(struct v2_disk_dqheader))
605 +       size = sb->s_op->quota_read(sb, type, (char *)&dqhead, sizeof(struct v2_disk_dqheader), 0);
606 +       if (size != sizeof(struct v2_disk_dqheader)) {
607 +               printk("failed read\n");
608                 return 0;
609 +       }
610         if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type] ||
611             le32_to_cpu(dqhead.dqh_version) != quota_versions[type])
612                 return 0;
613 @@ -52,20 +47,15 @@ static int v2_check_quota_file(struct su
614  /* Read information header from quota file */
615  static int v2_read_file_info(struct super_block *sb, int type)
616  {
617 -       mm_segment_t fs;
618         struct v2_disk_dqinfo dinfo;
619         struct mem_dqinfo *info = sb_dqopt(sb)->info+type;
620 -       struct file *f = sb_dqopt(sb)->files[type];
621         ssize_t size;
622 -       loff_t offset = V2_DQINFOOFF;
623  
624 -       fs = get_fs();
625 -       set_fs(KERNEL_DS);
626 -       size = f->f_op->read(f, (char *)&dinfo, sizeof(struct v2_disk_dqinfo), &offset);
627 -       set_fs(fs);
628 +       size = sb->s_op->quota_read(sb, type, (char *)&dinfo,
629 +              sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF);
630         if (size != sizeof(struct v2_disk_dqinfo)) {
631                 printk(KERN_WARNING "Can't read info structure on device %s.\n",
632 -                       f->f_dentry->d_sb->s_id);
633 +                       sb->s_id);
634                 return -1;
635         }
636         info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace);
637 @@ -80,12 +70,9 @@ static int v2_read_file_info(struct supe
638  /* Write information header to quota file */
639  static int v2_write_file_info(struct super_block *sb, int type)
640  {
641 -       mm_segment_t fs;
642         struct v2_disk_dqinfo dinfo;
643         struct mem_dqinfo *info = sb_dqopt(sb)->info+type;
644 -       struct file *f = sb_dqopt(sb)->files[type];
645         ssize_t size;
646 -       loff_t offset = V2_DQINFOOFF;
647  
648         spin_lock(&dq_data_lock);
649         info->dqi_flags &= ~DQF_INFO_DIRTY;
650 @@ -96,13 +83,11 @@ static int v2_write_file_info(struct sup
651         dinfo.dqi_blocks = cpu_to_le32(info->u.v2_i.dqi_blocks);
652         dinfo.dqi_free_blk = cpu_to_le32(info->u.v2_i.dqi_free_blk);
653         dinfo.dqi_free_entry = cpu_to_le32(info->u.v2_i.dqi_free_entry);
654 -       fs = get_fs();
655 -       set_fs(KERNEL_DS);
656 -       size = f->f_op->write(f, (char *)&dinfo, sizeof(struct v2_disk_dqinfo), &offset);
657 -       set_fs(fs);
658 +       size = sb->s_op->quota_write(sb, type, (char *)&dinfo,
659 +              sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF);
660         if (size != sizeof(struct v2_disk_dqinfo)) {
661                 printk(KERN_WARNING "Can't write info structure on device %s.\n",
662 -                       f->f_dentry->d_sb->s_id);
663 +                       sb->s_id);
664                 return -1;
665         }
666         return 0;
667 @@ -146,39 +131,24 @@ static inline void freedqbuf(dqbuf_t buf
668         kfree(buf);
669  }
670  
671 -static ssize_t read_blk(struct file *filp, uint blk, dqbuf_t buf)
672 +static inline ssize_t read_blk(struct super_block *sb, int type, uint blk, dqbuf_t buf)
673  {
674 -       mm_segment_t fs;
675 -       ssize_t ret;
676 -       loff_t offset = blk<<V2_DQBLKSIZE_BITS;
677 -
678         memset(buf, 0, V2_DQBLKSIZE);
679 -       fs = get_fs();
680 -       set_fs(KERNEL_DS);
681 -       ret = filp->f_op->read(filp, (char *)buf, V2_DQBLKSIZE, &offset);
682 -       set_fs(fs);
683 -       return ret;
684 +       return sb->s_op->quota_read(sb, type, (char *)buf,
685 +              V2_DQBLKSIZE, blk << V2_DQBLKSIZE_BITS);
686  }
687  
688 -static ssize_t write_blk(struct file *filp, uint blk, dqbuf_t buf)
689 +static inline ssize_t write_blk(struct super_block *sb, int type, uint blk, dqbuf_t buf)
690  {
691 -       mm_segment_t fs;
692 -       ssize_t ret;
693 -       loff_t offset = blk<<V2_DQBLKSIZE_BITS;
694 -
695 -       fs = get_fs();
696 -       set_fs(KERNEL_DS);
697 -       ret = filp->f_op->write(filp, (char *)buf, V2_DQBLKSIZE, &offset);
698 -       set_fs(fs);
699 -       return ret;
700 -
701 +       return sb->s_op->quota_write(sb, type, (char *)buf,
702 +              V2_DQBLKSIZE, blk << V2_DQBLKSIZE_BITS);
703  }
704  
705  /* Remove empty block from list and return it */
706 -static int get_free_dqblk(struct file *filp, int type)
707 +static int get_free_dqblk(struct super_block *sb, int type)
708  {
709         dqbuf_t buf = getdqbuf();
710 -       struct mem_dqinfo *info = sb_dqinfo(filp->f_dentry->d_sb, type);
711 +       struct mem_dqinfo *info = sb_dqinfo(sb, type);
712         struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
713         int ret, blk;
714  
715 @@ -186,17 +156,18 @@ static int get_free_dqblk(struct file *f
716                 return -ENOMEM;
717         if (info->u.v2_i.dqi_free_blk) {
718                 blk = info->u.v2_i.dqi_free_blk;
719 -               if ((ret = read_blk(filp, blk, buf)) < 0)
720 +               if ((ret = read_blk(sb, type, blk, buf)) < 0)
721                         goto out_buf;
722                 info->u.v2_i.dqi_free_blk = le32_to_cpu(dh->dqdh_next_free);
723         }
724         else {
725                 memset(buf, 0, V2_DQBLKSIZE);
726 -               if ((ret = write_blk(filp, info->u.v2_i.dqi_blocks, buf)) < 0)  /* Assure block allocation... */
727 +               /* Assure block allocation... */
728 +               if ((ret = write_blk(sb, type, info->u.v2_i.dqi_blocks, buf)) < 0)
729                         goto out_buf;
730                 blk = info->u.v2_i.dqi_blocks++;
731         }
732 -       mark_info_dirty(filp->f_dentry->d_sb, type);
733 +       mark_info_dirty(sb, type);
734         ret = blk;
735  out_buf:
736         freedqbuf(buf);
737 @@ -204,9 +175,9 @@ out_buf:
738  }
739  
740  /* Insert empty block to the list */
741 -static int put_free_dqblk(struct file *filp, int type, dqbuf_t buf, uint blk)
742 +static int put_free_dqblk(struct super_block *sb, int type, dqbuf_t buf, uint blk)
743  {
744 -       struct mem_dqinfo *info = sb_dqinfo(filp->f_dentry->d_sb, type);
745 +       struct mem_dqinfo *info = sb_dqinfo(sb, type);
746         struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
747         int err;
748  
749 @@ -214,17 +185,18 @@ static int put_free_dqblk(struct file *f
750         dh->dqdh_prev_free = cpu_to_le32(0);
751         dh->dqdh_entries = cpu_to_le16(0);
752         info->u.v2_i.dqi_free_blk = blk;
753 -       mark_info_dirty(filp->f_dentry->d_sb, type);
754 -       if ((err = write_blk(filp, blk, buf)) < 0)      /* Some strange block. We had better leave it... */
755 +       mark_info_dirty(sb, type);
756 +       /* Some strange block. We had better leave it... */
757 +       if ((err = write_blk(sb, type, blk, buf)) < 0)
758                 return err;
759         return 0;
760  }
761  
762  /* Remove given block from the list of blocks with free entries */
763 -static int remove_free_dqentry(struct file *filp, int type, dqbuf_t buf, uint blk)
764 +static int remove_free_dqentry(struct super_block *sb, int type, dqbuf_t buf, uint blk)
765  {
766         dqbuf_t tmpbuf = getdqbuf();
767 -       struct mem_dqinfo *info = sb_dqinfo(filp->f_dentry->d_sb, type);
768 +       struct mem_dqinfo *info = sb_dqinfo(sb, type);
769         struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
770         uint nextblk = le32_to_cpu(dh->dqdh_next_free), prevblk = le32_to_cpu(dh->dqdh_prev_free);
771         int err;
772 @@ -232,26 +204,27 @@ static int remove_free_dqentry(struct fi
773         if (!tmpbuf)
774                 return -ENOMEM;
775         if (nextblk) {
776 -               if ((err = read_blk(filp, nextblk, tmpbuf)) < 0)
777 +               if ((err = read_blk(sb, type, nextblk, tmpbuf)) < 0)
778                         goto out_buf;
779                 ((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = dh->dqdh_prev_free;
780 -               if ((err = write_blk(filp, nextblk, tmpbuf)) < 0)
781 +               if ((err = write_blk(sb, type, nextblk, tmpbuf)) < 0)
782                         goto out_buf;
783         }
784         if (prevblk) {
785 -               if ((err = read_blk(filp, prevblk, tmpbuf)) < 0)
786 +               if ((err = read_blk(sb, type, prevblk, tmpbuf)) < 0)
787                         goto out_buf;
788                 ((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_next_free = dh->dqdh_next_free;
789 -               if ((err = write_blk(filp, prevblk, tmpbuf)) < 0)
790 +               if ((err = write_blk(sb, type, prevblk, tmpbuf)) < 0)
791                         goto out_buf;
792         }
793         else {
794                 info->u.v2_i.dqi_free_entry = nextblk;
795 -               mark_info_dirty(filp->f_dentry->d_sb, type);
796 +               mark_info_dirty(sb, type);
797         }
798         freedqbuf(tmpbuf);
799         dh->dqdh_next_free = dh->dqdh_prev_free = cpu_to_le32(0);
800 -       if (write_blk(filp, blk, buf) < 0)      /* No matter whether write succeeds block is out of list */
801 +       /* No matter whether write succeeds block is out of list */
802 +       if (write_blk(sb, type, blk, buf) < 0)
803                 printk(KERN_ERR "VFS: Can't write block (%u) with free entries.\n", blk);
804         return 0;
805  out_buf:
806 @@ -260,10 +233,10 @@ out_buf:
807  }
808  
809  /* Insert given block to the beginning of list with free entries */
810 -static int insert_free_dqentry(struct file *filp, int type, dqbuf_t buf, uint blk)
811 +static int insert_free_dqentry(struct super_block *sb, int type, dqbuf_t buf, uint blk)
812  {
813         dqbuf_t tmpbuf = getdqbuf();
814 -       struct mem_dqinfo *info = sb_dqinfo(filp->f_dentry->d_sb, type);
815 +       struct mem_dqinfo *info = sb_dqinfo(sb, type);
816         struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
817         int err;
818  
819 @@ -271,18 +244,18 @@ static int insert_free_dqentry(struct fi
820                 return -ENOMEM;
821         dh->dqdh_next_free = cpu_to_le32(info->u.v2_i.dqi_free_entry);
822         dh->dqdh_prev_free = cpu_to_le32(0);
823 -       if ((err = write_blk(filp, blk, buf)) < 0)
824 +       if ((err = write_blk(sb, type, blk, buf)) < 0)
825                 goto out_buf;
826         if (info->u.v2_i.dqi_free_entry) {
827 -               if ((err = read_blk(filp, info->u.v2_i.dqi_free_entry, tmpbuf)) < 0)
828 +               if ((err = read_blk(sb, type, info->u.v2_i.dqi_free_entry, tmpbuf)) < 0)
829                         goto out_buf;
830                 ((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = cpu_to_le32(blk);
831 -               if ((err = write_blk(filp, info->u.v2_i.dqi_free_entry, tmpbuf)) < 0)
832 +               if ((err = write_blk(sb, type, info->u.v2_i.dqi_free_entry, tmpbuf)) < 0)
833                         goto out_buf;
834         }
835         freedqbuf(tmpbuf);
836         info->u.v2_i.dqi_free_entry = blk;
837 -       mark_info_dirty(filp->f_dentry->d_sb, type);
838 +       mark_info_dirty(sb, type);
839         return 0;
840  out_buf:
841         freedqbuf(tmpbuf);
842 @@ -292,8 +265,8 @@ out_buf:
843  /* Find space for dquot */
844  static uint find_free_dqentry(struct dquot *dquot, int *err)
845  {
846 -       struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
847 -       struct mem_dqinfo *info = sb_dqopt(dquot->dq_sb)->info+dquot->dq_type;
848 +       struct super_block *sb = dquot->dq_sb;
849 +       struct mem_dqinfo *info = sb_dqopt(sb)->info+dquot->dq_type;
850         uint blk, i;
851         struct v2_disk_dqdbheader *dh;
852         struct v2_disk_dqblk *ddquot;
853 @@ -309,22 +282,23 @@ static uint find_free_dqentry(struct dqu
854         ddquot = GETENTRIES(buf);
855         if (info->u.v2_i.dqi_free_entry) {
856                 blk = info->u.v2_i.dqi_free_entry;
857 -               if ((*err = read_blk(filp, blk, buf)) < 0)
858 +               if ((*err = read_blk(sb, dquot->dq_type, blk, buf)) < 0)
859                         goto out_buf;
860         }
861         else {
862 -               blk = get_free_dqblk(filp, dquot->dq_type);
863 +               blk = get_free_dqblk(sb, dquot->dq_type);
864                 if ((int)blk < 0) {
865                         *err = blk;
866                         freedqbuf(buf);
867                         return 0;
868                 }
869                 memset(buf, 0, V2_DQBLKSIZE);
870 -               info->u.v2_i.dqi_free_entry = blk;      /* This is enough as block is already zeroed and entry list is empty... */
871 -               mark_info_dirty(dquot->dq_sb, dquot->dq_type);
872 +               /* This is enough as block is already zeroed and entry list is empty... */
873 +               info->u.v2_i.dqi_free_entry = blk;
874 +               mark_info_dirty(sb, dquot->dq_type);
875         }
876         if (le16_to_cpu(dh->dqdh_entries)+1 >= V2_DQSTRINBLK)   /* Block will be full? */
877 -               if ((*err = remove_free_dqentry(filp, dquot->dq_type, buf, blk)) < 0) {
878 +               if ((*err = remove_free_dqentry(sb, dquot->dq_type, buf, blk)) < 0) {
879                         printk(KERN_ERR "VFS: find_free_dqentry(): Can't remove block (%u) from entry free list.\n", blk);
880                         goto out_buf;
881                 }
882 @@ -339,7 +313,7 @@ static uint find_free_dqentry(struct dqu
883                 goto out_buf;
884         }
885  #endif
886 -       if ((*err = write_blk(filp, blk, buf)) < 0) {
887 +       if ((*err = write_blk(sb, dquot->dq_type, blk, buf)) < 0) {
888                 printk(KERN_ERR "VFS: find_free_dqentry(): Can't write quota data block %u.\n", blk);
889                 goto out_buf;
890         }
891 @@ -354,7 +328,7 @@ out_buf:
892  /* Insert reference to structure into the trie */
893  static int do_insert_tree(struct dquot *dquot, uint *treeblk, int depth)
894  {
895 -       struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
896 +       struct super_block *sb = dquot->dq_sb;
897         dqbuf_t buf;
898         int ret = 0, newson = 0, newact = 0;
899         __le32 *ref;
900 @@ -363,7 +337,7 @@ static int do_insert_tree(struct dquot *
901         if (!(buf = getdqbuf()))
902                 return -ENOMEM;
903         if (!*treeblk) {
904 -               ret = get_free_dqblk(filp, dquot->dq_type);
905 +               ret = get_free_dqblk(sb, dquot->dq_type);
906                 if (ret < 0)
907                         goto out_buf;
908                 *treeblk = ret;
909 @@ -371,7 +345,7 @@ static int do_insert_tree(struct dquot *
910                 newact = 1;
911         }
912         else {
913 -               if ((ret = read_blk(filp, *treeblk, buf)) < 0) {
914 +               if ((ret = read_blk(sb, dquot->dq_type, *treeblk, buf)) < 0) {
915                         printk(KERN_ERR "VFS: Can't read tree quota block %u.\n", *treeblk);
916                         goto out_buf;
917                 }
918 @@ -394,10 +368,10 @@ static int do_insert_tree(struct dquot *
919                 ret = do_insert_tree(dquot, &newblk, depth+1);
920         if (newson && ret >= 0) {
921                 ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(newblk);
922 -               ret = write_blk(filp, *treeblk, buf);
923 +               ret = write_blk(sb, dquot->dq_type, *treeblk, buf);
924         }
925         else if (newact && ret < 0)
926 -               put_free_dqblk(filp, dquot->dq_type, buf, *treeblk);
927 +               put_free_dqblk(sb, dquot->dq_type, buf, *treeblk);
928  out_buf:
929         freedqbuf(buf);
930         return ret;
931 @@ -416,20 +390,15 @@ static inline int dq_insert_tree(struct 
932  static int v2_write_dquot(struct dquot *dquot)
933  {
934         int type = dquot->dq_type;
935 -       struct file *filp;
936 -       mm_segment_t fs;
937 -       loff_t offset;
938         ssize_t ret;
939         struct v2_disk_dqblk ddquot, empty;
940  
941         /* dq_off is guarded by dqio_sem */
942         if (!dquot->dq_off)
943                 if ((ret = dq_insert_tree(dquot)) < 0) {
944 -                       printk(KERN_ERR "VFS: Error %Zd occurred while creating quota.\n", ret);
945 +                       printk(KERN_ERR "VFS: Error %d occurred while creating quota.\n", ret);
946                         return ret;
947                 }
948 -       filp = sb_dqopt(dquot->dq_sb)->files[type];
949 -       offset = dquot->dq_off;
950         spin_lock(&dq_data_lock);
951         mem2diskdqb(&ddquot, &dquot->dq_dqb, dquot->dq_id);
952         /* Argh... We may need to write structure full of zeroes but that would be
953 @@ -439,10 +408,8 @@ static int v2_write_dquot(struct dquot *
954         if (!memcmp(&empty, &ddquot, sizeof(struct v2_disk_dqblk)))
955                 ddquot.dqb_itime = cpu_to_le64(1);
956         spin_unlock(&dq_data_lock);
957 -       fs = get_fs();
958 -       set_fs(KERNEL_DS);
959 -       ret = filp->f_op->write(filp, (char *)&ddquot, sizeof(struct v2_disk_dqblk), &offset);
960 -       set_fs(fs);
961 +       ret = dquot->dq_sb->s_op->quota_write(dquot->dq_sb, type,
962 +             (char *)&ddquot, sizeof(struct v2_disk_dqblk), dquot->dq_off);
963         if (ret != sizeof(struct v2_disk_dqblk)) {
964                 printk(KERN_WARNING "VFS: dquota write failed on dev %s\n", dquot->dq_sb->s_id);
965                 if (ret >= 0)
966 @@ -458,7 +425,8 @@ static int v2_write_dquot(struct dquot *
967  /* Free dquot entry in data block */
968  static int free_dqentry(struct dquot *dquot, uint blk)
969  {
970 -       struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
971 +       struct super_block *sb = dquot->dq_sb;
972 +       int type = dquot->dq_type;
973         struct v2_disk_dqdbheader *dh;
974         dqbuf_t buf = getdqbuf();
975         int ret = 0;
976 @@ -466,34 +434,39 @@ static int free_dqentry(struct dquot *dq
977         if (!buf)
978                 return -ENOMEM;
979         if (dquot->dq_off >> V2_DQBLKSIZE_BITS != blk) {
980 -               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));
981 +               printk(KERN_ERR "VFS: Quota structure has offset to other "
982 +                 "block (%u) than it should (%u).\n", blk,
983 +                 (uint)(dquot->dq_off >> V2_DQBLKSIZE_BITS));
984                 goto out_buf;
985         }
986 -       if ((ret = read_blk(filp, blk, buf)) < 0) {
987 +       if ((ret = read_blk(sb, type, blk, buf)) < 0) {
988                 printk(KERN_ERR "VFS: Can't read quota data block %u\n", blk);
989                 goto out_buf;
990         }
991         dh = (struct v2_disk_dqdbheader *)buf;
992         dh->dqdh_entries = cpu_to_le16(le16_to_cpu(dh->dqdh_entries)-1);
993         if (!le16_to_cpu(dh->dqdh_entries)) {   /* Block got free? */
994 -               if ((ret = remove_free_dqentry(filp, dquot->dq_type, buf, blk)) < 0 ||
995 -                   (ret = put_free_dqblk(filp, dquot->dq_type, buf, blk)) < 0) {
996 -                       printk(KERN_ERR "VFS: Can't move quota data block (%u) to free list.\n", blk);
997 +               if ((ret = remove_free_dqentry(sb, type, buf, blk)) < 0 ||
998 +                   (ret = put_free_dqblk(sb, type, buf, blk)) < 0) {
999 +                       printk(KERN_ERR "VFS: Can't move quota data block (%u) "
1000 +                         "to free list.\n", blk);
1001                         goto out_buf;
1002                 }
1003         }
1004         else {
1005 -               memset(buf+(dquot->dq_off & ((1 << V2_DQBLKSIZE_BITS)-1)), 0, sizeof(struct v2_disk_dqblk));
1006 +               memset(buf+(dquot->dq_off & ((1 << V2_DQBLKSIZE_BITS)-1)), 0,
1007 +                 sizeof(struct v2_disk_dqblk));
1008                 if (le16_to_cpu(dh->dqdh_entries) == V2_DQSTRINBLK-1) {
1009                         /* Insert will write block itself */
1010 -                       if ((ret = insert_free_dqentry(filp, dquot->dq_type, buf, blk)) < 0) {
1011 +                       if ((ret = insert_free_dqentry(sb, type, buf, blk)) < 0) {
1012                                 printk(KERN_ERR "VFS: Can't insert quota data block (%u) to free entry list.\n", blk);
1013                                 goto out_buf;
1014                         }
1015                 }
1016                 else
1017 -                       if ((ret = write_blk(filp, blk, buf)) < 0) {
1018 -                               printk(KERN_ERR "VFS: Can't write quota data block %u\n", blk);
1019 +                       if ((ret = write_blk(sb, type, blk, buf)) < 0) {
1020 +                               printk(KERN_ERR "VFS: Can't write quota data "
1021 +                                 "block %u\n", blk);
1022                                 goto out_buf;
1023                         }
1024         }
1025 @@ -506,7 +479,8 @@ out_buf:
1026  /* Remove reference to dquot from tree */
1027  static int remove_tree(struct dquot *dquot, uint *blk, int depth)
1028  {
1029 -       struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
1030 +       struct super_block *sb = dquot->dq_sb;
1031 +       int type = dquot->dq_type;
1032         dqbuf_t buf = getdqbuf();
1033         int ret = 0;
1034         uint newblk;
1035 @@ -514,7 +488,7 @@ static int remove_tree(struct dquot *dqu
1036         
1037         if (!buf)
1038                 return -ENOMEM;
1039 -       if ((ret = read_blk(filp, *blk, buf)) < 0) {
1040 +       if ((ret = read_blk(sb, type, *blk, buf)) < 0) {
1041                 printk(KERN_ERR "VFS: Can't read quota data block %u\n", *blk);
1042                 goto out_buf;
1043         }
1044 @@ -530,12 +504,13 @@ static int remove_tree(struct dquot *dqu
1045                 ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(0);
1046                 for (i = 0; i < V2_DQBLKSIZE && !buf[i]; i++);  /* Block got empty? */
1047                 if (i == V2_DQBLKSIZE) {
1048 -                       put_free_dqblk(filp, dquot->dq_type, buf, *blk);
1049 +                       put_free_dqblk(sb, type, buf, *blk);
1050                         *blk = 0;
1051                 }
1052                 else
1053 -                       if ((ret = write_blk(filp, *blk, buf)) < 0)
1054 -                               printk(KERN_ERR "VFS: Can't write quota tree block %u.\n", *blk);
1055 +                       if ((ret = write_blk(sb, type, *blk, buf)) < 0)
1056 +                               printk(KERN_ERR "VFS: Can't write quota tree "
1057 +                                 "block %u.\n", *blk);
1058         }
1059  out_buf:
1060         freedqbuf(buf);
1061 @@ -555,7 +530,6 @@ static int v2_delete_dquot(struct dquot 
1062  /* Find entry in block */
1063  static loff_t find_block_dqentry(struct dquot *dquot, uint blk)
1064  {
1065 -       struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
1066         dqbuf_t buf = getdqbuf();
1067         loff_t ret = 0;
1068         int i;
1069 @@ -563,27 +537,31 @@ static loff_t find_block_dqentry(struct 
1070  
1071         if (!buf)
1072                 return -ENOMEM;
1073 -       if ((ret = read_blk(filp, blk, buf)) < 0) {
1074 +       if ((ret = read_blk(dquot->dq_sb, dquot->dq_type, blk, buf)) < 0) {
1075                 printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
1076                 goto out_buf;
1077         }
1078         if (dquot->dq_id)
1079 -               for (i = 0; i < V2_DQSTRINBLK && le32_to_cpu(ddquot[i].dqb_id) != dquot->dq_id; i++);
1080 +               for (i = 0; i < V2_DQSTRINBLK &&
1081 +                    le32_to_cpu(ddquot[i].dqb_id) != dquot->dq_id; i++);
1082         else {  /* ID 0 as a bit more complicated searching... */
1083                 struct v2_disk_dqblk fakedquot;
1084  
1085                 memset(&fakedquot, 0, sizeof(struct v2_disk_dqblk));
1086                 for (i = 0; i < V2_DQSTRINBLK; i++)
1087 -                       if (!le32_to_cpu(ddquot[i].dqb_id) && memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk)))
1088 +                       if (!le32_to_cpu(ddquot[i].dqb_id) &&
1089 +                           memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk)))
1090                                 break;
1091         }
1092         if (i == V2_DQSTRINBLK) {
1093 -               printk(KERN_ERR "VFS: Quota for id %u referenced but not present.\n", dquot->dq_id);
1094 +               printk(KERN_ERR "VFS: Quota for id %u referenced "
1095 +                 "but not present.\n", dquot->dq_id);
1096                 ret = -EIO;
1097                 goto out_buf;
1098         }
1099         else
1100 -               ret = (blk << V2_DQBLKSIZE_BITS) + sizeof(struct v2_disk_dqdbheader) + i * sizeof(struct v2_disk_dqblk);
1101 +               ret = (blk << V2_DQBLKSIZE_BITS) + sizeof(struct
1102 +                 v2_disk_dqdbheader) + i * sizeof(struct v2_disk_dqblk);
1103  out_buf:
1104         freedqbuf(buf);
1105         return ret;
1106 @@ -592,14 +570,13 @@ out_buf:
1107  /* Find entry for given id in the tree */
1108  static loff_t find_tree_dqentry(struct dquot *dquot, uint blk, int depth)
1109  {
1110 -       struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
1111         dqbuf_t buf = getdqbuf();
1112         loff_t ret = 0;
1113         __le32 *ref = (__le32 *)buf;
1114  
1115         if (!buf)
1116                 return -ENOMEM;
1117 -       if ((ret = read_blk(filp, blk, buf)) < 0) {
1118 +       if ((ret = read_blk(dquot->dq_sb, dquot->dq_type, blk, buf)) < 0) {
1119                 printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
1120                 goto out_buf;
1121         }
1122 @@ -625,16 +602,13 @@ static inline loff_t find_dqentry(struct
1123  static int v2_read_dquot(struct dquot *dquot)
1124  {
1125         int type = dquot->dq_type;
1126 -       struct file *filp;
1127 -       mm_segment_t fs;
1128         loff_t offset;
1129         struct v2_disk_dqblk ddquot, empty;
1130         int ret = 0;
1131  
1132 -       filp = sb_dqopt(dquot->dq_sb)->files[type];
1133 -
1134  #ifdef __QUOTA_V2_PARANOIA
1135 -       if (!filp || !dquot->dq_sb) {   /* Invalidated quota? */
1136 +       /* Invalidated quota? */
1137 +       if (!dquot->dq_sb || !sb_dqopt(dquot->dq_sb)->files[type]) {
1138                 printk(KERN_ERR "VFS: Quota invalidated while reading!\n");
1139                 return -EIO;
1140         }
1141 @@ -642,7 +616,8 @@ static int v2_read_dquot(struct dquot *d
1142         offset = find_dqentry(dquot);
1143         if (offset <= 0) {      /* Entry not present? */
1144                 if (offset < 0)
1145 -                       printk(KERN_ERR "VFS: Can't read quota structure for id %u.\n", dquot->dq_id);
1146 +                       printk(KERN_ERR "VFS: Can't read quota "
1147 +                         "structure for id %u.\n", dquot->dq_id);
1148                 dquot->dq_off = 0;
1149                 set_bit(DQ_FAKE_B, &dquot->dq_flags);
1150                 memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
1151 @@ -650,12 +625,13 @@ static int v2_read_dquot(struct dquot *d
1152         }
1153         else {
1154                 dquot->dq_off = offset;
1155 -               fs = get_fs();
1156 -               set_fs(KERNEL_DS);
1157 -               if ((ret = filp->f_op->read(filp, (char *)&ddquot, sizeof(struct v2_disk_dqblk), &offset)) != sizeof(struct v2_disk_dqblk)) {
1158 +               if ((ret = dquot->dq_sb->s_op->quota_read(dquot->dq_sb, type,
1159 +                   (char *)&ddquot, sizeof(struct v2_disk_dqblk), offset))
1160 +                   != sizeof(struct v2_disk_dqblk)) {
1161                         if (ret >= 0)
1162                                 ret = -EIO;
1163 -                       printk(KERN_ERR "VFS: Error while reading quota structure for id %u.\n", dquot->dq_id);
1164 +                       printk(KERN_ERR "VFS: Error while reading quota "
1165 +                         "structure for id %u.\n", dquot->dq_id);
1166                         memset(&ddquot, 0, sizeof(struct v2_disk_dqblk));
1167                 }
1168                 else {
1169 @@ -666,7 +642,6 @@ static int v2_read_dquot(struct dquot *d
1170                         if (!memcmp(&empty, &ddquot, sizeof(struct v2_disk_dqblk)))
1171                                 ddquot.dqb_itime = 0;
1172                 }
1173 -               set_fs(fs);
1174                 disk2memdqb(&dquot->dq_dqb, &ddquot);
1175                 if (!dquot->dq_dqb.dqb_bhardlimit &&
1176                         !dquot->dq_dqb.dqb_bsoftlimit &&
1177 diff -rup RH_2_6_9_55.orig/include/linux/fs.h RH_2_6_9_55/include/linux/fs.h
1178 --- RH_2_6_9_55.orig/include/linux/fs.h
1179 +++ RH_2_6_9_55/include/linux/fs.h
1180 @@ -1042,6 +1042,9 @@ struct super_operations {
1181         void (*umount_lustre) (struct super_block *);
1182
1183         int (*show_options)(struct seq_file *, struct vfsmount *);
1184 +
1185 +       ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t);
1186 +       ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t);
1187  };
1188
1189  /* Inode state bits.  Protected by inode_lock. */
1190 diff -rup RH_2_6_9_55.orig/include/linux/quota.h RH_2_6_9_55/include/linux/quota.h
1191 --- RH_2_6_9_55.orig/include/linux/quota.h
1192 +++ RH_2_6_9_55/include/linux/quota.h
1193 @@ -285,7 +285,7 @@ struct quota_info {
1194         struct semaphore dqio_sem;              /* lock device while I/O in progress */
1195         struct semaphore dqonoff_sem;           /* Serialize quotaon & quotaoff */
1196         struct rw_semaphore dqptr_sem;          /* serialize ops using quota_info struct, pointers from inode to dquots */
1197 -       struct file *files[MAXQUOTAS];          /* fp's to quotafiles */
1198 +       struct inode *files[MAXQUOTAS];         /* inodes of quotafiles */
1199         struct mem_dqinfo info[MAXQUOTAS];      /* Information for each quota type */
1200         struct quota_format_ops *ops[MAXQUOTAS];        /* Operations for each type */
1201  };
1202 diff -rup RH_2_6_9_55.orig/include/linux/security.h RH_2_6_9_55/include/linux/security.h
1203 --- RH_2_6_9_55.orig/include/linux/security.h
1204 +++ RH_2_6_9_55/include/linux/security.h
1205 @@ -1033,7 +1033,7 @@ struct security_operations {
1206         int (*sysctl) (ctl_table * table, int op);
1207         int (*capable) (struct task_struct * tsk, int cap);
1208         int (*quotactl) (int cmds, int type, int id, struct super_block * sb);
1209 -       int (*quota_on) (struct file * f);
1210 +       int (*quota_on) (struct dentry * dentry);
1211         int (*syslog) (int type);
1212         int (*vm_enough_memory) (long pages);
1213
1214 @@ -1281,9 +1281,9 @@ static inline int security_quotactl (int
1215         return security_ops->quotactl (cmds, type, id, sb);
1216  }
1217  
1218 -static inline int security_quota_on (struct file * file)
1219 +static inline int security_quota_on (struct dentry * dentry)
1220  {
1221 -       return security_ops->quota_on (file);
1222 +       return security_ops->quota_on (dentry);
1223  }
1224  
1225  static inline int security_syslog(int type)
1226 @@ -1953,7 +1953,7 @@ static inline int security_quotactl (int
1227         return 0;
1228  }
1229  
1230 -static inline int security_quota_on (struct file * file)
1231 +static inline int security_quota_on (struct dentry * dentry)
1232  {
1233         return 0;
1234  }
1235 diff -rup RH_2_6_9_55.orig/security/dummy.c RH_2_6_9_55/security/dummy.c
1236 --- RH_2_6_9_55.orig/security/dummy.c
1237 +++ RH_2_6_9_55/security/dummy.c
1238 @@ -92,7 +92,7 @@ static int dummy_quotactl (int cmds, int
1239         return 0;
1240  }
1241  
1242 -static int dummy_quota_on (struct file *f)
1243 +static int dummy_quota_on (struct dentry *dentry)
1244  {
1245         return 0;
1246  }
1247 diff -rup RH_2_6_9_55.orig/security/selinux/hooks.c RH_2_6_9_55/security/selinux/hooks.c
1248 --- RH_2_6_9_55.orig/security/selinux/hooks.c
1249 +++ RH_2_6_9_55/security/selinux/hooks.c
1250 @@ -1485,9 +1485,9 @@ static int selinux_quotactl(int cmds, in
1251         return rc;
1252  }
1253  
1254 -static int selinux_quota_on(struct file *f)
1255 +static int selinux_quota_on(struct dentry *dentry)
1256  {
1257 -       return file_has_perm(current, f, FILE__QUOTAON);
1258 +       return dentry_has_perm(current, NULL, dentry, FILE__QUOTAON);
1259  }
1260  
1261  static int selinux_syslog(int type)