lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <Pine.LNX.4.44L0.1409161046380.1166-100000@iolanthe.rowland.org>
Date:	Tue, 16 Sep 2014 11:32:14 -0400 (EDT)
From:	Alan Stern <stern@...land.harvard.edu>
To:	Petr Mládek <pmladek@...e.cz>
cc:	Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
	Tejun Heo <tj@...nel.org>,
	Joe Lawrence <joe.lawrence@...atus.com>,
	Jiri Kosina <jkosina@...e.cz>,
	USB list <linux-usb@...r.kernel.org>,
	Kernel development list <linux-kernel@...r.kernel.org>
Subject: Re: [PATCH 1/4] usb: hub: convert khubd into workqueue

On Tue, 16 Sep 2014, Petr [iso-8859-1] Mládek wrote:

> Anyway, the solution for the race between kick_hub_wq() and
> hub_event() might be to get the reference already in kick_hub_wq().

Yes, this probably would work.

> I mean something like:
> 
> static void kick_hub_wq(struct usb_hub *hub)
> {
> 	if (hub->disconnected || work_pending(&hub->events))
> 		return;
> 	/*
> 	 * Suppress autosuspend until the event is proceed.
> 	 *
> 	 * Be careful and make sure that the symmetric operation is
> 	 * always called. We are here only when there is no pending
> 	 * work for this hub. Therefore put the interface either when
> 	 * the new work is called or when it is canceled.
> 	 */
> 	usb_autopm_get_interface_no_resume(to_usb_interface(hub->intfdev));
> 	kref_get(&hub->kref);
> 
> 	if (queue_work(hub_wq, &hub->events))
> 		return;
> 
> 	/* the work could not be scheduled twice */
> 	kref_put(&hub->kref, hub_release);
> 	usb_autopm_put_interface_no_suspend(intf);

This should be usb_autopm_put_interface_async, not *_no_suspend,
because you don't know at this point whether the runtime PM usage
counter is > 1.  (You do know it was > 1 at the time queue_work was 
called, but it may have changed since then.)

> }
> 
> And test for hub->disconnected at the very beginning of hub_event().

No, that's no good.  The value isn't fully meaningful unless you are 
holding the device lock.  That's why the test for hub->disconnected is 
placed where it is in hub_events.

> Also we would need to put the reference when the work is canceled in
> hub_disconnect().

You can't cancel the work in hub_disconnect.  That's because cancelling
a work item is always synchronous -- there's no cancel_work, only
cancel_work_sync.

This is okay; removing items from the hub_event_list was only a minor 
optimization anyway.  There's no harm in letting the work item go ahead 
and run.

> Hmm, I am not 100% sure if we could call
> usb_autopm_get_interface_no_resume() without any lock here.
> I guess so because otherwise the original code would not work.
> The check for "hub->disconnected" would fail if the struct was freed
> before the lock was taken.

The caller of kick_khubd has to guarantee that the hub structure hasn't 
been deallocated.

> It looks promissing. hub->intfdev is released together with "hub" in
> hub_release(). Also it seems that kick_* and *disconnect functions
> are called with some top level lock. For example, there is used dev
> lock in drivers/usb/core/device.c.

There's one more improvement you could make.  It's not necessary to
call usb_get_dev and usb_put_dev every time hub_events runs.  
Instead, we can call usb_get_dev once when the hub structure is created 
and usb_put_dev in hub_release.

> > But you ignored what the comment says about "don't let it be added 
> > again".
> 
> If we increase the reference in kick_hub_wq() and test
> hub->disconnected at the very beginning of hub_event() it
> should not cause real problem. In the worst case, it will release
> struct usb_hub there instead of in hub_disconnect(). It already happens
> with the original code in some circumstances.
> 
> If you think that this is too tricky, I will put the lock back.

It's probably okay without the lock.  Please post an updated patch 
(just the first one in the series; the later ones will remain the same) 
with the changes discussed here so I can review it.

Or better yet, rearrange the patch series.  Make the first patch be the 
one that removes the useless loop in hub_events.  That patch will be 
acceptable in any case, regardless of what happens with the workqueue 
change.  Then the second patch can be the conversion to a workqueue.

Alan Stern

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists