Bug in ext2 quota

Jan Kara (jack@ucw.cz)
Tue, 11 Sep 2001 14:37:51 +0200


Hello,

I'm sending you a patch which fixes bug in ext2 quota - inode quota was
decremented even if ext2_free_inode() was called on inode not counted to
quota (which can occur for example when user is over inode quota and so
creation of inode is canceled). Attached patch should fix it. Please apply.

Honza

--------------------------------------------------------------------------------
diff -r -u -X /home/jack/.kerndiffexclude linux-2.4.10-pre4/fs/dquot.c linux-2.4.10-pre4-fix/fs/dquot.c
--- linux-2.4.10-pre4/fs/dquot.c Tue Sep 4 12:13:23 2001
+++ linux-2.4.10-pre4-fix/fs/dquot.c Sat Sep 8 17:50:19 2001
@@ -627,27 +627,11 @@
return dquot;
}

-/* Check whether this inode is quota file */
-static inline int is_quotafile(struct inode *inode)
-{
- int cnt;
- struct quota_mount_options *dqopt = sb_dqopt(inode->i_sb);
- struct file **files;
-
- if (!dqopt)
- return 0;
- files = dqopt->files;
- for (cnt = 0; cnt < MAXQUOTAS; cnt++)
- if (files[cnt] && files[cnt]->f_dentry->d_inode == inode)
- return 1;
- return 0;
-}
-
static int dqinit_needed(struct inode *inode, short type)
{
int cnt;

- if (is_quotafile(inode))
+ if (IS_NOQUOTA(inode))
return 0;
if (type != -1)
return inode->i_dquot[type] == NODQUOT;
@@ -675,7 +659,6 @@
if (filp->f_mode & FMODE_WRITE && dqinit_needed(inode, type)) {
file_list_unlock();
sb->dq_op->initialize(inode, type);
- inode->i_flags |= S_QUOTA;
/* As we may have blocked we had better restart... */
goto restart;
}
@@ -1017,8 +1000,7 @@
short cnt;

lock_kernel();
- /* We don't want to have quotas on quota files - nasty deadlocks possible */
- if (is_quotafile(inode)) {
+ if (IS_NOQUOTA(inode)) {
unlock_kernel();
return;
}
@@ -1472,7 +1454,9 @@
error = -EINVAL;
if (inode->i_size == 0 || !check_quotafile_size(inode->i_size))
goto out_f;
- dquot_drop(inode); /* We don't want quota on quota files */
+ /* We don't want quota on quota files */
+ dquot_drop(inode);
+ inode->i_flags |= S_NOQUOTA;

set_enable_flags(dqopt, type);
dqopt->files[type] = f;
diff -r -u -X /home/jack/.kerndiffexclude linux-2.4.10-pre4/fs/ext2/ialloc.c linux-2.4.10-pre4-fix/fs/ext2/ialloc.c
--- linux-2.4.10-pre4/fs/ext2/ialloc.c Fri Jul 27 20:41:20 2001
+++ linux-2.4.10-pre4-fix/fs/ext2/ialloc.c Sat Sep 8 16:59:26 2001
@@ -194,9 +194,11 @@
* Note: we must free any quota before locking the superblock,
* as writing the quota to disk may need the lock as well.
*/
- DQUOT_INIT(inode);
- DQUOT_FREE_INODE(sb, inode);
- DQUOT_DROP(inode);
+ if (!is_bad_inode(inode)) {
+ /* Quota is already initialized in iput() */
+ DQUOT_FREE_INODE(sb, inode);
+ DQUOT_DROP(inode);
+ }

lock_super (sb);
es = sb->u.ext2_sb.s_es;
@@ -453,7 +455,8 @@

unlock_super (sb);
if(DQUOT_ALLOC_INODE(sb, inode)) {
- sb->dq_op->drop(inode);
+ DQUOT_DROP(inode);
+ inode->i_flags |= S_NOQUOTA;
inode->i_nlink = 0;
iput(inode);
return ERR_PTR(-EDQUOT);
@@ -463,6 +466,7 @@

fail:
unlock_super(sb);
+ make_bad_inode(inode);
iput(inode);
return ERR_PTR(err);
}
diff -r -u -X /home/jack/.kerndiffexclude linux-2.4.10-pre4/fs/inode.c linux-2.4.10-pre4-fix/fs/inode.c
--- linux-2.4.10-pre4/fs/inode.c Tue Sep 4 12:13:23 2001
+++ linux-2.4.10-pre4-fix/fs/inode.c Sat Sep 8 16:02:16 2001
@@ -513,8 +513,7 @@
if (inode->i_state & I_CLEAR)
BUG();
wait_on_inode(inode);
- if (IS_QUOTAINIT(inode))
- DQUOT_DROP(inode);
+ DQUOT_DROP(inode);
if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->clear_inode)
inode->i_sb->s_op->clear_inode(inode);
if (inode->i_bdev) {
@@ -1049,7 +1048,8 @@

if (op && op->delete_inode) {
void (*delete)(struct inode *) = op->delete_inode;
- DQUOT_INIT(inode);
+ if (!is_bad_inode(inode))
+ DQUOT_INIT(inode);
/* s_op->delete_inode internally recalls clear_inode() */
delete(inode);
} else
diff -r -u -X /home/jack/.kerndiffexclude linux-2.4.10-pre4/include/linux/fs.h linux-2.4.10-pre4-fix/include/linux/fs.h
--- linux-2.4.10-pre4/include/linux/fs.h Fri Sep 7 23:36:04 2001
+++ linux-2.4.10-pre4-fix/include/linux/fs.h Sat Sep 8 16:31:57 2001
@@ -129,6 +129,7 @@
#define S_APPEND 8 /* Append-only file */
#define S_IMMUTABLE 16 /* Immutable file */
#define S_DEAD 32 /* removed, but still open directory */
+#define S_NOQUOTA 64 /* Inode is not counted to quota */

/*
* Note that nosuid etc flags are inode-specific: setting some file-system
@@ -153,6 +154,7 @@
#define IS_MANDLOCK(inode) __IS_FLG(inode, MS_MANDLOCK)

#define IS_QUOTAINIT(inode) ((inode)->i_flags & S_QUOTA)
+#define IS_NOQUOTA(inode) ((inode)->i_flags & S_NOQUOTA)
#define IS_APPEND(inode) ((inode)->i_flags & S_APPEND)
#define IS_IMMUTABLE(inode) ((inode)->i_flags & S_IMMUTABLE)
#define IS_NOATIME(inode) (__IS_FLG(inode, MS_NOATIME) || ((inode)->i_flags & S_NOATIME))
diff -r -u -X /home/jack/.kerndiffexclude linux-2.4.10-pre4/include/linux/quotaops.h linux-2.4.10-pre4-fix/include/linux/quotaops.h
--- linux-2.4.10-pre4/include/linux/quotaops.h Fri Sep 7 23:39:55 2001
+++ linux-2.4.10-pre4-fix/include/linux/quotaops.h Sat Sep 8 17:09:29 2001
@@ -37,8 +37,10 @@
*/
static __inline__ void DQUOT_INIT(struct inode *inode)
{
- if (inode->i_sb && inode->i_sb->dq_op)
- inode->i_sb->dq_op->initialize(inode, -1);
+ if (!IS_NOQUOTA(inode)) {
+ if (inode->i_sb && inode->i_sb->dq_op)
+ inode->i_sb->dq_op->initialize(inode, -1);
+ }
}

static __inline__ void DQUOT_DROP(struct inode *inode)
@@ -70,7 +72,7 @@
static __inline__ int DQUOT_ALLOC_INODE(struct super_block *sb, struct inode *inode)
{
if (sb->dq_op) {
- sb->dq_op->initialize (inode, -1);
+ DQUOT_INIT(inode);
if (sb->dq_op->alloc_inode (inode, 1))
return 1;
}
@@ -94,8 +96,8 @@
{
int error = -EDQUOT;

- if (dentry->d_inode->i_sb->dq_op) {
- dentry->d_inode->i_sb->dq_op->initialize(dentry->d_inode, -1);
+ if (dentry->d_inode->i_sb->dq_op && !IS_NOQUOTA(dentry->d_inode)) {
+ DQUOT_INIT(dentry->d_inode);
error = dentry->d_inode->i_sb->dq_op->transfer(dentry, iattr);
} else {
error = notify_change(dentry, iattr);
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/