Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH] net: Fix sock freeing before sock_init_data() with __sk_free()
From: Jarek Poplawski @ 2009-08-31  7:07 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: David Miller, netdev
In-Reply-To: <4A9B72B1.2040908@gmail.com>

On Mon, Aug 31, 2009 at 08:50:25AM +0200, Eric Dumazet wrote:
> Jarek Poplawski a écrit :
> > On Mon, Aug 31, 2009 at 08:26:43AM +0200, Eric Dumazet wrote:
> >> Jarek Poplawski a écrit :
> >>> After recent changes sk_free() frees socks conditionally and depends
> >>> on sk_wmem_alloc beeing set e.g. in sock_init_data(). But in some
> >>> cases sk_free() is called earlier, usually after other alloc errors.
> >>> This patch fixes it by exporting and using __sk_free() directly.
> > ...
> >> Very nice catch Jarek, but dont you think it would be cleaner to make sure
> >> we can call sk_free() right after sk_alloc() instead, and not exporting
> >> __sk_free() ?
> >>
> >> ie initialize wmem_alloc in sk_alloc() instead of initializing it in 
> >> sock_init_data() ?
> >>
> > 
> > Most probably it should be better. But I meant this fix for -net and
> > didn't wan't to break too much... So, if you're sure it's OK feel free
> > to send your version. (Or it could be changed like this in the -next.)
> 
> Well, patch is yours, not mine, and I am confident it is OK.

Well, it's from you, and I guess you'll sign off too, but if you
think so...
 
Signed-off-by: Jarek Poplawski <jarkao2@gmail.com>

Thanks,
Jarek P.

> 
> We should check that no sk_alloc() user did a blind memset() or something
> strange like that, before calling sock_init_data() or sk_free()
> 
> diff --git a/net/core/sock.c b/net/core/sock.c
> index bbb25be..7633422 100644
> --- a/net/core/sock.c
> +++ b/net/core/sock.c
> @@ -1025,6 +1025,7 @@ struct sock *sk_alloc(struct net *net, int family, gfp_t priority,
>  		sk->sk_prot = sk->sk_prot_creator = prot;
>  		sock_lock_init(sk);
>  		sock_net_set(sk, get_net(net));
> +		atomic_set(&sk->sk_wmem_alloc, 1);
>  	}
>  
>  	return sk;
> @@ -1872,7 +1873,6 @@ void sock_init_data(struct socket *sock, struct sock *sk)
>  	 */
>  	smp_wmb();
>  	atomic_set(&sk->sk_refcnt, 1);
> -	atomic_set(&sk->sk_wmem_alloc, 1);
>  	atomic_set(&sk->sk_drops, 0);
>  }
>  EXPORT_SYMBOL(sock_init_data);
> 

^ permalink raw reply

* Re: [PATCH] net: Fix sock freeing before sock_init_data() with __sk_free()
From: Eric Dumazet @ 2009-08-31  7:18 UTC (permalink / raw)
  To: Jarek Poplawski; +Cc: David Miller, netdev
In-Reply-To: <20090831070733.GC5005@ff.dom.local>

Jarek Poplawski a écrit :
> On Mon, Aug 31, 2009 at 08:50:25AM +0200, Eric Dumazet wrote:
>> Jarek Poplawski a écrit :
>>> On Mon, Aug 31, 2009 at 08:26:43AM +0200, Eric Dumazet wrote:
>>>> Jarek Poplawski a écrit :
>>>>> After recent changes sk_free() frees socks conditionally and depends
>>>>> on sk_wmem_alloc beeing set e.g. in sock_init_data(). But in some
>>>>> cases sk_free() is called earlier, usually after other alloc errors.
>>>>> This patch fixes it by exporting and using __sk_free() directly.
>>> ...
>>>> Very nice catch Jarek, but dont you think it would be cleaner to make sure
>>>> we can call sk_free() right after sk_alloc() instead, and not exporting
>>>> __sk_free() ?
>>>>
>>>> ie initialize wmem_alloc in sk_alloc() instead of initializing it in 
>>>> sock_init_data() ?
>>>>
>>> Most probably it should be better. But I meant this fix for -net and
>>> didn't wan't to break too much... So, if you're sure it's OK feel free
>>> to send your version. (Or it could be changed like this in the -next.)
>> Well, patch is yours, not mine, and I am confident it is OK.
> 
> Well, it's from you, and I guess you'll sign off too, but if you
> think so...
>  
> Signed-off-by: Jarek Poplawski <jarkao2@gmail.com>
> 
> Thanks,
> Jarek P.
> 

Give me a few hours to review sk_alloc() call sites, test patch and officially submit it.

Thanks

^ permalink raw reply

* RE: [PATCH] net-next:can: add TI CAN (HECC) driver
From: Gole, Anant @ 2009-08-31  7:22 UTC (permalink / raw)
  To: Wolfgang Grandegger; +Cc: Linux Netdev List, Socketcan-core@lists.berlios.de
In-Reply-To: <4A98D36E.9070903@grandegger.com>


>-----Original Message-----
>From: Wolfgang Grandegger [mailto:wg@grandegger.com]
>Sent: Saturday, August 29, 2009 12:36 PM
>To: Gole, Anant
>Cc: Linux Netdev List; Socketcan-core@lists.berlios.de
>Subject: Re: [PATCH] net-next:can: add TI CAN (HECC) driver
>
>> TI HECC (High End CAN Controller) module is found on many TI devices. It
>has
>> 32 harwdare mailboxes with full implementation of CAN protocol version
>2.0B
>> and bus speeds up to 1Mbps. The module specifications are available at TI
>web
>> <http://www.ti.com>.
>>
>> This driver is tested on OMAP3517 EVM. Suspend/Resume not tested as yet.
>
>Nice driver, even using the NAPI interface. First some general comments.
>Please remove debugging code mainly useful for development, e.g. the
>CONFIG_DEBUG_FS block, many dev_info calls and special statistics
>counters. Also use dev_dbg for the remaining debug messages useful for
>the normal user, like state changes. More comments inline.

Ack on most comments you gave - some good bugs uncovered with this review. Thanks. I am answering those which I have some comment on.

[snip]

>
>> +#define HECC_MODULE_VERSION     "0.2"
>
>A version number is will usually not maintained. May drivers have it but
>it's never changed.

I understand but unless this is a strong objection I would like to keep it as it would be nice to update it when any major change happens.

[snip]

