fix to quotas for 2.0.30 and 2.1.46

Nick Kralevich (nickkral@ferrari.autobahn.org)
Mon, 21 Jul 1997 08:37:06 -0700 (PDT)


Under some circumstances, user quotas and group quotas can get mixed up,
and all block and inode allocations and deallocations are applied to only
the user quota, not to the group quota. The net result is that the user
ends up being quotaed for 2x the amount of disk space they should actually
have for any new blocks or inodes. The following fix fixes this problem.
Included below are patches for 2.0.30 and 2.1.46. I would appreciate it
if you could forward this to whoever's responsible for incorporating this
into the next kernel.

The problem is dependent on what specific device, uid, and gid that is in
use at the time. I was able to duplicate the problem on device /dev/sda8
(major 8, minor 8), with UID == GID == 540. This value hashes out to "0"
for both the user and group quota. When dqget() is called before the
patch, it could not tell the difference between a group quota and a user
quota (because they were both put into the same bucket in the hash
table). Now it can tell the difference.

I've tested these patches on my system (1100 users) and they seem to work
fine. Before, of the 773 accounts that we have on that one hard drive, 18
were having problems with quotas. After the patch, none of them are.

Thanks to Daniel Eischen for helping me solve this problem.

Take care,
-- Nick Kralevich
nickkral@autobahn.org

--- linux-2.0.30/fs/dquot.c Sun May 12 21:36:19 1996
+++ linux/fs/dquot.c Mon Jul 21 07:11:32 1997
@@ -19,6 +19,8 @@
*
* Fixes: Dmitry Gorodchanin <begemot@bgm.rosprint.net>, 11 Feb 96
* removed race conditions in dqput(), dqget() and iput().
+ * Nick Kralevich <nickkral@cal.alumni.berkeley.edu>, 21 Jul 97
+ * Fixed a condition where user and group quotas could get mixed up.
*
* (C) Copyright 1994, 1995 Marco van Wieringen
*
@@ -549,12 +551,14 @@
repeat:
dquot = *(hash(dev, id, type));
while (dquot) {
- if (dquot->dq_dev != dev || dquot->dq_id != id) {
+ if (dquot->dq_dev != dev || dquot->dq_id != id ||
+ dquot->dq_type != type) {
dquot = dquot->dq_hash_next;
continue;
}
wait_on_dquot(dquot);
- if (dquot->dq_dev != dev || dquot->dq_id != id)
+ if (dquot->dq_dev != dev || dquot->dq_id != id ||
+ dquot->dq_type != type)
goto repeat;
if (!dquot->dq_count)
nr_free_dquots--;

----------------------

--- linux-2.1.46/fs/dquot.c Sun Jul 13 21:20:10 1997
+++ linux/fs/dquot.c Mon Jul 21 07:18:09 1997
@@ -20,6 +20,8 @@
* Fixes: Dmitry Gorodchanin <begemot@bgm.rosprint.net>, 11 Feb 96
* removed race conditions in dqput(), dqget() and iput().
* Andi Kleen removed all verify_area() calls, 31 Dec 96
+ * Nick Kralevich <nickkral@cal.alumni.berkeley.edu>, 21 Jul 97
+ * Fixed a condition where user and group quotas could get mixed up.
*
* (C) Copyright 1994, 1995 Marco van Wieringen
*
@@ -555,12 +557,14 @@
repeat:
dquot = *(hash(dev, id, type));
while (dquot) {
- if (dquot->dq_dev != dev || dquot->dq_id != id) {
+ if (dquot->dq_dev != dev || dquot->dq_id != id ||
+ dquot->dq_type != type) {
dquot = dquot->dq_hash_next;
continue;
}
wait_on_dquot(dquot);
- if (dquot->dq_dev != dev || dquot->dq_id != id)
+ if (dquot->dq_dev != dev || dquot->dq_id != id ||
+ dquot->dq_type != type)
goto repeat;
if (!dquot->dq_count)
nr_free_dquots--;