lkml.org 
[lkml]   [2012]   [Feb]   [9]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    Date
    From
    SubjectRe: [PATCH 2/2] quota: Fix deadlock with suspend and quotas
    On 2/7/12 4:37 PM, Jan Kara wrote:
    > This script causes a kernel deadlock:
    > set -e
    > DEVICE=/dev/vg1/linear
    > lvchange -ay $DEVICE
    > mkfs.ext3 $DEVICE
    > mount -t ext3 -o usrquota,grpquota $DEVICE /mnt/test
    > quotacheck -gu /mnt/test
    > umount /mnt/test
    > mount -t ext3 -o usrquota,grpquota $DEVICE /mnt/test
    > quotaon /mnt/test
    > dmsetup suspend $DEVICE
    > setquota -u root 1 2 3 4 /mnt/test &
    > sleep 1
    > dmsetup resume $DEVICE
    >
    > setquota acquired semaphore s_umount for read and then tried to perform a
    > transaction (and waits because the device is suspended). dmsetup resume tries
    > to acquire s_umount for write before resuming the device (and waits for
    > setquota).
    >
    > Fix the deadlock by grabbing a thawed superblock for quota commands which need
    > it.
    >
    > Reported-by: Mikulas Patocka <mpatocka@redhat.com>
    > Signed-off-by: Jan Kara <jack@suse.cz>

    Makes sense to me, thanks.

    Reviewed-by: Eric Sandeen <sandeen@redhat.com>

    > ---
    > fs/quota/quota.c | 24 +++++++++++++++++++++---
    > 1 files changed, 21 insertions(+), 3 deletions(-)
    >
    > diff --git a/fs/quota/quota.c b/fs/quota/quota.c
    > index 7898cd6..fc2c438 100644
    > --- a/fs/quota/quota.c
    > +++ b/fs/quota/quota.c
    > @@ -292,11 +292,26 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,
    > }
    > }
    >
    > +/* Return 1 if 'cmd' will block on frozen filesystem */
    > +static int quotactl_cmd_write(int cmd)
    > +{
    > + switch (cmd) {
    > + case Q_GETFMT:
    > + case Q_GETINFO:
    > + case Q_SYNC:
    > + case Q_XGETQSTAT:
    > + case Q_XGETQUOTA:
    > + case Q_XQUOTASYNC:
    > + return 0;
    > + }
    > + return 1;
    > +}
    > +
    > /*
    > * look up a superblock on which quota ops will be performed
    > * - use the name of a block device to find the superblock thereon
    > */
    > -static struct super_block *quotactl_block(const char __user *special)
    > +static struct super_block *quotactl_block(const char __user *special, int cmd)
    > {
    > #ifdef CONFIG_BLOCK
    > struct block_device *bdev;
    > @@ -309,7 +324,10 @@ static struct super_block *quotactl_block(const char __user *special)
    > putname(tmp);
    > if (IS_ERR(bdev))
    > return ERR_CAST(bdev);
    > - sb = get_super(bdev);
    > + if (quotactl_cmd_write(cmd))
    > + sb = get_super_thawed(bdev);
    > + else
    > + sb = get_super(bdev);
    > bdput(bdev);
    > if (!sb)
    > return ERR_PTR(-ENODEV);
    > @@ -361,7 +379,7 @@ SYSCALL_DEFINE4(quotactl, unsigned int, cmd, const char __user *, special,
    > pathp = &path;
    > }
    >
    > - sb = quotactl_block(special);
    > + sb = quotactl_block(special, cmds);
    > if (IS_ERR(sb)) {
    > ret = PTR_ERR(sb);
    > goto out;



    \
     
     \ /
      Last update: 2012-02-09 17:49    [W:2.357 / U:0.844 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site