>> +
>> +/* CAN Bittiming constants as per HECC specs */
>> +static struct can_bittiming_const ti_hecc_bittiming_const = {
>> +       .name = DRV_NAME,
>> +       .tseg1_min = 1,
>> +       .tseg1_max = 16,
>> +       .tseg2_min = 1,
>
>Please check if tseg2_min is a valid value. Usually it's larger.
>
Yes I did. This controller allows tseg2_min = 1

[snip]
>
>> +       struct napi_struct napi;
>> +       struct net_device *ndev;
>> +       struct clk *clk;
>> +       void __iomem *base;
>> +       unsigned int scc_ram_offset;
>> +       unsigned int hecc_ram_offset;
>> +       unsigned int mbox_offset;
>> +       unsigned int int_line;
>> +       DECLARE_BITMAP(tx_free_mbx, TI_HECC_MAX_TX_MBOX);
>> +       spinlock_t tx_lock;
>
>Please document the spinlock tx_lock. What is it used for.

It is to protect the tx_free_mbx bitmap above - will document.

[snip]

>Right, automatic bus-off recovery should be disabled. To make that clear:
>
>           hecc_clear_bit(priv, HECC_CANMC, HECC_CANMC_ABO);

Since CANMC register is set to 0 and ABO bit is part of it I did not make this statement explicitly (it will be redundant). I will update the comment above to state that if it changes in future then enable auto bus off with that statement

[snip]

>> +
>> +static int ti_hecc_do_set_mode(struct net_device *ndev, enum can_mode
>mode)
>> +{
>> +       struct ti_hecc_priv *priv = netdev_priv(ndev);
>> +       int ret = 0;
>> +
>> +       switch (mode) {
>> +       case CAN_MODE_SLEEP:
>> +               dev_info(priv->ndev->dev.parent, "device going to
>sleep\n");
>> +               if (netif_running(ndev)) {
>> +                       netif_stop_queue(ndev);
>> +                       netif_device_detach(ndev);
>> +                       /* Put HECC in low power mode */
>> +                       hecc_set_bit(priv, HECC_CANMC, HECC_CANMC_PDR);
>> +               }
>> +               priv->can.state = CAN_STATE_SLEEPING;
>> +               break;
>
>Has sleeping been tested? Actually, we do not have an interface yet to
>enter sleep mode. Please remove. If there is a need for it, we should
>work togehter to refine the interface and to provide a solution.
>
No I have not yet tested sleep/suspend/resume. Will remove based upon response to CAN_MODE_STOP comment below

>> +       case CAN_MODE_STOP:
>> +               dev_info(priv->ndev->dev.parent, "device stopping\n");
>> +               ti_hecc_stop(ndev);
>> +               break;
>
>Only CAN_MODE_START is used by the CAN devicde interface for bus-off
>recovery.
>
I saw other drivers (like mscan) also have the code for sleep/stop. Agreed that I have not tested it as you mentioned that the CAN infrastructure does not call it right now. Do you want me to remove it?

[snip]

>> +
>> +       }
>> +       set_bit(mbxno, priv->tx_free_mbx);
>> +       spin_unlock_irqrestore(&priv->tx_lock, flags);
>
>Hm, I wonder how the driver ensures that packages go out in order. How
>does the CAN hardware schedule pending TX message objects? Vladislav
>posted a test programs recently to check message ordering. See:
>
>https://lists.berlios.de/pipermail/socketcan-core/2009-August/002871.html

TI HECC hardware has mailbox priority field and higher mailbox number will transmit if two mailboxes have same priority level. But the code does not use that feature as yet. Let me think of how I can ensure out of order issue.

[snip]
>> +
>> +       pending_pkts = hecc_read(priv, HECC_CANRMP);
>> +       while (pending_pkts && (num_pkts < quota)) {
>> +               mbxno = find_first_bit(&pending_pkts,
>HECC_MAX_MAILBOXES);
>
>Here I also wonder if the messages are handled in the correct order.

No I have not taken care of that. Let me look into the pkt handling to see how I can do it based upon hardware capability.

[snip]

>
>> +
>> +       ti_hecc_error(ndev, int_status, hecc_read(priv, HECC_CANES));
>
>Hm, you create an error frame for each interrupt!? What do you see with:
>
> # candump any,0:0,#FFFFFFFF
>
Good catch. I did not observe unnecessary error frames via candump (or I really missed them). But I will correct this anyway.

>> +
>> +       /* Handle Abort acknowledge interrupt */
>> +       if (int_status & HECC_CANGIF_AAIF) {
>> +               ack = hecc_read(priv, HECC_CANAA);
>> +               while (ack) {
>> +                       mbxno = find_first_bit(&ack, HECC_MAX_MAILBOXES);
>> +                       if (mbxno == HECC_MAX_MAILBOXES) {
>> +                               break;
>> +                       } else {
>> +                               clear_bit(mbxno, &ack);
>> +                               /* release echo pkt & update counters */
>> +                               hecc_set_bit(priv, HECC_CANAA, (1 <<
>mbxno));
>> +                               hecc_clear_bit(priv, HECC_CANME, (1 <<
>mbxno));
>> +                               /* FIXME: since net-next tree's dev.h
>does not
>> +                                * include can_free_echo_skb() doing
>equivalent
>> +                                * of can_free_echo_skb(ndev, mbxno);
>> +                                */
>> +                               if (priv->can.echo_skb[mbxno]) {
>> +                                       kfree_skb(priv-
>>can.echo_skb[mbxno]);
>> +                                       priv->can.echo_skb[mbxno] = NULL;
>> +                               }
>> +                               if (netif_queue_stopped(ndev))
>> +                                       netif_wake_queue(ndev);
>> +                               spin_lock_irqsave(&priv->tx_lock, flags);
>> +                               clear_bit(mbxno, priv->tx_free_mbx);
>> +                               spin_unlock_irqrestore(&priv->tx_lock,
>flags);
>> +                       }
>> +               }
>> +       }
>
>Can that interrupt happen? I have not found any code aborting messages.

It can happen only if a tx mailbox is told to abort. This interrupt is an ack for the same. I am not using the tx abort feature so will remove this.

[snip]
>> +       }
>> +
>> +       /* Open common can device */
>> +       err = open_candev(ndev);
>> +       if (err) {
>> +               dev_err(ndev->dev.parent, "open_candev() failed %08X\n",
>err);
>
>free_irq?

Good catch. Will fix it.

>
>> +               return err;
>> +       }
>> +
>
>Thanks for your contribution.
>
>Wolfgang.
>

Appreciate the review. I will send v2 of patch. Not sure still if the original patch reached the socketcan mailing list due to size.

--
Anant

^ permalink raw reply

* Re: [PATCH] net: Fix sock freeing before sock_init_data() with __sk_free()
From: Jarek Poplawski @ 2009-08-31  7:25 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: David Miller, netdev
In-Reply-To: <4A9B7956.40507@gmail.com>

On Mon, Aug 31, 2009 at 09:18:46AM +0200, Eric Dumazet wrote:
> Jarek Poplawski a écrit :
> > On Mon, Aug 31, 2009 at 08:50:25AM +0200, Eric Dumazet wrote:
...
> >> Well, patch is yours, not mine, and I am confident it is OK.
> > 
> > Well, it's from you, and I guess you'll sign off too, but if you
> > think so...
> >  
> > Signed-off-by: Jarek Poplawski <jarkao2@gmail.com>
> > 
> > Thanks,
> > Jarek P.
> > 
> 
> Give me a few hours to review sk_alloc() call sites, test patch and officially submit it.
> 
> Thanks

Hmm... but you're "confident it is OK"?! (You know, I could've risked
my life or something... ;-)

Jarek P.

^ permalink raw reply

* [patch, v2] IPVS: Add handling of incoming ICMPV6 messages
From: Simon Horman @ 2009-08-31  7:59 UTC (permalink / raw)
  To: lvs-devel, netdev; +Cc: David Miller, Julius Volz, Rob Gallagher

From: Julius Volz <julius.volz@gmail.com>

IPVS: Add handling of incoming ICMPV6 messages

Add handling of incoming ICMPv6 messages.
This follows the handling of IPv4 ICMP messages.

Amongst ther things this problem allows IPVS to behave sensibly
when an ICMPV6_PKT_TOOBIG message is received:

    This message is received when a realserver sends a packet >PMTU to the
    client. The hop on this path with insufficient MTU will generate an
    ICMPv6 Packet Too Big message back to the VIP. The LVS server receives
    this message, but the call to the function handling this has been
    missing. Thus, IPVS fails to forward the message to the real server,
    which then does not adjust the path MTU. This patch adds the missing
    call to ip_vs_in_icmp_v6() in ip_vs_in() to handle this situation.

    Thanks to Rob Gallagher from HEAnet for reporting this issue and for
    testing this patch in production (with direct routing mode).

[horms@verge.net.au: tweaked changelog]
Signed-off-by: Julius Volz <julius.volz@gmail.com>
Tested-by: Rob Gallagher <robert.gallagher@heanet.ie>
Signed-off-by: Simon Horman <horms@verge.net.au>

---
 net/netfilter/ipvs/ip_vs_core.c |   23 +++++++++++++++++------
 1 files changed, 17 insertions(+), 6 deletions(-)

Changelog
---------

* Fri, 24 Jul 2009 12:47:16 +1000
  Initial post to netdev

* Mon, 31 Aug 2009 17:53:40 +1000
  Tweaked commit message as per feedback

diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
index 8dddb17..5750800 100644
--- a/net/netfilter/ipvs/ip_vs_core.c
+++ b/net/netfilter/ipvs/ip_vs_core.c
@@ -1274,13 +1274,24 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb,
 		return NF_ACCEPT;
 	}
 
-	if (unlikely(iph.protocol == IPPROTO_ICMP)) {
-		int related, verdict = ip_vs_in_icmp(skb, &related, hooknum);
+#ifdef CONFIG_IP_VS_IPV6
+	if (af == AF_INET6) {
+		if (unlikely(iph.protocol == IPPROTO_ICMPV6)) {
+			int related, verdict = ip_vs_in_icmp_v6(skb, &related, hooknum);
 
-		if (related)
-			return verdict;
-		ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
-	}
+			if (related)
+				return verdict;
+			ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
+		}
+	} else
+#endif
+		if (unlikely(iph.protocol == IPPROTO_ICMP)) {
+			int related, verdict = ip_vs_in_icmp(skb, &related, hooknum);
+
+			if (related)
+				return verdict;
+			ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
+		}
 
 	/* Protocol supported? */
 	pp = ip_vs_proto_get(iph.protocol);
--
To unsubscribe from this list: send the line "unsubscribe lvs-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* Re: [PATCH] Re: iproute2 / tbf with large burst seems broken again
From: Denys Fedoryschenko @ 2009-08-31  8:03 UTC (permalink / raw)
  To: David Miller; +Cc: jarkao2, netdev
In-Reply-To: <20090830.223239.185830289.davem@davemloft.net>

On Monday 31 August 2009 08:32:39 David Miller wrote:
> From: Jarek Poplawski <jarkao2@gmail.com>
> Date: Mon, 31 Aug 2009 05:30:27 +0000
>
> > Actually, I think now, after 2.6.31, this patch might be a bit too
> > late. If people hit this problem they probably should've fixed it
> > until -next already, so let's forget about this patch until there are
> > more such reports.
>
> Ok.
>
> > Btw, I guess, Denys could submit some warnings into iproute's code
> > and/or documentation, as he proposed earlier.
>
> Yeah sounds like a good idea.
Sorry, just was busy with network overload on ramadan.
I will test now.


^ permalink raw reply

* Re: [PATCH] Re: iproute2 / tbf with large burst seems broken again
From: Denys Fedoryschenko @ 2009-08-31  8:18 UTC (permalink / raw)
  To: David Miller; +Cc: jarkao2, netdev
In-Reply-To: <20090830.223239.185830289.davem@davemloft.net>

On Monday 31 August 2009 08:32:39 David Miller wrote:
> From: Jarek Poplawski <jarkao2@gmail.com>
> Date: Mon, 31 Aug 2009 05:30:27 +0000
>
> > Actually, I think now, after 2.6.31, this patch might be a bit too
> > late. If people hit this problem they probably should've fixed it
> > until -next already, so let's forget about this patch until there are
> > more such reports.
>
> Ok.
>
> > Btw, I guess, Denys could submit some warnings into iproute's code
> > and/or documentation, as he proposed earlier.
>
> Yeah sounds like a good idea.

2.6.31-rc8 i got dmesg flooded. First message appearing even without patch, i 
will make sure now what is a reason of that (i have HTB classes on ifb0, and 
TBF on pppX).

[  155.199923] Attempt to kill tasklet from interrupt
[  158.425096] Attempt to kill tasklet from interrupt
[  158.425176] Attempt to kill tasklet from interrupt
[  162.549083] Attempt to kill tasklet from interrupt
[  162.549159] Attempt to kill tasklet from interrupt
[  162.601892] Attempt to kill tasklet from interrupt
[  162.601968] Attempt to kill tasklet from interrupt
[  183.719070] Attempt to kill tasklet from interrupt
[  183.719146] Attempt to kill tasklet from interrupt
[  192.147105] Attempt to kill tasklet from interrupt
[  192.147181] Attempt to kill tasklet from interrupt
[  192.604718] tbf: tokens overflow; fix limits.
[  193.085459] tbf: tokens overflow; fix limits.
[  193.102169] tbf: tokens overflow; fix limits.
[  194.100395] tbf: tokens overflow; fix limits.
[  196.010286] tbf: tokens overflow; fix limits.
[  196.014330] tbf: tokens overflow; fix limits.
[  196.100723] tbf: tokens overflow; fix limits.
[  196.104619] tbf: tokens overflow; fix limits.
[  196.998374] tbf: tokens overflow; fix limits.
[  197.854766] tbf: tokens overflow; fix limits.
[  198.676258] tbf: tokens overflow; fix limits.
[  198.676564] tbf: tokens overflow; fix limits.
[  198.984620] tbf: tokens overflow; fix limits.
[  199.599671] tbf: tokens overflow; fix limits.
[  200.101338] tbf: tokens overflow; fix limits.                                                                                                                                                          

^ permalink raw reply

* [PATCH] au1000_eth: possible NULL dereference of aup->mii_bus->irq in au1000_probe()
From: Roel Kluin @ 2009-08-31  8:40 UTC (permalink / raw)
  To: netdev, Andrew Morton, David S. Miller

aup->mii_bus->irq allocation may fail, prevent a dereference of NULL.

Signed-off-by: Roel Kluin <roel.kluin@gmail.com>
---
diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c
index d3c734f..02e4be0 100644
--- a/drivers/net/au1000_eth.c
+++ b/drivers/net/au1000_eth.c
@@ -1157,6 +1157,9 @@ static struct net_device * au1000_probe(int port_num)
 	aup->mii_bus->name = "au1000_eth_mii";
 	snprintf(aup->mii_bus->id, MII_BUS_ID_SIZE, "%x", aup->mac_id);
 	aup->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
+	if (aup->mii_bus->irq == NULL)
+		goto err_out;
+
 	for(i = 0; i < PHY_MAX_ADDR; ++i)
 		aup->mii_bus->irq[i] = PHY_POLL;
 

^ permalink raw reply related

* Re: [PATCH] Re: iproute2 / tbf with large burst seems broken again
From: David Miller @ 2009-08-31  8:37 UTC (permalink / raw)
  To: denys; +Cc: jarkao2, netdev
In-Reply-To: <200908311118.43024.denys@visp.net.lb>

From: Denys Fedoryschenko <denys@visp.net.lb>
Date: Mon, 31 Aug 2009 11:18:42 +0300

> 2.6.31-rc8 i got dmesg flooded. First message appearing even without patch, i 
> will make sure now what is a reason of that (i have HTB classes on ifb0, and 
> TBF on pppX).
> 
> [  155.199923] Attempt to kill tasklet from interrupt

We know the reasons for this message, it's an HTB regression and we're
working on it.

^ permalink raw reply

* Re: [PATCH] Re: iproute2 / tbf with large burst seems broken again
From: Jarek Poplawski @ 2009-08-31  8:49 UTC (permalink / raw)
  To: Denys Fedoryschenko; +Cc: David Miller, netdev
In-Reply-To: <200908311118.43024.denys@visp.net.lb>

On Mon, Aug 31, 2009 at 11:18:42AM +0300, Denys Fedoryschenko wrote:
> On Monday 31 August 2009 08:32:39 David Miller wrote:
> > From: Jarek Poplawski <jarkao2@gmail.com>
> > Date: Mon, 31 Aug 2009 05:30:27 +0000
> >
> > > Actually, I think now, after 2.6.31, this patch might be a bit too
> > > late. If people hit this problem they probably should've fixed it
> > > until -next already, so let's forget about this patch until there are
> > > more such reports.
> >
> > Ok.
> >
> > > Btw, I guess, Denys could submit some warnings into iproute's code
> > > and/or documentation, as he proposed earlier.
> >
> > Yeah sounds like a good idea.
> 
> 2.6.31-rc8 i got dmesg flooded. First message appearing even without patch, i 
> will make sure now what is a reason of that (i have HTB classes on ifb0, and 
> TBF on pppX).
> 
> [  155.199923] Attempt to kill tasklet from interrupt
> [  158.425096] Attempt to kill tasklet from interrupt
> [  158.425176] Attempt to kill tasklet from interrupt
> [  162.549083] Attempt to kill tasklet from interrupt
> [  162.549159] Attempt to kill tasklet from interrupt
> [  162.601892] Attempt to kill tasklet from interrupt
> [  162.601968] Attempt to kill tasklet from interrupt
> [  183.719070] Attempt to kill tasklet from interrupt
> [  183.719146] Attempt to kill tasklet from interrupt
> [  192.147105] Attempt to kill tasklet from interrupt
> [  192.147181] Attempt to kill tasklet from interrupt
> [  192.604718] tbf: tokens overflow; fix limits.
> [  193.085459] tbf: tokens overflow; fix limits.
> [  193.102169] tbf: tokens overflow; fix limits.
> [  194.100395] tbf: tokens overflow; fix limits.
> [  196.010286] tbf: tokens overflow; fix limits.
> [  196.014330] tbf: tokens overflow; fix limits.
> [  196.100723] tbf: tokens overflow; fix limits.
> [  196.104619] tbf: tokens overflow; fix limits.
> [  196.998374] tbf: tokens overflow; fix limits.
> [  197.854766] tbf: tokens overflow; fix limits.
> [  198.676258] tbf: tokens overflow; fix limits.
> [  198.676564] tbf: tokens overflow; fix limits.
> [  198.984620] tbf: tokens overflow; fix limits.
> [  199.599671] tbf: tokens overflow; fix limits.
> [  200.101338] tbf: tokens overflow; fix limits.                                                                                                                                                          

I guess it's with a very large (wrt. rate) tbf buffer setting?
Btw, of course testing it would be appreciated, but as I wrote
earlier we can probably wait with this patch for more reports.

Jarek P.

^ permalink raw reply

* Re: [PATCH resend] tracing/events: convert NAPI's tracepoint via TRACE_EVENT
From: Ingo Molnar @ 2009-08-31  8:49 UTC (permalink / raw)
  To: Xiao Guangrong
  Cc: David Miller, Neil Horman, Steven Rostedt, Frederic Weisbecker,
	Wei Yongjun, Netdev, LKML
In-Reply-To: <4A9B6AA7.5020508@cn.fujitsu.com>


* Xiao Guangrong <xiaoguangrong@cn.fujitsu.com> wrote:

> - Convert NAPI's tracepoint via TRACE_EVENT macro, the output information
>   like below:

I think as long as it does not touch tracing infrastructure (which 
your patches dont do in their current form) this should be 
done/merged via the networking tree.

[ There might be some small collisions in define_trace.h (because
  these tracepoints move from legacy to new-style TRACE_EVENT() 
  form) but that's OK. ]

	Ingo

^ permalink raw reply

* Re: [PATCH] Re: iproute2 / tbf with large burst seems broken again
From: Denys Fedoryschenko @ 2009-08-31  8:51 UTC (permalink / raw)
  To: David Miller; +Cc: jarkao2, netdev
In-Reply-To: <20090831.013738.127727614.davem@davemloft.net>

On Monday 31 August 2009 11:37:38 David Miller wrote:
> From: Denys Fedoryschenko <denys@visp.net.lb>
> Date: Mon, 31 Aug 2009 11:18:42 +0300
>
> > 2.6.31-rc8 i got dmesg flooded. First message appearing even without
> > patch, i will make sure now what is a reason of that (i have HTB classes
> > on ifb0, and TBF on pppX).
> >
> > [  155.199923] Attempt to kill tasklet from interrupt
>
> We know the reasons for this message, it's an HTB regression and we're
> working on it.

Well, those TBF warning seems works fine, i even found one missing shaper that 
was overflowing. Thanks to Jarek.
For now no false positives. Message is appearing only when real overflow 
happen.

^ permalink raw reply

* Re: [PATCH] Re: iproute2 / tbf with large burst seems broken again
From: Jarek Poplawski @ 2009-08-31  8:58 UTC (permalink / raw)
  To: David Miller; +Cc: denys, netdev
In-Reply-To: <20090831.013738.127727614.davem@davemloft.net>

On Mon, Aug 31, 2009 at 01:37:38AM -0700, David Miller wrote:
> From: Denys Fedoryschenko <denys@visp.net.lb>
> Date: Mon, 31 Aug 2009 11:18:42 +0300
> 
> > 2.6.31-rc8 i got dmesg flooded. First message appearing even without patch, i 
> > will make sure now what is a reason of that (i have HTB classes on ifb0, and 
> > TBF on pppX).
> > 
> > [  155.199923] Attempt to kill tasklet from interrupt
> 
> We know the reasons for this message, it's an HTB regression and we're
> working on it.

There is a few more than HTB. Btw, IMHO, we don't risk much (if at
all) if we revert this qdisc_watchdog change. There is still CBQ
problem, where we could probably reconsider Thomas Gleixner's first
attempt with additional locking and irq disabling as a temporary
solution?

Jarek P.

^ permalink raw reply

* Re: [PATCH] net-next:can: add TI CAN (HECC) driver
From: Wolfgang Grandegger @ 2009-08-31  8:59 UTC (permalink / raw)
  To: Gole, Anant; +Cc: Socketcan-core@lists.berlios.de, Linux Netdev List
In-Reply-To: <2A3DCF3DA181AD40BDE86A3150B27B6B02F6211427@dbde02.ent.ti.com>

Gole, Anant wrote:
>> -----Original Message-----
>> From: Wolfgang Grandegger [mailto:wg@grandegger.com]
>> Sent: Saturday, August 29, 2009 12:36 PM
>> To: Gole, Anant
>> Cc: Linux Netdev List; Socketcan-core@lists.berlios.de
>> Subject: Re: [PATCH] net-next:can: add TI CAN (HECC) driver
>>
>>> TI HECC (High End CAN Controller) module is found on many TI devices. It
>> has
>>> 32 harwdare mailboxes with full implementation of CAN protocol version
>> 2.0B
>>> and bus speeds up to 1Mbps. The module specifications are available at TI
>> web
>>> <http://www.ti.com>.
>>>
>>> This driver is tested on OMAP3517 EVM. Suspend/Resume not tested as yet.
>> Nice driver, even using the NAPI interface. First some general comments.
>> Please remove debugging code mainly useful for development, e.g. the
>> CONFIG_DEBUG_FS block, many dev_info calls and special statistics
>> counters. Also use dev_dbg for the remaining debug messages useful for
>> the normal user, like state changes. More comments inline.
> 
> Ack on most comments you gave - some good bugs uncovered with this review. Thanks. I am answering those which I have some comment on.
> 
> [snip]
> 
>>> +#define HECC_MODULE_VERSION     "0.2"
>> A version number is will usually not maintained. May drivers have it but
>> it's never changed.
> 
> I understand but unless this is a strong objection I would like to keep it as it would be nice to update it when any major change happens.

It's *not* a strong objection but I personally believe that git is doing
a much better job.

> [snip]
> 
>>> +
>>> +/* CAN Bittiming constants as per HECC specs */
>>> +static struct can_bittiming_const ti_hecc_bittiming_const = {
>>> +       .name = DRV_NAME,
>>> +       .tseg1_min = 1,
>>> +       .tseg1_max = 16,
>>> +       .tseg2_min = 1,
>> Please check if tseg2_min is a valid value. Usually it's larger.
>>
> Yes I did. This controller allows tseg2_min = 1

OK.
> 
> [snip]
>>> +       struct napi_struct napi;
>>> +       struct net_device *ndev;
>>> +       struct clk *clk;
>>> +       void __iomem *base;
>>> +       unsigned int scc_ram_offset;
>>> +       unsigned int hecc_ram_offset;
>>> +       unsigned int mbox_offset;
>>> +       unsigned int int_line;
>>> +       DECLARE_BITMAP(tx_free_mbx, TI_HECC_MAX_TX_MBOX);
>>> +       spinlock_t tx_lock;
>> Please document the spinlock tx_lock. What is it used for.
> 
> It is to protect the tx_free_mbx bitmap above - will document.

I know, but for kernel inclusion it should be documented.

> [snip]
> 
>> Right, automatic bus-off recovery should be disabled. To make that clear:
>>
>>           hecc_clear_bit(priv, HECC_CANMC, HECC_CANMC_ABO);
> 
> Since CANMC register is set to 0 and ABO bit is part of it I did not make this statement explicitly (it will be redundant). I will update the comment above to state that if it changes in future then enable auto bus off with that statement

OK.

> [snip]
> 
>>> +
>>> +static int ti_hecc_do_set_mode(struct net_device *ndev, enum can_mode
>> mode)
>>> +{
>>> +       struct ti_hecc_priv *priv = netdev_priv(ndev);
>>> +       int ret = 0;
>>> +
>>> +       switch (mode) {
>>> +       case CAN_MODE_SLEEP:
>>> +               dev_info(priv->ndev->dev.parent, "device going to
>> sleep\n");
>>> +               if (netif_running(ndev)) {
>>> +                       netif_stop_queue(ndev);
>>> +                       netif_device_detach(ndev);
>>> +                       /* Put HECC in low power mode */
>>> +                       hecc_set_bit(priv, HECC_CANMC, HECC_CANMC_PDR);
>>> +               }
>>> +               priv->can.state = CAN_STATE_SLEEPING;
>>> +               break;
>> Has sleeping been tested? Actually, we do not have an interface yet to
>> enter sleep mode. Please remove. If there is a need for it, we should
>> work togehter to refine the interface and to provide a solution.
>>
> No I have not yet tested sleep/suspend/resume. Will remove based upon response to CAN_MODE_STOP comment below
> 
>>> +       case CAN_MODE_STOP:
>>> +               dev_info(priv->ndev->dev.parent, "device stopping\n");
>>> +               ti_hecc_stop(ndev);
>>> +               break;
>> Only CAN_MODE_START is used by the CAN devicde interface for bus-off
>> recovery.
>>
> I saw other drivers (like mscan) also have the code for sleep/stop. Agreed that I have not tested it as you mentioned that the CAN infrastructure does not call it right now. Do you want me to remove it?

Yes, for kernel inclusion it should be removed. We are more relaxed to
keep that "preliminary" and "un-tested" code in the BerliOS SVN
repository. Note that the MSCAN driver is not yet mainline

> [snip]
> 
>>> +
>>> +       }
>>> +       set_bit(mbxno, priv->tx_free_mbx);
>>> +       spin_unlock_irqrestore(&priv->tx_lock, flags);
>> Hm, I wonder how the driver ensures that packages go out in order. How
>> does the CAN hardware schedule pending TX message objects? Vladislav
>> posted a test programs recently to check message ordering. See:
>>
>> https://lists.berlios.de/pipermail/socketcan-core/2009-August/002871.html
> 
> TI HECC hardware has mailbox priority field and higher mailbox number will transmit if two mailboxes have same priority level. But the code does not use that feature as yet. Let me think of how I can ensure out of order issue.

Have a look to the AT91 driver, it seems to be quite similar.

> [snip]
>>> +
>>> +       pending_pkts = hecc_read(priv, HECC_CANRMP);
>>> +       while (pending_pkts && (num_pkts < quota)) {
>>> +               mbxno = find_first_bit(&pending_pkts,
>> HECC_MAX_MAILBOXES);
>>
>> Here I also wonder if the messages are handled in the correct order.
> 
> No I have not taken care of that. Let me look into the pkt handling to see how I can do it based upon hardware capability.
> 
> [snip]
> 
>>> +
>>> +       ti_hecc_error(ndev, int_status, hecc_read(priv, HECC_CANES));
>> Hm, you create an error frame for each interrupt!? What do you see with:
>>
>> # candump any,0:0,#FFFFFFFF
>>
> Good catch. I did not observe unnecessary error frames via candump (or I really missed them). But I will correct this anyway.

I see. That's because the error code of can_id is 0 and the mask does
not trigger.

>>> +
>>> +       /* Handle Abort acknowledge interrupt */
>>> +       if (int_status & HECC_CANGIF_AAIF) {
>>> +               ack = hecc_read(priv, HECC_CANAA);
>>> +               while (ack) {
>>> +                       mbxno = find_first_bit(&ack, HECC_MAX_MAILBOXES);
>>> +                       if (mbxno == HECC_MAX_MAILBOXES) {
>>> +                               break;
>>> +                       } else {
>>> +                               clear_bit(mbxno, &ack);
>>> +                               /* release echo pkt & update counters */
>>> +                               hecc_set_bit(priv, HECC_CANAA, (1 <<
>> mbxno));
>>> +                               hecc_clear_bit(priv, HECC_CANME, (1 <<
>> mbxno));
>>> +                               /* FIXME: since net-next tree's dev.h
>> does not
>>> +                                * include can_free_echo_skb() doing
>> equivalent
>>> +                                * of can_free_echo_skb(ndev, mbxno);
>>> +                                */
>>> +                               if (priv->can.echo_skb[mbxno]) {
>>> +                                       kfree_skb(priv-
>>> can.echo_skb[mbxno]);
>>> +                                       priv->can.echo_skb[mbxno] = NULL;
>>> +                               }
>>> +                               if (netif_queue_stopped(ndev))
>>> +                                       netif_wake_queue(ndev);
>>> +                               spin_lock_irqsave(&priv->tx_lock, flags);
>>> +                               clear_bit(mbxno, priv->tx_free_mbx);
>>> +                               spin_unlock_irqrestore(&priv->tx_lock,
>> flags);
>>> +                       }
>>> +               }
>>> +       }
>> Can that interrupt happen? I have not found any code aborting messages.
> 
> It can happen only if a tx mailbox is told to abort. This interrupt is an ack for the same. I am not using the tx abort feature so will remove this.
> 
> [snip]
>>> +       }
>>> +
>>> +       /* Open common can device */
>>> +       err = open_candev(ndev);
>>> +       if (err) {
>>> +               dev_err(ndev->dev.parent, "open_candev() failed %08X\n",
>> err);
>>
>> free_irq?
> 
> Good catch. Will fix it.
> 
>>> +               return err;
>>> +       }
>>> +
>> Thanks for your contribution.
>>
>> Wolfgang.
>>
> 
> Appreciate the review. I will send v2 of patch. Not sure still if the original patch reached the socketcan mailing list due to size.

v2 will fit but I'm wondering who is moderating the ML. Oliver?

Wolfgang.

^ permalink raw reply

* Re: [PATCH] Re: iproute2 / tbf with large burst seems broken again
From: Jarek Poplawski @ 2009-08-31  9:05 UTC (permalink / raw)
  To: Denys Fedoryschenko; +Cc: David Miller, netdev
In-Reply-To: <200908311151.22607.denys@visp.net.lb>

On Mon, Aug 31, 2009 at 11:51:22AM +0300, Denys Fedoryschenko wrote:
> On Monday 31 August 2009 11:37:38 David Miller wrote:
> > From: Denys Fedoryschenko <denys@visp.net.lb>
> > Date: Mon, 31 Aug 2009 11:18:42 +0300
> >
> > > 2.6.31-rc8 i got dmesg flooded. First message appearing even without
> > > patch, i will make sure now what is a reason of that (i have HTB classes
> > > on ifb0, and TBF on pppX).
> > >
> > > [  155.199923] Attempt to kill tasklet from interrupt
> >
> > We know the reasons for this message, it's an HTB regression and we're
> > working on it.
> 
> Well, those TBF warning seems works fine, i even found one missing shaper that 
> was overflowing. Thanks to Jarek.
> For now no false positives. Message is appearing only when real overflow 
> happen.

I'm glad it helps. On the other hand, I doubt you'll have such configs
until 2.6.32 where this patch was intended. (It's a pity you didn't
report it a bit earlier.) So, let David decide...

Jarek P.

^ permalink raw reply

* [PATCH] net: sk_free() should be allowed right after sk_alloc()
From: Eric Dumazet @ 2009-08-31  9:15 UTC (permalink / raw)
  To: Jarek Poplawski, David Miller; +Cc: netdev
In-Reply-To: <4A9B7956.40507@gmail.com>

From: Jarek Poplawski <jarkao2@gmail.com>

After commit 2b85a34e911bf483c27cfdd124aeb1605145dc80
(net: No more expensive sock_hold()/sock_put() on each tx)
sk_free() frees socks conditionally and depends
on sk_wmem_alloc beeing set e.g. in sock_init_data(). But in some
cases sk_free() is called earlier, usually after other alloc errors.

Fix is to move sk_wmem_alloc initialization from sock_init_data()
to sk_alloc() itself.

Signed-off-by: Jarek Poplawski <jarkao2@gmail.com>
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
diff --git a/net/core/sock.c b/net/core/sock.c
index bbb25be..7633422 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1025,6 +1025,7 @@ struct sock *sk_alloc(struct net *net, int family, gfp_t priority,
 		sk->sk_prot = sk->sk_prot_creator = prot;
 		sock_lock_init(sk);
 		sock_net_set(sk, get_net(net));
+		atomic_set(&sk->sk_wmem_alloc, 1);
 	}
 
 	return sk;
@@ -1872,7 +1873,6 @@ void sock_init_data(struct socket *sock, struct sock *sk)
 	 */
 	smp_wmb();
 	atomic_set(&sk->sk_refcnt, 1);
-	atomic_set(&sk->sk_wmem_alloc, 1);
 	atomic_set(&sk->sk_drops, 0);
 }
 EXPORT_SYMBOL(sock_init_data);


^ permalink raw reply related

* Re: [PATCH] net: sk_free() should be allowed right after sk_alloc()
From: Jarek Poplawski @ 2009-08-31  9:30 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: David Miller, netdev
In-Reply-To: <4A9B94B8.4050808@gmail.com>

On Mon, Aug 31, 2009 at 11:15:36AM +0200, Eric Dumazet wrote:
> From: Jarek Poplawski <jarkao2@gmail.com>
> 
> After commit 2b85a34e911bf483c27cfdd124aeb1605145dc80
> (net: No more expensive sock_hold()/sock_put() on each tx)
> sk_free() frees socks conditionally and depends
> on sk_wmem_alloc beeing set e.g. in sock_init_data(). But in some

Very nice, but I hope David could fix btw. my "beeing" misspelling.

Thanks everyone,
Jarek P.

> cases sk_free() is called earlier, usually after other alloc errors.
> 
> Fix is to move sk_wmem_alloc initialization from sock_init_data()
> to sk_alloc() itself.
> 
> Signed-off-by: Jarek Poplawski <jarkao2@gmail.com>
> Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
> ---
> diff --git a/net/core/sock.c b/net/core/sock.c
> index bbb25be..7633422 100644
> --- a/net/core/sock.c
> +++ b/net/core/sock.c
> @@ -1025,6 +1025,7 @@ struct sock *sk_alloc(struct net *net, int family, gfp_t priority,
>  		sk->sk_prot = sk->sk_prot_creator = prot;
>  		sock_lock_init(sk);
>  		sock_net_set(sk, get_net(net));
> +		atomic_set(&sk->sk_wmem_alloc, 1);
>  	}
>  
>  	return sk;
> @@ -1872,7 +1873,6 @@ void sock_init_data(struct socket *sock, struct sock *sk)
>  	 */
>  	smp_wmb();
>  	atomic_set(&sk->sk_refcnt, 1);
> -	atomic_set(&sk->sk_wmem_alloc, 1);
>  	atomic_set(&sk->sk_drops, 0);
>  }
>  EXPORT_SYMBOL(sock_init_data);
> 

^ permalink raw reply

* Re: [PATCH 1/5] ucc_geth: Fix NULL pointer dereference in uec_get_ethtool_stats()
From: Benjamin Herrenschmidt @ 2009-08-31  9:35 UTC (permalink / raw)
  To: David Miller; +Cc: scottwood, netdev, timur, linuxppc-dev
In-Reply-To: <20090830.215224.203201252.davem@davemloft.net>

On Sun, 2009-08-30 at 21:52 -0700, David Miller wrote:
> All 5 patches applied to net-next-2.6
> 
> I would have liked to have seen at least one powerpc ACK for
> patch #2 but these were posted more than a week ago, the
> patch looks pretty reasonable, and we can't wait forever for
> stuff like this.

The qe stuff ? Well, that's entirely Kumar's domain, but Anton
patches tend to be of good quality so I wouldn't have too much
second thoughts here.

Cheers,
Ben.

^ permalink raw reply

* Re: [PATCH] sky2: Don't try to turn led off in sky2_down()
From: Rene Mayrhofer @ 2009-08-31  9:48 UTC (permalink / raw)
  To: Mike McCormack; +Cc: Stephen Hemminger, netdev, Richard Leitner
In-Reply-To: <4A9928C9.7000907@ring3k.org>

Hi Mika and Stephen,

Am Samstag, 29. August 2009 15:10:33 schrieb Mike McCormack:
> There are a few problems with the following line of code in sky2_down()
>
>      sky2_write16(hw, B0_Y2LED, LED_STAT_OFF);
>
>  * It doesn't specify which port's LED to turn off.
>  * We don't turn send LED_STAT_ON on in sky2_up()
>  * B0_LED is 0x0006 in the vendor driver, but 0x0005 in sky2.
>    B0_LED is right next to B0_POWER_CTRL, so this is possibly
>    accounts for the device being accidently powered down as
>    reported by Rene Mayrhofer.
>
> Signed-off-by: Mike McCormack <mikem@ring3k.org>

I tried the current net-next version with this patch, and a network restart 
still leads to a system reset. Is this patch aimed at net-next or the vanilla 
2.6.30.5 version?

I assume the updated 2 patches would not make any difference, right?

best regards,
Rene

-- 
-------------------------------------------------
Gibraltar firewall       http://www.gibraltar.at/

^ permalink raw reply

* Re: [PATCH] sky2: Don't try to turn led off in sky2_down()
From: Rene Mayrhofer @ 2009-08-31  9:58 UTC (permalink / raw)
  To: Mike McCormack; +Cc: Stephen Hemminger, netdev, Richard Leitner
In-Reply-To: <4A9928C9.7000907@ring3k.org>

Am Samstag, 29. August 2009 15:10:33 schrieb Mike McCormack:
> There are a few problems with the following line of code in sky2_down()
>
>      sky2_write16(hw, B0_Y2LED, LED_STAT_OFF);
>
>  * It doesn't specify which port's LED to turn off.
>  * We don't turn send LED_STAT_ON on in sky2_up()
>  * B0_LED is 0x0006 in the vendor driver, but 0x0005 in sky2.
>    B0_LED is right next to B0_POWER_CTRL, so this is possibly
>    accounts for the device being accidently powered down as
>    reported by Rene Mayrhofer.

With this patch applied to the net-next version from Friday, I now got this:

[~]# /etc/init.d/networking restart
Reconfiguring network interfaces...[  403.000092] sky2 0000:03:00.0: error 
interrupt status=0xffffffff
[  403.006905] sky2 0000:03:00.0: PCI hardware error (0xffff)                                         
[  403.013095] sky2 0000:03:00.0: PCI Express error (0xffffffff)                                      
[  403.019586] sky2 dmz: ram data read parity error                                                   
[  403.024814] sky2 dmz: ram data write parity error                                                  
[  403.030130] sky2 dmz: MAC parity error                                                             
[  403.034392] sky2 dmz: RX parity error                                                              
[  403.038560] sky2 dmz: TCP segmentation error                                                       
[  403.043531] BUG: unable to handle kernel NULL pointer dereference at 
0000038d                      
[  403.047392] IP: [<f8078ce0>] sky2_mac_intr+0x30/0xc1 [sky2]                                        
[  403.047392] *pde = 00000000                                                                        
[  403.047392] Thread overran stack, or stack corrupted                                               
[  403.047392] Oops: 0000 [#1] PREEMPT SMP                                                            
[  403.047392] last sysfs file: 
/sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed                 
[  403.047392] Modules linked in: xt_multiport cpufreq_userspace ip6t_REJECT 
xt_DSCP xt_length xt_mark xt_dscp xt_MARK xt_IMQ xt_CONNMARK xt_comment 
xt_policy ip6t_LOG xt_tcpudp ip6table_mangle iptable_mangle ip6table_filter 
ip6_tables sit tunnel4 8021q garp stp llc ipt_LOG xt_limit xt_state 
iptable_nat iptable_filter ip_tables x_tables dm_mod lm90 led_class p4_clockmod 
speedstep_lib freq_table tun imq nf_nat_ftp nf_nat nf_conntrack_ftp 
nf_conntrack_ipv6 nf_conntrack_ipv4 nf_conntrack nf_defrag_ipv4 ipv6 evdev 
iTCO_wdt parport_pc parport i2c_i801 i2c_core serio_raw rng_core button 
processor intel_agp pcspkr squashfs loop aufs exportfs nls_utf8 nls_cp437 
ide_generic sd_mod ata_generic pata_acpi ata_piix ide_pci_generic ide_core 
skge sky2 thermal fan thermal_sys                                  
[  403.047392]                                                                                                                        
[  403.047392] Pid: 0, comm: swapper Not tainted (2.6.30.5 #20)                                                                       
[  403.047392] EIP: 0060:[<f8078ce0>] EFLAGS: 00010286 CPU: 0                                                                         
[  403.047392] EIP is at sky2_mac_intr+0x30/0xc1 [sky2]                                                                               
[  403.047392] EAX: f8098f88 EBX: 00000001 ECX: 00000008 EDX: 000000ff                                                                
[  403.047392] ESI: 00000000 EDI: f68f5080 EBP: c1c8de3c ESP: c1c8de24                                                                
[  403.191036]  DS: 0068 ES: 0068 FS: 00d8 GS: 00e0 SS: 0068                                                                          
[  403.191036] Process swapper (pid: 0, ti=c1c8c000 task=c1c3f1d4 
task.ti=c1c8c000)                                                   
[  403.202984] Stack:                                                                                                                 
[  403.202984]  00000080 ff8f5080 4aa8b206 f70e54c0 ffffffff ffffffff c1c8deb0 f807c33b                                               
[  403.202984]  00000000 c1c8dea4 00000040 f68f5088 c184526c 00000000 f68f5080 
ffffffff                                               
[  403.202984]  00000001 f7224400 c2523140 00006497 00000001 00000000 4aa8b206 
c25229c8                                               
[  403.202984] Call Trace:                                                                                                            
[  403.202984]  [<f807c33b>] ? sky2_poll+0x1d2/0xa07 [sky2]                                                                           
[  403.202984]  [<c184526c>] ? insert_work+0xa5/0xbf                                                                                  
[  403.202984]  [<c1af8f7f>] ? _spin_unlock_irq+0x2f/0x42                                                                             
[  403.202984]  [<c1a6ebc5>] ? net_rx_action+0x9e/0x1ae                                                                               
[  403.202984]  [<c1838e5e>] ? __do_softirq+0xb2/0x188                                                                                
[  403.202984]  [<c1838f73>] ? do_softirq+0x3f/0x5c                                                                                   
[  403.202984]  [<c18390fd>] ? irq_exit+0x37/0x80                                                                                     
[  403.202984]  [<c18146fa>] ? smp_apic_timer_interrupt+0x7c/0x9b                                                                     
[  403.202984]  [<c1803a31>] ? apic_timer_interrupt+0x31/0x40                                                                         
[  403.202984]  [<c1840068>] ? complete_signal+0x97/0x1ac                                                                             
[  403.202984]  [<c180a262>] ? mwait_idle+0xad/0x116                                                                                  
[  403.202984]  [<c1801e2f>] ? cpu_idle+0x96/0xc3                                                                                     
[  403.202984]  [<c1ae6629>] ? rest_init+0x75/0x88                                                                                    
[  403.202984]  [<c102aa10>] ? start_kernel+0x32d/0x343                                                                               
[  403.202984]  [<c102a072>] ? _sinittext+0x72/0x88                                                                                   
[  403.323244] Code: c7 56 53 89 d3 83 ec 0c 65 a1 14 00 00 00 89 45 f0 31 c0 
8b 74 97 3c c1 e2 07 89 d0 05 08 0f 00 00 89 55 e8 03 07 8a 10 88 55 ef <f6> 
86 8d 03 00 00 02 74 12 0f b6 c2 50 56 68 74 e3 07 f8 e8 e2                                                      
[  403.323244] EIP: [<f8078ce0>] sky2_mac_intr+0x30/0xc1 [sky2] SS:ESP 
0068:c1c8de24                                                  
[  403.323244] CR2: 000000000000038d                                                                                                  
[  403.365775] ---[ end trace 7f4d83bf1130e18d ]---                                                                                   
[  403.370999] Kernel panic - not syncing: Fatal exception in interrupt                                                               
[  403.378154] Pid: 0, comm: swapper Tainted: G      D    2.6.30.5 #20                                                                
[  403.385185] Call Trace:                                                                                                            
[  403.388006]  [<c1af5bf7>] ? printk+0x1d/0x30                                                                                       
[  403.392861]  [<c1af5b35>] panic+0x53/0xf8                                                                                          
[  403.397404]  [<c1806787>] oops_end+0x9f/0xbf                                                                                       
[  403.402234]  [<c181d7ef>] no_context+0x15d/0x178                                                                                   
[  403.407443]  [<c181db53>] __bad_area_nosemaphore+0x349/0x362                                                                       
[  403.413797]  [<c197afed>] ? vsnprintf+0x2de/0x332                                                                                  
[  403.419104]  [<c197ada0>] ? vsnprintf+0x91/0x332                                                                                   
[  403.424312]  [<c1af8fc3>] ? _spin_unlock_irqrestore+0x31/0x44                                                                      
[  403.430773]  [<c1af8fc3>] ? _spin_unlock_irqrestore+0x31/0x44                                                                      
[  403.437280]  [<c18340f7>] ? release_console_sem+0x18b/0x1c9                                                                        
[  403.443583]  [<c181db89>] bad_area_nosemaphore+0x1d/0x34                                                                           
[  403.449590]  [<c181de56>] do_page_fault+0x10d/0x24b
[  403.455119]  [<c181dd49>] ? do_page_fault+0x0/0x24b
[  403.460654]  [<c1af945d>] error_code+0x7d/0x90
[  403.465759]  [<c1970068>] ? blk_alloc_devt+0x59/0xb9
[  403.471421]  [<f8078ce0>] ? sky2_mac_intr+0x30/0xc1 [sky2]
[  403.477684]  [<f807c33b>] sky2_poll+0x1d2/0xa07 [sky2]
[  403.483502]  [<c184526c>] ? insert_work+0xa5/0xbf
[  403.488843]  [<c1af8f7f>] ? _spin_unlock_irq+0x2f/0x42
[  403.494664]  [<c1a6ebc5>] net_rx_action+0x9e/0x1ae
[  403.500102]  [<c1838e5e>] __do_softirq+0xb2/0x188

Message from[  403.505490]  [<c1838f73>] do_softirq+0x3f/0x5c
 syslogd@gibralt[  403.511881]  [<c18390fd>] irq_exit+0x37/0x80
ar3-esys-master [  403.518089]  [<c18146fa>] 
smp_apic_timer_interrupt+0x7c/0x9b
at Aug 31 11:56:[  403.525829]  [<c1803a31>] apic_timer_interrupt+0x31/0x40
58 ...
 kernel[  403.533177]  [<c1840068>] ? complete_signal+0x97/0x1ac
:[  403.047392] [  403.540336]  [<c180a262>] ? mwait_idle+0xad/0x116
Oops: 0000 [#1] [  403.547010]  [<c1801e2f>] cpu_idle+0x96/0xc3
PREEMPT SMP
[  403.553229]  [<c1ae6629>] rest_init+0x75/0x88

Message from [  403.559515]  [<c102aa10>] start_kernel+0x32d/0x343
syslogd@gibralta[  403.566324]  [<c102a072>] _sinittext+0x72/0x88
r3-esys-master a[  403.572752] Rebooting in 30 seconds..

Potentially the last system reset was similar but just didn't print the stack 
trace for some reason (that is, on the previous reboot with the very same 
sky2.ko loaded, the system just hard-locked and rebooted itself after 30s 
without printing anything to the serial console).

best regards,
Rene

-- 
-------------------------------------------------
Gibraltar firewall       http://www.gibraltar.at/

^ permalink raw reply

* Re: [PATCH] net-next:can: add TI CAN (HECC) driver
From: Oliver Hartkopp @ 2009-08-31 10:29 UTC (permalink / raw)
  To: Wolfgang Grandegger, Jan Kiszka
  Cc: Gole, Anant, Socketcan-core@lists.berlios.de, Linux Netdev List
In-Reply-To: <4A9B90FD.3000301@grandegger.com>

Wolfgang Grandegger wrote:
> Gole, Anant wrote:


>>>
>> Appreciate the review. I will send v2 of patch. Not sure still if the original patch reached the socketcan mailing list due to size.
> 
> v2 will fit but I'm wondering who is moderating the ML. Oliver?
> 

No. SocketCAN Core is Jan Kiszka.

Jan, can you increase the message size in the SocketCAN-core-ML settings to 150kB?

Regards,
Oliver


^ permalink raw reply

* Re: [PATCH resend] drop_monitor: fix trace_napi_poll_hit()
From: Neil Horman @ 2009-08-31 11:12 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: Xiao Guangrong, David Miller, Wei Yongjun, Netdev, LKML
In-Reply-To: <4A9B6E57.7090703@gmail.com>

On Mon, Aug 31, 2009 at 08:31:51AM +0200, Eric Dumazet wrote:
> Xiao Guangrong a écrit :
> > The net_dev of backlog napi is NULL, like below:
> > 
> > __get_cpu_var(softnet_data).backlog.dev == NULL
> > 
> > So, we should check it in napi tracepoint's probe function
> > 
> > Acked-by: Neil Horman <nhorman@tuxdriver.com>
> > Signed-off-by: Xiao Guangrong <xiaoguangrong@cn.fujitsu.com>
> > ---
> >  net/core/drop_monitor.c |    3 ++-
> >  1 files changed, 2 insertions(+), 1 deletions(-)
> > 
> > diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c
> > index 9d66fa9..d311202 100644
> > --- a/net/core/drop_monitor.c
> > +++ b/net/core/drop_monitor.c
> > @@ -182,7 +182,8 @@ static void trace_napi_poll_hit(struct napi_struct *napi)
> >  	/*
> >  	 * Ratelimit our check time to dm_hw_check_delta jiffies
> >  	 */
> > -	if (!time_after(jiffies, napi->dev->last_rx + dm_hw_check_delta))
> > +	if (!napi->dev ||
> > +	    !time_after(jiffies, napi->dev->last_rx + dm_hw_check_delta))
> >  		return;
> >  
> >  	rcu_read_lock();
> 
> 
> This reminds me dev->last_rx is not anymore updated, unless special conditions
> are met.
> 
I still see a large number of drivers that update dev->last_rx, although its
not all as I look through the list, so something definately seems amiss.

If its not going to be consistently updated, why are still carrying that field
in dev?  Are we just waiting on someone to do the janitorial work to remove it?
If so, I can, and I'll fix up the drop monitor in the process, to use a private
timestamp.

Neil

> Test done in trace_napi_poll_hit() is probably not good, even with a non null napi->dev
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

^ permalink raw reply

* Re: [PATCH] net-next:can: add TI CAN (HECC) driver
From: Jan Kiszka @ 2009-08-31 10:43 UTC (permalink / raw)
  To: Oliver Hartkopp
  Cc: Wolfgang Grandegger, Gole, Anant, Socketcan-core@lists.berlios.de,
	Linux Netdev List
In-Reply-To: <4A9BA611.80505@hartkopp.net>

Oliver Hartkopp wrote:
> Wolfgang Grandegger wrote:
>> Gole, Anant wrote:
> 
> 
>>> Appreciate the review. I will send v2 of patch. Not sure still if the original patch reached the socketcan mailing list due to size.
>> v2 will fit but I'm wondering who is moderating the ML. Oliver?
>>
> 
> No. SocketCAN Core is Jan Kiszka.
> 
> Jan, can you increase the message size in the SocketCAN-core-ML settings to 150kB?

Done.

Jan

-- 
Siemens AG, Corporate Technology, CT SE 2
Corporate Competence Center Embedded Linux

^ permalink raw reply

* Re: [PATCH 1/2] lsm: Add hooks to the TUN driver
From: James Morris @ 2009-08-31 11:42 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, linux-security-module, selinux
In-Reply-To: <20090828.154636.192870325.davem@davemloft.net>

On Fri, 28 Aug 2009, David Miller wrote:

> I'm happy if you guys merge this via the security tree,
> feel free to add:
> 
> Acked-by: David S. Miller <davem@davemloft.net>

Thanks, I'll merge it via my tree.

-- 
James Morris
<jmorris@namei.org>

^ permalink raw reply

* RE: [PATCHv5 3/3] vhost_net: a kernel-level virtio server
From: Xin, Xiaohui @ 2009-08-31 11:42 UTC (permalink / raw)
  To: mst@redhat.com, netdev@vger.kernel.org,
	virtualization@lists.linux-foundation.org, "kvm@v
In-Reply-To: <E88DD564E9DC5446A76B2B47C3BCCA150219600F9B@pdsmsx503.ccr.corp.intel.com>

Hi, Michael
That's a great job. We are now working on support VMDq on KVM, and since the VMDq hardware presents L2 sorting based on MAC addresses and VLAN tags, our target is to implement a zero copy solution using VMDq. We stared from the virtio-net architecture. What we want to proposal is to use AIO combined with direct I/O:
1) Modify virtio-net Backend service in Qemu to submit aio requests composed from virtqueue.
2) Modify TUN/TAP device to support aio operations and the user space buffer directly mapping into the host kernel.
3) Let a TUN/TAP device binds to single rx/tx queue from the NIC.
4) Modify the net_dev and skb structure to permit allocated skb to use user space directly mapped payload buffer address rather then kernel allocated.

As zero copy is also your goal, we are interested in what's in your mind, and would like to collaborate with you if possible.
BTW, we will send our VMDq write-up very soon.

Thanks
Xiaohui

-----Original Message-----
From: kvm-owner@vger.kernel.org [mailto:kvm-owner@vger.kernel.org] On Behalf Of Michael S. Tsirkin
Sent: Wednesday, August 19, 2009 11:03 PM
To: netdev@vger.kernel.org; virtualization@lists.linux-foundation.org; kvm@vger.kernel.org; linux-kernel@vger.kernel.org; mingo@elte.hu; linux-mm@kvack.org; akpm@linux-foundation.org; hpa@zytor.com; gregory.haskins@gmail.com
Subject: [PATCHv4 2/2] vhost_net: a kernel-level virtio server

What it is: vhost net is a character device that can be used to reduce
the number of system calls involved in virtio networking.
Existing virtio net code is used in the guest without modification.

There's similarity with vringfd, with some differences and reduced scope
- uses eventfd for signalling
- structures can be moved around in memory at any time (good for migration)
- support memory table and not just an offset (needed for kvm)

common virtio related code has been put in a separate file vhost.c and
can be made into a separate module if/when more backends appear.  I used
Rusty's lguest.c as the source for developing this part : this supplied
me with witty comments I wouldn't be able to write myself.

What it is not: vhost net is not a bus, and not a generic new system
call. No assumptions are made on how guest performs hypercalls.
Userspace hypervisors are supported as well as kvm.

How it works: Basically, we connect virtio frontend (configured by
userspace) to a backend. The backend could be a network device, or a
tun-like device. In this version I only support raw socket as a backend,
which can be bound to e.g. SR IOV, or to macvlan device.  Backend is
also configured by userspace, including vlan/mac etc.

Status:
This works for me, and I haven't see any crashes.
I have not run any benchmarks yet, compared to userspace, I expect to
see improved latency (as I save up to 4 system calls per packet) but not
bandwidth/CPU (as TSO and interrupt mitigation are not supported).

Features that I plan to look at in the future:
- TSO
- interrupt mitigation
- zero copy

Acked-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
 MAINTAINERS                |   10 +
 arch/x86/kvm/Kconfig       |    1 +
 drivers/Makefile           |    1 +
 drivers/vhost/Kconfig      |   11 +
 drivers/vhost/Makefile     |    2 +
 drivers/vhost/net.c        |  429 ++++++++++++++++++++++++++++
 drivers/vhost/vhost.c      |  664 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/vhost/vhost.h      |  108 +++++++
 include/linux/Kbuild       |    1 +
 include/linux/miscdevice.h |    1 +
 include/linux/vhost.h      |  100 +++++++
 11 files changed, 1328 insertions(+), 0 deletions(-)
 create mode 100644 drivers/vhost/Kconfig
 create mode 100644 drivers/vhost/Makefile
 create mode 100644 drivers/vhost/net.c
 create mode 100644 drivers/vhost/vhost.c
 create mode 100644 drivers/vhost/vhost.h
 create mode 100644 include/linux/vhost.h

diff --git a/MAINTAINERS b/MAINTAINERS
index b1114cf..de4587f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5431,6 +5431,16 @@ S:       Maintained
 F:     Documentation/filesystems/vfat.txt
 F:     fs/fat/

+VIRTIO HOST (VHOST)
+P:     Michael S. Tsirkin
+M:     mst@redhat.com
+L:     kvm@vger.kernel.org
+L:     virtualization@lists.osdl.org
+L:     netdev@vger.kernel.org
+S:     Maintained
+F:     drivers/vhost/
+F:     include/linux/vhost.h
+
 VIA RHINE NETWORK DRIVER
 M:     Roger Luethi <rl@hellgate.ch>
 S:     Maintained
diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig
index b84e571..94f44d9 100644
--- a/arch/x86/kvm/Kconfig
+++ b/arch/x86/kvm/Kconfig
@@ -64,6 +64,7 @@ config KVM_AMD

 # OK, it's a little counter-intuitive to do this, but it puts it neatly under
 # the virtualization menu.
+source drivers/vhost/Kconfig
 source drivers/lguest/Kconfig
 source drivers/virtio/Kconfig

diff --git a/drivers/Makefile b/drivers/Makefile
index bc4205d..1551ae1 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -105,6 +105,7 @@ obj-$(CONFIG_HID)           += hid/
 obj-$(CONFIG_PPC_PS3)          += ps3/
 obj-$(CONFIG_OF)               += of/
 obj-$(CONFIG_SSB)              += ssb/
+obj-$(CONFIG_VHOST_NET)                += vhost/
 obj-$(CONFIG_VIRTIO)           += virtio/
 obj-$(CONFIG_VLYNQ)            += vlynq/
 obj-$(CONFIG_STAGING)          += staging/
diff --git a/drivers/vhost/Kconfig b/drivers/vhost/Kconfig
new file mode 100644
index 0000000..d955406
--- /dev/null
+++ b/drivers/vhost/Kconfig
@@ -0,0 +1,11 @@
+config VHOST_NET
+       tristate "Host kernel accelerator for virtio net"
+       depends on NET && EVENTFD
+       ---help---
+         This kernel module can be loaded in host kernel to accelerate
+         guest networking with virtio_net. Not to be confused with virtio_net
+         module itself which needs to be loaded in guest kernel.
+
+         To compile this driver as a module, choose M here: the module will
+         be called vhost_net.
+
diff --git a/drivers/vhost/Makefile b/drivers/vhost/Makefile
new file mode 100644
index 0000000..72dd020
--- /dev/null
+++ b/drivers/vhost/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_VHOST_NET) += vhost_net.o
+vhost_net-y := vhost.o net.o
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
new file mode 100644
index 0000000..64d0c13
--- /dev/null
+++ b/drivers/vhost/net.c
@@ -0,0 +1,429 @@
+/* Copyright (C) 2009 Red Hat, Inc.
+ * Author: Michael S. Tsirkin <mst@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ *
+ * virtio-net server in host kernel.
+ */
+
+#include <linux/compat.h>
+#include <linux/eventfd.h>
+#include <linux/vhost.h>
+#include <linux/virtio_net.h>
+#include <linux/mmu_context.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/rcupdate.h>
+#include <linux/file.h>
+
+#include <linux/net.h>
+#include <linux/if_packet.h>
+#include <linux/if_arp.h>
+
+#include <net/sock.h>
+
+#include "vhost.h"
+
+enum {
+       VHOST_NET_VQ_RX = 0,
+       VHOST_NET_VQ_TX = 1,
+       VHOST_NET_VQ_MAX = 2,
+};
+
+struct vhost_net {
+       struct vhost_dev dev;
+       struct vhost_virtqueue vqs[VHOST_NET_VQ_MAX];
+       /* We use a kind of RCU to access sock pointer.
+        * All readers access it from workqueue, which makes it possible to
+        * flush the workqueue instead of synchronize_rcu. Therefore readers do
+        * not need to call rcu_read_lock/rcu_read_unlock: the beginning of
+        * work item execution acts instead of rcu_read_lock() and the end of
+        * work item execution acts instead of rcu_read_lock().
+        * Writers use device mutex. */
+       struct socket *sock;
+       struct vhost_poll poll[VHOST_NET_VQ_MAX];
+};
+
+/* Expects to be always run from workqueue - which acts as
+ * read-size critical section for our kind of RCU. */
+static void handle_tx(struct vhost_net *net)
+{
+       struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_TX];
+       unsigned head, out, in;
+       struct msghdr msg = {
+               .msg_name = NULL,
+               .msg_namelen = 0,
+               .msg_control = NULL,
+               .msg_controllen = 0,
+               .msg_iov = (struct iovec *)vq->iov + 1,
+               .msg_flags = MSG_DONTWAIT,
+       };
+       size_t len;
+       int err;
+       struct socket *sock = rcu_dereference(net->sock);
+       if (!sock || !sock_writeable(sock->sk))
+               return;
+
+       use_mm(net->dev.mm);
+       mutex_lock(&vq->mutex);
+       for (;;) {
+               head = vhost_get_vq_desc(&net->dev, vq, vq->iov, &out, &in);
+               /* Nothing new?  Wait for eventfd to tell us they refilled. */
+               if (head == vq->num)
+                       break;
+               if (out <= 1 || in) {
+                       vq_err(vq, "Unexpected descriptor format for TX: "
+                              "out %d, int %d\n", out, in);
+                       break;
+               }
+               /* Sanity check */
+               if (vq->iov->iov_len != sizeof(struct virtio_net_hdr)) {
+                       vq_err(vq, "Unexpected header len for TX: "
+                              "%ld expected %zd\n", vq->iov->iov_len,
+                              sizeof(struct virtio_net_hdr));
+                       break;
+               }
+               /* Skip header. TODO: support TSO. */
+               msg.msg_iovlen = out - 1;
+               len = iov_length(vq->iov + 1, out - 1);
+               /* TODO: Check specific error and bomb out unless ENOBUFS? */
+               err = sock->ops->sendmsg(NULL, sock, &msg, len);
+               if (err < 0) {
+                       vhost_discard_vq_desc(vq);
+                       break;
+               }
+               if (err != len)
+                       pr_err("Truncated TX packet: "
+                              " len %d != %zd\n", err, len);
+               vhost_add_used_and_trigger(vq, head,
+                                    len + sizeof(struct virtio_net_hdr));
+       }
+
+       mutex_unlock(&vq->mutex);
+       unuse_mm(net->dev.mm);
+}
+
+/* Expects to be always run from workqueue - which acts as
+ * read-size critical section for our kind of RCU. */
+static void handle_rx(struct vhost_net *net)
+{
+       struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_RX];
+       unsigned head, out, in;
+       struct msghdr msg = {
+               .msg_name = NULL,
+               .msg_namelen = 0,
+               .msg_control = NULL, /* FIXME: get and handle RX aux data. */
+               .msg_controllen = 0,
+               .msg_iov = vq->iov + 1,
+               .msg_flags = MSG_DONTWAIT,
+       };
+
+       struct virtio_net_hdr hdr = {
+               .flags = 0,
+               .gso_type = VIRTIO_NET_HDR_GSO_NONE
+       };
+
+       size_t len;
+       int err;
+       struct socket *sock = rcu_dereference(net->sock);
+       if (!sock || skb_queue_empty(&sock->sk->sk_receive_queue))
+               return;
+
+       use_mm(net->dev.mm);
+       mutex_lock(&vq->mutex);
+
+       for (;;) {
+               head = vhost_get_vq_desc(&net->dev, vq, vq->iov, &out, &in);
+               if (head == vq->num)
+                       break;
+               if (in <= 1 || out) {
+                       vq_err(vq, "Unexpected descriptor format for RX: "
+                              "out %d, int %d\n",
+                              out, in);
+                       break;
+               }
+               /* Sanity check */
+               if (vq->iov->iov_len != sizeof(struct virtio_net_hdr)) {
+                       vq_err(vq, "Unexpected header len for RX: "
+                              "%ld expected %zd\n",
+                              vq->iov->iov_len, sizeof(struct virtio_net_hdr));
+                       break;
+               }
+               /* Skip header. TODO: support TSO/mergeable rx buffers. */
+               msg.msg_iovlen = in - 1;
+               len = iov_length(vq->iov + 1, in - 1);
+               err = sock->ops->recvmsg(NULL, sock, &msg,
+                                        len, MSG_DONTWAIT | MSG_TRUNC);
+               /* TODO: Check specific error and bomb out unless EAGAIN? */
+               if (err < 0) {
+                       vhost_discard_vq_desc(vq);
+                       break;
+               }
+               /* TODO: Should check and handle checksum. */
+               if (err > len) {
+                       pr_err("Discarded truncated rx packet: "
+                              " len %d > %zd\n", err, len);
+                       vhost_discard_vq_desc(vq);
+                       continue;
+               }
+               len = err;
+               err = copy_to_user(vq->iov->iov_base, &hdr, sizeof hdr);
+               if (err) {
+                       vq_err(vq, "Unable to write vnet_hdr at addr %p: %d\n",
+                              vq->iov->iov_base, err);
+                       break;
+               }
+               vhost_add_used_and_trigger(vq, head, len + sizeof hdr);
+       }
+
+       mutex_unlock(&vq->mutex);
+       unuse_mm(net->dev.mm);
+}
+
+static void handle_tx_kick(struct work_struct *work)
+{
+       struct vhost_virtqueue *vq;
+       struct vhost_net *net;
+       vq = container_of(work, struct vhost_virtqueue, poll.work);
+       net = container_of(vq->dev, struct vhost_net, dev);
+       handle_tx(net);
+}
+
+static void handle_rx_kick(struct work_struct *work)
+{
+       struct vhost_virtqueue *vq;
+       struct vhost_net *net;
+       vq = container_of(work, struct vhost_virtqueue, poll.work);
+       net = container_of(vq->dev, struct vhost_net, dev);
+       handle_rx(net);
+}
+
+static void handle_tx_net(struct work_struct *work)
+{
+       struct vhost_net *net;
+       net = container_of(work, struct vhost_net, poll[VHOST_NET_VQ_TX].work);
+       handle_tx(net);
+}
+
+static void handle_rx_net(struct work_struct *work)
+{
+       struct vhost_net *net;
+       net = container_of(work, struct vhost_net, poll[VHOST_NET_VQ_RX].work);
+       handle_rx(net);
+}
+
+static int vhost_net_open(struct inode *inode, struct file *f)
+{
+       struct vhost_net *n = kzalloc(sizeof *n, GFP_KERNEL);
+       int r;
+       if (!n)
+               return -ENOMEM;
+       f->private_data = n;
+       n->vqs[VHOST_NET_VQ_TX].handle_kick = handle_tx_kick;
+       n->vqs[VHOST_NET_VQ_RX].handle_kick = handle_rx_kick;
+       r = vhost_dev_init(&n->dev, n->vqs, VHOST_NET_VQ_MAX);
+       if (r < 0) {
+               kfree(n);
+               return r;
+       }
+
+       vhost_poll_init(n->poll + VHOST_NET_VQ_TX, handle_tx_net, POLLOUT);
+       vhost_poll_init(n->poll + VHOST_NET_VQ_RX, handle_rx_net, POLLIN);
+       return 0;
+}
+
+static struct socket *vhost_net_stop(struct vhost_net *n)
+{
+       struct socket *sock = n->sock;
+       rcu_assign_pointer(n->sock, NULL);
+       if (sock) {
+               vhost_poll_flush(n->poll + VHOST_NET_VQ_TX);
+               vhost_poll_flush(n->poll + VHOST_NET_VQ_RX);
+       }
+       return sock;
+}
+
+static int vhost_net_release(struct inode *inode, struct file *f)
+{
+       struct vhost_net *n = f->private_data;
+       struct socket *sock;
+
+       sock = vhost_net_stop(n);
+       vhost_dev_cleanup(&n->dev);
+       if (sock)
+               fput(sock->file);
+       kfree(n);
+       return 0;
+}
+
+static long vhost_net_set_socket(struct vhost_net *n, int fd)
+{
+       struct {
+               struct sockaddr_ll sa;
+               char  buf[MAX_ADDR_LEN];
+       } uaddr;
+       struct socket *sock, *oldsock = NULL;
+       int uaddr_len = sizeof uaddr, r;
+
+       mutex_lock(&n->dev.mutex);
+       r = vhost_dev_check_owner(&n->dev);
+       if (r)
+               goto done;
+
+       if (fd == -1) {
+               /* Disconnect from socket and device. */
+               oldsock = vhost_net_stop(n);
+               goto done;
+       }
+
+       sock = sockfd_lookup(fd, &r);
+       if (!sock) {
+               r = -ENOTSOCK;
+               goto done;
+       }
+
+       /* Parameter checking */
+       if (sock->sk->sk_type != SOCK_RAW) {
+               r = -ESOCKTNOSUPPORT;
+               goto done;
+       }
+
+       r = sock->ops->getname(sock, (struct sockaddr *)&uaddr.sa,
+                              &uaddr_len, 0);
+       if (r)
+               goto done;
+
+       if (uaddr.sa.sll_family != AF_PACKET) {
+               r = -EPFNOSUPPORT;
+               goto done;
+       }
+
+       /* start polling new socket */
+       if (sock == oldsock)
+               goto done;
+
+       if (oldsock) {
+               vhost_poll_stop(n->poll + VHOST_NET_VQ_TX);
+               vhost_poll_stop(n->poll + VHOST_NET_VQ_RX);
+       }
+       oldsock = n->sock;
+       rcu_assign_pointer(n->sock, sock);
+       vhost_poll_start(n->poll + VHOST_NET_VQ_TX, sock->file);
+       vhost_poll_start(n->poll + VHOST_NET_VQ_RX, sock->file);
+done:
+       mutex_unlock(&n->dev.mutex);
+       if (oldsock) {
+               vhost_poll_flush(n->poll + VHOST_NET_VQ_TX);
+               vhost_poll_flush(n->poll + VHOST_NET_VQ_RX);
+               vhost_poll_flush(&n->dev.vqs[VHOST_NET_VQ_TX].poll);
+               vhost_poll_flush(&n->dev.vqs[VHOST_NET_VQ_RX].poll);
+               fput(oldsock->file);
+       }
+       return r;
+}
+
+static long vhost_net_reset_owner(struct vhost_net *n)
+{
+       struct socket *sock = NULL;
+       long r;
+       mutex_lock(&n->dev.mutex);
+       r = vhost_dev_check_owner(&n->dev);
+       if (r)
+               goto done;
+       sock = vhost_net_stop(n);
+       r = vhost_dev_reset_owner(&n->dev);
+done:
+       mutex_unlock(&n->dev.mutex);
+       if (sock)
+               fput(sock->file);
+       return r;
+}
+
+static long vhost_net_ioctl(struct file *f, unsigned int ioctl,
+                           unsigned long arg)
+{
+       struct vhost_net *n = f->private_data;
+       void __user *argp = (void __user *)arg;
+       u32 __user *featurep = argp;
+       int __user *fdp = argp;
+       u32 features;
+       int fd, r;
+       switch (ioctl) {
+       case VHOST_NET_SET_SOCKET:
+               r = get_user(fd, fdp);
+               if (r < 0)
+                       return r;
+               return vhost_net_set_socket(n, fd);
+       case VHOST_GET_FEATURES:
+               /* No features for now */
+               features = 0;
+               return put_user(features, featurep);
+       case VHOST_ACK_FEATURES:
+               r = get_user(features, featurep);
+               /* No features for now */
+               if (r < 0)
+                       return r;
+               if (features)
+                       return -EOPNOTSUPP;
+               return 0;
+       case VHOST_RESET_OWNER:
+               return vhost_net_reset_owner(n);
+       default:
+               return vhost_dev_ioctl(&n->dev, ioctl, arg);
+       }
+}
+
+#ifdef CONFIG_COMPAT
+static long vhost_net_compat_ioctl(struct file *f, unsigned int ioctl,
+                                  unsigned long arg)
+{
+       return vhost_net_ioctl(f, ioctl, (unsigned long)compat_ptr(arg));
+}
+#endif
+
+const static struct file_operations vhost_net_fops = {
+       .owner          = THIS_MODULE,
+       .release        = vhost_net_release,
+       .unlocked_ioctl = vhost_net_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = vhost_net_compat_ioctl,
+#endif
+       .open           = vhost_net_open,
+};
+
+static struct miscdevice vhost_net_misc = {
+       VHOST_NET_MINOR,
+       "vhost-net",
+       &vhost_net_fops,
+};
+
+int vhost_net_init(void)
+{
+       int r = vhost_init();
+       if (r)
+               goto err_init;
+       r = misc_register(&vhost_net_misc);
+       if (r)
+               goto err_reg;
+       return 0;
+err_reg:
+       vhost_cleanup();
+err_init:
+       return r;
+
+}
+module_init(vhost_net_init);
+
+void vhost_net_exit(void)
+{
+       misc_deregister(&vhost_net_misc);
+       vhost_cleanup();
+}
+module_exit(vhost_net_exit);
+
+MODULE_VERSION("0.0.1");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Michael S. Tsirkin");
+MODULE_DESCRIPTION("Host kernel accelerator for virtio net");
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
new file mode 100644
index 0000000..e14169f
--- /dev/null
+++ b/drivers/vhost/vhost.c
@@ -0,0 +1,664 @@
+/* Copyright (C) 2009 Red Hat, Inc.
+ * Copyright (C) 2006 Rusty Russell IBM Corporation
+ *
+ * Author: Michael S. Tsirkin <mst@redhat.com>
+ *
+ * Inspiration, some code, and most witty comments come from
+ * Documentation/lguest/lguest.c, by Rusty Russell
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ *
+ * Generic code for virtio server in host kernel.
+ */
+
+#include <linux/eventfd.h>
+#include <linux/vhost.h>
+#include <linux/virtio_net.h>
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/rcupdate.h>
+#include <linux/poll.h>
+#include <linux/file.h>
+
+#include <linux/net.h>
+#include <linux/if_packet.h>
+#include <linux/if_arp.h>
+
+#include <net/sock.h>
+
+#include "vhost.h"
+
+enum {
+       VHOST_MEMORY_MAX_NREGIONS = 64,
+};
+
+static struct workqueue_struct *vhost_workqueue;
+
+static void vhost_poll_func(struct file *file, wait_queue_head_t *wqh,
+                           poll_table *pt)
+{
+       struct vhost_poll *poll;
+       poll = container_of(pt, struct vhost_poll, table);
+
+       poll->wqh = wqh;
+       add_wait_queue(wqh, &poll->wait);
+}
+
+static int vhost_poll_wakeup(wait_queue_t *wait, unsigned mode, int sync,
+                            void *key)
+{
+       struct vhost_poll *poll;
+       poll = container_of(wait, struct vhost_poll, wait);
+       if (!((unsigned long)key & poll->mask))
+               return 0;
+
+       queue_work(vhost_workqueue, &poll->work);
+       return 0;
+}
+
+/* Init poll structure */
+void vhost_poll_init(struct vhost_poll *poll, work_func_t func,
+                    unsigned long mask)
+{
+       INIT_WORK(&poll->work, func);
+       init_waitqueue_func_entry(&poll->wait, vhost_poll_wakeup);
+       init_poll_funcptr(&poll->table, vhost_poll_func);
+       poll->mask = mask;
+}
+
+/* Start polling a file. We add ourselves to file's wait queue. The user must
+ * keep a reference to a file until after vhost_poll_stop is called. */
+void vhost_poll_start(struct vhost_poll *poll, struct file *file)
+{
+       unsigned long mask;
+       mask = file->f_op->poll(file, &poll->table);
+       if (mask)
+               vhost_poll_wakeup(&poll->wait, 0, 0, (void *)mask);
+}
+
+/* Stop polling a file. After this function returns, it becomes safe to drop the
+ * file reference. You must also flush afterwards. */
+void vhost_poll_stop(struct vhost_poll *poll)
+{
+       remove_wait_queue(poll->wqh, &poll->wait);
+}
+
+/* Flush any work that has been scheduled. When calling this, don't hold any
+ * locks that are also used by the callback. */
+void vhost_poll_flush(struct vhost_poll *poll)
+{
+       flush_work(&poll->work);
+}
+
+long vhost_dev_init(struct vhost_dev *dev,
+                   struct vhost_virtqueue *vqs, int nvqs)
+{
+       int i;
+       dev->vqs = vqs;
+       dev->nvqs = nvqs;
+       mutex_init(&dev->mutex);
+
+       for (i = 0; i < dev->nvqs; ++i) {
+               dev->vqs[i].dev = dev;
+               mutex_init(&dev->vqs[i].mutex);
+               if (dev->vqs[i].handle_kick)
+                       vhost_poll_init(&dev->vqs[i].poll,
+                                       dev->vqs[i].handle_kick,
+                                       POLLIN);
+       }
+       return 0;
+}
+
+/* User should have device mutex */
+long vhost_dev_check_owner(struct vhost_dev *dev)
+{
+       return dev->mm == current->mm ? 0 : -EPERM;
+}
+
+/* User should have device mutex */
+static long vhost_dev_set_owner(struct vhost_dev *dev)
+{
+       if (dev->mm)
+               return -EBUSY;
+       dev->mm = get_task_mm(current);
+       return 0;
+}
+
+/* User should have device mutex */
+long vhost_dev_reset_owner(struct vhost_dev *dev)
+{
+       struct vhost_memory *memory;
+
+       /* Restore memory to default 1:1 mapping. */
+       memory = kmalloc(offsetof(struct vhost_memory, regions) +
+                        2 * sizeof *memory->regions, GFP_KERNEL);
+       if (!memory)
+               return -ENOMEM;
+
+       vhost_dev_cleanup(dev);
+
+       memory->nregions = 2;
+       memory->regions[0].guest_phys_addr = 1;
+       memory->regions[0].userspace_addr = 1;
+       memory->regions[0].memory_size = ~0ULL;
+       memory->regions[1].guest_phys_addr = 0;
+       memory->regions[1].userspace_addr = 0;
+       memory->regions[1].memory_size = 1;
+       dev->memory = memory;
+       return 0;
+}
+
+/* User should have device mutex */
+void vhost_dev_cleanup(struct vhost_dev *dev)
+{
+       int i;
+       for (i = 0; i < dev->nvqs; ++i) {
+               if (dev->vqs[i].kick && dev->vqs[i].handle_kick) {
+                       vhost_poll_stop(&dev->vqs[i].poll);
+                       vhost_poll_flush(&dev->vqs[i].poll);
+               }
+               if (dev->vqs[i].error_ctx)
+                       eventfd_ctx_put(dev->vqs[i].error_ctx);
+               if (dev->vqs[i].error)
+                       fput(dev->vqs[i].error);
+               if (dev->vqs[i].kick)
+                       fput(dev->vqs[i].kick);
+               if (dev->vqs[i].call_ctx)
+                       eventfd_ctx_put(dev->vqs[i].call_ctx);
+               if (dev->vqs[i].call)
+                       fput(dev->vqs[i].call);
+               dev->vqs[i].error_ctx = NULL;
+               dev->vqs[i].error = NULL;
+               dev->vqs[i].kick = NULL;
+               dev->vqs[i].call_ctx = NULL;
+               dev->vqs[i].call = NULL;
+       }
+       /* No one will access memory at this point */
+       kfree(dev->memory);
+       dev->memory = NULL;
+       if (dev->mm)
+               mmput(dev->mm);
+       dev->mm = NULL;
+}
+
+static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m)
+{
+       struct vhost_memory mem, *newmem, *oldmem;
+       unsigned long size = offsetof(struct vhost_memory, regions);
+       long r;
+       r = copy_from_user(&mem, m, size);
+       if (r)
+               return r;
+       if (mem.padding)
+               return -EOPNOTSUPP;
+       if (mem.nregions > VHOST_MEMORY_MAX_NREGIONS)
+               return -E2BIG;
+       newmem = kmalloc(size + mem.nregions * sizeof *m->regions, GFP_KERNEL);
+       if (!newmem)
+               return -ENOMEM;
+
+       memcpy(newmem, &mem, size);
+       r = copy_from_user(newmem->regions, m->regions,
+                          mem.nregions * sizeof *m->regions);
+       if (r) {
+               kfree(newmem);
+               return r;
+       }
+       oldmem = d->memory;
+       rcu_assign_pointer(d->memory, newmem);
+       synchronize_rcu();
+       kfree(oldmem);
+       return 0;
+}
+
+static int init_used(struct vhost_virtqueue *vq)
+{
+       u16 flags = 0;
+       int r = put_user(flags, &vq->used->flags);
+       if (r)
+               return r;
+       return get_user(vq->last_used_idx, &vq->used->idx);
+}
+
+static long vhost_set_vring(struct vhost_dev *d, int ioctl, void __user *argp)
+{
+       struct file *eventfp, *filep = NULL,
+                   *pollstart = NULL, *pollstop = NULL;
+       struct eventfd_ctx *ctx = NULL;
+       u32 __user *idxp = argp;
+       struct vhost_virtqueue *vq;
+       struct vhost_vring_state s;
+       struct vhost_vring_file f;
+       struct vhost_vring_addr a;
+       u32 idx;
+       long r;
+
+       r = get_user(idx, idxp);
+       if (r < 0)
+               return r;
+       if (idx > d->nvqs)
+               return -ENOBUFS;
+
+       vq = d->vqs + idx;
+
+       mutex_lock(&vq->mutex);
+
+       switch (ioctl) {
+       case VHOST_SET_VRING_NUM:
+               r = copy_from_user(&s, argp, sizeof s);
+               if (r < 0)
+                       break;
+               if (s.num > 0xffff) {
+                       r = -EINVAL;
+                       break;
+               }
+               vq->num = s.num;
+               break;
+       case VHOST_SET_VRING_BASE:
+               r = copy_from_user(&s, argp, sizeof s);
+               if (r < 0)
+                       break;
+               if (s.num > 0xffff) {
+                       r = -EINVAL;
+                       break;
+               }
+               vq->last_avail_idx = s.num;
+               break;
+       case VHOST_GET_VRING_BASE:
+               s.index = idx;
+               s.num = vq->last_avail_idx;
+               r = copy_to_user(argp, &s, sizeof s);
+               break;
+       case VHOST_SET_VRING_DESC:
+               r = copy_from_user(&a, argp, sizeof a);
+               if (r < 0)
+                       break;
+               if (a.padding) {
+                       r = -EOPNOTSUPP;
+                       break;
+               }
+               if ((u64)(long)a.user_addr != a.user_addr) {
+                       r = -EFAULT;
+                       break;
+               }
+               vq->desc = (void __user *)(long)a.user_addr;
+               break;
+       case VHOST_SET_VRING_AVAIL:
+               r = copy_from_user(&a, argp, sizeof a);
+               if (r < 0)
+                       break;
+               if (a.padding) {
+                       r = -EOPNOTSUPP;
+                       break;
+               }
+               if ((u64)(long)a.user_addr != a.user_addr) {
+                       r = -EFAULT;
+                       break;
+               }
+               vq->avail = (void __user *)(long)a.user_addr;
+               break;
+       case VHOST_SET_VRING_USED:
+               r = copy_from_user(&a, argp, sizeof a);
+               if (r < 0)
+                       break;
+               if (a.padding) {
+                       r = -EOPNOTSUPP;
+                       break;
+               }
+               if ((u64)(long)a.user_addr != a.user_addr) {
+                       r = -EFAULT;
+                       break;
+               }
+               vq->used = (void __user *)(long)a.user_addr;
+               r = init_used(vq);
+               if (r)
+                       break;
+               break;
+       case VHOST_SET_VRING_KICK:
+               r = copy_from_user(&f, argp, sizeof f);
+               if (r < 0)
+                       break;
+               eventfp = f.fd == -1 ? NULL : eventfd_fget(f.fd);
+               if (IS_ERR(eventfp))
+                       return PTR_ERR(eventfp);
+               if (eventfp != vq->kick) {
+                       pollstop = filep = vq->kick;
+                       pollstart = vq->kick = eventfp;
+               } else
+                       filep = eventfp;
+               break;
+       case VHOST_SET_VRING_CALL:
+               r = copy_from_user(&f, argp, sizeof f);
+               if (r < 0)
+                       break;
+               eventfp = f.fd == -1 ? NULL : eventfd_fget(f.fd);
+               if (IS_ERR(eventfp))
+                       return PTR_ERR(eventfp);
+               if (eventfp != vq->call) {
+                       filep = vq->call;
+                       ctx = vq->call_ctx;
+                       vq->call = eventfp;
+                       vq->call_ctx = eventfp ?
+                               eventfd_ctx_fileget(eventfp) : NULL;
+               } else
+                       filep = eventfp;
+               break;
+       case VHOST_SET_VRING_ERR:
+               r = copy_from_user(&f, argp, sizeof f);
+               if (r < 0)
+                       break;
+               eventfp = f.fd == -1 ? NULL : eventfd_fget(f.fd);
+               if (IS_ERR(eventfp))
+                       return PTR_ERR(eventfp);
+               if (eventfp != vq->error) {
+                       filep = vq->error;
+                       vq->error = eventfp;
+                       ctx = vq->error_ctx;
+                       vq->error_ctx = eventfp ?
+                               eventfd_ctx_fileget(eventfp) : NULL;
+               } else
+                       filep = eventfp;
+               break;
+       default:
+               r = -ENOIOCTLCMD;
+       }
+
+       if (pollstop && vq->handle_kick)
+               vhost_poll_stop(&vq->poll);
+
+       if (ctx)
+               eventfd_ctx_put(ctx);
+       if (filep)
+               fput(filep);
+
+       if (pollstart && vq->handle_kick)
+               vhost_poll_start(&vq->poll, vq->kick);
+
+       mutex_unlock(&vq->mutex);
+
+       if (pollstop && vq->handle_kick)
+               vhost_poll_flush(&vq->poll);
+       return 0;
+}
+
+long vhost_dev_ioctl(struct vhost_dev *d, unsigned int ioctl, unsigned long arg)
+{
+       void __user *argp = (void __user *)arg;
+       long r;
+
+       mutex_lock(&d->mutex);
+       if (ioctl == VHOST_SET_OWNER) {
+               r = vhost_dev_set_owner(d);
+               goto done;
+       }
+
+       r = vhost_dev_check_owner(d);
+       if (r)
+               goto done;
+
+       switch (ioctl) {
+       case VHOST_SET_MEM_TABLE:
+               r = vhost_set_memory(d, argp);
+               break;
+       default:
+               r = vhost_set_vring(d, ioctl, argp);
+               break;
+       }
+done:
+       mutex_unlock(&d->mutex);
+       return r;
+}
+
+static const struct vhost_memory_region *find_region(struct vhost_memory *mem,
+                                                    __u64 addr, __u32 len)
+{
+       struct vhost_memory_region *reg;
+       int i;
+       /* linear search is not brilliant, but we really have on the order of 6
+        * regions in practice */
+       for (i = 0; i < mem->nregions; ++i) {
+               reg = mem->regions + i;
+               if (reg->guest_phys_addr <= addr &&
+                   reg->guest_phys_addr + reg->memory_size - 1 >= addr)
+                       return reg;
+       }
+       return NULL;
+}
+
+/* FIXME: this does not handle a region that spans multiple
+ * address/len pairs */
+int translate_desc(struct vhost_dev *dev, u64 addr, u32 len,
+                  struct iovec iov[], int iov_count, int iov_size,
+                  unsigned *num)
+{
+       const struct vhost_memory_region *reg;
+       struct vhost_memory *mem;
+       struct iovec *_iov;
+       u64 s = 0;
+       int ret = 0;
+
+       rcu_read_lock();
+
+       mem = rcu_dereference(dev->memory);
+       while ((u64)len > s) {
+               u64 size;
+               if (*num + iov_count >= iov_size) {
+                       ret = -ENOBUFS;
+                       break;
+               }
+               reg = find_region(mem, addr, len);
+               if (!reg) {
+                       ret = -EFAULT;
+                       break;
+               }
+               _iov = iov + iov_count + *num;
+               size = reg->memory_size - addr + reg->guest_phys_addr;
+               _iov->iov_len = min((u64)len, size);
+               _iov->iov_base = (void *)
+                       (reg->userspace_addr + addr - reg->guest_phys_addr);
+               s += size;
+               addr += size;
+               ++*num;
+       }
+
+       rcu_read_unlock();
+       return ret;
+}
+
+/* Each buffer in the virtqueues is actually a chain of descriptors.  This
+ * function returns the next descriptor in the chain, or vq->vring.num if we're
+ * at the end. */
+static unsigned next_desc(struct vhost_virtqueue *vq, struct vring_desc *desc)
+{
+       unsigned int next;
+
+       /* If this descriptor says it doesn't chain, we're done. */
+       if (!(desc->flags & VRING_DESC_F_NEXT))
+               return vq->num;
+
+       /* Check they're not leading us off end of descriptors. */
+       next = desc->next;
+       /* Make sure compiler knows to grab that: we don't want it changing! */
+       /* We will use the result as an index in an array, so most
+        * architectures only need a compiler barrier here. */
+       read_barrier_depends();
+
+       if (next >= vq->num) {
+               vq_err(vq, "Desc next is %u > %u", next, vq->num);
+               return vq->num;
+       }
+
+       return next;
+}
+
+/* This looks in the virtqueue and for the first available buffer, and converts
+ * it to an iovec for convenient access.  Since descriptors consist of some
+ * number of output then some number of input descriptors, it's actually two
+ * iovecs, but we pack them into one and note how many of each there were.
+ *
+ * This function returns the descriptor number found, or vq->num (which
+ * is never a valid descriptor number) if none was found. */
+unsigned vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq,
+                          struct iovec iov[],
+                          unsigned int *out_num, unsigned int *in_num)
+{
+       struct vring_desc desc;
+       unsigned int i, head;
+       u16 last_avail_idx, idx;
+
+       /* Check it isn't doing very strange things with descriptor numbers. */
+       last_avail_idx = vq->last_avail_idx;
+       if (get_user(idx, &vq->avail->idx)) {
+               vq_err(vq, "Failed to access avail idx at %p\n",
+                      &vq->avail->idx);
+               return vq->num;
+       }
+
+       if ((u16)(idx - last_avail_idx) > vq->num) {
+               vq_err(vq, "Guest moved used index from %u to %u",
+                      last_avail_idx, idx);
+               return vq->num;
+       }
+
+       /* If there's nothing new since last we looked, return invalid. */
+       if (idx == last_avail_idx)
+               return vq->num;
+
+       /* Grab the next descriptor number they're advertising, and increment
+        * the index we've seen. */
+       if (get_user(head, &vq->avail->ring[last_avail_idx % vq->num])) {
+               vq_err(vq, "Failed to read head: idx %d address %p\n",
+                      idx, &vq->avail->ring[last_avail_idx % vq->num]);
+               return vq->num;
+       }
+
+       /* If their number is silly, that's a fatal mistake. */
+       if (head >= vq->num) {
+               vq_err(vq, "Guest says index %u > %u is available",
+                      head, vq->num);
+               return vq->num;
+       }
+
+       vq->last_avail_idx++;
+
+       /* When we start there are none of either input nor output. */
+       *out_num = *in_num = 0;
+
+       i = head;
+       do {
+               unsigned *num;
+               unsigned iov_count;
+               if (copy_from_user(&desc, vq->desc + i, sizeof desc)) {
+                       vq_err(vq, "Failed to get descriptor: idx %d addr %p\n",
+                              i, vq->desc + i);
+                       return vq->num;
+               }
+               /* If this is an input descriptor, increment that count. */
+               if (desc.flags & VRING_DESC_F_WRITE) {
+                       num = in_num;
+                       iov_count = *out_num;
+               } else {
+                       /* If it's an output descriptor, they're all supposed
+                        * to come before any input descriptors. */
+                       if (*in_num) {
+                               vq_err(vq, "Descriptor has out after in: "
+                                      "idx %d\n", i);
+                               return vq->num;
+                       }
+                       num = out_num;
+                       iov_count = *in_num;
+               }
+               if (translate_desc(dev, desc.addr, desc.len, iov, iov_count,
+                                  VHOST_NET_MAX_SG, num)) {
+                       vq_err(vq, "Failed to translate descriptor: idx %d\n",
+                              i);
+                       return vq->num;
+               }
+
+               /* If we've got too many, that implies a descriptor loop. */
+               if (*out_num + *in_num > vq->num) {
+                       vq_err(vq, "Looped descriptor: idx %d\n", i);
+                       return vq->num;
+               }
+       } while ((i = next_desc(vq, &desc)) != vq->num);
+
+       vq->inflight++;
+       return head;
+}
+
+/* Reverse the effect of vhost_get_vq_desc. Useful for error handling. */
+void vhost_discard_vq_desc(struct vhost_virtqueue *vq)
+{
+       vq->last_avail_idx--;
+       vq->inflight--;
+}
+
+/* After we've used one of their buffers, we tell them about it.  We'll then
+ * want to send them an interrupt, using vq->call. */
+int vhost_add_used(struct vhost_virtqueue *vq,
+                         unsigned int head, int len)
+{
+       struct vring_used_elem *used;
+
+       /* The virtqueue contains a ring of used buffers.  Get a pointer to the
+        * next entry in that used ring. */
+       used = &vq->used->ring[vq->last_used_idx % vq->num];
+       if (put_user(head, &used->id)) {
+               vq_err(vq, "Failed to write used id");
+               return -EFAULT;
+       }
+       if (put_user(len, &used->len)) {
+               vq_err(vq, "Failed to write used len");
+               return -EFAULT;
+       }
+       /* Make sure buffer is written before we update index. */
+       wmb();
+       if (put_user(vq->last_used_idx + 1, &vq->used->idx)) {
+               vq_err(vq, "Failed to increment used idx");
+               return -EFAULT;
+       }
+       vq->last_used_idx++;
+       vq->inflight--;
+       return 0;
+}
+
+/* This actually sends the interrupt for this virtqueue */
+void vhost_trigger_irq(struct vhost_virtqueue *vq)
+{
+       __u16 flags = 0;
+       if (get_user(flags, &vq->avail->flags)) {
+               vq_err(vq, "Failed to get flags");
+               return;
+       }
+
+       /* If they don't want an interrupt, don't send one, unless empty. */
+       if ((flags & VRING_AVAIL_F_NO_INTERRUPT) && vq->inflight)
+               return;
+
+       /* Send the Guest an interrupt tell them we used something up. */
+       if (vq->call_ctx)
+               eventfd_signal(vq->call_ctx, 1);
+}
+
+/* And here's the combo meal deal.  Supersize me! */
+void vhost_add_used_and_trigger(struct vhost_virtqueue *vq,
+                               unsigned int head, int len)
+{
+       vhost_add_used(vq, head, len);
+       vhost_trigger_irq(vq);
+}
+
+int vhost_init(void)
+{
+       vhost_workqueue = create_workqueue("vhost");
+       if (!vhost_workqueue)
+               return -ENOMEM;
+       return 0;
+}
+
+void vhost_cleanup(void)
+{
+       destroy_workqueue(vhost_workqueue);
+}
diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h
new file mode 100644
index 0000000..7f7ffcd
--- /dev/null
+++ b/drivers/vhost/vhost.h
@@ -0,0 +1,108 @@
+#ifndef _VHOST_H
+#define _VHOST_H
+
+#include <linux/eventfd.h>
+#include <linux/vhost.h>
+#include <linux/mm.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/poll.h>
+#include <linux/file.h>
+#include <linux/skbuff.h>
+
+struct vhost_device;
+
+enum {
+       VHOST_NET_MAX_SG = MAX_SKB_FRAGS + 2,
+};
+
+/* Poll a file (eventfd or socket) */
+/* Note: there's nothing vhost specific about this structure. */
+struct vhost_poll {
+       poll_table                table;
+       wait_queue_head_t        *wqh;
+       wait_queue_t              wait;
+       /* struct which will handle all actual work. */
+       struct work_struct        work;
+       unsigned long             mask;
+};
+
+void vhost_poll_init(struct vhost_poll *poll, work_func_t func,
+                    unsigned long mask);
+void vhost_poll_start(struct vhost_poll *poll, struct file *file);
+void vhost_poll_stop(struct vhost_poll *poll);
+void vhost_poll_flush(struct vhost_poll *poll);
+
+/* The virtqueue structure describes a queue attached to a device. */
+struct vhost_virtqueue {
+       struct vhost_dev *dev;
+
+       /* The actual ring of buffers. */
+       struct mutex mutex;
+       unsigned int num;
+       struct vring_desc __user *desc;
+       struct vring_avail __user *avail;
+       struct vring_used __user *used;
+       struct file *kick;
+       struct file *call;
+       struct file *error;
+       struct eventfd_ctx *call_ctx;
+       struct eventfd_ctx *error_ctx;
+
+       struct vhost_poll poll;
+
+       /* The routine to call when the Guest pings us, or timeout. */
+       work_func_t handle_kick;
+
+       /* Last available index we saw. */
+       u16 last_avail_idx;
+
+       /* Last index we used. */
+       u16 last_used_idx;
+
+       /* Outstanding buffers */
+       unsigned int inflight;
+
+       /* Is this blocked? */
+       bool blocked;
+
+       struct iovec iov[VHOST_NET_MAX_SG];
+
+} ____cacheline_aligned;
+
+struct vhost_dev {
+       /* Readers use RCU to access memory table pointer.
+        * Writers use mutex below.*/
+       struct vhost_memory *memory;
+       struct mm_struct *mm;
+       struct vhost_virtqueue *vqs;
+       int nvqs;
+       struct mutex mutex;
+};
+
+long vhost_dev_init(struct vhost_dev *, struct vhost_virtqueue *vqs, int nvqs);
+long vhost_dev_check_owner(struct vhost_dev *);
+long vhost_dev_reset_owner(struct vhost_dev *);
+void vhost_dev_cleanup(struct vhost_dev *);
+long vhost_dev_ioctl(struct vhost_dev *, unsigned int ioctl, unsigned long arg);
+
+unsigned vhost_get_vq_desc(struct vhost_dev *, struct vhost_virtqueue *,
+                          struct iovec iov[],
+                          unsigned int *out_num, unsigned int *in_num);
+void vhost_discard_vq_desc(struct vhost_virtqueue *);
+
+int vhost_add_used(struct vhost_virtqueue *, unsigned int head, int len);
+void vhost_trigger_irq(struct vhost_virtqueue *);
+void vhost_add_used_and_trigger(struct vhost_virtqueue *,
+                               unsigned int head, int len);
+
+int vhost_init(void);
+void vhost_cleanup(void);
+
+#define vq_err(vq, fmt, ...) do {                                  \
+               printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__);       \
+               if ((vq)->error_ctx)                               \
+                               eventfd_signal((vq)->error_ctx, 1);\
+       } while (0)
+
+#endif
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index dec2f18..975df9a 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -360,6 +360,7 @@ unifdef-y += uio.h
 unifdef-y += unistd.h
 unifdef-y += usbdevice_fs.h
 unifdef-y += utsname.h
+unifdef-y += vhost.h
 unifdef-y += videodev2.h
 unifdef-y += videodev.h
 unifdef-y += virtio_config.h
diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h
index 0521177..781a8bb 100644
--- a/include/linux/miscdevice.h
+++ b/include/linux/miscdevice.h
@@ -30,6 +30,7 @@
 #define HPET_MINOR             228
 #define FUSE_MINOR             229
 #define KVM_MINOR              232
+#define VHOST_NET_MINOR                233
 #define MISC_DYNAMIC_MINOR     255

 struct device;
diff --git a/include/linux/vhost.h b/include/linux/vhost.h
new file mode 100644
index 0000000..9ec6d5f
--- /dev/null
+++ b/include/linux/vhost.h
@@ -0,0 +1,100 @@
+#ifndef _LINUX_VHOST_H
+#define _LINUX_VHOST_H
+/* Userspace interface for in-kernel virtio accelerators. */
+
+/* vhost is used to reduce the number of system calls involved in virtio.
+ *
+ * Existing virtio net code is used in the guest without modification.
+ *
+ * This header includes interface used by userspace hypervisor for
+ * device configuration.
+ */
+
+#include <linux/types.h>
+#include <linux/compiler.h>
+#include <linux/ioctl.h>
+#include <linux/virtio_config.h>
+#include <linux/virtio_ring.h>
+
+struct vhost_vring_state {
+       unsigned int index;
+       unsigned int num;
+};
+
+struct vhost_vring_file {
+       unsigned int index;
+       int fd;
+};
+
+struct vhost_vring_addr {
+       unsigned int index;
+       unsigned int padding;
+       __u64 user_addr;
+};
+
+struct vhost_memory_region {
+       __u64 guest_phys_addr;
+       __u64 memory_size; /* bytes */
+       __u64 userspace_addr;
+       __u64 padding; /* read/write protection? */
+};
+
+struct vhost_memory {
+       __u32 nregions;
+       __u32 padding;
+       struct vhost_memory_region regions[0];
+};
+
+/* ioctls */
+
+#define VHOST_VIRTIO 0xAF
+
+/* Features bitmask for forward compatibility. Transport bits must be zero. */
+#define VHOST_GET_FEATURES     _IOR(VHOST_VIRTIO, 0x00, __u32)
+#define VHOST_ACK_FEATURES     _IOW(VHOST_VIRTIO, 0x00, __u32)
+
+/* Set current process as the (exclusive) owner of this file descriptor.  This
+ * must be called before any other vhost command.  Further calls to
+ * VHOST_OWNER_SET fail until VHOST_OWNER_RESET is called. */
+#define VHOST_SET_OWNER _IO(VHOST_VIRTIO, 0x01)
+/* Give up ownership, and reset the device to default values.
+ * Allows subsequent call to VHOST_OWNER_SET to succeed. */
+#define VHOST_RESET_OWNER _IO(VHOST_VIRTIO, 0x02)
+
+/* Set up/modify memory layout */
+#define VHOST_SET_MEM_TABLE    _IOW(VHOST_VIRTIO, 0x03, struct vhost_memory)
+
+/* Ring setup. These parameters can not be modified while ring is running
+ * (bound to a device). */
+/* Set number of descriptors in ring */
+#define VHOST_SET_VRING_NUM _IOW(VHOST_VIRTIO, 0x10, struct vhost_vring_state)
+/* Start of array of descriptors (virtually contiguous) */
+#define VHOST_SET_VRING_DESC _IOW(VHOST_VIRTIO, 0x11, struct vhost_vring_addr)
+/* Used structure address */
+#define VHOST_SET_VRING_USED _IOW(VHOST_VIRTIO, 0x12, struct vhost_vring_addr)
+/* Available structure address */
+#define VHOST_SET_VRING_AVAIL _IOW(VHOST_VIRTIO, 0x13, struct vhost_vring_addr)
+/* Base value where queue looks for available descriptors */
+#define VHOST_SET_VRING_BASE _IOW(VHOST_VIRTIO, 0x14, struct vhost_vring_state)
+/* Get accessor: reads index, writes value in num */
+#define VHOST_GET_VRING_BASE _IOWR(VHOST_VIRTIO, 0x14, struct vhost_vring_state)
+
+/* The following ioctls use eventfd file descriptors to signal and poll
+ * for events. */
+
+/* Set eventfd to poll for added buffers */
+#define VHOST_SET_VRING_KICK _IOW(VHOST_VIRTIO, 0x20, struct vhost_vring_file)
+/* Set eventfd to signal when buffers have beed used */
+#define VHOST_SET_VRING_CALL _IOW(VHOST_VIRTIO, 0x21, struct vhost_vring_file)
+/* Set eventfd to signal an error */
+#define VHOST_SET_VRING_ERR _IOW(VHOST_VIRTIO, 0x22, struct vhost_vring_file)
+
+/* VHOST_NET specific defines */
+
+/* Attach virtio net device to a raw socket. The socket must be already
+ * bound to an ethernet device, this device will be used for transmit.
+ * Pass -1 to unbind from the socket and the transmit device.
+ * This can be used to stop the device (e.g. for migration). */
+#define VHOST_NET_SET_SOCKET _IOW(VHOST_VIRTIO, 0x30, int)
+
+#endif
--
1.6.2.5
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox