Fix it by updating __blkdev_get() to issue partition rescan after
-ENOMEDIA too.
This was reported in the following bz.
https://bugzilla.kernel.org/show_bug.cgi?id=13029
Signed-off-by: Tejun Heo <t...@kernel.org>
Reported-by: David Zeuthen <zeu...@gmail.com>
Reported-by: Martin Pitt <marti...@ubuntu.com>
Reported-by: Kay Sievers <kay.s...@vrfy.org>
Tested-by: Kay Sievers <kay.s...@vrfy.org>
Cc: Alan Cox <al...@lxorguk.ukuu.org.uk>
---
fs/block_dev.c | 27 ++++++++++++++++++---------
1 file changed, 18 insertions(+), 9 deletions(-)
diff --git a/fs/block_dev.c b/fs/block_dev.c
index c1511c6..a926ad4 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -1102,6 +1102,7 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
if (!bdev->bd_part)
goto out_clear;
+ ret = 0;
if (disk->fops->open) {
ret = disk->fops->open(bdev, mode);
if (ret == -ERESTARTSYS) {
@@ -1118,9 +1119,18 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
put_disk(disk);
goto restart;
}
- if (ret)
- goto out_clear;
}
+ /*
+ * If the device is invalidated, rescan partition
+ * if open succeeded or failed with -ENOMEDIUM.
+ * The latter is necessary to prevent ghost
+ * partitions on a removed medium.
+ */
+ if (bdev->bd_invalidated && (!ret || ret == -ENOMEDIUM))
+ rescan_partitions(disk, bdev);
+ if (ret)
+ goto out_clear;
+
if (!bdev->bd_openers) {
bd_set_size(bdev,(loff_t)get_capacity(disk)<<9);
bdi = blk_get_backing_dev_info(bdev);
@@ -1128,8 +1138,6 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
bdi = &default_backing_dev_info;
bdev_inode_switch_bdi(bdev->bd_inode, bdi);
}
- if (bdev->bd_invalidated)
- rescan_partitions(disk, bdev);
} else {
struct block_device *whole;
whole = bdget_disk(disk, 0);
@@ -1153,13 +1161,14 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
}
} else {
if (bdev->bd_contains == bdev) {
- if (bdev->bd_disk->fops->open) {
+ ret = 0;
+ if (bdev->bd_disk->fops->open)
ret = bdev->bd_disk->fops->open(bdev, mode);
- if (ret)
- goto out_unlock_bdev;
- }
- if (bdev->bd_invalidated)
+ /* the same as first opener case, read comment there */
+ if (bdev->bd_invalidated && (!ret || ret == -ENOMEDIUM))
rescan_partitions(bdev->bd_disk, bdev);
+ if (ret)
+ goto out_unlock_bdev;
}
/* only one opener holds refs to the module and disk */
module_put(disk->fops->owner);
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majo...@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
* After media change, if the device opened without O_NONBLOCK,
open_for_data() naturally fails with -ENOMEDIA and
check_disk_change() is never called. The media is known to be gone
and the open failure makes it obvious to the userland but device
invalidation never happens.
* But if the device is opened with O_NONBLOCK, all the checks are
bypassed and cdrom_open() doesn't notice that the media is not there
and check_disk_change() is called and invalidation happens.
There's nothing to be gained by avoiding calling check_disk_change()
on open failure. Common cases end up calling check_disk_change()
anyway. All we get is inconsistent behavior.
Fix it by moving check_disk_change() invocation to the top of
cdrom_open() so that it always gets called regardless of how the rest
of open proceeds.
Signed-off-by: Tejun Heo <t...@kernel.org>
Reported-by: Amit Shah <amit...@redhat.com>
Tested-by: Amit Shah <amit...@redhat.com>
---
drivers/cdrom/cdrom.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index e2c48a7..5ade78a 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -986,6 +986,9 @@ int cdrom_open(struct cdrom_device_info *cdi, struct block_device *bdev, fmode_t
cdinfo(CD_OPEN, "entering cdrom_open\n");
+ /* open is event synchronization point, check events first */
+ check_disk_change(bdev);
+
/* if this was a O_NONBLOCK open and we should honor the flags,
* do a quick open without drive/disc integrity checks. */
cdi->use_count++;
@@ -1012,9 +1015,6 @@ int cdrom_open(struct cdrom_device_info *cdi, struct block_device *bdev, fmode_t
cdinfo(CD_OPEN, "Use count for \"/dev/%s\" now %d\n",
cdi->name, cdi->use_count);
- /* Do this on open. Don't wait for mount, because they might
- not be mounting, but opening with O_NONBLOCK */
- check_disk_change(bdev);
return 0;
err_release:
if (CDROM_CAN(CDC_LOCK) && cdi->options & CDO_LOCK) {
Ping?
Also, please mark this for stable-2.6.38.
Thanks,
Amit
Jens?
--
tejun
Done, added for 2.6.39 and marked stable for 2.6.38.
--
Jens Axboe
Indeed :-)
Heh, mid-air collision. Good morning, Jens. :)
--
tejun
Ping again. Don't see this yet in Linus's git tree.
Amit
It was added for 2.6.40 and marked for stable.
--
Jens Axboe
OK, Thanks.
Amit
Various people[1] have been noticing a race (or races?) in which the
cdrom_id and scsi_id programs from udev can get stuck in the D state
if udev doesn't sleep a little while before running them. This
prevents the machine from suspending. The problem was discovered with
Debian kernels
2.6.39-1
2.6.39-2
3.0.0-1
and was not experienced with kernel
2.6.38-5
(These kernels are closely based on v2.6.39, v2.6.39.1, v3.0, and
v2.6.38.5, respectively.) Reverting commit bf2253a6f00e (cdrom:
always check_disk_change() on open, 2011-04-29) seems to avoid
trouble.
One common theme seems to be DVD drives. Details at [1].
Known problem? Any ideas for tracking it down?
Looking forward to your thoughts,
Jonathan
[1] <http://bugs.debian.org/628600>. Submitters cc-ed.
On Sat, Sep 03, 2011 at 05:14:56PM -0500, Jonathan Nieder wrote:
> Various people[1] have been noticing a race (or races?) in which the
> cdrom_id and scsi_id programs from udev can get stuck in the D state
> if udev doesn't sleep a little while before running them. This
> prevents the machine from suspending. The problem was discovered with
> Debian kernels
>
> 2.6.39-1
> 2.6.39-2
> 3.0.0-1
>
> and was not experienced with kernel
>
> 2.6.38-5
>
> (These kernels are closely based on v2.6.39, v2.6.39.1, v3.0, and
> v2.6.38.5, respectively.) Reverting commit bf2253a6f00e (cdrom:
> always check_disk_change() on open, 2011-04-29) seems to avoid
> trouble.
>
> One common theme seems to be DVD drives. Details at [1].
>
> Known problem? Any ideas for tracking it down?
Can you please build vanilla kernel with CONFIG_FRAME_POINTER turned
on, reproduce the problem and attach full dmesg output?
Thanks.
--
tejun
>> Various people[1] have been noticing a race (or races?) in which the
>> cdrom_id and scsi_id programs from udev can get stuck in the D state
[...]
> Can you please build vanilla kernel with CONFIG_FRAME_POINTER turned
> on, reproduce the problem and attach full dmesg output?
Thanks, Tejun. I haven't been able to reproduce it here, but I'd be
happy to help anyone cc-ed wanting to do that who has questions (feel
free to email me privately).
Hi, Tejun. I recompiled the kernel from the Debian linux-source-3.0.0
(following the instructions here [0]) with the following config:
CONFIG_FRAME_POINTER=y
I then rebooted into this new kernel and triggered the bug. Attached is
the dmesg output from right before and right after the bug was
triggered. The bug was triggered by ejecting my laptop from it's dock,
and then trying to put it to sleep (which of course it failed to do).
Please let me know if there's anything else I can do, or any other
information I can provide. Thanks so much for the help.
jamie.
[0] http://kernel-handbook.alioth.debian.org/ch-common-tasks.html#s-common-building
On Sun, Sep 04, 2011 at 06:49:38PM -0700, Jameson Graef Rollins wrote:
> I then rebooted into this new kernel and triggered the bug. Attached is
> the dmesg output from right before and right after the bug was
> triggered. The bug was triggered by ejecting my laptop from it's dock,
> and then trying to put it to sleep (which of course it failed to do).
If you wait (five mins) after triggering the problem, does the kernel
print further messages? Also, can you please explain the steps needed
to trigger this problem?
> [ 221.306959] cdrom_id D 0000000000000000 0 2693 2689 0x00800004
> [ 221.306969] ffff88023180b8e8 0000000000000082 7fffffffffffffff ffff880200000000
> [ 221.306978] ffff8802314b83c0 ffff88023180bfd8 ffff88023180bfd8 0000000000012840
> [ 221.306987] ffff880232e18f60 ffff8802314b83c0 ffff88023180b938 000000018133e5cf
> [ 221.306995] Call Trace:
> [ 221.307011] [<ffffffff8133ea82>] schedule_timeout+0x2f/0xd9
> [ 221.307021] [<ffffffff8133e86e>] wait_for_common+0x9e/0x115
> [ 221.307029] [<ffffffff8133e97b>] wait_for_completion+0x18/0x1a
> [ 221.307035] [<ffffffff8105b0fe>] flush_work+0x29/0x2f
> [ 221.307042] [<ffffffff8105b48a>] flush_delayed_work+0x3a/0x3e
> [ 221.307047] [<ffffffff81199bc6>] disk_clear_events+0x8f/0xf5
> [ 221.307073] [<ffffffff81121827>] check_disk_change+0x29/0x5b
> [ 221.307081] [<ffffffffa0069e71>] cdrom_open+0x44/0x4b2 [cdrom]
> [ 221.307097] [<ffffffffa010786b>] sr_block_open+0x90/0xb7 [sr_mod]
> [ 221.307101] [<ffffffff811226dd>] __blkdev_get+0xe5/0x39b
> [ 221.307104] [<ffffffff81122b5f>] blkdev_get+0x1cc/0x2bb
> [ 221.307111] [<ffffffff81122cb3>] blkdev_open+0x65/0x6a
> [ 221.307115] [<ffffffff810f98f2>] __dentry_open+0x185/0x29f
> [ 221.307129] [<ffffffff810fa842>] nameidata_to_filp+0x5b/0x62
> [ 221.307135] [<ffffffff81105843>] do_last+0x448/0x55d
> [ 221.307138] [<ffffffff81106483>] path_openat+0xc3/0x304
> [ 221.307142] [<ffffffff811066f7>] do_filp_open+0x33/0x81
> [ 221.307150] [<ffffffff810fa8b2>] do_sys_open+0x69/0xfb
> [ 221.307153] [<ffffffff810fa95f>] sys_open+0x1b/0x1d
> [ 221.307157] [<ffffffff81344d52>] system_call_fastpath+0x16/0x1b
Hmmm... so, this is cdrom_id waiting for event check work item to
complete. The event work is executed on system_nrt_wq which is frozen
after all userland tasks are frozen so there's no reason for the above
to stall. Can you please enable sysrq, trigger the problem and while
the system is in that 20 sec freeze stall, hit sysrq-t and report the
dmesg?
> [ 242.681434] INFO: task cdrom_id:2693 blocked for more than 120 seconds.
> [ 242.681438] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
> [ 242.681442] cdrom_id D 0000000000000000 0 2693 2689 0x00000004
> [ 242.681448] ffff88023180b8e8 0000000000000082 7fffffffffffffff ffff880200000000
> [ 242.681455] ffff8802314b83c0 ffff88023180bfd8 ffff88023180bfd8 0000000000012840
> [ 242.681460] ffff880232e18f60 ffff8802314b83c0 ffff88023180b938 000000018133e5cf
> [ 242.681466] Call Trace:
> [ 242.681478] [<ffffffff8133ea82>] schedule_timeout+0x2f/0xd9
> [ 242.681490] [<ffffffff8133e86e>] wait_for_common+0x9e/0x115
> [ 242.681500] [<ffffffff8133e97b>] wait_for_completion+0x18/0x1a
> [ 242.681507] [<ffffffff8105b0fe>] flush_work+0x29/0x2f
Does the cdrom eventually become usable afterwards?