quota: fix infinite loop
Jan Kara [Tue, 11 Sep 2007 22:23:29 +0000 (15:23 -0700)]
If we fail to start a transaction when releasing dquot, we have to call
dquot_release() anyway to mark dquot structure as inactive.  Otherwise we
end in an infinite loop inside dqput().

Signed-off-by: Jan Kara <jack@suse.cz>
Cc: xb <xavier.bru@bull.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

fs/ext3/super.c
fs/ext4/super.c
fs/reiserfs/super.c

index 22cfdd6..9537316 100644 (file)
@@ -2578,8 +2578,11 @@ static int ext3_release_dquot(struct dquot *dquot)
 
        handle = ext3_journal_start(dquot_to_inode(dquot),
                                        EXT3_QUOTA_DEL_BLOCKS(dquot->dq_sb));
-       if (IS_ERR(handle))
+       if (IS_ERR(handle)) {
+               /* Release dquot anyway to avoid endless cycle in dqput() */
+               dquot_release(dquot);
                return PTR_ERR(handle);
+       }
        ret = dquot_release(dquot);
        err = ext3_journal_stop(handle);
        if (!ret)
@@ -2712,6 +2715,12 @@ static ssize_t ext3_quota_write(struct super_block *sb, int type,
        struct buffer_head *bh;
        handle_t *handle = journal_current_handle();
 
+       if (!handle) {
+               printk(KERN_WARNING "EXT3-fs: Quota write (off=%Lu, len=%Lu)"
+                       " cancelled because transaction is not started.\n",
+                       (unsigned long long)off, (unsigned long long)len);
+               return -EIO;
+       }
        mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA);
        while (towrite > 0) {
                tocopy = sb->s_blocksize - offset < towrite ?
index 4550b83..3c1397f 100644 (file)
@@ -2698,8 +2698,11 @@ static int ext4_release_dquot(struct dquot *dquot)
 
        handle = ext4_journal_start(dquot_to_inode(dquot),
                                        EXT4_QUOTA_DEL_BLOCKS(dquot->dq_sb));
-       if (IS_ERR(handle))
+       if (IS_ERR(handle)) {
+               /* Release dquot anyway to avoid endless cycle in dqput() */
+               dquot_release(dquot);
                return PTR_ERR(handle);
+       }
        ret = dquot_release(dquot);
        err = ext4_journal_stop(handle);
        if (!ret)
@@ -2832,6 +2835,12 @@ static ssize_t ext4_quota_write(struct super_block *sb, int type,
        struct buffer_head *bh;
        handle_t *handle = journal_current_handle();
 
+       if (!handle) {
+               printk(KERN_WARNING "EXT4-fs: Quota write (off=%Lu, len=%Lu)"
+                       " cancelled because transaction is not started.\n",
+                       (unsigned long long)off, (unsigned long long)len);
+               return -EIO;
+       }
        mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA);
        while (towrite > 0) {
                tocopy = sb->s_blocksize - offset < towrite ?
index 5b68dd3..a005451 100644 (file)
@@ -1915,8 +1915,11 @@ static int reiserfs_release_dquot(struct dquot *dquot)
        ret =
            journal_begin(&th, dquot->dq_sb,
                          REISERFS_QUOTA_DEL_BLOCKS(dquot->dq_sb));
-       if (ret)
+       if (ret) {
+               /* Release dquot anyway to avoid endless cycle in dqput() */
+               dquot_release(dquot);
                goto out;
+       }
        ret = dquot_release(dquot);
        err =
            journal_end(&th, dquot->dq_sb,
@@ -2067,6 +2070,12 @@ static ssize_t reiserfs_quota_write(struct super_block *sb, int type,
        size_t towrite = len;
        struct buffer_head tmp_bh, *bh;
 
+       if (!current->journal_info) {
+               printk(KERN_WARNING "reiserfs: Quota write (off=%Lu, len=%Lu)"
+                       " cancelled because transaction is not started.\n",
+                       (unsigned long long)off, (unsigned long long)len);
+               return -EIO;
+       }
        mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA);
        while (towrite > 0) {
                tocopy = sb->s_blocksize - offset < towrite ?
@@ -2098,7 +2107,7 @@ static ssize_t reiserfs_quota_write(struct super_block *sb, int type,
                data += tocopy;
                blk++;
        }
-      out:
+out:
        if (len == towrite)
                return err;
        if (inode->i_size < off + len - towrite)