diff mbox

[6/8] block: add eject request callback

Message ID 1319540020-32484-7-git-send-email-pbonzini@redhat.com
State New
Headers show

Commit Message

Paolo Bonzini Oct. 25, 2011, 10:53 a.m. UTC
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 block.c    |    7 +++++++
 block.h    |    7 +++++++
 blockdev.c |    8 +++++---
 3 files changed, 19 insertions(+), 3 deletions(-)

Comments

Kevin Wolf Oct. 28, 2011, 5:21 p.m. UTC | #1
Am 25.10.2011 12:53, schrieb Paolo Bonzini:
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  block.c    |    7 +++++++
>  block.h    |    7 +++++++
>  blockdev.c |    8 +++++---
>  3 files changed, 19 insertions(+), 3 deletions(-)
> 
> diff --git a/block.c b/block.c
> index 9873b57..53e21ba 100644
> --- a/block.c
> +++ b/block.c
> @@ -821,6 +821,13 @@ bool bdrv_dev_has_removable_media(BlockDriverState *bs)
>      return !bs->dev || (bs->dev_ops && bs->dev_ops->change_media_cb);
>  }
>  
> +void bdrv_dev_eject_request(BlockDriverState *bs, bool force)
> +{
> +    if (bs->dev_ops && bs->dev_ops->eject_request_cb) {
> +        bs->dev_ops->eject_request_cb(bs->dev_opaque, force);
> +    }
> +}
> +
>  bool bdrv_dev_is_tray_open(BlockDriverState *bs)
>  {
>      if (bs->dev_ops && bs->dev_ops->is_tray_open) {
> diff --git a/block.h b/block.h
> index e77988e..d3c3d62 100644
> --- a/block.h
> +++ b/block.h
> @@ -39,6 +39,12 @@ typedef struct BlockDevOps {
>       */
>      void (*change_media_cb)(void *opaque, bool load);
>      /*
> +     * Runs when an eject request is issued from the monitor, the tray
> +     * is closed, and the medium is locked.
> +     * Device models with removable media must implement this callback.
> +     */
> +    void (*eject_request_cb)(void *opaque, bool force);
> +    /*
>       * Is the virtual tray open?
>       * Device models implement this only when the device has a tray.
>       */
> @@ -116,6 +122,7 @@ void bdrv_detach_dev(BlockDriverState *bs, void *dev);
>  void *bdrv_get_attached_dev(BlockDriverState *bs);
>  void bdrv_set_dev_ops(BlockDriverState *bs, const BlockDevOps *ops,
>                        void *opaque);
> +void bdrv_dev_eject_request(BlockDriverState *bs, bool force);
>  bool bdrv_dev_has_removable_media(BlockDriverState *bs);
>  bool bdrv_dev_is_tray_open(BlockDriverState *bs);
>  bool bdrv_dev_is_medium_locked(BlockDriverState *bs);
> diff --git a/blockdev.c b/blockdev.c
> index 0827bf7..4cf333a 100644
> --- a/blockdev.c
> +++ b/blockdev.c
> @@ -635,9 +635,11 @@ static int eject_device(Monitor *mon, BlockDriverState *bs, int force)
>          qerror_report(QERR_DEVICE_NOT_REMOVABLE, bdrv_get_device_name(bs));
>          return -1;
>      }
> -    if (!force && !bdrv_dev_is_tray_open(bs)
> -        && bdrv_dev_is_medium_locked(bs)) {
> -        qerror_report(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs));
> +    if (bdrv_dev_is_medium_locked(bs) && !bdrv_dev_is_tray_open(bs)) {
> +        bdrv_dev_eject_request(bs, force);
> +        if (!force) {
> +            qerror_report(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs));
> +        }
>          return -1;
>      }
>      bdrv_close(bs);

Now force doesn't force any more. It avoids the error message, but
doesn't forcefully close the BlockDriverState any more. Intentional? If
so, why is it a good idea?

Kevin
Paolo Bonzini Oct. 29, 2011, 7:46 a.m. UTC | #2
On 10/28/2011 07:21 PM, Kevin Wolf wrote:
>> >  -    if (!force&&  !bdrv_dev_is_tray_open(bs)
>> >  -&&  bdrv_dev_is_medium_locked(bs)) {
>> >  -        qerror_report(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs));
>> >  +    if (bdrv_dev_is_medium_locked(bs)&&  !bdrv_dev_is_tray_open(bs)) {
>> >  +        bdrv_dev_eject_request(bs, force);
>> >  +        if (!force) {
>> >  +            qerror_report(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs));
>> >  +        }
>> >            return -1;
>> >        }
>> >        bdrv_close(bs);
> Now force doesn't force any more. It avoids the error message, but
> doesn't forcefully close the BlockDriverState any more. Intentional? If
> so, why is it a good idea?

