quota: Fix deadlock with suspend and quotas
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> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
Родитель
6b6dc836a1
Коммит
dcdbed853d
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче