diff options
author | Jan Kara <jack@suse.cz> | 2007-09-11 15:23:29 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-09-11 17:21:19 -0700 |
commit | 9c3013e9b91ad23ecae88e45405e98208cce455d (patch) | |
tree | 2f18bb2d539727e2d9228a3d02a2e8810aa2ac3d /fs | |
parent | af7b83f9324a77ef9a9080044bf0461f444ca651 (diff) | |
download | kernel-common-9c3013e9b91ad23ecae88e45405e98208cce455d.tar.gz kernel-common-9c3013e9b91ad23ecae88e45405e98208cce455d.tar.bz2 kernel-common-9c3013e9b91ad23ecae88e45405e98208cce455d.zip |
quota: fix infinite loop
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>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ext3/super.c | 11 | ||||
-rw-r--r-- | fs/ext4/super.c | 11 | ||||
-rw-r--r-- | fs/reiserfs/super.c | 13 |
3 files changed, 31 insertions, 4 deletions
diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 22cfdd61c060..9537316a0714 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -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 ? diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 4550b83ab1c9..3c1397fa83df 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -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 ? diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 5b68dd3f191a..a005451930b7 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -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) |