From: Eric Sandeen <sandeen@redhat.com> Date: Thu, 8 May 2008 15:09:30 -0500 Subject: [fs] ext3: unmount hang when quota-enabled goes error-RO Message-id: 48235DFA.8080504@redhat.com O-Subject: [PATCH RHEL5.3] ext3: fix unmount hangs when quota-enabled fs goes error-RO Bugzilla: 429054 RH-Acked-by: Larry Woodman <lwoodman@redhat.com> RH-Acked-by: Josef Bacik <jbacik@redhat.com> RH-Acked-by: Stephen C. Tweedie <sct@redhat.com> For - Bug 429054: soft lockup while unmounting a read-only filesystem with errors If the filesystem goes remount-readonly due to an error, new transactions cannot be started, but unmounting the filesystem tries to do just that for ext3_release_dquot(). This fails and leads to a loop in dqput. This is a combination of the following 2 upstream patches to resolve the problem. (actually the earlier patch addresses it in ext3_release_dquot(), the 2nd patch is related and worth picking up). Tested with something like: mkfs.ext3 /dev/sdb5 mount -o quota /dev/sdb5 /mnt/test quotacheck /mnt/test setquota -u root 10000 10000 10000 10000 /mnt/test quotaon /mnt/test cd /mnt/test cp ../linux-2.6.25.1.tar . tar xvf linux-2.6.25.1.tar sync cd mount -o remount,abort /mnt/test sleep 10 umount /mnt/test Thanks, -Eric --------------------- Date: Tue, 11 Sep 2007 22:23:29 +0000 (-0700) Subject: quota: fix infinite loop X-Git-Tag: v2.6.23-rc7~94 X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=9c3013e9b91ad23ecae88e45405e98208cce455d 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> Date: Mon, 28 Apr 2008 09:16:13 +0000 (-0700) Subject: ext3: fix hang on umount with quotas when journal is aborted X-Git-Tag: v2.6.26-rc1~747 X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=07c9938a4e2c92b796b163dc70e99d3d1870aaee ext3: fix hang on umount with quotas when journal is aborted Call dquot_drop() from ext3_dquot_drop() even if we fail to start a transaction. Otherwise we never get to dropping references to quota structures from the inode and umount will hang indefinitely. Thanks to Payphone LIOU for spotting the problem. Signed-off-by: Jan Kara <jack@suse.cz> Cc: Payphone LIOU <lioupayphone@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> fs/ext3/super.c | 19 +++++++++++++++++-- 1 files changed, 17 insertions(+), 2 deletions(-) diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 49ff567..c828b0b 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -2497,8 +2497,14 @@ static int ext3_dquot_drop(struct inode *inode) /* We may delete quota structure so we need to reserve enough blocks */ handle = ext3_journal_start(inode, 2*EXT3_QUOTA_DEL_BLOCKS(inode->i_sb)); - if (IS_ERR(handle)) + if (IS_ERR(handle)) { + /* + * We call dquot_drop() anyway to at least release references + * to quota structures so that umount does not hang. + */ + dquot_drop(inode); return PTR_ERR(handle); + } ret = dquot_drop(inode); err = ext3_journal_stop(handle); if (!ret) @@ -2547,8 +2553,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) @@ -2681,6 +2690,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 ?