In theory the guest OS should eject the disk itself.  However, force 
does unlock the disk so that: 1) two ejects will have the desired 
effect; 2) force eject followed by change will work even with the tray 
locked, unlike before this series.

Paolo
Markus Armbruster Nov. 7, 2011, 1:21 p.m. UTC | #3
I apologize for the lateness of this review.

Paolo Bonzini <pbonzini@redhat.com> writes:

> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

The commit message should explain why we need this callback.  The cover
letter says "support for eject requests is required by udev 173."
Please elaborate on that.

> ---
>  block.c    |    7 +++++++
>  block.h    |    7 +++++++
>  blockdev.c |    8 +++++---
>  3 files changed, 19 insertions(+), 3 deletions(-)
>
> diff --git a/block.c b/block.c
> index 9873b57..53e21ba 100644
> --- a/block.c
> +++ b/block.c
> @@ -821,6 +821,13 @@ bool bdrv_dev_has_removable_media(BlockDriverState *bs)
>      return !bs->dev || (bs->dev_ops && bs->dev_ops->change_media_cb);
>  }
>  
> +void bdrv_dev_eject_request(BlockDriverState *bs, bool force)
> +{
> +    if (bs->dev_ops && bs->dev_ops->eject_request_cb) {
> +        bs->dev_ops->eject_request_cb(bs->dev_opaque, force);
> +    }
> +}
> +
>  bool bdrv_dev_is_tray_open(BlockDriverState *bs)
>  {
>      if (bs->dev_ops && bs->dev_ops->is_tray_open) {
> diff --git a/block.h b/block.h
> index e77988e..d3c3d62 100644
> --- a/block.h
> +++ b/block.h
> @@ -39,6 +39,12 @@ typedef struct BlockDevOps {
>       */
>      void (*change_media_cb)(void *opaque, bool load);
>      /*
> +     * Runs when an eject request is issued from the monitor, the tray
> +     * is closed, and the medium is locked.
> +     * Device models with removable media must implement this callback.
> +     */
> +    void (*eject_request_cb)(void *opaque, bool force);
> +    /*

You implement it for IDE in PATCH 7/8 and SCSI in PATCH 8/8.  You don't
implement it for floppy, despite the comment.  That's okay; floppy has
no use for it.  It's the comment that needs fixing.  Devices that
implement is_medium_locked() must implement this one as well.

>       * Is the virtual tray open?
>       * Device models implement this only when the device has a tray.
>       */
> @@ -116,6 +122,7 @@ void bdrv_detach_dev(BlockDriverState *bs, void *dev);
>  void *bdrv_get_attached_dev(BlockDriverState *bs);
>  void bdrv_set_dev_ops(BlockDriverState *bs, const BlockDevOps *ops,
>                        void *opaque);
> +void bdrv_dev_eject_request(BlockDriverState *bs, bool force);
>  bool bdrv_dev_has_removable_media(BlockDriverState *bs);
>  bool bdrv_dev_is_tray_open(BlockDriverState *bs);
>  bool bdrv_dev_is_medium_locked(BlockDriverState *bs);
> diff --git a/blockdev.c b/blockdev.c
> index 0827bf7..4cf333a 100644
> --- a/blockdev.c
> +++ b/blockdev.c
> @@ -635,9 +635,11 @@ static int eject_device(Monitor *mon, BlockDriverState *bs, int force)
>          qerror_report(QERR_DEVICE_NOT_REMOVABLE, bdrv_get_device_name(bs));
>          return -1;
>      }
> -    if (!force && !bdrv_dev_is_tray_open(bs)
> -        && bdrv_dev_is_medium_locked(bs)) {
> -        qerror_report(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs));
> +    if (bdrv_dev_is_medium_locked(bs) && !bdrv_dev_is_tray_open(bs)) {
> +        bdrv_dev_eject_request(bs, force);
> +        if (!force) {
> +            qerror_report(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs));
> +        }
>          return -1;
>      }
>      bdrv_close(bs);

Like Kevin, I'm not entirely comfortable with changing the meaning of
"-f".

Here's my mental model of monitor command eject:

1. eject without -f behaves like the physical tray button.  It has
immediate effect, unless the tray is locked closed.  Then, the drive
just notifies the OS of the button push, so the OS can react to it.  The
latter isn't implemented in QEMU.

2. eject with -f behaves like whatever physical way there is to pry the
tray open, locked or not.  CD-ROM drives commonly have a little button
hidden in some hope you can reach with a bent paperclip.

Could you explain your mental model?
Paolo Bonzini Nov. 7, 2011, 1:36 p.m. UTC | #4
On 11/07/2011 02:21 PM, Markus Armbruster wrote:
> The commit message should explain why we need this callback.  The cover
> letter says "support for eject requests is required by udev 173."
> Please elaborate on that.

Well, first and foremost eject requests are in the spec.  :)  The fact 
that recent guests need it is more a justification for pulling this in 1.0.

