From: Denis Joseph Barrow <D.Barow@option.com>
To: Oliver Neukum <oliver@neukum.org>,
Linux USB kernel mailing list <linux-usb@vger.kernel.org>,
Linux netdev Mailing list <netdev@vger.kernel.org>
Cc: Chris Snook <csnook@redhat.com>,
Paul Hardwick <P.Hardwick@option.com>,
ajb@spheresystems.co.uk, Greg Kroah-Hartman <greg@kroah.com>,
linux-usb@vger.kernel.org, netdev@vger.kernel.org,
Alan Cox <alan@lxorguk.ukuu.org.uk>
Subject: Re: another race in hso
Date: Mon, 12 Jan 2009 14:25:33 +0100 [thread overview]
Message-ID: <496B44CD.5080702@option.com> (raw)
In-Reply-To: <200812221454.57794.oliver@neukum.org>
Hi Oliver,
Correct me if I'm wrong but I probably am as usual but
this patch could be a lot more minimal, 70-80% of the patch seems to be
removing net_lock & serial_lock from hso_serial & hso_net
& adding lock to hso_device which to me appears to me to
have almost nothing to do with fixing the bug you found.
Admittedly seeing as the is_active flags are in the hso_device
structure it might make sense to have the lock there too
as it's common to hso_serial & hso_net.
You also changed is_active & usb_gone to chars rather than
leave them as u8's this is also unneccessary & even if I didnt write the
code I prefer u8's.
Thanks for fixing the bug, I'll do a bit more examination of
the patch before applying it, how do the rest of you feel about the patch?
I personally would accept it as is if it passes a little testing.
Oliver Neukum wrote:
> Am Freitag, 19. Dezember 2008 13:26:34 schrieb Chris Snook:
>> Denis Joseph Barrow wrote:
>>> Get Martin Schwidefsky to look over it.
>>> I hope he needs to write a 3g modem driver for linux on the z series anyway
>>> so he may as well get used to the code.
>> I hope they come out with one soon, so I can get that ultraportable mainframe
>> I've been thinking about.
>
> Hi,
>
> if nobody has tested the last patch, don't bother. Here's a newer version.
>
> Regards
> Oliver
>
> ---
> diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
> index cc75c8b..52f12fb 100644
> --- a/drivers/net/usb/hso.c
> +++ b/drivers/net/usb/hso.c
> @@ -167,7 +167,6 @@ struct hso_net {
> struct sk_buff *skb_tx_buf;
>
> enum pkt_parse_state rx_parse_state;
> - spinlock_t net_lock;
>
> unsigned short rx_buf_size;
> unsigned short rx_buf_missing;
> @@ -216,7 +215,6 @@ struct hso_serial {
> /* from usb_serial_port */
> struct tty_struct *tty;
> int open_count;
> - spinlock_t serial_lock;
>
> int (*write_data) (struct hso_serial *serial);
> /* Hacks required to get flow control
> @@ -238,10 +236,13 @@ struct hso_device {
>
> u32 port_spec;
>
> - u8 is_active;
> - u8 usb_gone;
> + char is_active:1;
> + char is_suspended:1;
> + char is_elevated:1;
> + char usb_gone:1;
> struct work_struct async_get_intf;
> struct work_struct async_put_intf;
> + spinlock_t lock;
>
> struct usb_device *usb;
> struct usb_interface *interface;
> @@ -642,7 +643,6 @@ static void log_usb_status(int status, const char *function)
> static int hso_net_open(struct net_device *net)
> {
> struct hso_net *odev = netdev_priv(net);
> - unsigned long flags = 0;
>
> if (!odev) {
> dev_err(&net->dev, "No net device !\n");
> @@ -652,11 +652,11 @@ static int hso_net_open(struct net_device *net)
> odev->skb_tx_buf = NULL;
>
> /* setup environment */
> - spin_lock_irqsave(&odev->net_lock, flags);
> + spin_lock_irq(&odev->parent->lock);
> odev->rx_parse_state = WAIT_IP;
> odev->rx_buf_size = 0;
> odev->rx_buf_missing = sizeof(struct iphdr);
> - spin_unlock_irqrestore(&odev->net_lock, flags);
> + spin_unlock_irq(&odev->parent->lock);
>
> /* We are up and running. */
> set_bit(HSO_NET_RUNNING, &odev->flags);
> @@ -708,7 +708,9 @@ static void write_bulk_callback(struct urb *urb)
> if (status)
> log_usb_status(status, __func__);
>
> + spin_lock(&odev->parent->lock);
> hso_put_activity(odev->parent);
> + spin_unlock(&odev->parent->lock);
>
> /* Tell the network interface we are ready for another frame */
> netif_wake_queue(odev->net);
> @@ -718,14 +720,26 @@ static void write_bulk_callback(struct urb *urb)
> static int hso_net_start_xmit(struct sk_buff *skb, struct net_device *net)
> {
> struct hso_net *odev = netdev_priv(net);
> - int result;
> + struct hso_device *pdev = odev->parent;
> + int result = 0;
>
> /* Tell the kernel, "No more frames 'til we are done with this one." */
> netif_stop_queue(net);
> - if (hso_get_activity(odev->parent) == -EAGAIN) {
> - odev->skb_tx_buf = skb;
> - return 0;
> +
> + usb_mark_last_busy(pdev->usb);
> + spin_lock(&pdev->lock);
> + if (!pdev->is_active) {
> + if (!pdev->is_suspended) {
> + pdev->is_active = 1;
> + } else {
> + odev->skb_tx_buf = skb;
> + hso_get_activity(pdev);
> + result = 1;
> + }
> }
> + spin_unlock(&pdev->lock);
> + if (result)
> + return 0;
>
> /* log if asked */
> DUMP1(skb->data, skb->len);
> @@ -735,8 +749,8 @@ static int hso_net_start_xmit(struct sk_buff *skb, struct net_device *net)
>
> /* Fill in the URB for shipping it out. */
> usb_fill_bulk_urb(odev->mux_bulk_tx_urb,
> - odev->parent->usb,
> - usb_sndbulkpipe(odev->parent->usb,
> + pdev->usb,
> + usb_sndbulkpipe(pdev->usb,
> odev->out_endp->
> bEndpointAddress & 0x7F),
> odev->mux_bulk_tx_buf, skb->len, write_bulk_callback,
> @@ -748,7 +762,7 @@ static int hso_net_start_xmit(struct sk_buff *skb, struct net_device *net)
> /* Send the URB on its merry way. */
> result = usb_submit_urb(odev->mux_bulk_tx_urb, GFP_ATOMIC);
> if (result) {
> - dev_warn(&odev->parent->interface->dev,
> + dev_warn(&pdev->interface->dev,
> "failed mux_bulk_tx_urb %d", result);
> net->stats.tx_errors++;
> netif_start_queue(net);
> @@ -976,11 +990,11 @@ static void read_bulk_callback(struct urb *urb)
> if (urb->actual_length) {
> /* Handle the IP stream, add header and push it onto network
> * stack if the packet is complete. */
> - spin_lock(&odev->net_lock);
> + spin_lock(&odev->parent->lock);
> packetizeRx(odev, urb->transfer_buffer, urb->actual_length,
> (urb->transfer_buffer_length >
> urb->actual_length) ? 1 : 0);
> - spin_unlock(&odev->net_lock);
> + spin_unlock(&odev->parent->lock);
> }
>
> /* We are done with this URB, resubmit it. Prep the USB to wait for
> @@ -1167,17 +1181,17 @@ static void hso_std_serial_read_bulk_callback(struct urb *urb)
> }
> }
> /* Valid data, handle RX data */
> - spin_lock(&serial->serial_lock);
> + spin_lock(&serial->parent->lock);
> serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 1;
> put_rxbuf_data_and_resubmit_bulk_urb(serial);
> - spin_unlock(&serial->serial_lock);
> + spin_unlock(&serial->parent->lock);
> } else if (status == -ENOENT || status == -ECONNRESET) {
> /* Unlinked - check for throttled port. */
> D2("Port %d, successfully unlinked urb", serial->minor);
> - spin_lock(&serial->serial_lock);
> + spin_lock(&serial->parent->lock);
> serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0;
> hso_resubmit_rx_bulk_urb(serial, urb);
> - spin_unlock(&serial->serial_lock);
> + spin_unlock(&serial->parent->lock);
> } else {
> D2("Port %d, status = %d for read urb", serial->minor, status);
> return;
> @@ -1192,12 +1206,12 @@ void hso_unthrottle_tasklet(struct hso_serial *serial)
> {
> unsigned long flags;
>
> - spin_lock_irqsave(&serial->serial_lock, flags);
> + spin_lock_irqsave(&serial->parent->lock, flags);
> if ((serial->parent->port_spec & HSO_INTF_MUX))
> put_rxbuf_data_and_resubmit_ctrl_urb(serial);
> else
> put_rxbuf_data_and_resubmit_bulk_urb(serial);
> - spin_unlock_irqrestore(&serial->serial_lock, flags);
> + spin_unlock_irqrestore(&serial->parent->lock, flags);
> }
>
> static void hso_unthrottle(struct tty_struct *tty)
> @@ -1322,7 +1336,7 @@ static int hso_serial_write(struct tty_struct *tty, const unsigned char *buf,
> return -ENODEV;
> }
>
> - spin_lock_irqsave(&serial->serial_lock, flags);
> + spin_lock_irqsave(&serial->parent->lock, flags);
>
> space = serial->tx_data_length - serial->tx_buffer_count;
> tx_bytes = (count < space) ? count : space;
> @@ -1334,7 +1348,7 @@ static int hso_serial_write(struct tty_struct *tty, const unsigned char *buf,
> serial->tx_buffer_count += tx_bytes;
>
> out:
> - spin_unlock_irqrestore(&serial->serial_lock, flags);
> + spin_unlock_irqrestore(&serial->parent->lock, flags);
>
> hso_kick_transmit(serial);
> /* done */
> @@ -1348,9 +1362,9 @@ static int hso_serial_write_room(struct tty_struct *tty)
> int room;
> unsigned long flags;
>
> - spin_lock_irqsave(&serial->serial_lock, flags);
> + spin_lock_irqsave(&serial->parent->lock, flags);
> room = serial->tx_data_length - serial->tx_buffer_count;
> - spin_unlock_irqrestore(&serial->serial_lock, flags);
> + spin_unlock_irqrestore(&serial->parent->lock, flags);
>
> /* return free room */
> return room;
> @@ -1367,12 +1381,12 @@ static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old)
> tty->termios->c_cflag, old->c_cflag);
>
> /* the actual setup */
> - spin_lock_irqsave(&serial->serial_lock, flags);
> + spin_lock_irqsave(&serial->parent->lock, flags);
> if (serial->open_count)
> _hso_serial_set_termios(tty, old);
> else
> tty->termios = old;
> - spin_unlock_irqrestore(&serial->serial_lock, flags);
> + spin_unlock_irqrestore(&serial->parent->lock, flags);
>
> /* done */
> return;
> @@ -1389,9 +1403,9 @@ static int hso_serial_chars_in_buffer(struct tty_struct *tty)
> if (serial == NULL)
> return 0;
>
> - spin_lock_irqsave(&serial->serial_lock, flags);
> + spin_lock_irqsave(&serial->parent->lock, flags);
> chars = serial->tx_buffer_count;
> - spin_unlock_irqrestore(&serial->serial_lock, flags);
> + spin_unlock_irqrestore(&serial->parent->lock, flags);
>
> return chars;
> }
> @@ -1408,10 +1422,10 @@ static int hso_serial_tiocmget(struct tty_struct *tty, struct file *file)
> return -EINVAL;
> }
>
> - spin_lock_irqsave(&serial->serial_lock, flags);
> + spin_lock_irqsave(&serial->parent->lock, flags);
> value = ((serial->rts_state) ? TIOCM_RTS : 0) |
> ((serial->dtr_state) ? TIOCM_DTR : 0);
> - spin_unlock_irqrestore(&serial->serial_lock, flags);
> + spin_unlock_irqrestore(&serial->parent->lock, flags);
>
> return value;
> }
> @@ -1431,7 +1445,7 @@ static int hso_serial_tiocmset(struct tty_struct *tty, struct file *file,
> }
> if_num = serial->parent->interface->altsetting->desc.bInterfaceNumber;
>
> - spin_lock_irqsave(&serial->serial_lock, flags);
> + spin_lock_irqsave(&serial->parent->lock, flags);
> if (set & TIOCM_RTS)
> serial->rts_state = 1;
> if (set & TIOCM_DTR)
> @@ -1447,7 +1461,7 @@ static int hso_serial_tiocmset(struct tty_struct *tty, struct file *file,
> if (serial->rts_state)
> val |= 0x02;
>
> - spin_unlock_irqrestore(&serial->serial_lock, flags);
> + spin_unlock_irqrestore(&serial->parent->lock, flags);
>
> return usb_control_msg(serial->parent->usb,
> usb_rcvctrlpipe(serial->parent->usb, 0), 0x22,
> @@ -1462,7 +1476,7 @@ static void hso_kick_transmit(struct hso_serial *serial)
> unsigned long flags;
> int res;
>
> - spin_lock_irqsave(&serial->serial_lock, flags);
> + spin_lock_irqsave(&serial->parent->lock, flags);
> if (!serial->tx_buffer_count)
> goto out;
>
> @@ -1470,7 +1484,8 @@ static void hso_kick_transmit(struct hso_serial *serial)
> goto out;
>
> /* Wakeup USB interface if necessary */
> - if (hso_get_activity(serial->parent) == -EAGAIN)
> + hso_get_activity(serial->parent);
> + if (serial->parent->is_suspended)
> goto out;
>
> /* Switch pointers around to avoid memcpy */
> @@ -1487,7 +1502,7 @@ static void hso_kick_transmit(struct hso_serial *serial)
> serial->tx_urb_used = 1;
> }
> out:
> - spin_unlock_irqrestore(&serial->serial_lock, flags);
> + spin_unlock_irqrestore(&serial->parent->lock, flags);
> }
>
> /* make a request (for reading and writing data to muxed serial port) */
> @@ -1607,7 +1622,7 @@ static void intr_callback(struct urb *urb)
> (1 << i));
> if (serial != NULL) {
> D1("Pending read interrupt on port %d\n", i);
> - spin_lock(&serial->serial_lock);
> + spin_lock(&serial->parent->lock);
> if (serial->rx_state == RX_IDLE) {
> /* Setup and send a ctrl req read on
> * port i */
> @@ -1621,7 +1636,7 @@ static void intr_callback(struct urb *urb)
> D1("Already pending a read on "
> "port %d\n", i);
> }
> - spin_unlock(&serial->serial_lock);
> + spin_unlock(&serial->parent->lock);
> }
> }
> }
> @@ -1655,9 +1670,9 @@ static void hso_std_serial_write_bulk_callback(struct urb *urb)
> return;
> }
>
> - spin_lock(&serial->serial_lock);
> + spin_lock(&serial->parent->lock);
> serial->tx_urb_used = 0;
> - spin_unlock(&serial->serial_lock);
> + spin_unlock(&serial->parent->lock);
> if (status) {
> log_usb_status(status, __func__);
> return;
> @@ -1706,9 +1721,9 @@ static void ctrl_callback(struct urb *urb)
> if (!serial)
> return;
>
> - spin_lock(&serial->serial_lock);
> + spin_lock(&serial->parent->lock);
> serial->tx_urb_used = 0;
> - spin_unlock(&serial->serial_lock);
> + spin_unlock(&serial->parent->lock);
> if (status) {
> log_usb_status(status, __func__);
> return;
> @@ -1724,9 +1739,9 @@ static void ctrl_callback(struct urb *urb)
> (USB_DIR_IN | USB_TYPE_OPTION_VENDOR | USB_RECIP_INTERFACE)) {
> /* response to a read command */
> serial->rx_urb_filled[0] = 1;
> - spin_lock(&serial->serial_lock);
> + spin_lock(&serial->parent->lock);
> put_rxbuf_data_and_resubmit_ctrl_urb(serial);
> - spin_unlock(&serial->serial_lock);
> + spin_unlock(&serial->parent->lock);
> } else {
> hso_put_activity(serial->parent);
> if (serial->tty)
> @@ -1999,7 +2014,7 @@ static int hso_serial_common_create(struct hso_serial *serial, int num_urbs,
> /* fill in specific data for later use */
> serial->minor = minor;
> serial->magic = HSO_SERIAL_MAGIC;
> - spin_lock_init(&serial->serial_lock);
> + spin_lock_init(&serial->parent->lock);
> serial->num_rx_urbs = num_urbs;
>
> /* RX, allocate urb and initialize */
> @@ -2140,9 +2155,6 @@ static void hso_net_init(struct net_device *net)
> net->mtu = DEFAULT_MTU - 14;
> net->tx_queue_len = 10;
> SET_ETHTOOL_OPS(net, &ops);
> -
> - /* and initialize the semaphore */
> - spin_lock_init(&hso_net->net_lock);
> }
>
> /* Adds a network device in the network device table */
> @@ -2630,6 +2642,7 @@ static int hso_probe(struct usb_interface *interface,
> goto exit;
> }
>
> + spin_lock_init(&hso_dev->lock);
> usb_driver_claim_interface(&hso_driver, interface, hso_dev);
>
> /* save our data pointer in this device */
> @@ -2669,38 +2682,36 @@ static void async_put_intf(struct work_struct *data)
>
> static int hso_get_activity(struct hso_device *hso_dev)
> {
> - if (hso_dev->usb->state == USB_STATE_SUSPENDED) {
> - if (!hso_dev->is_active) {
> - hso_dev->is_active = 1;
> - schedule_work(&hso_dev->async_get_intf);
> - }
> + if (!hso_dev->is_elevated) {
> + hso_dev->is_elevated = 1;
> + schedule_work(&hso_dev->async_get_intf);
> }
> -
> - if (hso_dev->usb->state != USB_STATE_CONFIGURED)
> - return -EAGAIN;
> -
> - usb_mark_last_busy(hso_dev->usb);
> -
> return 0;
> }
>
> static int hso_put_activity(struct hso_device *hso_dev)
> {
> - if (hso_dev->usb->state != USB_STATE_SUSPENDED) {
> - if (hso_dev->is_active) {
> - hso_dev->is_active = 0;
> - schedule_work(&hso_dev->async_put_intf);
> - return -EAGAIN;
> - }
> + if (hso_dev->is_elevated) {
> + hso_dev->is_elevated = 0;
> + schedule_work(&hso_dev->async_put_intf);
> }
> - hso_dev->is_active = 0;
> return 0;
> }
>
> /* called by kernel when we need to suspend device */
> static int hso_suspend(struct usb_interface *iface, pm_message_t message)
> {
> - int i, result;
> + struct hso_device *pdev = usb_get_intfdata(iface);
> + int i, result = 0;
> +
> + spin_lock_irq(&pdev->lock);
> + if (pdev->usb->auto_pm && pdev->is_active)
> + result = -EBUSY;
> + else
> + pdev->is_suspended = 1;
> + spin_unlock_irq(&pdev->lock);
> + if (result)
> + return result;
>
> /* Stop all serial ports */
> for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) {
> @@ -2730,6 +2741,7 @@ static int hso_resume(struct usb_interface *iface)
> {
> int i, result = 0;
> struct hso_net *hso_net;
> + struct hso_device *pdev = usb_get_intfdata(iface);
>
> /* Start all serial ports */
> for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) {
> @@ -2765,6 +2777,10 @@ static int hso_resume(struct usb_interface *iface)
> }
>
> out:
> + spin_lock_irq(&pdev->lock);
> + pdev->is_suspended = 0;
> + spin_unlock_irq(&pdev->lock);
> +
> return result;
> }
>
--
best regards,
D.J. Barrow
Linux Kernel Developer
Option NV, Gaston Geenslaan 14, 3001 Leuven, Belgium
T: +32 16 311 621
F: +32 16 207 164
d.barow@option.com
www.option.com
Disclaimer:
http://www.option.com/company/disclaimer.shtml
next prev parent reply other threads:[~2009-01-12 13:25 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-12-22 13:54 another race in hso Oliver Neukum
2009-01-12 8:57 ` Denis Joseph Barrow
2009-01-12 9:11 ` Oliver Neukum
2009-01-12 11:33 ` Oliver Neukum
2009-01-12 13:25 ` Denis Joseph Barrow [this message]
[not found] ` <496B44CD.5080702-x9gZzRpC1QbQT0dZR+AlfA@public.gmane.org>
2009-01-12 13:36 ` Oliver Neukum
[not found] ` <200901121436.16576.oliver-GvhC2dPhHPQdnm+yROfE0A@public.gmane.org>
2009-01-12 13:52 ` Denis Joseph Barrow
[not found] ` <496B4B39.3090908-x9gZzRpC1QbQT0dZR+AlfA@public.gmane.org>
2009-01-12 14:02 ` Oliver Neukum
[not found] ` <200812221454.57794.oliver-GvhC2dPhHPQdnm+yROfE0A@public.gmane.org>
2009-01-12 16:35 ` Denis Joseph Barrow
[not found] ` <496B7159.3000500-x9gZzRpC1QbQT0dZR+AlfA@public.gmane.org>
2009-01-12 16:46 ` Oliver Neukum
-- strict thread matches above, loose matches on Subject: below --
2008-12-19 10:45 Oliver Neukum
2008-12-19 11:06 ` Denis Joseph Barrow
[not found] ` <494B803B.9000703-x9gZzRpC1QbQT0dZR+AlfA@public.gmane.org>
2008-12-19 12:26 ` Chris Snook
2008-12-19 12:42 ` Oliver Neukum
2008-12-19 12:56 ` Denis Joseph Barrow
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=496B44CD.5080702@option.com \
--to=d.barow@option.com \
--cc=P.Hardwick@option.com \
--cc=ajb@spheresystems.co.uk \
--cc=alan@lxorguk.ukuu.org.uk \
--cc=csnook@redhat.com \
--cc=greg@kroah.com \
--cc=linux-usb@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=oliver@neukum.org \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.