All of lore.kernel.org
 help / color / mirror / Atom feed
From: Denis Joseph Barrow <D.Barow-x9gZzRpC1QbQT0dZR+AlfA@public.gmane.org>
To: Oliver Neukum <oliver-GvhC2dPhHPQdnm+yROfE0A@public.gmane.org>,
	Linux USB kernel mailing list
	<linux-usb-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>,
	Linux netdev Mailing list
	<netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>
Subject: Re: another race in hso
Date: Mon, 12 Jan 2009 17:35:37 +0100	[thread overview]
Message-ID: <496B7159.3000500@option.com> (raw)
In-Reply-To: <200812221454.57794.oliver-GvhC2dPhHPQdnm+yROfE0A@public.gmane.org>

Hi Oliver,
Your patch fails in 3 places against 2.6.29-rc1,
The first place being hso_serial_tiocmget.
the spin_lock_irqsave is spin_lock_irq in my kernel sources.
What kernel is this patch supposed to apply against?

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-x9gZzRpC1QbQT0dZR+AlfA@public.gmane.org
www.option.com

Disclaimer:
http://www.option.com/company/disclaimer.shtml
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

  parent reply	other threads:[~2009-01-12 16:35 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
     [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 [this message]
     [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=496B7159.3000500@option.com \
    --to=d.barow-x9gzzrpc1qbqt0dzr+alfa@public.gmane.org \
    --cc=linux-usb-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=oliver-GvhC2dPhHPQdnm+yROfE0A@public.gmane.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.