2007-10-22 11:03:37 +10:00
/* A simple network driver using virtio.
*
* Copyright 2007 Rusty Russell < rusty @ rustcorp . com . au > IBM Corporation
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
//#define DEBUG
# include <linux/netdevice.h>
# include <linux/etherdevice.h>
# include <linux/module.h>
# include <linux/virtio.h>
# include <linux/virtio_net.h>
# include <linux/scatterlist.h>
2007-12-16 15:19:43 +02:00
static int napi_weight = 128 ;
module_param ( napi_weight , int , 0444 ) ;
2008-02-04 23:50:02 -05:00
static int csum = 1 , gso = 1 ;
module_param ( csum , bool , 0444 ) ;
module_param ( gso , bool , 0444 ) ;
2007-10-22 11:03:37 +10:00
/* FIXME: MTU in config. */
# define MAX_PACKET_LEN (ETH_HLEN+ETH_DATA_LEN)
struct virtnet_info
{
struct virtio_device * vdev ;
struct virtqueue * rvq , * svq ;
struct net_device * dev ;
struct napi_struct napi ;
/* Number of input buffers, and max we've ever had. */
unsigned int num , max ;
/* Receive & send queues. */
struct sk_buff_head recv ;
struct sk_buff_head send ;
} ;
static inline struct virtio_net_hdr * skb_vnet_hdr ( struct sk_buff * skb )
{
return ( struct virtio_net_hdr * ) skb - > cb ;
}
static inline void vnet_hdr_to_sg ( struct scatterlist * sg , struct sk_buff * skb )
{
sg_init_one ( sg , skb_vnet_hdr ( skb ) , sizeof ( struct virtio_net_hdr ) ) ;
}
2008-02-04 23:50:07 -05:00
static void skb_xmit_done ( struct virtqueue * svq )
2007-10-22 11:03:37 +10:00
{
2008-02-04 23:50:07 -05:00
struct virtnet_info * vi = svq - > vdev - > priv ;
2007-10-22 11:03:37 +10:00
2008-02-04 23:50:07 -05:00
/* Suppress further interrupts. */
svq - > vq_ops - > disable_cb ( svq ) ;
/* We were waiting for more output buffers. */
2007-10-22 11:03:37 +10:00
netif_wake_queue ( vi - > dev ) ;
}
static void receive_skb ( struct net_device * dev , struct sk_buff * skb ,
unsigned len )
{
struct virtio_net_hdr * hdr = skb_vnet_hdr ( skb ) ;
if ( unlikely ( len < sizeof ( struct virtio_net_hdr ) + ETH_HLEN ) ) {
pr_debug ( " %s: short packet %i \n " , dev - > name , len ) ;
dev - > stats . rx_length_errors + + ;
goto drop ;
}
len - = sizeof ( struct virtio_net_hdr ) ;
BUG_ON ( len > MAX_PACKET_LEN ) ;
skb_trim ( skb , len ) ;
skb - > protocol = eth_type_trans ( skb , dev ) ;
pr_debug ( " Receiving skb proto 0x%04x len %i type %i \n " ,
ntohs ( skb - > protocol ) , skb - > len , skb - > pkt_type ) ;
dev - > stats . rx_bytes + = skb - > len ;
dev - > stats . rx_packets + + ;
if ( hdr - > flags & VIRTIO_NET_HDR_F_NEEDS_CSUM ) {
pr_debug ( " Needs csum! \n " ) ;
2008-02-04 23:49:54 -05:00
if ( ! skb_partial_csum_set ( skb , hdr - > csum_start , hdr - > csum_offset ) )
2007-10-22 11:03:37 +10:00
goto frame_err ;
}
if ( hdr - > gso_type ! = VIRTIO_NET_HDR_GSO_NONE ) {
pr_debug ( " GSO! \n " ) ;
2008-02-04 23:50:02 -05:00
switch ( hdr - > gso_type & ~ VIRTIO_NET_HDR_GSO_ECN ) {
2007-10-22 11:03:37 +10:00
case VIRTIO_NET_HDR_GSO_TCPV4 :
skb_shinfo ( skb ) - > gso_type = SKB_GSO_TCPV4 ;
break ;
case VIRTIO_NET_HDR_GSO_UDP :
skb_shinfo ( skb ) - > gso_type = SKB_GSO_UDP ;
break ;
case VIRTIO_NET_HDR_GSO_TCPV6 :
skb_shinfo ( skb ) - > gso_type = SKB_GSO_TCPV6 ;
break ;
default :
if ( net_ratelimit ( ) )
printk ( KERN_WARNING " %s: bad gso type %u. \n " ,
dev - > name , hdr - > gso_type ) ;
goto frame_err ;
}
2008-02-04 23:50:02 -05:00
if ( hdr - > gso_type & VIRTIO_NET_HDR_GSO_ECN )
skb_shinfo ( skb ) - > gso_type | = SKB_GSO_TCP_ECN ;
2007-10-22 11:03:37 +10:00
skb_shinfo ( skb ) - > gso_size = hdr - > gso_size ;
if ( skb_shinfo ( skb ) - > gso_size = = 0 ) {
if ( net_ratelimit ( ) )
printk ( KERN_WARNING " %s: zero gso size. \n " ,
dev - > name ) ;
goto frame_err ;
}
/* Header must be checked, and gso_segs computed. */
skb_shinfo ( skb ) - > gso_type | = SKB_GSO_DODGY ;
skb_shinfo ( skb ) - > gso_segs = 0 ;
}
netif_receive_skb ( skb ) ;
return ;
frame_err :
dev - > stats . rx_frame_errors + + ;
drop :
dev_kfree_skb ( skb ) ;
}
static void try_fill_recv ( struct virtnet_info * vi )
{
struct sk_buff * skb ;
struct scatterlist sg [ 1 + MAX_SKB_FRAGS ] ;
int num , err ;
2007-11-07 16:34:49 +11:00
sg_init_table ( sg , 1 + MAX_SKB_FRAGS ) ;
2007-10-22 11:03:37 +10:00
for ( ; ; ) {
skb = netdev_alloc_skb ( vi - > dev , MAX_PACKET_LEN ) ;
if ( unlikely ( ! skb ) )
break ;
skb_put ( skb , MAX_PACKET_LEN ) ;
vnet_hdr_to_sg ( sg , skb ) ;
num = skb_to_sgvec ( skb , sg + 1 , 0 , skb - > len ) + 1 ;
skb_queue_head ( & vi - > recv , skb ) ;
err = vi - > rvq - > vq_ops - > add_buf ( vi - > rvq , sg , 0 , num , skb ) ;
if ( err ) {
skb_unlink ( skb , & vi - > recv ) ;
kfree_skb ( skb ) ;
break ;
}
vi - > num + + ;
}
if ( unlikely ( vi - > num > vi - > max ) )
vi - > max = vi - > num ;
vi - > rvq - > vq_ops - > kick ( vi - > rvq ) ;
}
2008-02-04 23:49:57 -05:00
static void skb_recv_done ( struct virtqueue * rvq )
2007-10-22 11:03:37 +10:00
{
struct virtnet_info * vi = rvq - > vdev - > priv ;
2008-02-04 23:49:57 -05:00
/* Schedule NAPI, Suppress further interrupts if successful. */
if ( netif_rx_schedule_prep ( vi - > dev , & vi - > napi ) ) {
rvq - > vq_ops - > disable_cb ( rvq ) ;
__netif_rx_schedule ( vi - > dev , & vi - > napi ) ;
}
2007-10-22 11:03:37 +10:00
}
static int virtnet_poll ( struct napi_struct * napi , int budget )
{
struct virtnet_info * vi = container_of ( napi , struct virtnet_info , napi ) ;
struct sk_buff * skb = NULL ;
unsigned int len , received = 0 ;
again :
while ( received < budget & &
( skb = vi - > rvq - > vq_ops - > get_buf ( vi - > rvq , & len ) ) ! = NULL ) {
__skb_unlink ( skb , & vi - > recv ) ;
receive_skb ( vi - > dev , skb , len ) ;
vi - > num - - ;
received + + ;
}
/* FIXME: If we oom and completely run out of inbufs, we need
* to start a timer trying to fill more . */
if ( vi - > num < vi - > max / 2 )
try_fill_recv ( vi ) ;
2007-11-19 11:20:43 -05:00
/* Out of packets? */
if ( received < budget ) {
2007-10-22 11:03:37 +10:00
netif_rx_complete ( vi - > dev , napi ) ;
2008-02-04 23:49:57 -05:00
if ( unlikely ( ! vi - > rvq - > vq_ops - > enable_cb ( vi - > rvq ) )
virtio: fix race in enable_cb
There is a race in virtio_net, dealing with disabling/enabling the callback.
I saw the following oops:
kernel BUG at /space/kvm/drivers/virtio/virtio_ring.c:218!
illegal operation: 0001 [#1] SMP
Modules linked in: sunrpc dm_mod
CPU: 2 Not tainted 2.6.25-rc1zlive-host-10623-gd358142-dirty #99
Process swapper (pid: 0, task: 000000000f85a610, ksp: 000000000f873c60)
Krnl PSW : 0404300180000000 00000000002b81a6 (vring_disable_cb+0x16/0x20)
R:0 T:1 IO:0 EX:0 Key:0 M:1 W:0 P:0 AS:0 CC:3 PM:0 EA:3
Krnl GPRS: 0000000000000001 0000000000000001 0000000010005800 0000000000000001
000000000f3a0900 000000000f85a610 0000000000000000 0000000000000000
0000000000000000 000000000f870000 0000000000000000 0000000000001237
000000000f3a0920 000000000010ff74 00000000002846f6 000000000fa0bcd8
Krnl Code: 00000000002b819a: a7110001 tmll %r1,1
00000000002b819e: a7840004 brc 8,2b81a6
00000000002b81a2: a7f40001 brc 15,2b81a4
>00000000002b81a6: a51b0001 oill %r1,1
00000000002b81aa: 40102000 sth %r1,0(%r2)
00000000002b81ae: 07fe bcr 15,%r14
00000000002b81b0: eb7ff0380024 stmg %r7,%r15,56(%r15)
00000000002b81b6: a7f13e00 tmll %r15,15872
Call Trace:
([<000000000fa0bcd0>] 0xfa0bcd0)
[<00000000002b8350>] vring_interrupt+0x5c/0x6c
[<000000000010ab08>] do_extint+0xb8/0xf0
[<0000000000110716>] ext_no_vtime+0x16/0x1a
[<0000000000107e72>] cpu_idle+0x1c2/0x1e0
The problem can be triggered with a high amount of host->guest traffic.
I think its the following race:
poll says netif_rx_complete
poll calls enable_cb
enable_cb opens the interrupt mask
a new packet comes, an interrupt is triggered----\
enable_cb sees that there is more work |
enable_cb disables the interrupt |
. V
. interrupt is delivered
. skb_recv_done does atomic napi test, ok
some waiting disable_cb is called->check fails->bang!
.
poll would do napi check
poll would do disable_cb
The fix is to let enable_cb not disable the interrupt again, but expect the
caller to do the cleanup if it returns false. In that case, the interrupt is
only disabled, if the napi test_set_bit was successful.
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> (cleaned up doco)
2008-03-14 14:17:05 +01:00
& & napi_schedule_prep ( napi ) ) {
vi - > rvq - > vq_ops - > disable_cb ( vi - > rvq ) ;
__netif_rx_schedule ( vi - > dev , napi ) ;
2007-10-22 11:03:37 +10:00
goto again ;
virtio: fix race in enable_cb
There is a race in virtio_net, dealing with disabling/enabling the callback.
I saw the following oops:
kernel BUG at /space/kvm/drivers/virtio/virtio_ring.c:218!
illegal operation: 0001 [#1] SMP
Modules linked in: sunrpc dm_mod
CPU: 2 Not tainted 2.6.25-rc1zlive-host-10623-gd358142-dirty #99
Process swapper (pid: 0, task: 000000000f85a610, ksp: 000000000f873c60)
Krnl PSW : 0404300180000000 00000000002b81a6 (vring_disable_cb+0x16/0x20)
R:0 T:1 IO:0 EX:0 Key:0 M:1 W:0 P:0 AS:0 CC:3 PM:0 EA:3
Krnl GPRS: 0000000000000001 0000000000000001 0000000010005800 0000000000000001
000000000f3a0900 000000000f85a610 0000000000000000 0000000000000000
0000000000000000 000000000f870000 0000000000000000 0000000000001237
000000000f3a0920 000000000010ff74 00000000002846f6 000000000fa0bcd8
Krnl Code: 00000000002b819a: a7110001 tmll %r1,1
00000000002b819e: a7840004 brc 8,2b81a6
00000000002b81a2: a7f40001 brc 15,2b81a4
>00000000002b81a6: a51b0001 oill %r1,1
00000000002b81aa: 40102000 sth %r1,0(%r2)
00000000002b81ae: 07fe bcr 15,%r14
00000000002b81b0: eb7ff0380024 stmg %r7,%r15,56(%r15)
00000000002b81b6: a7f13e00 tmll %r15,15872
Call Trace:
([<000000000fa0bcd0>] 0xfa0bcd0)
[<00000000002b8350>] vring_interrupt+0x5c/0x6c
[<000000000010ab08>] do_extint+0xb8/0xf0
[<0000000000110716>] ext_no_vtime+0x16/0x1a
[<0000000000107e72>] cpu_idle+0x1c2/0x1e0
The problem can be triggered with a high amount of host->guest traffic.
I think its the following race:
poll says netif_rx_complete
poll calls enable_cb
enable_cb opens the interrupt mask
a new packet comes, an interrupt is triggered----\
enable_cb sees that there is more work |
enable_cb disables the interrupt |
. V
. interrupt is delivered
. skb_recv_done does atomic napi test, ok
some waiting disable_cb is called->check fails->bang!
.
poll would do napi check
poll would do disable_cb
The fix is to let enable_cb not disable the interrupt again, but expect the
caller to do the cleanup if it returns false. In that case, the interrupt is
only disabled, if the napi test_set_bit was successful.
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> (cleaned up doco)
2008-03-14 14:17:05 +01:00
}
2007-10-22 11:03:37 +10:00
}
return received ;
}
static void free_old_xmit_skbs ( struct virtnet_info * vi )
{
struct sk_buff * skb ;
unsigned int len ;
while ( ( skb = vi - > svq - > vq_ops - > get_buf ( vi - > svq , & len ) ) ! = NULL ) {
pr_debug ( " Sent skb %p \n " , skb ) ;
__skb_unlink ( skb , & vi - > send ) ;
vi - > dev - > stats . tx_bytes + = len ;
vi - > dev - > stats . tx_packets + + ;
kfree_skb ( skb ) ;
}
}
static int start_xmit ( struct sk_buff * skb , struct net_device * dev )
{
struct virtnet_info * vi = netdev_priv ( dev ) ;
int num , err ;
struct scatterlist sg [ 1 + MAX_SKB_FRAGS ] ;
struct virtio_net_hdr * hdr ;
const unsigned char * dest = ( ( struct ethhdr * ) skb - > data ) - > h_dest ;
2007-11-07 16:34:49 +11:00
sg_init_table ( sg , 1 + MAX_SKB_FRAGS ) ;
2008-04-08 16:50:44 -07:00
pr_debug ( " %s: xmit %p " MAC_FMT " \n " , dev - > name , skb ,
dest [ 0 ] , dest [ 1 ] , dest [ 2 ] ,
dest [ 3 ] , dest [ 4 ] , dest [ 5 ] ) ;
2007-10-22 11:03:37 +10:00
/* Encode metadata header at front. */
hdr = skb_vnet_hdr ( skb ) ;
if ( skb - > ip_summed = = CHECKSUM_PARTIAL ) {
hdr - > flags = VIRTIO_NET_HDR_F_NEEDS_CSUM ;
hdr - > csum_start = skb - > csum_start - skb_headroom ( skb ) ;
hdr - > csum_offset = skb - > csum_offset ;
} else {
hdr - > flags = 0 ;
hdr - > csum_offset = hdr - > csum_start = 0 ;
}
if ( skb_is_gso ( skb ) ) {
2008-02-04 23:50:01 -05:00
hdr - > hdr_len = skb_transport_header ( skb ) - skb - > data ;
2007-10-22 11:03:37 +10:00
hdr - > gso_size = skb_shinfo ( skb ) - > gso_size ;
2008-02-04 23:50:02 -05:00
if ( skb_shinfo ( skb ) - > gso_type & SKB_GSO_TCPV4 )
2007-10-22 11:03:37 +10:00
hdr - > gso_type = VIRTIO_NET_HDR_GSO_TCPV4 ;
else if ( skb_shinfo ( skb ) - > gso_type & SKB_GSO_TCPV6 )
hdr - > gso_type = VIRTIO_NET_HDR_GSO_TCPV6 ;
else if ( skb_shinfo ( skb ) - > gso_type & SKB_GSO_UDP )
hdr - > gso_type = VIRTIO_NET_HDR_GSO_UDP ;
else
BUG ( ) ;
2008-02-04 23:50:02 -05:00
if ( skb_shinfo ( skb ) - > gso_type & SKB_GSO_TCP_ECN )
hdr - > gso_type | = VIRTIO_NET_HDR_GSO_ECN ;
2007-10-22 11:03:37 +10:00
} else {
hdr - > gso_type = VIRTIO_NET_HDR_GSO_NONE ;
2008-02-04 23:50:01 -05:00
hdr - > gso_size = hdr - > hdr_len = 0 ;
2007-10-22 11:03:37 +10:00
}
vnet_hdr_to_sg ( sg , skb ) ;
num = skb_to_sgvec ( skb , sg + 1 , 0 , skb - > len ) + 1 ;
__skb_queue_head ( & vi - > send , skb ) ;
2008-02-04 23:50:07 -05:00
again :
/* Free up any pending old buffers before queueing new ones. */
free_old_xmit_skbs ( vi ) ;
2007-10-22 11:03:37 +10:00
err = vi - > svq - > vq_ops - > add_buf ( vi - > svq , sg , num , 0 , skb ) ;
if ( err ) {
pr_debug ( " %s: virtio not prepared to send \n " , dev - > name ) ;
netif_stop_queue ( dev ) ;
2008-02-04 23:50:07 -05:00
virtio: fix race in enable_cb
There is a race in virtio_net, dealing with disabling/enabling the callback.
I saw the following oops:
kernel BUG at /space/kvm/drivers/virtio/virtio_ring.c:218!
illegal operation: 0001 [#1] SMP
Modules linked in: sunrpc dm_mod
CPU: 2 Not tainted 2.6.25-rc1zlive-host-10623-gd358142-dirty #99
Process swapper (pid: 0, task: 000000000f85a610, ksp: 000000000f873c60)
Krnl PSW : 0404300180000000 00000000002b81a6 (vring_disable_cb+0x16/0x20)
R:0 T:1 IO:0 EX:0 Key:0 M:1 W:0 P:0 AS:0 CC:3 PM:0 EA:3
Krnl GPRS: 0000000000000001 0000000000000001 0000000010005800 0000000000000001
000000000f3a0900 000000000f85a610 0000000000000000 0000000000000000
0000000000000000 000000000f870000 0000000000000000 0000000000001237
000000000f3a0920 000000000010ff74 00000000002846f6 000000000fa0bcd8
Krnl Code: 00000000002b819a: a7110001 tmll %r1,1
00000000002b819e: a7840004 brc 8,2b81a6
00000000002b81a2: a7f40001 brc 15,2b81a4
>00000000002b81a6: a51b0001 oill %r1,1
00000000002b81aa: 40102000 sth %r1,0(%r2)
00000000002b81ae: 07fe bcr 15,%r14
00000000002b81b0: eb7ff0380024 stmg %r7,%r15,56(%r15)
00000000002b81b6: a7f13e00 tmll %r15,15872
Call Trace:
([<000000000fa0bcd0>] 0xfa0bcd0)
[<00000000002b8350>] vring_interrupt+0x5c/0x6c
[<000000000010ab08>] do_extint+0xb8/0xf0
[<0000000000110716>] ext_no_vtime+0x16/0x1a
[<0000000000107e72>] cpu_idle+0x1c2/0x1e0
The problem can be triggered with a high amount of host->guest traffic.
I think its the following race:
poll says netif_rx_complete
poll calls enable_cb
enable_cb opens the interrupt mask
a new packet comes, an interrupt is triggered----\
enable_cb sees that there is more work |
enable_cb disables the interrupt |
. V
. interrupt is delivered
. skb_recv_done does atomic napi test, ok
some waiting disable_cb is called->check fails->bang!
.
poll would do napi check
poll would do disable_cb
The fix is to let enable_cb not disable the interrupt again, but expect the
caller to do the cleanup if it returns false. In that case, the interrupt is
only disabled, if the napi test_set_bit was successful.
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> (cleaned up doco)
2008-03-14 14:17:05 +01:00
/* Activate callback for using skbs: if this returns false it
2008-02-04 23:50:07 -05:00
* means some were used in the meantime . */
if ( unlikely ( ! vi - > svq - > vq_ops - > enable_cb ( vi - > svq ) ) ) {
virtio: fix race in enable_cb
There is a race in virtio_net, dealing with disabling/enabling the callback.
I saw the following oops:
kernel BUG at /space/kvm/drivers/virtio/virtio_ring.c:218!
illegal operation: 0001 [#1] SMP
Modules linked in: sunrpc dm_mod
CPU: 2 Not tainted 2.6.25-rc1zlive-host-10623-gd358142-dirty #99
Process swapper (pid: 0, task: 000000000f85a610, ksp: 000000000f873c60)
Krnl PSW : 0404300180000000 00000000002b81a6 (vring_disable_cb+0x16/0x20)
R:0 T:1 IO:0 EX:0 Key:0 M:1 W:0 P:0 AS:0 CC:3 PM:0 EA:3
Krnl GPRS: 0000000000000001 0000000000000001 0000000010005800 0000000000000001
000000000f3a0900 000000000f85a610 0000000000000000 0000000000000000
0000000000000000 000000000f870000 0000000000000000 0000000000001237
000000000f3a0920 000000000010ff74 00000000002846f6 000000000fa0bcd8
Krnl Code: 00000000002b819a: a7110001 tmll %r1,1
00000000002b819e: a7840004 brc 8,2b81a6
00000000002b81a2: a7f40001 brc 15,2b81a4
>00000000002b81a6: a51b0001 oill %r1,1
00000000002b81aa: 40102000 sth %r1,0(%r2)
00000000002b81ae: 07fe bcr 15,%r14
00000000002b81b0: eb7ff0380024 stmg %r7,%r15,56(%r15)
00000000002b81b6: a7f13e00 tmll %r15,15872
Call Trace:
([<000000000fa0bcd0>] 0xfa0bcd0)
[<00000000002b8350>] vring_interrupt+0x5c/0x6c
[<000000000010ab08>] do_extint+0xb8/0xf0
[<0000000000110716>] ext_no_vtime+0x16/0x1a
[<0000000000107e72>] cpu_idle+0x1c2/0x1e0
The problem can be triggered with a high amount of host->guest traffic.
I think its the following race:
poll says netif_rx_complete
poll calls enable_cb
enable_cb opens the interrupt mask
a new packet comes, an interrupt is triggered----\
enable_cb sees that there is more work |
enable_cb disables the interrupt |
. V
. interrupt is delivered
. skb_recv_done does atomic napi test, ok
some waiting disable_cb is called->check fails->bang!
.
poll would do napi check
poll would do disable_cb
The fix is to let enable_cb not disable the interrupt again, but expect the
caller to do the cleanup if it returns false. In that case, the interrupt is
only disabled, if the napi test_set_bit was successful.
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> (cleaned up doco)
2008-03-14 14:17:05 +01:00
printk ( " Unlikely: restart svq race \n " ) ;
vi - > svq - > vq_ops - > disable_cb ( vi - > svq ) ;
2008-02-04 23:50:07 -05:00
netif_start_queue ( dev ) ;
goto again ;
}
__skb_unlink ( skb , & vi - > send ) ;
2007-10-22 11:03:37 +10:00
return NETDEV_TX_BUSY ;
}
vi - > svq - > vq_ops - > kick ( vi - > svq ) ;
return 0 ;
}
2008-02-29 16:24:50 +05:30
# ifdef CONFIG_NET_POLL_CONTROLLER
static void virtnet_netpoll ( struct net_device * dev )
{
struct virtnet_info * vi = netdev_priv ( dev ) ;
napi_schedule ( & vi - > napi ) ;
}
# endif
2007-10-22 11:03:37 +10:00
static int virtnet_open ( struct net_device * dev )
{
struct virtnet_info * vi = netdev_priv ( dev ) ;
napi_enable ( & vi - > napi ) ;
2008-02-04 23:50:07 -05:00
/* If all buffers were filled by other side before we napi_enabled, we
* won ' t get another interrupt , so process any outstanding packets
virtio net: fix oops on interface-up
I got the following oops during interface ifup. Unfortunately its not
easily reproducable so I cant say for sure that my fix fixes this
problem, but I am confident and I think its correct anyway:
<2>kernel BUG at /space/kvm/drivers/virtio/virtio_ring.c:234!
<4>illegal operation: 0001 [#1] PREEMPT SMP
<4>Modules linked in:
<4>CPU: 0 Not tainted 2.6.24zlive-guest-07293-gf1ca151-dirty #91
<4>Process swapper (pid: 0, task: 0000000000800938, ksp: 000000000084ddb8)
<4>Krnl PSW : 0404300180000000 0000000000466374 (vring_disable_cb+0x30/0x34)
<4> R:0 T:1 IO:0 EX:0 Key:0 M:1 W:0 P:0 AS:0 CC:3 PM:0 EA:3
<4>Krnl GPRS: 0000000000000001 0000000000000001 0000000010003800 0000000000466344
<4> 000000000e980900 00000000008848b0 000000000084e748 0000000000000000
<4> 000000000087b300 0000000000001237 0000000000001237 000000000f85bdd8
<4> 000000000e980920 00000000001137c0 0000000000464754 000000000f85bdd8
<4>Krnl Code: 0000000000466368: e3b0b0700004 lg %r11,112(%r11)
<4> 000000000046636e: 07fe bcr 15,%r14
<4> 0000000000466370: a7f40001 brc 15,466372
<4> >0000000000466374: a7f4fff6 brc 15,466360
<4> 0000000000466378: eb7ff0500024 stmg %r7,%r15,80(%r15)
<4> 000000000046637e: a7f13e00 tmll %r15,15872
<4> 0000000000466382: b90400ef lgr %r14,%r15
<4> 0000000000466386: a7840001 brc 8,466388
<4>Call Trace:
<4>([<000201500f85c000>] 0x201500f85c000)
<4> [<0000000000466556>] vring_interrupt+0x72/0x88
<4> [<00000000004801a0>] kvm_extint_handler+0x34/0x44
<4> [<000000000010d22c>] do_extint+0xbc/0xf8
<4> [<0000000000113f98>] ext_no_vtime+0x16/0x1a
<4> [<000000000010a182>] cpu_idle+0x216/0x238
<4>([<000000000010a162>] cpu_idle+0x1f6/0x238)
<4> [<0000000000568656>] rest_init+0xaa/0xb8
<4> [<000000000084ee2c>] start_kernel+0x3fc/0x490
<4> [<0000000000100020>] _stext+0x20/0x80
<4>
<4> <0>Kernel panic - not syncing: Fatal exception in interrupt
<4>
After looking at the code and the dump I think the following scenario
happened: Ifup was running on cpu2 and the interrupt arrived on cpu0.
Now virtnet_open on cpu 2 managed to execute napi_enable and disable_cb
but did not execute rx_schedule. Meanwhile on cpu 0 skb_recv_done was
called by vring_interrupt, executed netif_rx_schedule_prep, which
succeeded and therefore called disable_cb. This triggered the BUG_ON,
as interrupts were already disabled by cpu 2.
I think the proper solution is to make the call to disable_cb depend on
the atomic update of NAPI_STATE_SCHED by using netif_rx_schedule_prep
in the same way as skb_recv_done.
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Acked-by: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
2008-02-06 08:50:11 +01:00
* now . virtnet_poll wants re - enable the queue , so we disable here .
* We synchronize against interrupts via NAPI_STATE_SCHED */
if ( netif_rx_schedule_prep ( dev , & vi - > napi ) ) {
vi - > rvq - > vq_ops - > disable_cb ( vi - > rvq ) ;
__netif_rx_schedule ( dev , & vi - > napi ) ;
}
2007-10-22 11:03:37 +10:00
return 0 ;
}
static int virtnet_close ( struct net_device * dev )
{
struct virtnet_info * vi = netdev_priv ( dev ) ;
napi_disable ( & vi - > napi ) ;
return 0 ;
}
static int virtnet_probe ( struct virtio_device * vdev )
{
int err ;
struct net_device * dev ;
struct virtnet_info * vi ;
/* Allocate ourselves a network device with room for our info */
dev = alloc_etherdev ( sizeof ( struct virtnet_info ) ) ;
if ( ! dev )
return - ENOMEM ;
/* Set up network device as normal. */
dev - > open = virtnet_open ;
dev - > stop = virtnet_close ;
dev - > hard_start_xmit = start_xmit ;
dev - > features = NETIF_F_HIGHDMA ;
2008-02-29 16:24:50 +05:30
# ifdef CONFIG_NET_POLL_CONTROLLER
dev - > poll_controller = virtnet_netpoll ;
# endif
2007-10-22 11:03:37 +10:00
SET_NETDEV_DEV ( dev , & vdev - > dev ) ;
/* Do we support "hardware" checksums? */
2008-02-04 23:50:02 -05:00
if ( csum & & vdev - > config - > feature ( vdev , VIRTIO_NET_F_CSUM ) ) {
2007-10-22 11:03:37 +10:00
/* This opens up the world of extra features. */
dev - > features | = NETIF_F_HW_CSUM | NETIF_F_SG | NETIF_F_FRAGLIST ;
2008-02-04 23:50:02 -05:00
if ( gso & & vdev - > config - > feature ( vdev , VIRTIO_NET_F_GSO ) ) {
dev - > features | = NETIF_F_TSO | NETIF_F_UFO
| NETIF_F_TSO_ECN | NETIF_F_TSO6 ;
}
2007-10-22 11:03:37 +10:00
}
/* Configuration may specify what MAC to use. Otherwise random. */
2008-02-04 23:49:56 -05:00
if ( vdev - > config - > feature ( vdev , VIRTIO_NET_F_MAC ) ) {
vdev - > config - > get ( vdev ,
offsetof ( struct virtio_net_config , mac ) ,
dev - > dev_addr , dev - > addr_len ) ;
2007-10-22 11:03:37 +10:00
} else
random_ether_addr ( dev - > dev_addr ) ;
/* Set up our device-specific information */
vi = netdev_priv ( dev ) ;
2007-12-16 15:19:43 +02:00
netif_napi_add ( dev , & vi - > napi , virtnet_poll , napi_weight ) ;
2007-10-22 11:03:37 +10:00
vi - > dev = dev ;
vi - > vdev = vdev ;
2008-02-18 10:02:51 +01:00
vdev - > priv = vi ;
2007-10-22 11:03:37 +10:00
/* We expect two virtqueues, receive then send. */
2008-02-04 23:49:56 -05:00
vi - > rvq = vdev - > config - > find_vq ( vdev , 0 , skb_recv_done ) ;
2007-10-22 11:03:37 +10:00
if ( IS_ERR ( vi - > rvq ) ) {
err = PTR_ERR ( vi - > rvq ) ;
goto free ;
}
2008-02-04 23:49:56 -05:00
vi - > svq = vdev - > config - > find_vq ( vdev , 1 , skb_xmit_done ) ;
2007-10-22 11:03:37 +10:00
if ( IS_ERR ( vi - > svq ) ) {
err = PTR_ERR ( vi - > svq ) ;
goto free_recv ;
}
/* Initialize our empty receive and send queues. */
skb_queue_head_init ( & vi - > recv ) ;
skb_queue_head_init ( & vi - > send ) ;
err = register_netdev ( dev ) ;
if ( err ) {
pr_debug ( " virtio_net: registering device failed \n " ) ;
goto free_send ;
}
2008-02-04 23:50:02 -05:00
/* Last of all, set up some receive buffers. */
try_fill_recv ( vi ) ;
/* If we didn't even get one input buffer, we're useless. */
if ( vi - > num = = 0 ) {
err = - ENOMEM ;
goto unregister ;
}
2007-10-22 11:03:37 +10:00
pr_debug ( " virtnet: registered device %s \n " , dev - > name ) ;
return 0 ;
2008-02-04 23:50:02 -05:00
unregister :
unregister_netdev ( dev ) ;
2007-10-22 11:03:37 +10:00
free_send :
vdev - > config - > del_vq ( vi - > svq ) ;
free_recv :
vdev - > config - > del_vq ( vi - > rvq ) ;
free :
free_netdev ( dev ) ;
return err ;
}
static void virtnet_remove ( struct virtio_device * vdev )
{
2007-11-19 11:20:42 -05:00
struct virtnet_info * vi = vdev - > priv ;
2008-02-04 23:50:02 -05:00
struct sk_buff * skb ;
2008-02-04 23:50:03 -05:00
/* Stop all the virtqueues. */
vdev - > config - > reset ( vdev ) ;
2008-02-04 23:50:02 -05:00
/* Free our skbs in send and recv queues, if any. */
while ( ( skb = __skb_dequeue ( & vi - > recv ) ) ! = NULL ) {
kfree_skb ( skb ) ;
vi - > num - - ;
}
while ( ( skb = __skb_dequeue ( & vi - > send ) ) ! = NULL )
kfree_skb ( skb ) ;
BUG_ON ( vi - > num ! = 0 ) ;
2007-11-19 11:20:42 -05:00
vdev - > config - > del_vq ( vi - > svq ) ;
vdev - > config - > del_vq ( vi - > rvq ) ;
unregister_netdev ( vi - > dev ) ;
free_netdev ( vi - > dev ) ;
2007-10-22 11:03:37 +10:00
}
static struct virtio_device_id id_table [ ] = {
{ VIRTIO_ID_NET , VIRTIO_DEV_ANY_ID } ,
{ 0 } ,
} ;
static struct virtio_driver virtio_net = {
. driver . name = KBUILD_MODNAME ,
. driver . owner = THIS_MODULE ,
. id_table = id_table ,
. probe = virtnet_probe ,
. remove = __devexit_p ( virtnet_remove ) ,
} ;
static int __init init ( void )
{
return register_virtio_driver ( & virtio_net ) ;
}
static void __exit fini ( void )
{
unregister_virtio_driver ( & virtio_net ) ;
}
module_init ( init ) ;
module_exit ( fini ) ;
MODULE_DEVICE_TABLE ( virtio , id_table ) ;
MODULE_DESCRIPTION ( " Virtio network driver " ) ;
MODULE_LICENSE ( " GPL " ) ;