> You implement it for IDE in PATCH 7/8 and SCSI in PATCH 8/8.  You don't
> implement it for floppy, despite the comment.  That's okay; floppy has
> no use for it.  It's the comment that needs fixing.  Devices that
> implement is_medium_locked() must implement this one as well.

Right.

> 1. eject without -f behaves like the physical tray button.  It has
> immediate effect, unless the tray is locked closed.  Then, the drive
> just notifies the OS of the button push, so the OS can react to it.  The
> latter isn't implemented in QEMU.
>
> 2. eject with -f behaves like whatever physical way there is to pry the
> tray open, locked or not.  CD-ROM drives commonly have a little button
> hidden in some hope you can reach with a bent paperclip.
>
> Could you explain your mental model?

1. eject without -f is as you mentioned.

2. eject with -f should really never be needed, but it does whatever is 
needed to be able to follow up with a "change" command.  It turns out it 
is really "unlock" and "ask the guest to eject" combined, but that's the 
implementation, not the model.

The difference from the paperclip model is that it gives a chance for 
the OS to clean up and eject safely.  It wouldn't be hard to convince me 
otherwise though, especially if it can help getting the patch in 1.0. 
The "eject -f"+"change" can be replaced by "eject", possibly followed by 
"eject -f" after a timeout, and then followed again by "change".

Paolo
Kevin Wolf Nov. 7, 2011, 1:49 p.m. UTC | #5
Am 07.11.2011 14:36, schrieb Paolo Bonzini:
> On 11/07/2011 02:21 PM, Markus Armbruster wrote:
>> The commit message should explain why we need this callback.  The cover
>> letter says "support for eject requests is required by udev 173."
>> Please elaborate on that.
> 
> Well, first and foremost eject requests are in the spec.  :)  The fact 
> that recent guests need it is more a justification for pulling this in 1.0.
> 
>> You implement it for IDE in PATCH 7/8 and SCSI in PATCH 8/8.  You don't
>> implement it for floppy, despite the comment.  That's okay; floppy has
>> no use for it.  It's the comment that needs fixing.  Devices that
>> implement is_medium_locked() must implement this one as well.
> 
> Right.
> 
>> 1. eject without -f behaves like the physical tray button.  It has
>> immediate effect, unless the tray is locked closed.  Then, the drive
>> just notifies the OS of the button push, so the OS can react to it.  The
>> latter isn't implemented in QEMU.
>>
>> 2. eject with -f behaves like whatever physical way there is to pry the
>> tray open, locked or not.  CD-ROM drives commonly have a little button
>> hidden in some hope you can reach with a bent paperclip.
>>
>> Could you explain your mental model?
> 
> 1. eject without -f is as you mentioned.
> 
> 2. eject with -f should really never be needed, but it does whatever is 
> needed to be able to follow up with a "change" command.  It turns out it 
> is really "unlock" and "ask the guest to eject" combined, but that's the 
> implementation, not the model.

Does this give different results than just asking the guest to eject
without forcefully unlocking? I would expect that a guest that responds
to the eject request would also unlock the drive. In which case I think
eject without -f should be enough?

> The difference from the paperclip model is that it gives a chance for 
> the OS to clean up and eject safely.  It wouldn't be hard to convince me 
> otherwise though, especially if it can help getting the patch in 1.0. 
> The "eject -f"+"change" can be replaced by "eject", possibly followed by 
> "eject -f" after a timeout, and then followed again by "change".

Kevin
Paolo Bonzini Nov. 7, 2011, 1:56 p.m. UTC | #6
On 11/07/2011 02:49 PM, Kevin Wolf wrote:
> >  2. eject with -f should really never be needed, but it does whatever is
> >  needed to be able to follow up with a "change" command.  It turns out it
> >  is really "unlock" and "ask the guest to eject" combined, but that's the
> >  implementation, not the model.
>
> Does this give different results than just asking the guest to eject
> without forcefully unlocking? I would expect that a guest that responds
> to the eject request would also unlock the drive. In which case I think
> eject without -f should be enough?

Only if the guest is not buggy (e.g. locks the tray but stops polling 
for eject requests) and has not crashed.

Paolo
Kevin Wolf Nov. 7, 2011, 2:12 p.m. UTC | #7
Am 07.11.2011 14:56, schrieb Paolo Bonzini:
> On 11/07/2011 02:49 PM, Kevin Wolf wrote:
>>>  2. eject with -f should really never be needed, but it does whatever is
>>>  needed to be able to follow up with a "change" command.  It turns out it
>>>  is really "unlock" and "ask the guest to eject" combined, but that's the
>>>  implementation, not the model.
>>
>> Does this give different results than just asking the guest to eject
>> without forcefully unlocking? I would expect that a guest that responds
>> to the eject request would also unlock the drive. In which case I think
>> eject without -f should be enough?
> 
> Only if the guest is not buggy (e.g. locks the tray but stops polling 
> for eject requests) and has not crashed.

If the guest is broken, forcefully unlocking and doing an eject request
won't help either (the drive will be unlocked, but not ejected) and the
only way to do anything useful with the drive is sending another eject
command. This doesn't help with cleanly unmounting the medium, of course.

So I think this is actually a point for the eject -f = paperclip model.

Kevin
Markus Armbruster Nov. 7, 2011, 3:23 p.m. UTC | #8
Paolo Bonzini <pbonzini@redhat.com> writes:

> On 11/07/2011 02:21 PM, Markus Armbruster wrote:
>> The commit message should explain why we need this callback.  The cover
>> letter says "support for eject requests is required by udev 173."
>> Please elaborate on that.
>
> Well, first and foremost eject requests are in the spec.  :)  The fact
> that recent guests need it is more a justification for pulling this in
> 1.0.

I agree we should try to solve the problem for 1.0.

>> You implement it for IDE in PATCH 7/8 and SCSI in PATCH 8/8.  You don't
>> implement it for floppy, despite the comment.  That's okay; floppy has
>> no use for it.  It's the comment that needs fixing.  Devices that
>> implement is_medium_locked() must implement this one as well.
>
> Right.
>
>> 1. eject without -f behaves like the physical tray button.  It has
>> immediate effect, unless the tray is locked closed.  Then, the drive
>> just notifies the OS of the button push, so the OS can react to it.  The
>> latter isn't implemented in QEMU.
>>
>> 2. eject with -f behaves like whatever physical way there is to pry the
>> tray open, locked or not.  CD-ROM drives commonly have a little button
>> hidden in some hope you can reach with a bent paperclip.
>>
>> Could you explain your mental model?
>
> 1. eject without -f is as you mentioned.

Would implementing the missing part help with the problem at hand?

> 2. eject with -f should really never be needed, but it does whatever
> is needed to be able to follow up with a "change" command.  It turns
> out it is really "unlock" and "ask the guest to eject" combined, but
> that's the implementation, not the model.

Physical hardware doesn't work that way (unless I misunderstand it).
Always a warning sign.

> The difference from the paperclip model is that it gives a chance for
> the OS to clean up and eject safely.  It wouldn't be hard to convince
> me otherwise though, especially if it can help getting the patch in
> 1.0. The "eject -f"+"change" can be replaced by "eject", possibly
> followed by "eject -f" after a timeout, and then followed again by
> "change".

On bare metal, the pressing the tray button accomplishes that: the drive
notifies the OS the button was pressed, the well-behaved OS cleans up
and ejects.  With a misbehaving OS, you're reduced to the paperclip.

Can't we replicate that?

1. Tray button / eject without -f

   A. when the tray is not locked: tray opens immediately.

   B. when the tray is locked: OS gets notified.  We expect it to clean
      up, unlock and open the tray at some point in the near future.

2. Paperclip / eject with -f

   Tray opens immediately.  Guest OS may be unhappy about it.
Paolo Bonzini Nov. 7, 2011, 4:14 p.m. UTC | #9
On 11/07/2011 04:23 PM, Markus Armbruster wrote:
>> 1. eject without -f is as you mentioned.
>
> Would implementing the missing part help with the problem at hand?

It would help for non-buggy guests.  Buggy means even "echo -1 > 
/sys/block/sr0/events_poll_msecs".

However, a full solution would require a change in management, and 
adding a TRAY_STATUS_CHANGED event to QEMU.  Not sure this is required 
for 1.0, as it can even be added later to stable.

>> 2. eject with -f should really never be needed, but it does whatever
>> is needed to be able to follow up with a "change" command.  It turns
>> out it is really "unlock" and "ask the guest to eject" combined, but
>> that's the implementation, not the model.
>
> Physical hardware doesn't work that way (unless I misunderstand it).
> Always a warning sign.

True.

>> The difference from the paperclip model is that it gives a chance for
>> the OS to clean up and eject safely.  It wouldn't be hard to convince
>> me otherwise though, especially if it can help getting the patch in
>> 1.0. The "eject -f"+"change" can be replaced by "eject", possibly
>> followed by "eject -f" after a timeout, and then followed again by
>> "change".
>
> On bare metal, the pressing the tray button accomplishes that: the drive
> notifies the OS the button was pressed, the well-behaved OS cleans up
> and ejects.  With a misbehaving OS, you're reduced to the paperclip.
>
> Can't we replicate that?
>
> 1. Tray button / eject without -f
>
>     A. when the tray is not locked: tray opens immediately.
>
>     B. when the tray is locked: OS gets notified.  We expect it to clean
>        up, unlock and open the tray at some point in the near future.
>
> 2. Paperclip / eject with -f
>
>     Tray opens immediately.  Guest OS may be unhappy about it.

I now redid my tests with the paperclip behavior (it's really one line 
of different code) and everything seems to work.  Will submit v2.

Paolo
diff mbox

Patch

diff --git a/block.c b/block.c
index 9873b57..53e21ba 100644
--- a/block.c
+++ b/block.c
@@ -821,6 +821,13 @@  bool bdrv_dev_has_removable_media(BlockDriverState *bs)
     return !bs->dev || (bs->dev_ops && bs->dev_ops->change_media_cb);
 }
 
+void bdrv_dev_eject_request(BlockDriverState *bs, bool force)
+{
+    if (bs->dev_ops && bs->dev_ops->eject_request_cb) {
+        bs->dev_ops->eject_request_cb(bs->dev_opaque, force);
+    }
+}
+
 bool bdrv_dev_is_tray_open(BlockDriverState *bs)
 {
     if (bs->dev_ops && bs->dev_ops->is_tray_open) {
diff --git a/block.h b/block.h
index e77988e..d3c3d62 100644
--- a/block.h
+++ b/block.h
@@ -39,6 +39,12 @@  typedef struct BlockDevOps {
      */
     void (*change_media_cb)(void *opaque, bool load);
     /*
+     * Runs when an eject request is issued from the monitor, the tray
+     * is closed, and the medium is locked.
+     * Device models with removable media must implement this callback.
+     */
+    void (*eject_request_cb)(void *opaque, bool force);
+    /*
      * Is the virtual tray open?
      * Device models implement this only when the device has a tray.
      */
@@ -116,6 +122,7 @@  void bdrv_detach_dev(BlockDriverState *bs, void *dev);
 void *bdrv_get_attached_dev(BlockDriverState *bs);
 void bdrv_set_dev_ops(BlockDriverState *bs, const BlockDevOps *ops,
                       void *opaque);
+void bdrv_dev_eject_request(BlockDriverState *bs, bool force);
 bool bdrv_dev_has_removable_media(BlockDriverState *bs);
 bool bdrv_dev_is_tray_open(BlockDriverState *bs);
 bool bdrv_dev_is_medium_locked(BlockDriverState *bs);
diff --git a/blockdev.c b/blockdev.c
index 0827bf7..4cf333a 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -635,9 +635,11 @@  static int eject_device(Monitor *mon, BlockDriverState *bs, int force)
         qerror_report(QERR_DEVICE_NOT_REMOVABLE, bdrv_get_device_name(bs));
         return -1;
     }
-    if (!force && !bdrv_dev_is_tray_open(bs)
-        && bdrv_dev_is_medium_locked(bs)) {
-        qerror_report(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs));
+    if (bdrv_dev_is_medium_locked(bs) && !bdrv_dev_is_tray_open(bs)) {
+        bdrv_dev_eject_request(bs, force);
+        if (!force) {
+            qerror_report(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs));
+        }
         return -1;
     }
     bdrv_close(bs);