From: Max Reitz <mreitz@redhat.com>
To: Kevin Wolf <kwolf@redhat.com>
Cc: John Snow <jsnow@redhat.com>,
qemu-devel@nongnu.org, Stefan Hajnoczi <stefanha@redhat.com>,
Markus Armbruster <armbru@redhat.com>
Subject: Re: [Qemu-devel] [PATCH v2 03/37] hw/block/fdc: Implement tray status
Date: Mon, 16 Mar 2015 09:36:51 -0400 [thread overview]
Message-ID: <5506DC73.5050207@redhat.com> (raw)
In-Reply-To: <20150305101145.GA5427@noname.redhat.com>
On 2015-03-05 at 05:11, Kevin Wolf wrote:
> Am 04.03.2015 um 23:06 hat Max Reitz geschrieben:
>> On 2015-03-04 at 09:00, Kevin Wolf wrote:
>>> Am 09.02.2015 um 18:11 hat Max Reitz geschrieben:
>>>> The tray of an FDD is open iff there is no medium inserted (there are
>>>> only two states for an FDD: "medium inserted" or "no medium inserted").
>>>>
>>>> This results in the tray being reported as open if qemu has been started
>>>> with the default floppy drive, which breaks some tests. Fix them.
>>>>
>>>> Signed-off-by: Max Reitz <mreitz@redhat.com>
>>>> ---
>>>> hw/block/fdc.c | 20 +++++++++++++---
>>>> tests/fdc-test.c | 4 +---
>>>> tests/qemu-iotests/067.out | 60 +++++++---------------------------------------
>>>> tests/qemu-iotests/071.out | 2 --
>>>> tests/qemu-iotests/081.out | 1 -
>>>> tests/qemu-iotests/087.out | 6 -----
>>>> 6 files changed, 26 insertions(+), 67 deletions(-)
>>>>
>>>> diff --git a/hw/block/fdc.c b/hw/block/fdc.c
>>>> index 2bf87c9..0c5a6b4 100644
>>>> --- a/hw/block/fdc.c
>>>> +++ b/hw/block/fdc.c
>>>> @@ -192,6 +192,8 @@ typedef struct FDrive {
>>>> uint8_t ro; /* Is read-only */
>>>> uint8_t media_changed; /* Is media changed */
>>>> uint8_t media_rate; /* Data rate of medium */
>>>> +
>>>> + bool media_inserted; /* Is there a medium in the tray */
>>>> } FDrive;
>>>> static void fd_init(FDrive *drv)
>>>> @@ -261,7 +263,7 @@ static int fd_seek(FDrive *drv, uint8_t head, uint8_t track, uint8_t sect,
>>>> #endif
>>>> drv->head = head;
>>>> if (drv->track != track) {
>>>> - if (drv->blk != NULL && blk_is_inserted(drv->blk)) {
>>>> + if (drv->media_inserted) {
>>> I suspect that with the removal of blk_is_inserted() in several places,
>>> floppy passthrough (host_floppy block driver) is now even more broken
>>> than before, potentially not noticing removal of a medium any more.
>>>
>>> While checking this, I noticed that since commit 21fcf360,
>>> bdrv_media_changed() is completely unused. Media change has therefore
>>> probably been broken since at least May 2012.
>>>
>>> Considering this, it might actually be reasonable enough to remove the
>>> block driver. It's definitely better than having it there, but not
>>> working any better than host_device.
>>>
>>> Of course, alternatively you would also be welcome to fix the device
>>> model and reintroduce bdrv_media_changed() and blk_is_inserted() calls
>>> where necessary.
>> Status:
>>
>> I thought about why I need this tray status at all. The result is:
>> We need it because otherwise blockdev-close-tray doesn't do anything
>> on floppy disk drives (you'd insert a medium with
>> blockdev-insert-medium and the tray would immediately be reported as
>> being closed, without any TRAY_MOVED event). So we do need it.
>>
>> I tested floppy passthrough in a VM and it's horror, as can be
>> expected. For instance, one cannot start qemu with floppy
>> passthrough if the host drive is empty (which is actually helpful).
>>
>> So what I'll be doing is set media_inserted to load && drv->blk in
>> the media change CB and set it to true in the floppy drive
>> initialization code if there is a BB and blk_is_inserted() is true.
>> The tray will be considered closed if media_inserted &&
>> blk_is_inserted().
>>
>> So why do I check blk_is_inserted() in the initialization code? If
>> we just set media_inserted to true, that would be wrong. Imagine an
>> empty drive (no BDS tree), media_inserted will be set to true, then
>> you inserted a BDS tree (blockdev-insert-medium) and the tray will
>> be considered closed without you having executed blockdev-close-tray
>> (media_inserted is true, and now blk_is_inserted() is true as well).
>>
>> So I have to check whether there's a BDS tree in the initialization
>> code, if there isn't, media_inserted must be false. Why am I not
>> using blk_bs() for that? I tried to explain for the USB patch:
>> blk_bs() returns a BDS, and that's something for the block layer,
>> nobody else should care about that.
> This is silly, Max.
>
> Correctness isn't defined by what you _should_ care about, but by what
> you actually _need_ to know. This is where you need to start your
> considerations, not with what you think you're supposed to be asking.
>
> If the two contradict, then there are two options: Either the assumption
> that you shouldn't care is wrong, or your decision that you need the
> information is. This conflict needs to be resolved rather than just
> working with the answer to a different question.
>
> In this case, I think the problem starts with "empty drive (no BDS
> tree)".
I meant "Imagine an empty drive without a BDS tree" or "Imagine a drive
without a BDS tree, thus empty.", so rather "an empty drive, e.g. no BDS
tree" than "an empty drive, i.e. no BDS tree".
> This is not correct, an empty drive is defined by
> !blk_is_inserted(bs) and not by an empty BDS tree. The passthrough case
> (with a hypothetical correct implementation) helps you distinguish the
> two. So your assumption that you really need to check whether there is
> no BDS tree is wrong here. You need to check whether there is a medium,
> and that is blk_is_inserted(). (So yes, I agree with your conclusion,
> but not with the way you got there.)
So what I was justifying is that blk_bs() will work, not that
blk_is_inserted() will not work. So why do I think that
blk_is_inserted() is not really what we want here?
Okay, so imagine the case where !!blk_bs() != blk_is_inserted() at
startup. That means, the host drive is empty. Now we insert a medium in
the host drive. Floppy being floppy, qemu won't have any idea that a
medium has been inserted. This means that media_inserted will still be
false and any read to the BB will be stopped in the device model, so
qemu will not have a chance of noticing there is a medium now (it only
has if the host floppy BDS is accessed).
Thus, using blk_is_inserted() without a medium at startup will not allow
the guest to ever read from the disk, unless you manually execute
blockdev-close-tray over QMP (I'm not even sure whether that works, but
I guess it might).
> In the USB case, the problem was that a bdrv_*() function is called
> (which already violates the rule that this is not for outside the block
> layer) and a NULL check is needed there. In that case the assumption
> that calling blk_bs() isn't allowed is wrong; it's simply necessary for
> calling bdrv_*() functions.
>
> In any case "I want to know A, but I'm not supposed to ask for A, so
> I'll just check B" is not the way to go.
Except for when A and B are functionally equivalent.
>> How could blk_is_inserted() be wrong here, if blk_bs() is the thing
>> that will work? Correct, if blk_bs() && !bdrv_is_inserted(blk_bs()).
>> However, this will never be the case, because as said above, qemu
>> actually cannot start with a host floppy drive without a medium, so
>> !!blk_is_inserted(blk) == !!blk_bs(blk).
> You called it "horror" above and now you want to rely on it?
I said: It's horror, but it "is actually helpful". And this is what I
meant by it.
> The good thing is that I suspect that blk_bs() does _not_ work and
> blk_is_inserted() is what you really needed in the first place.
>
>> I see the question popping up "Why don't you just add a bool
>> has_bs(BB) { return blk_bs(BB); } and then not add that test to
>> blk_is_inserted()"? I've asked that myself. Answer: Again, anything
>> outside of the block layer should not care about things like BDS
>> trees. But moreover, bdrv_is_inserted() does not only check whether
>> all the host devices represented by BDSs are inserted, but also
>> whether BDS.drv != NULL, which until this series was the sign for an
>> empty drive. Therefore, checking blk_is_inserted() is the logical
>> conclusion of bdrv_is_inserted() (bdrv_is_inserted() tests whether
>> BDS.drv != NULL, blk_is_inserted() tests whether BLK.bs != NULL).
>>
>> But medium management is now done on the BB level, so a separate
>> function for checking whether there's a BDS tree (because that
>> should be equivalent to "whether there's a medium") seems to have
>> its merits. However, I don't think so. blk_is_inserted() is exactly
>> that function: It's true if there is a BDS tree and, if there is
>> host passthrough, whether all the media are inserted, which is
>> correct.
> No, no, no, no, no.
>
> Stop talking about implementation details, talk about concepts. The only
> valid reason for calling blk_is_inserted() is that you want to know
> whether a medium is inserted. If this is what you want to know, call it.
> And if it isn't, be sure not to call it.
Maybe. I hate host passthrough, and floppy is the worst incarnation of
it. What does this have to do with anything? See my reasoning above why
blk_is_inserted() is actually sometimes not what we want to use.
> Whether it has a NULL check here or a BDS tree there doesn't matter at
> all. You can't just call a function because it happens to have the right
> side effects if it was never meant for the purpose you're using it.
The problem is that blk_is_inserted() was meant for the purpose I'm
using it for, as you yourself said, but it just breaks with floppy
passthrough because we have to make the guest access the BDS tree even
if there is no medium there.
> For our specific case: blk->bs == NULL implies an empty drive, but
> that's just an implication, not an equivalence. The other direction
> isn't true. That's why it's important to distinguish the cases.
>
>> In theory, guest models should not have to distinguish whether a BB
>> does not have a medium because there is no BDS tree or because we're
>> using passthrough and that BDS does not have a medium. So why does
>> floppy have to distinguish? Because it does not have a real tray,
>> but that's the model we have to be working with. Inserting a medium
>> into a passed-through host drive must result in the tray being
>> considered closed immediately; inserting a medium into a guest
>> device through blockdev-insert-medium must not.
> That's the job of the block layer, not of the floppy emulation.
So do you want to fix the floppy passthrough code? I don't even know how
to fix it. I don't even know what's wrong with it, other than that
something's ought to be wrong.
>
> It's actually not much different from CD-ROM passthrough, where you do
> have a tray on both the guest and the host. Loading the new medium and
> closing the tray will have to be a single action there, because real
> CD-ROMs just don't report whether there is a medium in their open tray.
>
> Kevin
So, what I'm taking from this is the following: media_inserted is a kind
of strong attribute. If it is false, no accesses to the BB will be
generated whatsoever, and thus the host drive status will not be
updated. So we need to make sure it's only false if we really don't care
about the BB or the BDS tree; and that's only if there is no BDS tree at
all.
Because I understand your reasoning on "don't use B if A gives you what
you really want, and B just happens to behave the same here", I will be
using blk_bs() here, too, instead of blk_is_inserted(), unless you don't
find my reasoning correct, and although I'm still very much against
using blk_bs() somewhere like here. I will be able to live with it here,
just because it's FDD emulation and adding a drive status to it is kind
of kaput in itself.
Max
next prev parent reply other threads:[~2015-03-16 13:36 UTC|newest]
Thread overview: 80+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-02-09 17:11 [Qemu-devel] [PATCH v2 00/37] blockdev: BlockBackend and media Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 01/37] blockdev: Allow creation of BDS trees without BB Max Reitz
2015-02-09 18:17 ` Eric Blake
2015-02-09 18:29 ` Max Reitz
2015-03-04 13:39 ` Kevin Wolf
2015-03-04 14:04 ` Max Reitz
2015-03-04 14:15 ` Kevin Wolf
2015-03-04 14:23 ` Max Reitz
2015-03-04 21:44 ` Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 02/37] iotests: Only create BB if necessary Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 03/37] hw/block/fdc: Implement tray status Max Reitz
2015-02-09 18:23 ` Eric Blake
2015-03-04 14:00 ` Kevin Wolf
2015-03-04 14:07 ` Max Reitz
2015-03-04 22:06 ` Max Reitz
2015-03-05 10:11 ` Kevin Wolf
2015-03-16 13:36 ` Max Reitz [this message]
2015-03-16 15:47 ` Markus Armbruster
2015-03-16 15:48 ` Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 04/37] hw/usb-storage: Check whether BB is inserted Max Reitz
2015-03-04 14:02 ` Kevin Wolf
2015-03-04 14:07 ` Max Reitz
2015-03-04 14:20 ` Kevin Wolf
2015-03-04 14:24 ` Max Reitz
2015-03-04 14:39 ` Kevin Wolf
2015-03-04 14:41 ` Max Reitz
2015-03-04 14:52 ` Max Reitz
2015-03-04 14:53 ` Kevin Wolf
2015-03-04 14:58 ` Max Reitz
2015-03-04 22:06 ` Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 05/37] block: Fix BB AIOCB AioContext without BDS Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 06/37] block: Make bdrv_is_inserted() return a bool Max Reitz
2015-02-09 18:29 ` Eric Blake
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 07/37] block: Add blk_is_available() Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 08/37] block: Make bdrv_is_inserted() recursive Max Reitz
2015-02-09 19:16 ` Eric Blake
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 09/37] block/quorum: Implement bdrv_is_inserted() Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 10/37] block: Move guest_block_size into BlockBackend Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 11/37] block: Remove wr_highest_sector from BlockAcctStats Max Reitz
2015-02-09 19:20 ` Eric Blake
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 12/37] block: Move BlockAcctStats into BlockBackend Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 13/37] block: Move I/O status and error actions into BB Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 14/37] block: Add BlockBackendRootState Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 15/37] block: Make some BB functions fall back to BBRS Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 16/37] block: Fail requests to empty BlockBackend Max Reitz
2015-02-25 18:18 ` Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 17/37] block: Prepare remaining BB functions for NULL BDS Max Reitz
2015-02-09 20:47 ` Eric Blake
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 18/37] blockdev: Use BB for blockdev-backup transaction Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 19/37] block: Add blk_insert_bs() Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 20/37] block: Prepare for NULL BDS Max Reitz
2015-02-09 21:21 ` Eric Blake
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 21/37] blockdev: Do not create BDS for empty drive Max Reitz
2015-02-09 21:32 ` Eric Blake
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 22/37] blockdev: Pull out blockdev option extraction Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 23/37] blockdev: Allow more options for BB-less BDS tree Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 24/37] block: Add blk_remove_bs() Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 25/37] blockdev: Add blockdev-open-tray Max Reitz
2015-02-09 22:01 ` Eric Blake
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 26/37] blockdev: Add blockdev-close-tray Max Reitz
2015-02-09 22:18 ` Eric Blake
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 27/37] blockdev: Add blockdev-remove-medium Max Reitz
2015-02-09 22:21 ` Eric Blake
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 28/37] blockdev: Add blockdev-insert-medium Max Reitz
2015-02-09 22:23 ` Eric Blake
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 29/37] blockdev: Implement eject with basic operations Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 30/37] blockdev: Implement change " Max Reitz
2015-02-09 22:28 ` Eric Blake
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 31/37] block: Inquire tray state before tray-moved events Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 32/37] qmp: Introduce blockdev-change-medium Max Reitz
2015-02-09 23:09 ` Eric Blake
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 33/37] hmp: Use blockdev-change-medium for change command Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 34/37] blockdev: read-only-mode for blockdev-change-medium Max Reitz
2015-02-09 23:15 ` Eric Blake
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 35/37] hmp: Add read-only-mode option to change command Max Reitz
2015-02-09 23:17 ` Eric Blake
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 36/37] iotests: More options for VM.add_drive() Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 37/37] iotests: Add test for change-related QMP commands Max Reitz
2015-02-10 0:06 ` Eric Blake
2015-02-10 20:37 ` Max Reitz
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=5506DC73.5050207@redhat.com \
--to=mreitz@redhat.com \
--cc=armbru@redhat.com \
--cc=jsnow@redhat.com \
--cc=kwolf@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=stefanha@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).