[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Poking around bdrv_is_inserted()
From: |
Markus Armbruster |
Subject: |
Re: Poking around bdrv_is_inserted() |
Date: |
Tue, 09 Nov 2021 16:20:32 +0100 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/27.2 (gnu/linux) |
Kevin Wolf <kwolf@redhat.com> writes:
> Am 09.11.2021 um 07:44 hat Markus Armbruster geschrieben:
>> Screwed up qemu-devel@nongnu.org, sorry for the inconvenience.
>>
>> Markus Armbruster <armbru@redhat.com> writes:
>>
>> > bdrv_is_inserted() returns false when:
>> >
>> > /**
>> > * Return TRUE if the media is present
>> > */
>> > bool bdrv_is_inserted(BlockDriverState *bs)
>> > {
>> > BlockDriver *drv = bs->drv;
>> > BdrvChild *child;
>> >
>> > if (!drv) {
>> > return false;
>> >
>> > 1. @bs has no driver (this is how we represent "no medium").
>
> Not really any more. "No medium" is blk->root == NULL.
Uh, blk_is_inserted() does *not* check blk->root:
bool blk_is_inserted(BlockBackend *blk)
{
BlockDriverState *bs = blk_bs(blk);
return bs && bdrv_is_inserted(bs);
}
Now I'm confused.
> These days
> bs->drv == NULL basically means "the backend is broken". This happens
> after qcow2_signal_corruption(), and I'm not sure if we have more
> circumstances like it.
I'm not sure having bdrv_is_inserted() return true for "broken" backends
makes sense.
>> > }
>> > if (drv->bdrv_is_inserted) {
>> > return drv->bdrv_is_inserted(bs);
>> >
>> > 2. Its driver's ->bdrv_is_inserted() returns false. This is how
>> > passthrough block backends signal "host device has no medium". Right
>> > now, the only user is "host_cdrom".
>> >
>> > }
>> > QLIST_FOREACH(child, &bs->children, next) {
>> > if (!bdrv_is_inserted(child->bs)) {
>> > return false;
>> >
>> > 3. Any of its children has no medium. Common use looking through
>> > filters, which have a single child.
>> >
>> > }
>> > }
>> > return true;
>> > }
>> >
>> > Makes sense.
>> >
>> > Now look at the uses of QERR_DEVICE_HAS_NO_MEDIUM.
>> >
>> > * external_snapshot_prepare() in blockdev.c:
>> >
>> > if (!bdrv_is_inserted(state->old_bs)) {
>> > error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
>> > goto out;
>> > }
>> >
>> > where @device is the device name, i.e. BlockdevSnapshot member @node
>> > or BlockdevSnapshotSync member @device. Uh-oh: the latter can be
>> > null. If we can reach the error_setg() then, we crash on some
>> > systems.
>
> Sounds like we should write a test case and then fix it.
>
>> > * bdrv_snapshot_delete() and bdrv_snapshot_load_tmp() in
>> > block/snaphot.c:
>> >
>> > if (!drv) {
>> > error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM,
>> > bdrv_get_device_name(bs));
>> > return -ENOMEDIUM;
>> > }
>> >
>> > where @drv is bs->drv.
>> >
>> > Why do we check only for 1. here instead of calling
>> > bdrv_is_inserted()?
>
> I guess we could philosophise about the theoretically right thing to do,
> but last time I checked, host_cdrom didn't support snapshots, so it
> probably doesn't matter either way.
We could also philosophize about "any of its children has no medium".
As far as I know, nothing stops me from using a host_cdrom as a backing
file for a QCOW2, and that I *can* snapshot.
Functions (and methods) bdrv_is_inserted(), bdrv_eject(), and
bdrv_lock_medium() are related. block_int.h groups them under
/* removable device specific */, and block.c under /* removable device
support */. But only bdrv_is_inserted() recurses into children. Is
this how it should be?