lkml.org 
[lkml]   [2005]   [Jun]   [8]   [last100]   RSS Feed
Views: [more markup]  [less markup]  [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
DateWed, 08 Jun 2005 14:21:39 +0400
From"Eugeny S. Mints" <>
Subjectrace in usbnet.c in full RT
Hi,

seems there is a race in drivers/net/usbnet.c in full RT mode. To be 
honest I haven't hardly checked this on the latest kernel and latest RT 
patch but just took a look at usbnet.c and latest RT patch and haven't 
observed any related changes.

The  usbnet_start_xmit() contains the following code:

	...
	spin_lock_irqsave (&dev->txq.lock, flags);

#ifdef	CONFIG_USB_NET1080
	if (info->flags & FLAG_FRAMING_NC) {
		header->packet_id = cpu_to_le16 ((u16)dev->dev_packet_id++);
		put_unaligned (header->packet_id, &trailer->packet_id);
#if 0
		devdbg (dev, "frame >tx h %d p %d id %d",
			header->hdr_len, header->packet_len,
			header->packet_id);
#endif
	}
#endif	/* CONFIG_USB_NET1080 */
	switch ((retval = usb_submit_urb (urb, GFP_ATOMIC))) {
	case -EPIPE:
		netif_stop_queue (net);
		defer_kevent (dev, EVENT_TX_HALT);
		break;
	default:
		devdbg (dev, "tx: submit urb err %d", retval);
		break;
	case 0:
		net->trans_start = jiffies;
		__skb_queue_tail (&dev->txq, skb);
		if (dev->txq.qlen >= TX_QLEN (dev))
			netif_stop_queue (net);
	}
	spin_unlock_irqrestore (&dev->txq.lock, flags);
	...
THe race in full RT is between tx_complete() routine and 
__skb_queue_tail (&dev->txq, skb): skb->list gets initialized in 
__skb_queue_tail() but may be dereferenced before initialization at 
defer_bh() called from tx_complete() (since tx_complete() and 
usbnet_start_xmit() are completely asynchronous routines).

in non-RT case spin_lock_irqsave (&dev->txq.lock, flags) disables 
interrupts and thus code from usb_submit_urb() call upto 
__skb_queue_tail (&dev->txq, skb) executes atomically. But in RT case 
interrupts are not disabled and usb_submit_urb() triggers an interrupt 
which may cause tx_complete() execution before __skb_queue_tail () call. 
And since skb->list gets initialized just at __skb_queue_tail(), call to 
tx_complete() (via defer_bh() which thus executes before 
__skb_queue_tail) dereferences NULL (skb->list) pointer.

Thus looks tx_complete() and usbnet_start_xmit() require a 
serialization. Please find proposed fix attached though not sure the 
patch will apply cleanly to the latest kernel.

	Eugeny
--- a/drivers/usb/net/usbnet.c	2004-12-25 00:34:58.000000000 +0300
+++ b/drivers/usb/net/usbnet.c	2005-05-26 21:02:58.000000000 +0400
@@ -2820,6 +2820,8 @@
 
 	urb->dev = NULL;
 	entry->state = tx_done;
+	spin_lock_rt (&dev->txq.lock);
+	spin_unlock_rt(&dev->txq.lock);
 	defer_bh (dev, skb);
 }
 
\
 
 \ /
  Last update: 2005-06-08 12:16    [from the cache]
©2003-2008