Re: [PATCH] usb: gadget: f_mass_storage: break IO operations via configfs

From: Maxim Devaev
Date: Wed Apr 06 2022 - 14:54:21 EST


В Wed, 6 Apr 2022 13:51:40 -0400
Alan Stern <stern@xxxxxxxxxxxxxxxxxxx> wrote:

> On Wed, Apr 06, 2022 at 07:52:34PM +0300, Maxim Devaev wrote:
> > > It's not clear to me how breaking I/O operations allows you to do a
> > > "force eject". It seems that what you would need is something like
> > > fsg_store_file() that omits the curlun->prevent_medium_removal check.
> > > Interrupting a lengthy I/O operation doesn't really have anything to do
> > > with this.
> >
> > Perhaps I chose the wrong path, it's just how my userspace code works now.
> > If the drive is connected to a Linux host, then in order to clear
> > the "file" and extract the image, I sent a SIGUSR1 signal to the "file-storage"
> > thread. This interrupted long IO operations, reset curlun->prevent_medium_removal
> > and I got the ability to extract.
>
> Oh, I see. That's kind of an unintended side effect of not calling
> raise_exception().
>
> And while it does interrupt long I/O operations, it does so in
> non-sanctioned way. To the host it will appear as though the gadget's
> firmware has crashed, since the gadget will stop sending or receiving
> data. Eventually the host will time out and reset the gadget.
>
> Maybe that's the sort of thing you want, but I rather doubt it.

It's hard to say how it actually should work in case of force removing.
At least the currect approach with SIGUSR1 is really working on thousands
systems and with Linux, Mac and Windows. I believe that the criterion
of the experiment is quite important here. I know of several other utilities
that use SIGUSR1 for similar purposes.

> > Will masking the curlun->prevent_medium_removal flag be enough?
>
> I think so. But it will be blocked to some extent by long-running I/O
> operations, because those operations acquire the filesem rw-semaphore
> for reading.
>
> More precisely, each individual command holds the rw-semaphore. But the
> semaphore is dropped between commands, and a long-running I/O operation
> typically consists of many separate commands. So the blocking may be
> acceptable.

It is very important for KVM-over-IP to be able to command "turn it off immediately".
In this context, I would prefer "break_io" rather than "allow_force_remove".

> > > You should not call send_sig_info() directly; instead call
> > > raise_exception(). It already does the work you need (including some
> > > things you left out).
> >
> > raise_exception() assumes the setting of a new state, and I did not want to do this,
> > since the same does not happen when throwing a signal from userspace.
>
> Userspace isn't supposed to send the USR1 signal, only the INT, TERM, or
> KILL signals. USR1 is supposed to be reserved for the driver's internal
> use. Unfortunately, AFAIK there's no way to allow the driver to send a
> signal to itself without also allowing the signal to be sent by
> userspace. :-(

It's funny that you actually helped me solve my problem thanks to this undocumented
behavior. If it were not for the ability to send a signal, I would not be able to make
the necessary code, and my software would always be waiting for the completion of IO.

So here I am grateful to you - I didn't have to patch the kernel a few years ago,
and now I just want to turn it into a clear feature :)

Given the needs of the userspace code, maybe the suggested "break_io"
would be the best choice?

> And sending the signal _does_ set a new state, whether you intended to
> or not. Although in this case, the new state is always the same as the
> old state, i.e., FSG_STATE_NORMAL.

So I could call raise_exception(fsg->common, FSG_STATE_NORMAL) instead of sending
the signal from break_io handler. There will be a slight difference
in exception_req_tag and exception_arg, but it does not seem to cause any side effects.
Please correct me if I'm wrong.