* RE: 82571EB: Detected Hardware Unit Hang
From: Dave, Tushar N @ 2012-11-20 8:59 UTC (permalink / raw)
To: Joe Jin
Cc: e1000-devel@lists.sf.net, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org, Mary Mcgrath
In-Reply-To: <50A9C5CC.1030300@oracle.com>
>-----Original Message-----
>From: Joe Jin [mailto:joe.jin@oracle.com]
>Sent: Sunday, November 18, 2012 9:38 PM
>To: Dave, Tushar N
>Cc: e1000-devel@lists.sf.net; netdev@vger.kernel.org; linux-
>kernel@vger.kernel.org; Mary Mcgrath
>Subject: Re: 82571EB: Detected Hardware Unit Hang
>
>On 11/16/12 04:26, Dave, Tushar N wrote:
>>> Would you please help to fine the offset of max payload size in eeprom?
>>> I'd like to have a try to modify it by ethtool.
>>
>> It is defined using bit 8 of word 0x1A.
>> Bit value 0 = 128B , bit value 1 = 256B
>
>Hi Tushar,
>
>I checked one of my server which Max Payload Size is 128:
>
># lspci -vvv -s 52:00.1
>52:00.1 Ethernet controller: Intel Corporation 82571EB Gigabit Ethernet
>Controller (rev 06)
> Subsystem: Intel Corporation PRO/1000 PT Quad Port Server Adapter
> Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop-
>ParErr+ Stepping- SERR- FastB2B- DisINTx+
> Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
><TAbort- <MAbort- >SERR- <PERR- INTx-
> Latency: 0, Cache Line Size: 64 bytes
> Interrupt: pin B routed to IRQ 266
> Region 0: Memory at dfea0000 (32-bit, non-prefetchable)
>[size=128K]
> Region 1: Memory at dfe80000 (32-bit, non-prefetchable)
>[size=128K]
> Region 2: I/O ports at 6020 [size=32]
> [virtual] Expansion ROM at d8120000 [disabled] [size=128K]
> Capabilities: [c8] Power Management version 2
> Flags: PMEClk- DSI+ D1- D2- AuxCurrent=0mA PME(D0+,D1-,D2-
>,D3hot+,D3cold-)
> Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=1 PME-
> Capabilities: [d0] MSI: Enable+ Count=1/1 Maskable- 64bit+
> Address: 00000000fee00000 Data: 409a
> Capabilities: [e0] Express (v1) Endpoint, MSI 00
> DevCap: MaxPayload 256 bytes, PhantFunc 0, Latency L0s
><512ns, L1 <64us
> ExtTag- AttnBtn- AttnInd- PwrInd- RBE- FLReset-
> DevCtl: Report errors: Correctable+ Non-Fatal+ Fatal+
>Unsupported+
> RlxdOrd+ ExtTag- PhantFunc- AuxPwr- NoSnoop+
> MaxPayload 128 bytes, MaxReadReq 4096 bytes
> DevSta: CorrErr- UncorrErr- FatalErr+ UnsuppReq+ AuxPwr-
>TransPend-
> LnkCap: Port #0, Speed 2.5GT/s, Width x4, ASPM L0s,
>Latency L0 <4us, L1 <64us
> ClockPM- Surprise- LLActRep- BwNot-
> LnkCtl: ASPM Disabled; RCB 64 bytes Disabled- Retrain-
>CommClk+
> ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
> LnkSta: Speed 2.5GT/s, Width x4, TrErr- Train- SlotClk+
>DLActive- BWMgmt- ABWMgmt-
> Capabilities: [100 v1] Advanced Error Reporting
> UESta: DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- UnxCmplt-
>RxOF- MalfTLP- ECRC- UnsupReq+ ACSViol-
> UEMsk: DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- UnxCmplt-
>RxOF- MalfTLP- ECRC- UnsupReq+ ACSViol-
> UESvrt: DLP+ SDES- TLP+ FCP+ CmpltTO+ CmpltAbrt+ UnxCmplt+
>RxOF+ MalfTLP+ ECRC- UnsupReq+ ACSViol-
> CESta: RxErr- BadTLP- BadDLLP- Rollover- Timeout-
>NonFatalErr-
> CEMsk: RxErr+ BadTLP+ BadDLLP+ Rollover+ Timeout+
>NonFatalErr-
> AERCap: First Error Pointer: 14, GenCap- CGenEn- ChkCap-
>ChkEn-
> Capabilities: [140 v1] Device Serial Number 00-15-17-ff-ff-16-ed-
>86
> Kernel driver in use: e1000e
> Kernel modules: e1000e
>
>And eeprom dump as below:
>
>Offset Values
>------ ------
>0x0000 00 15 17 16 ed 86 24 05 ff ff a2 50 ff ff ff ff
>0x0010 57 d4 07 74 2f a4 a4 11 86 80 a4 10 86 80 65 b1
>0x0020 08 00 a4 10 00 58 00 00 01 50 00 00 00 00 00 01
>0x0030 f6 6c b0 37 a6 07 03 84 83 07 00 00 03 c3 02 06
>0x0040 08 00 f0 0e 64 21 40 00 01 40 00 00 00 00 00 00
>0x0050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
>0x0060 00 01 00 40 1e 12 07 40 00 01 00 40 ff ff ff ff
>
>
>If I did not misunderstand, the value of offset 0x1a is 0x07a6, then the
>bit 8 is 1, but my NIC's MPS is 128b, anything I'm wrong?
Have you power off the system completely after modifying eeprom? If not please do so.
-Tushar
^ permalink raw reply
* Re: [PATCH 7/7] netprio_cgroup: allow nesting and inherit config on cgroup creation
From: Daniel Wagner @ 2012-11-20 8:57 UTC (permalink / raw)
To: Tejun Heo
Cc: nhorman-2XuSBdqkA4R54TAoqtyWWQ, netdev-u79uwXL29TY76Z2rM5mHXA,
containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
ebiederm-aS9lmoZGLiVWk0Htik3J/w, tgraf-G/eBtMaohhA,
cgroups-u79uwXL29TY76Z2rM5mHXA, davem-fT/PcQaiUtIeIZ0/mPfg9Q
In-Reply-To: <1353400211-5182-8-git-send-email-tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Hi Tejun,
On 20.11.2012 09:30, Tejun Heo wrote:
> Inherit netprio configuration from ->css_online(), allow nesting and
> remove .broken_hierarchy marking. This makes netprio_cgroup's
> behavior match netcls_cgroup's.
>
> Note that this patch changes userland-visible behavior. Nesting is
> allowed and the first level cgroups below the root cgroup behave
> differently - they inherit priorities from the root cgroup on creation
> instead of starting with 0. This is unfortunate but not doing so is
> much crazier.
>
> Signed-off-by: Tejun Heo <tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Tested and Acked-by: Daniel Wagner <daniel.wagner-98C5kh4wR6ohFhg+JK9F0w@public.gmane.org>
> ---
> Documentation/cgroups/net_prio.txt | 2 ++
> net/core/netprio_cgroup.c | 42 ++++++++++++++++++++++----------------
> 2 files changed, 26 insertions(+), 18 deletions(-)
>
> diff --git a/Documentation/cgroups/net_prio.txt b/Documentation/cgroups/net_prio.txt
> index 01b3226..a82cbd2 100644
> --- a/Documentation/cgroups/net_prio.txt
> +++ b/Documentation/cgroups/net_prio.txt
> @@ -51,3 +51,5 @@ One usage for the net_prio cgroup is with mqprio qdisc allowing application
> traffic to be steered to hardware/driver based traffic classes. These mappings
> can then be managed by administrators or other networking protocols such as
> DCBX.
> +
> +A new net_prio cgroup inherits the parent's configuration.
> diff --git a/net/core/netprio_cgroup.c b/net/core/netprio_cgroup.c
> index b2af0d0..bde53da 100644
> --- a/net/core/netprio_cgroup.c
> +++ b/net/core/netprio_cgroup.c
> @@ -136,9 +136,6 @@ static struct cgroup_subsys_state *cgrp_css_alloc(struct cgroup *cgrp)
> {
> struct cgroup_netprio_state *cs;
>
> - if (cgrp->parent && cgrp->parent->id)
> - return ERR_PTR(-EINVAL);
> -
> cs = kzalloc(sizeof(*cs), GFP_KERNEL);
> if (!cs)
> return ERR_PTR(-ENOMEM);
> @@ -146,16 +143,34 @@ static struct cgroup_subsys_state *cgrp_css_alloc(struct cgroup *cgrp)
> return &cs->css;
> }
>
> -static void cgrp_css_free(struct cgroup *cgrp)
> +static int cgrp_css_online(struct cgroup *cgrp)
> {
> - struct cgroup_netprio_state *cs = cgrp_netprio_state(cgrp);
> + struct cgroup *parent = cgrp->parent;
> struct net_device *dev;
> + int ret = 0;
> +
> + if (!parent)
> + return 0;
BTW, parent is always != NULL, because the root cgroup will be attached
to the dummytop cgroup.
This is the reason why there are this check in netprio_prio()
static u32 netprio_prio(struct cgroup *cgrp, struct net_device *dev)
{
struct netprio_map *map = rcu_dereference_rtnl(dev->priomap);
if (map && cgrp->id < map->priomap_len)
return map->priomap[cgrp->id];
is necessary.
cheer,
daniel
^ permalink raw reply
* Re: [PATCH 6/7] netprio_cgroup: implement netprio[_set]_prio() helpers
From: Daniel Wagner @ 2012-11-20 8:52 UTC (permalink / raw)
To: Tejun Heo
Cc: nhorman-2XuSBdqkA4R54TAoqtyWWQ, netdev-u79uwXL29TY76Z2rM5mHXA,
containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
daniel.wagner-98C5kh4wR6ohFhg+JK9F0w,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
ebiederm-aS9lmoZGLiVWk0Htik3J/w, tgraf-G/eBtMaohhA,
cgroups-u79uwXL29TY76Z2rM5mHXA, davem-fT/PcQaiUtIeIZ0/mPfg9Q
In-Reply-To: <1353400211-5182-7-git-send-email-tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
On 20.11.2012 09:30, Tejun Heo wrote:
> Introduce two helpers - netprio_prio() and netprio_set_prio() - which
> hide the details of priomap access and expansion. This will help
> implementing hierarchy support.
>
> Signed-off-by: Tejun Heo <tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> Acked-by: Neil Horman <nhorman-2XuSBdqkA4R54TAoqtyWWQ@public.gmane.org>
Tested and Acked-by: Daniel Wagner <daniel.wagner-98C5kh4wR6ohFhg+JK9F0w@public.gmane.org>
^ permalink raw reply
* Re: [PATCH] bonding: rlb mode of bond should not alter ARP originating via bridge
From: zheng.li @ 2012-11-20 8:51 UTC (permalink / raw)
To: Jay Vosburgh; +Cc: netdev, andy, linux-kernel, davem, joe.jin
In-Reply-To: <30871.1353373354@death.nxdomain>
After i applied my prior patch to the latest kernel and tested ,i change
the patch as this. The prior patch is running ok on 2.6.32,but after
2.6.32 it runs no effect ,it still cause domu(which arp through bridge
via bonding) network intermittently unreachable. I found the reason is
that the alb_monitor of bonding(after 2.6.32) send unicast arp reply
which using rlb_client_info's assigned slave's MAC,so cause peer host
update arp cache of domu with wrong MAC to cause domu unreachable again.
The rlb_client_info is created when rlb_arp_xmit sending ARP request.
rlb_client_info contain local IP with assigned
slave,it will cause all local ip's ARP use slave's mac by
rlb_update_client function.
Bug reproduced rate: 100%.
So i change the patch also affect the ARP request to don't through rlb
to no create rlb_client_info. Applied the new patch on the latest
version,it runs ok.
So,the patch should affect ARP request and reply to work well.
bond_alb_monitor -> rlb_update_rx_clients --> rlb_update_client
rlb_update_client(struct rlb_client_info *client_info)
{
for (i = 0; i < RLB_ARP_BURST_SIZE; i++) {
struct sk_buff *skb;
skb = arp_create(ARPOP_REPLY, ETH_P_ARP,
//peer host's IP
client_info->ip_dst,
client_info->slave->dev,
//Domu 's IP
client_info->ip_src,
//peer host's MAC which be set in rlb_arp_recv
client_info->mac_dst,
//use slave's MAC to send unicast arp reply to peer ,so cause peer host
//update MAC of domu with wrong mac address.
client_info->slave->dev->dev_addr,
client_info->mac_dst);
.......
}
Thanks
Zheng Li
> Zheng Li <zheng.x.li@oracle.com> wrote:
>
>> ARP traffic passing through a bridge and out via the bond (when the bond is a
>> port of the bridge) should not have its source MAC address adjusted by the
>> receive load balance code in rlb_arp_xmit.
>
> This patch differs from prior versions in that it does more than
> what's described here; it also disables the receive load balance logic
> for any ARPs (request or reply) that are passing through the bond (not
> of local origin). For ARP replies, that's mostly harmless, as the ARPs
> passing through will simply always be sent from one particular slave
> (the active slave) instead of being balanced.
>
> For ARP requests, though, they are already always sent via the
> active slave, but there is also some logic in rlb_arp_xmit to limit the
> side effects from the broadcast ARP, in particular this part:
>
> /* The ARP reply packets must be delayed so that
> * they can cancel out the influence of the ARP request.
> */
> bond->alb_info.rlb_update_delay_counter = RLB_UPDATE_DELAY;
>
> /* arp requests are broadcast and are sent on the primary
> * the arp request will collapse all clients on the subnet to
> * the primary slave. We must register these clients to be
> * updated with their assigned mac.
> */
> rlb_req_update_subnet_clients(bond, arp->ip_src);
>
> that arranges for clients to be given ARP updates for their
> slave assignments (which may change to the active slave, due to the ARP
> broadcast being sent via the active slave).
>
> I think the ARP reply side of this is fine (and is what is
> described in teh changelog), but the ARP request behavior change is new
> with this version.
>
> Since prior versions of the patch didn't cause this code to be
> skipped, is this change intentional?
>
> Did you check to see if the above logic is necessary for ARP
> requests passing through via a bridge to prevent peers from "stacking"
> (in terms of load balance assignment) on the active slave due to bridged
> ARP traffic?
>
> -J
>
>> Signed-off-by: Zheng Li <zheng.x.li@oracle.com>
>> Cc: Jay Vosburgh <fubar@us.ibm.com>
>> Cc: Andy Gospodarek <andy@greyhouse.net>
>> Cc: "David S. Miller" <davem@davemloft.net>
>>
>> ---
>> drivers/net/bonding/bond_alb.c | 6 ++++++
>> drivers/net/bonding/bonding.h | 13 +++++++++++++
>> 2 files changed, 19 insertions(+), 0 deletions(-)
>>
>> diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
>> index e15cc11..75f6f0d 100644
>> --- a/drivers/net/bonding/bond_alb.c
>> +++ b/drivers/net/bonding/bond_alb.c
>> @@ -694,6 +694,12 @@ static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond)
>> struct arp_pkt *arp = arp_pkt(skb);
>> struct slave *tx_slave = NULL;
>>
>> + /* Only modify ARP's MAC if it originates locally;
>> + * don't change ARPs arriving via a bridge.
>> + */
>> + if (!bond_slave_has_mac(bond, arp->mac_src))
>> + return NULL;
>> +
>> if (arp->op_code == htons(ARPOP_REPLY)) {
>> /* the arp must be sent on the selected
>> * rx channel
>> diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
>> index f8af2fc..6dded56 100644
>> --- a/drivers/net/bonding/bonding.h
>> +++ b/drivers/net/bonding/bonding.h
>> @@ -22,6 +22,7 @@
>> #include <linux/in6.h>
>> #include <linux/netpoll.h>
>> #include <linux/inetdevice.h>
>> +#include <linux/etherdevice.h>
>> #include "bond_3ad.h"
>> #include "bond_alb.h"
>>
>> @@ -450,6 +451,18 @@ static inline void bond_destroy_proc_dir(struct bond_net *bn)
>> }
>> #endif
>>
>> +static inline struct slave *bond_slave_has_mac(struct bonding *bond,
>> + const u8 *mac)
>> +{
>> + int i = 0;
>> + struct slave *tmp;
>> +
>> + bond_for_each_slave(bond, tmp, i)
>> + if (ether_addr_equal_64bits(mac, tmp->dev->dev_addr))
>> + return tmp;
>> +
>> + return NULL;
>> +}
>>
>> /* exported from bond_main.c */
>> extern int bond_net_id;
>> --
>> 1.7.6.5
>
> ---
> -Jay Vosburgh, IBM Linux Technology Center, fubar@us.ibm.com
>
^ permalink raw reply
* Re: [PATCH 5/7] netprio_cgroup: use cgroup->id instead of cgroup_netprio_state->prioidx
From: Daniel Wagner @ 2012-11-20 8:47 UTC (permalink / raw)
To: Tejun Heo
Cc: nhorman-2XuSBdqkA4R54TAoqtyWWQ, netdev-u79uwXL29TY76Z2rM5mHXA,
containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
ebiederm-aS9lmoZGLiVWk0Htik3J/w, tgraf-G/eBtMaohhA,
cgroups-u79uwXL29TY76Z2rM5mHXA, davem-fT/PcQaiUtIeIZ0/mPfg9Q
In-Reply-To: <1353400211-5182-6-git-send-email-tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
On 20.11.2012 09:30, Tejun Heo wrote:
> With priomap expansion no longer depending on knowing max id
> allocated, netprio_cgroup can use cgroup->id insted of cs->prioidx.
> Drop prioidx alloc/free logic and convert all uses to cgroup->id.
>
> * In cgrp_css_alloc(), parent->id test is moved above @cs allocation
> to simplify error path.
>
> * In cgrp_css_free(), @cs assignment is made initialization.
>
> Signed-off-by: Tejun Heo <tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> Acked-by: Neil Horman <nhorman-2XuSBdqkA4R54TAoqtyWWQ@public.gmane.org>
Tested and Acked-by: Daniel Wagner <daniel.wagner-98C5kh4wR6ohFhg+JK9F0w@public.gmane.org>
^ permalink raw reply
* Re: [PATCH v5] can: kvaser_usb: Add support for Kvaser CAN/USB devices
From: Olivier Sobrie @ 2012-11-20 8:46 UTC (permalink / raw)
To: Marc Kleine-Budde; +Cc: Wolfgang Grandegger, linux-can, netdev, linux-usb
In-Reply-To: <509AC491.2090701@pengutronix.de>
Hi Marc,
On Wed, Nov 07, 2012 at 09:29:05PM +0100, Marc Kleine-Budde wrote:
> On 10/02/2012 09:16 AM, Olivier Sobrie wrote:
> > This driver provides support for several Kvaser CAN/USB devices.
> > Such kind of devices supports up to three CAN network interfaces.
> >
> > It has been tested with a Kvaser USB Leaf Light (one network interface)
> > connected to a pch_can interface.
> > The firmware version of the Kvaser device was 2.5.205.
> >
> > List of Kvaser devices supported by the driver:
> > - Kvaser Leaf Light
> > - Kvaser Leaf Professional HS
> > - Kvaser Leaf SemiPro HS
> > - Kvaser Leaf Professional LS
> > - Kvaser Leaf Professional SWC
> > - Kvaser Leaf Professional LIN
> > - Kvaser Leaf SemiPro LS
> > - Kvaser Leaf SemiPro SWC
> > - Kvaser Memorator II HS/HS
> > - Kvaser USBcan Professional HS/HS
> > - Kvaser Leaf Light GI
> > - Kvaser Leaf Professional HS (OBD-II connector)
> > - Kvaser Memorator Professional HS/LS
> > - Kvaser Leaf Light "China"
> > - Kvaser BlackBird SemiPro
> > - Kvaser USBcan R
> >
> > Signed-off-by: Daniel Berglund <db@kvaser.com>
> > Signed-off-by: Olivier Sobrie <olivier@sobrie.be>
>
> Sorry I forgot about the review.
> Looks quite good, some comments inline.
Sorry for the late reply but I was in holiday during the last
3 weeks :-)
See my comments below.
>
> > ---
> > Hi,
> >
> > This new patch fixes the errors pointed out by Marc and Wolfgang.
> >
> > Changes since v4:
> > - add missing usb_free_urb()
> > - put error message in a separate function
> > - handle return code of kvaser_usb_init_one() in probe function
> >
> > Olivier
> >
> > drivers/net/can/usb/Kconfig | 29 +
> > drivers/net/can/usb/Makefile | 1 +
> > drivers/net/can/usb/kvaser_usb.c | 1596 ++++++++++++++++++++++++++++++++++++++
> > 3 files changed, 1626 insertions(+)
> > create mode 100644 drivers/net/can/usb/kvaser_usb.c
> >
> > diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig
> > index 0a68768..a4e4bee 100644
> > --- a/drivers/net/can/usb/Kconfig
> > +++ b/drivers/net/can/usb/Kconfig
> > @@ -13,6 +13,35 @@ config CAN_ESD_USB2
> > This driver supports the CAN-USB/2 interface
> > from esd electronic system design gmbh (http://www.esd.eu).
> >
> > +config CAN_KVASER_USB
> > + tristate "Kvaser CAN/USB interface"
> > + ---help---
> > + This driver adds support for Kvaser CAN/USB devices like Kvaser
> > + Leaf Light.
> > +
> > + The driver gives support for the following devices:
> > + - Kvaser Leaf Light
> > + - Kvaser Leaf Professional HS
> > + - Kvaser Leaf SemiPro HS
> > + - Kvaser Leaf Professional LS
> > + - Kvaser Leaf Professional SWC
> > + - Kvaser Leaf Professional LIN
> > + - Kvaser Leaf SemiPro LS
> > + - Kvaser Leaf SemiPro SWC
> > + - Kvaser Memorator II HS/HS
> > + - Kvaser USBcan Professional HS/HS
> > + - Kvaser Leaf Light GI
> > + - Kvaser Leaf Professional HS (OBD-II connector)
> > + - Kvaser Memorator Professional HS/LS
> > + - Kvaser Leaf Light "China"
> > + - Kvaser BlackBird SemiPro
> > + - Kvaser USBcan R
> > +
> > + If unsure, say N.
> > +
> > + To compile this driver as a module, choose M here: the
> > + module will be called kvaser_usb.
> > +
> > config CAN_PEAK_USB
> > tristate "PEAK PCAN-USB/USB Pro interfaces"
> > ---help---
> > diff --git a/drivers/net/can/usb/Makefile b/drivers/net/can/usb/Makefile
> > index da6d1d3..80a2ee4 100644
> > --- a/drivers/net/can/usb/Makefile
> > +++ b/drivers/net/can/usb/Makefile
> > @@ -4,6 +4,7 @@
> >
> > obj-$(CONFIG_CAN_EMS_USB) += ems_usb.o
> > obj-$(CONFIG_CAN_ESD_USB2) += esd_usb2.o
> > +obj-$(CONFIG_CAN_KVASER_USB) += kvaser_usb.o
> > obj-$(CONFIG_CAN_PEAK_USB) += peak_usb/
> >
> > ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
> > diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
> > new file mode 100644
> > index 0000000..bd48807
> > --- /dev/null
> > +++ b/drivers/net/can/usb/kvaser_usb.c
> > @@ -0,0 +1,1596 @@
> > +/*
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License as
> > + * published by the Free Software Foundation version 2.
> > + *
> > + * Parts of this driver are based on the following:
> > + * - Kvaser linux leaf driver (version 4.78)
> > + * - CAN driver for esd CAN-USB/2
> > + *
> > + * Copyright (C) 2002-2006 KVASER AB, Sweden. All rights reserved.
> > + * Copyright (C) 2010 Matthias Fuchs <matthias.fuchs@esd.eu>, esd gmbh
> > + * Copyright (C) 2012 Olivier Sobrie <olivier@sobrie.be>
> > + */
> > +
> > +#include <linux/init.h>
> > +#include <linux/completion.h>
> > +#include <linux/module.h>
> > +#include <linux/netdevice.h>
> > +#include <linux/usb.h>
> > +
> > +#include <linux/can.h>
> > +#include <linux/can/dev.h>
> > +#include <linux/can/error.h>
> > +
> > +#define MAX_TX_URBS 16
> > +#define MAX_RX_URBS 4
> > +#define START_TIMEOUT 1000 /* msecs */
> > +#define STOP_TIMEOUT 1000 /* msecs */
> > +#define USB_SEND_TIMEOUT 1000 /* msecs */
> > +#define USB_RECV_TIMEOUT 1000 /* msecs */
> > +#define RX_BUFFER_SIZE 3072
> > +#define CAN_USB_CLOCK 8000000
> > +#define MAX_NET_DEVICES 3
> > +
> > +/* Kvaser USB devices */
> > +#define KVASER_VENDOR_ID 0x0bfd
> > +#define USB_LEAF_DEVEL_PRODUCT_ID 10
> > +#define USB_LEAF_LITE_PRODUCT_ID 11
> > +#define USB_LEAF_PRO_PRODUCT_ID 12
> > +#define USB_LEAF_SPRO_PRODUCT_ID 14
> > +#define USB_LEAF_PRO_LS_PRODUCT_ID 15
> > +#define USB_LEAF_PRO_SWC_PRODUCT_ID 16
> > +#define USB_LEAF_PRO_LIN_PRODUCT_ID 17
> > +#define USB_LEAF_SPRO_LS_PRODUCT_ID 18
> > +#define USB_LEAF_SPRO_SWC_PRODUCT_ID 19
> > +#define USB_MEMO2_DEVEL_PRODUCT_ID 22
> > +#define USB_MEMO2_HSHS_PRODUCT_ID 23
> > +#define USB_UPRO_HSHS_PRODUCT_ID 24
> > +#define USB_LEAF_LITE_GI_PRODUCT_ID 25
> > +#define USB_LEAF_PRO_OBDII_PRODUCT_ID 26
> > +#define USB_MEMO2_HSLS_PRODUCT_ID 27
> > +#define USB_LEAF_LITE_CH_PRODUCT_ID 28
> > +#define USB_BLACKBIRD_SPRO_PRODUCT_ID 29
> > +#define USB_OEM_MERCURY_PRODUCT_ID 34
> > +#define USB_OEM_LEAF_PRODUCT_ID 35
> > +#define USB_CAN_R_PRODUCT_ID 39
> > +
> > +/* USB devices features */
> > +#define KVASER_HAS_SILENT_MODE BIT(0)
> > +#define KVASER_HAS_TXRX_ERRORS BIT(1)
> > +
> > +/* Message header size */
> > +#define MSG_HEADER_LEN 2
> > +
> > +/* Can message flags */
> > +#define MSG_FLAG_ERROR_FRAME BIT(0)
> > +#define MSG_FLAG_OVERRUN BIT(1)
> > +#define MSG_FLAG_NERR BIT(2)
> > +#define MSG_FLAG_WAKEUP BIT(3)
> > +#define MSG_FLAG_REMOTE_FRAME BIT(4)
> > +#define MSG_FLAG_RESERVED BIT(5)
> > +#define MSG_FLAG_TX_ACK BIT(6)
> > +#define MSG_FLAG_TX_REQUEST BIT(7)
> > +
> > +/* Can states */
> > +#define M16C_STATE_BUS_RESET BIT(0)
> > +#define M16C_STATE_BUS_ERROR BIT(4)
> > +#define M16C_STATE_BUS_PASSIVE BIT(5)
> > +#define M16C_STATE_BUS_OFF BIT(6)
> > +
> > +/* Can msg ids */
> > +#define CMD_RX_STD_MESSAGE 12
> > +#define CMD_TX_STD_MESSAGE 13
> > +#define CMD_RX_EXT_MESSAGE 14
> > +#define CMD_TX_EXT_MESSAGE 15
> > +#define CMD_SET_BUS_PARAMS 16
> > +#define CMD_GET_BUS_PARAMS 17
> > +#define CMD_GET_BUS_PARAMS_REPLY 18
> > +#define CMD_GET_CHIP_STATE 19
> > +#define CMD_CHIP_STATE_EVENT 20
> > +#define CMD_SET_CTRL_MODE 21
> > +#define CMD_GET_CTRL_MODE 22
> > +#define CMD_GET_CTRL_MODE_REPLY 23
> > +#define CMD_RESET_CHIP 24
> > +#define CMD_RESET_CARD 25
> > +#define CMD_START_CHIP 26
> > +#define CMD_START_CHIP_REPLY 27
> > +#define CMD_STOP_CHIP 28
> > +#define CMD_STOP_CHIP_REPLY 29
> > +#define CMD_GET_CARD_INFO2 32
> > +#define CMD_GET_CARD_INFO 34
> > +#define CMD_GET_CARD_INFO_REPLY 35
> > +#define CMD_GET_SOFTWARE_INFO 38
> > +#define CMD_GET_SOFTWARE_INFO_REPLY 39
> > +#define CMD_ERROR_EVENT 45
> > +#define CMD_FLUSH_QUEUE 48
> > +#define CMD_RESET_ERROR_COUNTER 49
> > +#define CMD_TX_ACKNOWLEDGE 50
> > +#define CMD_CAN_ERROR_EVENT 51
> > +#define CMD_USB_THROTTLE 77
> > +#define CMD_LOG_MESSAGE 106
> > +
> > +/* error factors */
> > +#define M16C_EF_ACKE BIT(0)
> > +#define M16C_EF_CRCE BIT(1)
> > +#define M16C_EF_FORME BIT(2)
> > +#define M16C_EF_STFE BIT(3)
> > +#define M16C_EF_BITE0 BIT(4)
> > +#define M16C_EF_BITE1 BIT(5)
> > +#define M16C_EF_RCVE BIT(6)
> > +#define M16C_EF_TRE BIT(7)
> > +
> > +/* bittiming parameters */
> > +#define KVASER_USB_TSEG1_MIN 1
> > +#define KVASER_USB_TSEG1_MAX 16
> > +#define KVASER_USB_TSEG2_MIN 1
> > +#define KVASER_USB_TSEG2_MAX 8
> > +#define KVASER_USB_SJW_MAX 4
> > +#define KVASER_USB_BRP_MIN 1
> > +#define KVASER_USB_BRP_MAX 64
> > +#define KVASER_USB_BRP_INC 1
> > +
> > +/* ctrl modes */
> > +#define KVASER_CTRL_MODE_NORMAL 1
> > +#define KVASER_CTRL_MODE_SILENT 2
> > +#define KVASER_CTRL_MODE_SELFRECEPTION 3
> > +#define KVASER_CTRL_MODE_OFF 4
> > +
> > +struct kvaser_msg_simple {
> > + u8 tid;
> > + u8 channel;
> > +} __packed;
> > +
> > +struct kvaser_msg_cardinfo {
> > + u8 tid;
> > + u8 nchannels;
> > + __le32 serial_number;
> > + __le32 padding;
> > + __le32 clock_resolution;
> > + __le32 mfgdate;
> > + u8 ean[8];
> > + u8 hw_revision;
> > + u8 usb_hs_mode;
> > + __le16 padding2;
> > +} __packed;
> > +
> > +struct kvaser_msg_cardinfo2 {
> > + u8 tid;
> > + u8 channel;
> > + u8 pcb_id[24];
> > + __le32 oem_unlock_code;
> > +} __packed;
> > +
> > +struct kvaser_msg_softinfo {
> > + u8 tid;
> > + u8 channel;
> > + __le32 sw_options;
> > + __le32 fw_version;
> > + __le16 max_outstanding_tx;
> > + __le16 padding[9];
> > +} __packed;
> > +
> > +struct kvaser_msg_busparams {
> > + u8 tid;
> > + u8 channel;
> > + __le32 bitrate;
> > + u8 tseg1;
> > + u8 tseg2;
> > + u8 sjw;
> > + u8 no_samp;
> > +} __packed;
> > +
> > +struct kvaser_msg_tx_can {
> > + u8 channel;
> > + u8 tid;
> > + u8 msg[14];
> > + u8 padding;
> > + u8 flags;
> > +} __packed;
> > +
> > +struct kvaser_msg_rx_can {
> > + u8 channel;
> > + u8 flag;
> > + __le16 time[3];
> > + u8 msg[14];
> > +} __packed;
> > +
> > +struct kvaser_msg_chip_state_event {
> > + u8 tid;
> > + u8 channel;
> > + __le16 time[3];
> > + u8 tx_errors_count;
> > + u8 rx_errors_count;
> > + u8 status;
> > + u8 padding[3];
> > +} __packed;
> > +
> > +struct kvaser_msg_tx_acknowledge {
> > + u8 channel;
> > + u8 tid;
> > + __le16 time[3];
> > + u8 flags;
> > + u8 time_offset;
> > +} __packed;
> > +
> > +struct kvaser_msg_error_event {
> > + u8 tid;
> > + u8 flags;
> > + __le16 time[3];
> > + u8 channel;
> > + u8 padding;
> > + u8 tx_errors_count;
> > + u8 rx_errors_count;
> > + u8 status;
> > + u8 error_factor;
> > +} __packed;
> > +
> > +struct kvaser_msg_ctrl_mode {
> > + u8 tid;
> > + u8 channel;
> > + u8 ctrl_mode;
> > + u8 padding[3];
> > +} __packed;
> > +
> > +struct kvaser_msg_flush_queue {
> > + u8 tid;
> > + u8 channel;
> > + u8 flags;
> > + u8 padding[3];
> > +} __packed;
> > +
> > +struct kvaser_msg_log_message {
> > + u8 channel;
> > + u8 flags;
> > + __le16 time[3];
> > + u8 dlc;
> > + u8 time_offset;
> > + __le32 id;
> > + u8 data[8];
> > +} __packed;
> > +
> > +struct kvaser_msg {
> > + u8 len;
> > + u8 id;
> > + union {
> > + struct kvaser_msg_simple simple;
> > + struct kvaser_msg_cardinfo cardinfo;
> > + struct kvaser_msg_cardinfo2 cardinfo2;
> > + struct kvaser_msg_softinfo softinfo;
> > + struct kvaser_msg_busparams busparams;
> > + struct kvaser_msg_tx_can tx_can;
> > + struct kvaser_msg_rx_can rx_can;
> > + struct kvaser_msg_chip_state_event chip_state_event;
> > + struct kvaser_msg_tx_acknowledge tx_acknowledge;
> > + struct kvaser_msg_error_event error_event;
> > + struct kvaser_msg_ctrl_mode ctrl_mode;
> > + struct kvaser_msg_flush_queue flush_queue;
> > + struct kvaser_msg_log_message log_message;
> > + } u;
> > +} __packed;
> > +
> > +struct kvaser_usb_tx_urb_context {
> > + struct kvaser_usb_net_priv *priv;
> > + u32 echo_index;
> > + int dlc;
> > +};
> > +
> > +struct kvaser_usb {
> > + struct usb_device *udev;
> > + struct kvaser_usb_net_priv *nets[MAX_NET_DEVICES];
> > +
> > + struct usb_endpoint_descriptor *bulk_in, *bulk_out;
> > + struct usb_anchor rx_submitted;
> > +
> > + u32 fw_version;
> > + unsigned int nchannels;
> > +
> > + bool rxinitdone;
> > + void *rxbuf[MAX_RX_URBS];
> > + dma_addr_t rxbuf_dma[MAX_RX_URBS];
> > +};
> > +
> > +struct kvaser_usb_net_priv {
> > + struct can_priv can;
> > +
> > + atomic_t active_tx_urbs;
> > + struct usb_anchor tx_submitted;
> > + struct kvaser_usb_tx_urb_context tx_contexts[MAX_TX_URBS];
> > +
> > + struct completion start_comp, stop_comp;
> > +
> > + struct kvaser_usb *dev;
> > + struct net_device *netdev;
> > + int channel;
> > +
> > + struct can_berr_counter bec;
> > +};
> > +
> > +static struct usb_device_id kvaser_usb_table[] = {
> > + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_DEVEL_PRODUCT_ID) },
> > + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_PRODUCT_ID) },
> > + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_PRODUCT_ID),
> > + .driver_info = KVASER_HAS_TXRX_ERRORS |
> > + KVASER_HAS_SILENT_MODE },
> > + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_PRODUCT_ID),
> > + .driver_info = KVASER_HAS_TXRX_ERRORS |
> > + KVASER_HAS_SILENT_MODE },
> > + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_LS_PRODUCT_ID),
> > + .driver_info = KVASER_HAS_TXRX_ERRORS |
> > + KVASER_HAS_SILENT_MODE },
> > + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_SWC_PRODUCT_ID),
> > + .driver_info = KVASER_HAS_TXRX_ERRORS |
> > + KVASER_HAS_SILENT_MODE },
> > + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_LIN_PRODUCT_ID),
> > + .driver_info = KVASER_HAS_TXRX_ERRORS |
> > + KVASER_HAS_SILENT_MODE },
> > + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_LS_PRODUCT_ID),
> > + .driver_info = KVASER_HAS_TXRX_ERRORS |
> > + KVASER_HAS_SILENT_MODE },
> > + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_SWC_PRODUCT_ID),
> > + .driver_info = KVASER_HAS_TXRX_ERRORS |
> > + KVASER_HAS_SILENT_MODE },
> > + { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_DEVEL_PRODUCT_ID),
> > + .driver_info = KVASER_HAS_TXRX_ERRORS |
> > + KVASER_HAS_SILENT_MODE },
> > + { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_HSHS_PRODUCT_ID),
> > + .driver_info = KVASER_HAS_TXRX_ERRORS |
> > + KVASER_HAS_SILENT_MODE },
> > + { USB_DEVICE(KVASER_VENDOR_ID, USB_UPRO_HSHS_PRODUCT_ID),
> > + .driver_info = KVASER_HAS_TXRX_ERRORS },
> > + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_GI_PRODUCT_ID) },
> > + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_OBDII_PRODUCT_ID),
> > + .driver_info = KVASER_HAS_TXRX_ERRORS |
> > + KVASER_HAS_SILENT_MODE },
> > + { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_HSLS_PRODUCT_ID),
> > + .driver_info = KVASER_HAS_TXRX_ERRORS },
> > + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_CH_PRODUCT_ID),
> > + .driver_info = KVASER_HAS_TXRX_ERRORS },
> > + { USB_DEVICE(KVASER_VENDOR_ID, USB_BLACKBIRD_SPRO_PRODUCT_ID),
> > + .driver_info = KVASER_HAS_TXRX_ERRORS },
> > + { USB_DEVICE(KVASER_VENDOR_ID, USB_OEM_MERCURY_PRODUCT_ID),
> > + .driver_info = KVASER_HAS_TXRX_ERRORS },
> > + { USB_DEVICE(KVASER_VENDOR_ID, USB_OEM_LEAF_PRODUCT_ID),
> > + .driver_info = KVASER_HAS_TXRX_ERRORS },
> > + { USB_DEVICE(KVASER_VENDOR_ID, USB_CAN_R_PRODUCT_ID),
> > + .driver_info = KVASER_HAS_TXRX_ERRORS },
> > + { }
> > +};
> > +MODULE_DEVICE_TABLE(usb, kvaser_usb_table);
> > +
> > +static inline int kvaser_usb_send_msg(const struct kvaser_usb *dev,
> > + struct kvaser_msg *msg)
> > +{
> > + int actual_len;
> > +
> > + return usb_bulk_msg(dev->udev,
> > + usb_sndbulkpipe(dev->udev,
> > + dev->bulk_out->bEndpointAddress),
> > + msg, msg->len, &actual_len,
> > + USB_SEND_TIMEOUT);
> > +}
> > +
> > +static int kvaser_usb_wait_msg(const struct kvaser_usb *dev, u8 id,
> > + struct kvaser_msg *msg)
> > +{
> > + struct kvaser_msg *tmp;
> > + void *buf;
> > + int actual_len;
> > + int err;
> > + int pos = 0;
> > +
> > + buf = kzalloc(RX_BUFFER_SIZE, GFP_KERNEL);
> > + if (!buf)
> > + return -ENOMEM;
> > +
> > + err = usb_bulk_msg(dev->udev,
> > + usb_rcvbulkpipe(dev->udev,
> > + dev->bulk_in->bEndpointAddress),
> > + buf, RX_BUFFER_SIZE, &actual_len,
> > + USB_RECV_TIMEOUT);
> > + if (err < 0)
> > + goto end;
> > +
> > + while (pos <= actual_len - MSG_HEADER_LEN) {
> > + tmp = buf + pos;
> > +
> > + if (!tmp->len)
> > + break;
> > +
> > + if (pos + tmp->len > actual_len) {
> > + dev_err(dev->udev->dev.parent, "Format error\n");
> > + break;
> > + }
> > +
> > + if (tmp->id == id) {
> > + memcpy(msg, tmp, tmp->len);
> > + goto end;
> > + }
> > +
> > + pos += tmp->len;
> > + }
> > +
> > + err = -EINVAL;
> > +
> > +end:
> > + kfree(buf);
> > +
> > + return err;
> > +}
> > +
> > +static int kvaser_usb_send_simple_msg(const struct kvaser_usb *dev,
> > + u8 msg_id, int channel)
> > +{
> > + struct kvaser_msg msg = {
> > + .len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_simple),
> > + .id = msg_id,
> > + .u.simple.channel = channel,
> > + .u.simple.tid = 0xff,
> > + };
> > +
> > + return kvaser_usb_send_msg(dev, &msg);
> > +}
> > +
> > +static int kvaser_usb_get_software_info(struct kvaser_usb *dev)
> > +{
> > + struct kvaser_msg msg;
> > + int err;
> > +
> > + err = kvaser_usb_send_simple_msg(dev, CMD_GET_SOFTWARE_INFO, 0);
> > + if (err)
> > + return err;
> > +
> > + err = kvaser_usb_wait_msg(dev, CMD_GET_SOFTWARE_INFO_REPLY, &msg);
> > + if (err)
> > + return err;
> > +
> > + dev->fw_version = le32_to_cpu(msg.u.softinfo.fw_version);
> > +
> > + return 0;
> > +}
> > +
> > +static int kvaser_usb_get_card_info(struct kvaser_usb *dev)
> > +{
> > + struct kvaser_msg msg;
> > + int err;
> > +
> > + err = kvaser_usb_send_simple_msg(dev, CMD_GET_CARD_INFO, 0);
> > + if (err)
> > + return err;
> > +
> > + err = kvaser_usb_wait_msg(dev, CMD_GET_CARD_INFO_REPLY, &msg);
> > + if (err)
> > + return err;
> > +
> > + dev->nchannels = msg.u.cardinfo.nchannels;
> > +
> > + return 0;
> > +}
> > +
> > +static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev,
> > + const struct kvaser_msg *msg)
> > +{
> > + struct net_device_stats *stats;
> > + struct kvaser_usb_tx_urb_context *context;
> > + struct kvaser_usb_net_priv *priv;
> > + struct sk_buff *skb;
> > + struct can_frame *cf;
> > + u8 channel = msg->u.tx_acknowledge.channel;
> > + u8 tid = msg->u.tx_acknowledge.tid;
> > +
> > + if (channel >= dev->nchannels) {
> > + dev_err(dev->udev->dev.parent,
> > + "Invalid channel number (%d)\n", channel);
> > + return;
> > + }
> > +
> > + priv = dev->nets[channel];
> > +
> > + if (!netif_device_present(priv->netdev))
> > + return;
> > +
> > + stats = &priv->netdev->stats;
> > +
> > + context = &priv->tx_contexts[tid % MAX_TX_URBS];
> > +
> > + /* Sometimes the state change doesn't come after a bus-off event */
> > + if (priv->can.restart_ms &&
> > + (priv->can.state >= CAN_STATE_BUS_OFF)) {
> > + skb = alloc_can_err_skb(priv->netdev, &cf);
> > + if (skb) {
> > + cf->can_id |= CAN_ERR_RESTARTED;
> > + netif_rx(skb);
> > +
> > + stats->rx_packets++;
> > + stats->rx_bytes += cf->can_dlc;
> > + } else {
> > + netdev_err(priv->netdev,
> > + "No memory left for err_skb\n");
> > + }
> > +
> > + priv->can.can_stats.restarts++;
> > + netif_carrier_on(priv->netdev);
> > +
> > + priv->can.state = CAN_STATE_ERROR_ACTIVE;
> > + }
> > +
> > + stats->tx_packets++;
> > + stats->tx_bytes += context->dlc;
> > + can_get_echo_skb(priv->netdev, context->echo_index);
> > +
> > + context->echo_index = MAX_TX_URBS;
> > + atomic_dec(&priv->active_tx_urbs);
> > +
> > + netif_wake_queue(priv->netdev);
> > +}
> > +
> > +static void kvaser_usb_simple_msg_callback(struct urb *urb)
> > +{
> > + struct net_device *netdev = urb->context;
> > +
> > + kfree(urb->transfer_buffer);
> > +
> > + if (urb->status)
> > + netdev_warn(netdev, "urb status received: %d\n",
> > + urb->status);
> > +}
> > +
> > +static int kvaser_usb_simple_msg_async(struct kvaser_usb_net_priv *priv,
> > + u8 msg_id)
> > +{
> > + struct kvaser_usb *dev = priv->dev;
> > + struct net_device *netdev = priv->netdev;
> > + struct kvaser_msg *msg;
> > + struct urb *urb;
> > + void *buf;
> > + int err;
> > +
> > + urb = usb_alloc_urb(0, GFP_ATOMIC);
> > + if (!urb) {
> > + netdev_err(netdev, "No memory left for URBs\n");
> > + return -ENOMEM;
> > + }
> > +
> > + buf = kmalloc(sizeof(struct kvaser_msg), GFP_ATOMIC);
> > + if (!buf) {
> > + netdev_err(netdev, "No memory left for USB buffer\n");
> > + usb_free_urb(urb);
> > + return -ENOMEM;
> > + }
> > +
> > + msg = (struct kvaser_msg *)buf;
> > + msg->len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_simple);
> > + msg->id = msg_id;
> > + msg->u.simple.channel = priv->channel;
> > +
> > + usb_fill_bulk_urb(urb, dev->udev,
> > + usb_sndbulkpipe(dev->udev,
> > + dev->bulk_out->bEndpointAddress),
> > + buf, msg->len,
> > + kvaser_usb_simple_msg_callback, priv);
> > + usb_anchor_urb(urb, &priv->tx_submitted);
> > +
> > + err = usb_submit_urb(urb, GFP_ATOMIC);
> > + if (err) {
> > + netdev_err(netdev, "Error transmitting URB\n");
> > + usb_unanchor_urb(urb);
> > + usb_free_urb(urb);
> > + kfree(buf);
> > + return err;
> > + }
> > +
> > + usb_free_urb(urb);
> > +
> > + return 0;
> > +}
> > +
> > +static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv)
> > +{
> > + int i;
> > +
> > + usb_kill_anchored_urbs(&priv->tx_submitted);
> > + atomic_set(&priv->active_tx_urbs, 0);
> > +
> > + for (i = 0; i < MAX_TX_URBS; i++)
> > + priv->tx_contexts[i].echo_index = MAX_TX_URBS;
> > +}
> > +
> > +static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
> > + const struct kvaser_msg *msg)
> > +{
> > + struct can_frame *cf;
> > + struct sk_buff *skb;
> > + struct net_device_stats *stats;
> > + struct kvaser_usb_net_priv *priv;
> > + unsigned int new_state;
> > + u8 channel, status, txerr, rxerr, error_factor;
> > +
> > + switch (msg->id) {
> > + case CMD_CAN_ERROR_EVENT:
> > + channel = msg->u.error_event.channel;
> > + status = msg->u.error_event.status;
> > + txerr = msg->u.error_event.tx_errors_count;
> > + rxerr = msg->u.error_event.rx_errors_count;
> > + error_factor = msg->u.error_event.error_factor;
> > + break;
> > + case CMD_LOG_MESSAGE:
> > + channel = msg->u.log_message.channel;
> > + status = msg->u.log_message.data[0];
> > + txerr = msg->u.log_message.data[2];
> > + rxerr = msg->u.log_message.data[3];
> > + error_factor = msg->u.log_message.data[1];
> > + break;
> > + case CMD_CHIP_STATE_EVENT:
> > + channel = msg->u.chip_state_event.channel;
> > + status = msg->u.chip_state_event.status;
> > + txerr = msg->u.chip_state_event.tx_errors_count;
> > + rxerr = msg->u.chip_state_event.rx_errors_count;
> > + error_factor = 0;
> > + break;
> > + default:
> > + dev_err(dev->udev->dev.parent, "Invalid msg id (%d)\n",
> > + msg->id);
> > + return;
> > + }
> > +
> > + if (channel >= dev->nchannels) {
> > + dev_err(dev->udev->dev.parent,
> > + "Invalid channel number (%d)\n", channel);
> > + return;
> > + }
> > +
> > + priv = dev->nets[channel];
> > + stats = &priv->netdev->stats;
> > +
> > + if (status & M16C_STATE_BUS_RESET) {
> > + kvaser_usb_unlink_tx_urbs(priv);
> > + return;
> > + }
> > +
> > + skb = alloc_can_err_skb(priv->netdev, &cf);
> > + if (!skb) {
> > + stats->rx_dropped++;
> > + return;
> > + }
> > +
> > + new_state = priv->can.state;
> > +
> > + netdev_dbg(priv->netdev, "Error status: 0x%02x\n", status);
> > +
> > + if (status & M16C_STATE_BUS_OFF) {
> > + cf->can_id |= CAN_ERR_BUSOFF;
> > +
> > + priv->can.can_stats.bus_off++;
> > + if (!priv->can.restart_ms)
> > + kvaser_usb_simple_msg_async(priv, CMD_STOP_CHIP);
> > +
> > + netif_carrier_off(priv->netdev);
> > +
> > + new_state = CAN_STATE_BUS_OFF;
> > + } else if (status & M16C_STATE_BUS_PASSIVE) {
> > + if (priv->can.state != CAN_STATE_ERROR_PASSIVE) {
> > + cf->can_id |= CAN_ERR_CRTL;
> > +
> > + if (txerr || rxerr)
> > + cf->data[1] = (txerr > rxerr)
> > + ? CAN_ERR_CRTL_TX_PASSIVE
> > + : CAN_ERR_CRTL_RX_PASSIVE;
> > + else
> > + cf->data[1] = CAN_ERR_CRTL_TX_PASSIVE |
> > + CAN_ERR_CRTL_RX_PASSIVE;
> > +
> > + priv->can.can_stats.error_passive++;
> > + }
> > +
> > + new_state = CAN_STATE_ERROR_PASSIVE;
> > + }
> > +
> > + if (status == M16C_STATE_BUS_ERROR) {
> > + if ((priv->can.state < CAN_STATE_ERROR_WARNING) &&
> > + ((txerr >= 96) || (rxerr >= 96))) {
> > + cf->can_id |= CAN_ERR_CRTL;
> > + cf->data[1] = (txerr > rxerr)
> > + ? CAN_ERR_CRTL_TX_WARNING
> > + : CAN_ERR_CRTL_RX_WARNING;
> > +
> > + priv->can.can_stats.error_warning++;
> > + new_state = CAN_STATE_ERROR_WARNING;
> > + } else if (priv->can.state > CAN_STATE_ERROR_ACTIVE) {
> > + cf->can_id |= CAN_ERR_PROT;
> > + cf->data[2] = CAN_ERR_PROT_ACTIVE;
> > +
> > + new_state = CAN_STATE_ERROR_ACTIVE;
> > + }
> > + }
> > +
> > + if (!status) {
> > + cf->can_id |= CAN_ERR_PROT;
> > + cf->data[2] = CAN_ERR_PROT_ACTIVE;
> > +
> > + new_state = CAN_STATE_ERROR_ACTIVE;
> > + }
> > +
> > + if (priv->can.restart_ms &&
> > + (priv->can.state >= CAN_STATE_BUS_OFF) &&
> > + (new_state < CAN_STATE_BUS_OFF)) {
> > + cf->can_id |= CAN_ERR_RESTARTED;
> > + netif_carrier_on(priv->netdev);
> > +
> > + priv->can.can_stats.restarts++;
> > + }
> > +
> > + if (error_factor) {
> > + priv->can.can_stats.bus_error++;
> > + stats->rx_errors++;
> > +
> > + cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT;
> > +
> > + if (error_factor & M16C_EF_ACKE)
> > + cf->data[3] |= (CAN_ERR_PROT_LOC_ACK);
> > + if (error_factor & M16C_EF_CRCE)
> > + cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
> > + CAN_ERR_PROT_LOC_CRC_DEL);
> > + if (error_factor & M16C_EF_FORME)
> > + cf->data[2] |= CAN_ERR_PROT_FORM;
> > + if (error_factor & M16C_EF_STFE)
> > + cf->data[2] |= CAN_ERR_PROT_STUFF;
> > + if (error_factor & M16C_EF_BITE0)
> > + cf->data[2] |= CAN_ERR_PROT_BIT0;
> > + if (error_factor & M16C_EF_BITE1)
> > + cf->data[2] |= CAN_ERR_PROT_BIT1;
> > + if (error_factor & M16C_EF_TRE)
> > + cf->data[2] |= CAN_ERR_PROT_TX;
> > + }
> > +
> > + cf->data[6] = txerr;
> > + cf->data[7] = rxerr;
> > +
> > + priv->bec.txerr = txerr;
> > + priv->bec.rxerr = rxerr;
> > +
> > + priv->can.state = new_state;
> > +
> > + netif_rx(skb);
> > +
> > + stats->rx_packets++;
> > + stats->rx_bytes += cf->can_dlc;
> > +}
> > +
> > +static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv,
> > + const struct kvaser_msg *msg)
> > +{
> > + struct can_frame *cf;
> > + struct sk_buff *skb;
> > + struct net_device_stats *stats = &priv->netdev->stats;
> > +
> > + if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME |
> > + MSG_FLAG_NERR)) {
> > + netdev_err(priv->netdev, "Unknow error (flags: 0x%02x)\n",
> > + msg->u.rx_can.flag);
> > +
> > + stats->rx_errors++;
> > + return;
> > + }
> > +
> > + if (msg->u.rx_can.flag & MSG_FLAG_OVERRUN) {
> > + skb = alloc_can_err_skb(priv->netdev, &cf);
> > + if (!skb) {
> > + stats->tx_dropped++;
>
> Should be rx, as we are in the rx function.
Ok I'll fix that.
>
> > + return;
> > + }
> > +
> > + cf->can_id |= CAN_ERR_CRTL;
> > + cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
> > +
> > + stats->rx_over_errors++;
> > + stats->rx_errors++;
> > +
> > + netif_rx(skb);
> > +
> > + stats->rx_packets++;
> > + stats->rx_bytes += cf->can_dlc;
> > + }
> > +}
> > +
> > +static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,
> > + const struct kvaser_msg *msg)
> > +{
> > + struct kvaser_usb_net_priv *priv;
> > + struct can_frame *cf;
> > + struct sk_buff *skb;
> > + struct net_device_stats *stats;
> > + u8 channel = msg->u.rx_can.channel;
> > +
> > + if (channel >= dev->nchannels) {
> > + dev_err(dev->udev->dev.parent,
> > + "Invalid channel number (%d)\n", channel);
> > + return;
> > + }
> > +
> > + priv = dev->nets[channel];
> > + stats = &priv->netdev->stats;
> > +
> > + if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME | MSG_FLAG_NERR |
> > + MSG_FLAG_OVERRUN)) {
> > + kvaser_usb_rx_can_err(priv, msg);
> > + return;
> > + } else if (msg->u.rx_can.flag & ~MSG_FLAG_REMOTE_FRAME) {
> > + netdev_warn(priv->netdev,
> > + "Unhandled frame (flags: 0x%02x)",
> > + msg->u.rx_can.flag);
> > + return;
> > + }
> > +
> > + skb = alloc_can_skb(priv->netdev, &cf);
> > + if (!skb) {
> > + stats->tx_dropped++;
> > + return;
> > + }
> > +
> > + cf->can_id = ((msg->u.rx_can.msg[0] & 0x1f) << 6) |
> > + (msg->u.rx_can.msg[1] & 0x3f);
> > + cf->can_dlc = get_can_dlc(msg->u.rx_can.msg[5]);
> > +
> > + if (msg->id == CMD_RX_EXT_MESSAGE) {
> > + cf->can_id <<= 18;
> > + cf->can_id |= ((msg->u.rx_can.msg[2] & 0x0f) << 14) |
> > + ((msg->u.rx_can.msg[3] & 0xff) << 6) |
> > + (msg->u.rx_can.msg[4] & 0x3f);
> > + cf->can_id |= CAN_EFF_FLAG;
> > + }
> > +
> > + if (msg->u.rx_can.flag & MSG_FLAG_REMOTE_FRAME)
> > + cf->can_id |= CAN_RTR_FLAG;
> > + else
> > + memcpy(cf->data, &msg->u.rx_can.msg[6], cf->can_dlc);
> > +
> > + netif_rx(skb);
> > +
> > + stats->rx_packets++;
> > + stats->rx_bytes += cf->can_dlc;
> > +}
> > +
> > +static void kvaser_usb_start_chip_reply(const struct kvaser_usb *dev,
> > + const struct kvaser_msg *msg)
> > +{
> > + struct kvaser_usb_net_priv *priv;
> > + u8 channel = msg->u.simple.channel;
> > +
> > + if (channel >= dev->nchannels) {
> > + dev_err(dev->udev->dev.parent,
> > + "Invalid channel number (%d)\n", channel);
> > + return;
> > + }
> > +
> > + priv = dev->nets[channel];
> > +
> > + if (completion_done(&priv->start_comp) &&
> > + netif_queue_stopped(priv->netdev)) {
> > + netif_wake_queue(priv->netdev);
> > + } else {
> > + netif_start_queue(priv->netdev);
> > + complete(&priv->start_comp);
> > + }
> > +}
> > +
> > +static void kvaser_usb_stop_chip_reply(const struct kvaser_usb *dev,
> > + const struct kvaser_msg *msg)
> > +{
> > + struct kvaser_usb_net_priv *priv;
> > + u8 channel = msg->u.simple.channel;
> > +
> > + if (channel >= dev->nchannels) {
> > + dev_err(dev->udev->dev.parent,
> > + "Invalid channel number (%d)\n", channel);
> > + return;
> > + }
> > +
> > + priv = dev->nets[channel];
> > +
> > + complete(&priv->stop_comp);
> > +}
> > +
> > +static void kvaser_usb_handle_message(const struct kvaser_usb *dev,
> > + const struct kvaser_msg *msg)
> > +{
> > + switch (msg->id) {
> > + case CMD_START_CHIP_REPLY:
> > + kvaser_usb_start_chip_reply(dev, msg);
> > + break;
> > +
> > + case CMD_STOP_CHIP_REPLY:
> > + kvaser_usb_stop_chip_reply(dev, msg);
> > + break;
> > +
> > + case CMD_RX_STD_MESSAGE:
> > + case CMD_RX_EXT_MESSAGE:
> > + kvaser_usb_rx_can_msg(dev, msg);
> > + break;
> > +
> > + case CMD_CHIP_STATE_EVENT:
> > + case CMD_CAN_ERROR_EVENT:
> > + kvaser_usb_rx_error(dev, msg);
> > + break;
> > +
> > + case CMD_LOG_MESSAGE:
> > + if (msg->u.log_message.flags & MSG_FLAG_ERROR_FRAME)
> > + kvaser_usb_rx_error(dev, msg);
> > + break;
> > +
> > + case CMD_TX_ACKNOWLEDGE:
> > + kvaser_usb_tx_acknowledge(dev, msg);
> > + break;
> > +
> > + default:
> > + dev_warn(dev->udev->dev.parent,
> > + "Unhandled message (%d)\n", msg->id);
> > + break;
> > + }
> > +}
> > +
> > +static void kvaser_usb_read_bulk_callback(struct urb *urb)
> > +{
> > + struct kvaser_usb *dev = urb->context;
> > + struct kvaser_msg *msg;
> > + int pos = 0;
> > + int err, i;
> > +
> > + switch (urb->status) {
> > + case 0:
> > + break;
> > + case -ENOENT:
> > + case -ESHUTDOWN:
> > + return;
> > + default:
> > + dev_info(dev->udev->dev.parent, "Rx URB aborted (%d)\n",
> > + urb->status);
> > + goto resubmit_urb;
> > + }
> > +
> > + while (pos <= urb->actual_length - MSG_HEADER_LEN) {
> > + msg = urb->transfer_buffer + pos;
> > +
> > + if (!msg->len)
> > + break;
> > +
> > + if (pos + msg->len > urb->actual_length) {
> > + dev_err(dev->udev->dev.parent, "Format error\n");
> > + break;
> > + }
> > +
> > + kvaser_usb_handle_message(dev, msg);
> > +
> > + pos += msg->len;
> > + }
> > +
> > +resubmit_urb:
> > + usb_fill_bulk_urb(urb, dev->udev,
> > + usb_rcvbulkpipe(dev->udev,
> > + dev->bulk_in->bEndpointAddress),
> > + urb->transfer_buffer, RX_BUFFER_SIZE,
> > + kvaser_usb_read_bulk_callback, dev);
> > +
> > + err = usb_submit_urb(urb, GFP_ATOMIC);
> > + if (err == -ENODEV) {
> > + for (i = 0; i < dev->nchannels; i++) {
> > + if (!dev->nets[i])
> > + continue;
> > +
> > + netif_device_detach(dev->nets[i]->netdev);
> > + }
> > + } else if (err) {
> > + dev_err(dev->udev->dev.parent,
> > + "Failed resubmitting read bulk urb: %d\n", err);
> > + }
> > +
> > + return;
> > +}
> > +
> > +static int kvaser_usb_setup_rx_urbs(struct kvaser_usb *dev)
> > +{
> > + int i, err = 0;
> > +
> > + if (dev->rxinitdone)
> > + return 0;
> > +
> > + for (i = 0; i < MAX_RX_URBS; i++) {
> > + struct urb *urb = NULL;
> > + u8 *buf = NULL;
> > + dma_addr_t buf_dma;
> > +
> > + urb = usb_alloc_urb(0, GFP_KERNEL);
> > + if (!urb) {
> > + dev_warn(dev->udev->dev.parent,
> > + "No memory left for URBs\n");
> > + err = -ENOMEM;
> > + break;
> > + }
> > +
> > + buf = usb_alloc_coherent(dev->udev, RX_BUFFER_SIZE,
> > + GFP_KERNEL, &buf_dma);
> > + if (!buf) {
> > + dev_warn(dev->udev->dev.parent,
> > + "No memory left for USB buffer\n");
> > + usb_free_urb(urb);
> > + err = -ENOMEM;
> > + break;
> > + }
> > +
> > + usb_fill_bulk_urb(urb, dev->udev,
> > + usb_rcvbulkpipe(dev->udev,
> > + dev->bulk_in->bEndpointAddress),
> > + buf, RX_BUFFER_SIZE,
> > + kvaser_usb_read_bulk_callback,
> > + dev);
> > + urb->transfer_dma = buf_dma;
> > + urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
> > + usb_anchor_urb(urb, &dev->rx_submitted);
> > +
> > + err = usb_submit_urb(urb, GFP_KERNEL);
> > + if (err) {
> > + usb_unanchor_urb(urb);
> > + usb_free_coherent(dev->udev, RX_BUFFER_SIZE, buf,
> > + buf_dma);
> > + usb_free_urb(urb);
> > + break;
> > + }
> > +
> > + dev->rxbuf[i] = buf;
> > + dev->rxbuf_dma[i] = buf_dma;
> > +
> > + usb_free_urb(urb);
> > + }
> > +
> > + if (i == 0) {
> > + dev_warn(dev->udev->dev.parent,
> > + "Cannot setup read URBs, error %d\n", err);
> > + return err;
> > + } else if (i < MAX_RX_URBS) {
> > + dev_warn(dev->udev->dev.parent,
> > + "RX performances may be slow\n");
> > + }
> > +
> > + dev->rxinitdone = true;
> > +
> > + return 0;
> > +}
> > +
> > +static int kvaser_usb_set_opt_mode(const struct kvaser_usb_net_priv *priv)
> > +{
> > + struct kvaser_msg msg = {
> > + .id = CMD_SET_CTRL_MODE,
> > + .len = MSG_HEADER_LEN +
> > + sizeof(struct kvaser_msg_ctrl_mode),
> > + .u.ctrl_mode.tid = 0xff,
> > + .u.ctrl_mode.channel = priv->channel,
> > + };
> > +
> > + if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
> > + msg.u.ctrl_mode.ctrl_mode = KVASER_CTRL_MODE_SILENT;
> > + else
> > + msg.u.ctrl_mode.ctrl_mode = KVASER_CTRL_MODE_NORMAL;
> > +
> > + return kvaser_usb_send_msg(priv->dev, &msg);
> > +}
> > +
> > +static int kvaser_usb_start_chip(struct kvaser_usb_net_priv *priv)
> > +{
> > + int err;
> > +
> > + init_completion(&priv->start_comp);
> > +
> > + err = kvaser_usb_send_simple_msg(priv->dev, CMD_START_CHIP,
> > + priv->channel);
> > + if (err)
> > + return err;
> > +
> > + if (!wait_for_completion_timeout(&priv->start_comp,
> > + msecs_to_jiffies(START_TIMEOUT)))
> > + return -ETIMEDOUT;
> > +
> > + return 0;
> > +}
> > +
> > +static int kvaser_usb_open(struct net_device *netdev)
> > +{
> > + struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
> > + struct kvaser_usb *dev = priv->dev;
> > + int err;
> > +
> > + err = open_candev(netdev);
> > + if (err)
> > + return err;
> > +
> > + err = kvaser_usb_setup_rx_urbs(dev);
> > + if (err)
> > + goto error;
> > +
> > + err = kvaser_usb_set_opt_mode(priv);
> > + if (err)
> > + goto error;
> > +
> > + err = kvaser_usb_start_chip(priv);
> > + if (err) {
> > + netdev_warn(netdev, "Cannot start device, error %d\n", err);
> > + goto error;
> > + }
> > +
> > + priv->can.state = CAN_STATE_ERROR_ACTIVE;
> > +
> > + return 0;
> > +
> > +error:
> > + close_candev(netdev);
> > + return err;
> > +}
> > +
> > +static void kvaser_usb_unlink_all_urbs(struct kvaser_usb *dev)
> > +{
> > + int i;
> > +
> > + usb_kill_anchored_urbs(&dev->rx_submitted);
> > +
> > + for (i = 0; i < MAX_RX_URBS; i++)
> > + usb_free_coherent(dev->udev, RX_BUFFER_SIZE,
> > + dev->rxbuf[i],
> > + dev->rxbuf_dma[i]);
> > +
> > + for (i = 0; i < MAX_NET_DEVICES; i++) {
> > + struct kvaser_usb_net_priv *priv = dev->nets[i];
> > +
> > + if (priv)
> > + kvaser_usb_unlink_tx_urbs(priv);
> > + }
> > +}
> > +
> > +static int kvaser_usb_stop_chip(struct kvaser_usb_net_priv *priv)
> > +{
> > + int err;
> > +
> > + init_completion(&priv->stop_comp);
> > +
> > + err = kvaser_usb_send_simple_msg(priv->dev, CMD_STOP_CHIP,
> > + priv->channel);
> > + if (err)
> > + return err;
> > +
> > + if (!wait_for_completion_timeout(&priv->stop_comp,
> > + msecs_to_jiffies(STOP_TIMEOUT)))
> > + return -ETIMEDOUT;
> > +
> > + return 0;
> > +}
> > +
> > +static int kvaser_usb_flush_queue(struct kvaser_usb_net_priv *priv)
> > +{
> > + struct kvaser_msg msg = {
> > + .id = CMD_FLUSH_QUEUE,
> > + .len = MSG_HEADER_LEN +
> > + sizeof(struct kvaser_msg_flush_queue),
> > + .u.flush_queue.channel = priv->channel,
> > + .u.flush_queue.flags = 0x00,
> > + };
> > +
> > + return kvaser_usb_send_msg(priv->dev, &msg);
> > +}
> > +
> > +static int kvaser_usb_close(struct net_device *netdev)
> > +{
> > + struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
> > + struct kvaser_usb *dev = priv->dev;
> > + int err;
> > +
> > + netif_stop_queue(netdev);
> > +
> > + err = kvaser_usb_flush_queue(priv);
> > + if (err)
> > + netdev_warn(netdev, "Cannot flush queue, error %d\n", err);
> > +
> > + if (kvaser_usb_send_simple_msg(dev, CMD_RESET_CHIP, priv->channel))
> > + netdev_warn(netdev, "Cannot reset card, error %d\n", err);
> > +
> > + err = kvaser_usb_stop_chip(priv);
> > + if (err)
> > + netdev_warn(netdev, "Cannot stop device, error %d\n", err);
> > +
> > + priv->can.state = CAN_STATE_STOPPED;
> > + close_candev(priv->netdev);
> > +
> > + return 0;
> > +}
> > +
> > +static void kvaser_usb_write_bulk_callback(struct urb *urb)
> > +{
> > + struct kvaser_usb_tx_urb_context *context = urb->context;
> > + struct kvaser_usb_net_priv *priv;
> > + struct net_device *netdev;
> > +
> > + if (WARN_ON(!context))
> > + return;
> > +
> > + priv = context->priv;
> > + netdev = priv->netdev;
> > +
> > + kfree(urb->transfer_buffer);
> > +
> > + if (!netif_device_present(netdev))
> > + return;
> > +
> > + if (urb->status)
> > + netdev_info(netdev, "Tx URB aborted (%d)\n", urb->status);
> > +}
> > +
> > +static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
> > + struct net_device *netdev)
> > +{
> > + struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
> > + struct kvaser_usb *dev = priv->dev;
> > + struct net_device_stats *stats = &netdev->stats;
> > + struct can_frame *cf = (struct can_frame *)skb->data;
> > + struct kvaser_usb_tx_urb_context *context = NULL;
> > + struct urb *urb;
> > + void *buf;
> > + struct kvaser_msg *msg;
> > + int i, err;
> > + int ret = NETDEV_TX_OK;
> > +
> > + if (can_dropped_invalid_skb(netdev, skb))
> > + return NETDEV_TX_OK;
> > +
> > + urb = usb_alloc_urb(0, GFP_ATOMIC);
> > + if (!urb) {
> > + netdev_err(netdev, "No memory left for URBs\n");
> > + stats->tx_dropped++;
>
> Move the dev_kfree_skb to the end and goto there.
I assume you mean doing something like that at the end of the function:
releasebuf:
kfree(buf);
nobufmem:
usb_free_urb(urb);
nourbmem:
dev_kfree_skb(skb);
return ret;
If I do that it will give problems when the 'releasebuf' condition is
reached. The skb buffer will be freed twice. The skb is already freed
by the function can_free_echo_skb().
>
> > + dev_kfree_skb(skb);
> > + return NETDEV_TX_OK;
> > + }
> > +
> > + buf = kmalloc(sizeof(struct kvaser_msg), GFP_ATOMIC);
> > + if (!buf) {
> > + netdev_err(netdev, "No memory left for USB buffer\n");
> > + stats->tx_dropped++;
> You cann usb_free_urb twice...here and in the error handling at the end.
Indeed thanks.
>
> > + dev_kfree_skb(skb);
> > + usb_free_urb(urb);
> > + goto nobufmem;
> > + }
> > +
> > + msg = buf;
> > + msg->len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_tx_can);
> > + msg->u.tx_can.flags = 0;
> > + msg->u.tx_can.channel = priv->channel;
> > +
> > + if (cf->can_id & CAN_EFF_FLAG) {
> > + msg->id = CMD_TX_EXT_MESSAGE;
> > + msg->u.tx_can.msg[0] = (cf->can_id >> 24) & 0x1f;
> > + msg->u.tx_can.msg[1] = (cf->can_id >> 18) & 0x3f;
> > + msg->u.tx_can.msg[2] = (cf->can_id >> 14) & 0x0f;
> > + msg->u.tx_can.msg[3] = (cf->can_id >> 6) & 0xff;
> > + msg->u.tx_can.msg[4] = cf->can_id & 0x3f;
> > + } else {
> > + msg->id = CMD_TX_STD_MESSAGE;
> > + msg->u.tx_can.msg[0] = (cf->can_id >> 6) & 0x1f;
> > + msg->u.tx_can.msg[1] = cf->can_id & 0x3f;
> > + }
> > +
> > + msg->u.tx_can.msg[5] = cf->can_dlc;
> > + memcpy(&msg->u.tx_can.msg[6], cf->data, cf->can_dlc);
> > +
> > + if (cf->can_id & CAN_RTR_FLAG)
> > + msg->u.tx_can.flags |= MSG_FLAG_REMOTE_FRAME;
> > +
> > + for (i = 0; i < ARRAY_SIZE(priv->tx_contexts); i++) {
> > + if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) {
> > + context = &priv->tx_contexts[i];
> > + break;
> > + }
> > + }
> > +
> > + if (!context) {
> > + netdev_warn(netdev, "cannot find free context\n");
> > + ret = NETDEV_TX_BUSY;
> > + goto releasebuf;
> > + }
> > +
> > + context->priv = priv;
> > + context->echo_index = i;
> > + context->dlc = cf->can_dlc;
> > +
> > + msg->u.tx_can.tid = context->echo_index;
> > +
> > + usb_fill_bulk_urb(urb, dev->udev,
> > + usb_sndbulkpipe(dev->udev,
> > + dev->bulk_out->bEndpointAddress),
> > + buf, msg->len,
> > + kvaser_usb_write_bulk_callback, context);
> > + usb_anchor_urb(urb, &priv->tx_submitted);
> > +
> > + can_put_echo_skb(skb, netdev, context->echo_index);
> > +
> > + atomic_inc(&priv->active_tx_urbs);
> > +
> > + if (atomic_read(&priv->active_tx_urbs) >= MAX_TX_URBS)
> > + netif_stop_queue(netdev);
> > +
> > + err = usb_submit_urb(urb, GFP_ATOMIC);
> > + if (unlikely(err)) {
> > + can_free_echo_skb(netdev, context->echo_index);
> > +
> > + atomic_dec(&priv->active_tx_urbs);
> > + usb_unanchor_urb(urb);
> > +
> > + stats->tx_dropped++;
> > +
> > + if (err == -ENODEV)
> > + netif_device_detach(netdev);
> > + else
> > + netdev_warn(netdev, "Failed tx_urb %d\n", err);
> > +
> > + goto releasebuf;
> > + }
> > +
> > + usb_free_urb(urb);
> > +
> > + return NETDEV_TX_OK;
> > +
> > +releasebuf:
> > + kfree(buf);
> > +nobufmem:
> > + usb_free_urb(urb);
> > + return ret;
> > +}
> > +
> > +static const struct net_device_ops kvaser_usb_netdev_ops = {
> > + .ndo_open = kvaser_usb_open,
> > + .ndo_stop = kvaser_usb_close,
> > + .ndo_start_xmit = kvaser_usb_start_xmit,
> > +};
> > +
> > +static struct can_bittiming_const kvaser_usb_bittiming_const = {
> > + .name = "kvaser_usb",
> > + .tseg1_min = KVASER_USB_TSEG1_MIN,
> > + .tseg1_max = KVASER_USB_TSEG1_MAX,
> > + .tseg2_min = KVASER_USB_TSEG2_MIN,
> > + .tseg2_max = KVASER_USB_TSEG2_MAX,
> > + .sjw_max = KVASER_USB_SJW_MAX,
> > + .brp_min = KVASER_USB_BRP_MIN,
> > + .brp_max = KVASER_USB_BRP_MAX,
> > + .brp_inc = KVASER_USB_BRP_INC,
> > +};
> > +
> > +static int kvaser_usb_set_bittiming(struct net_device *netdev)
> > +{
> > + struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
> > + struct can_bittiming *bt = &priv->can.bittiming;
> > + struct kvaser_usb *dev = priv->dev;
> > + struct kvaser_msg msg = {
> > + .id = CMD_SET_BUS_PARAMS,
> > + .len = MSG_HEADER_LEN +
> > + sizeof(struct kvaser_msg_busparams),
> > + .u.busparams.channel = priv->channel,
> > + .u.busparams.tid = 0xff,
> > + .u.busparams.bitrate = cpu_to_le32(bt->bitrate),
> > + .u.busparams.sjw = bt->sjw,
> > + .u.busparams.tseg1 = bt->prop_seg + bt->phase_seg1,
> > + .u.busparams.tseg2 = bt->phase_seg2,
> > + };
> > +
> > + if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
> > + msg.u.busparams.no_samp = 3;
> > + else
> > + msg.u.busparams.no_samp = 1;
> > +
> > + return kvaser_usb_send_msg(dev, &msg);
> > +}
> > +
> > +static int kvaser_usb_set_mode(struct net_device *netdev,
> > + enum can_mode mode)
> > +{
> > + struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
> > + int err;
> > +
> > + switch (mode) {
> > + case CAN_MODE_START:
> > + err = kvaser_usb_simple_msg_async(priv, CMD_START_CHIP);
> > + if (err)
> > + return err;
> > + break;
> > + default:
> > + return -EOPNOTSUPP;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int kvaser_usb_get_berr_counter(const struct net_device *netdev,
> > + struct can_berr_counter *bec)
> > +{
> > + struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
> > +
> > + *bec = priv->bec;
> > +
> > + return 0;
> > +}
> > +
> > +static void kvaser_usb_remove_interfaces(struct kvaser_usb *dev)
> > +{
> > + int i;
> > +
> > + for (i = 0; i < dev->nchannels; i++) {
> > + if (!dev->nets[i])
> > + continue;
> > +
> > + unregister_netdev(dev->nets[i]->netdev);
> > + }
> > +
> > + kvaser_usb_unlink_all_urbs(dev);
> > +
> > + for (i = 0; i < dev->nchannels; i++) {
> > + if (!dev->nets[i])
> > + continue;
> > +
> > + free_candev(dev->nets[i]->netdev);
> > + }
> > +}
> > +
> > +static int kvaser_usb_init_one(struct usb_interface *intf,
> > + const struct usb_device_id *id, int channel)
> > +{
> > + struct kvaser_usb *dev = usb_get_intfdata(intf);
> > + struct net_device *netdev;
> > + struct kvaser_usb_net_priv *priv;
> > + int i, err;
> > +
> > + netdev = alloc_candev(sizeof(*priv), MAX_TX_URBS);
> > + if (!netdev) {
> > + dev_err(&intf->dev, "Cannot alloc candev\n");
> > + return -ENOMEM;
> > + }
> > +
> > + priv = netdev_priv(netdev);
> > +
> > + init_completion(&priv->start_comp);
> > + init_completion(&priv->stop_comp);
> > +
> > + init_usb_anchor(&priv->tx_submitted);
> > + atomic_set(&priv->active_tx_urbs, 0);
> > +
> > + for (i = 0; i < ARRAY_SIZE(priv->tx_contexts); i++)
> > + priv->tx_contexts[i].echo_index = MAX_TX_URBS;
> > +
> > + priv->dev = dev;
> > + priv->netdev = netdev;
> > + priv->channel = channel;
> > +
> > + priv->can.state = CAN_STATE_STOPPED;
> > + priv->can.clock.freq = CAN_USB_CLOCK;
> > + priv->can.bittiming_const = &kvaser_usb_bittiming_const;
> > + priv->can.do_set_bittiming = kvaser_usb_set_bittiming;
> > + priv->can.do_set_mode = kvaser_usb_set_mode;
> > + if (id->driver_info & KVASER_HAS_TXRX_ERRORS)
> > + priv->can.do_get_berr_counter = kvaser_usb_get_berr_counter;
> > + priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
> > + if (id->driver_info & KVASER_HAS_SILENT_MODE)
> > + priv->can.ctrlmode_supported |= CAN_CTRLMODE_LISTENONLY;
> > +
> > + netdev->flags |= IFF_ECHO;
> > +
> > + netdev->netdev_ops = &kvaser_usb_netdev_ops;
> > +
> > + SET_NETDEV_DEV(netdev, &intf->dev);
> > +
> > + dev->nets[channel] = priv;
> > +
> > + err = register_candev(netdev);
> > + if (err) {
> > + dev_err(&intf->dev, "Failed to register can device\n");
> > + free_candev(netdev);
> > + dev->nets[channel] = NULL;
> > + return err;
> > + }
> > +
> > + netdev_dbg(netdev, "device registered\n");
> > +
> > + return 0;
> > +}
> > +
> > +static void kvaser_usb_get_endpoints(const struct usb_interface *intf,
> > + struct usb_endpoint_descriptor **in,
> > + struct usb_endpoint_descriptor **out)
> > +{
> > + const struct usb_host_interface *iface_desc;
> > + struct usb_endpoint_descriptor *endpoint;
> > + int i;
> > +
> > + iface_desc = &intf->altsetting[0];
> > +
> > + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
> > + endpoint = &iface_desc->endpoint[i].desc;
> > +
> > + if (usb_endpoint_is_bulk_in(endpoint))
> > + *in = endpoint;
> > +
> > + if (usb_endpoint_is_bulk_out(endpoint))
> > + *out = endpoint;
> > + }
> > +}
> > +
> > +static int kvaser_usb_probe(struct usb_interface *intf,
> > + const struct usb_device_id *id)
> > +{
> > + struct kvaser_usb *dev;
> > + int err = -ENOMEM;
> > + int i;
> > +
> > + dev = devm_kzalloc(&intf->dev, sizeof(*dev), GFP_KERNEL);
> > + if (!dev)
> > + return -ENOMEM;
> > +
> > + kvaser_usb_get_endpoints(intf, &dev->bulk_in, &dev->bulk_out);
> > + if (!dev->bulk_in || !dev->bulk_out) {
> > + dev_err(&intf->dev, "Cannot get usb endpoint(s)");
> > + return err;
> > + }
> > +
> > + dev->udev = interface_to_usbdev(intf);
> > +
> > + init_usb_anchor(&dev->rx_submitted);
> > +
> > + usb_set_intfdata(intf, dev);
> > +
> > + for (i = 0; i < MAX_NET_DEVICES; i++)
> > + kvaser_usb_send_simple_msg(dev, CMD_RESET_CHIP, i);
> > +
> > + err = kvaser_usb_get_software_info(dev);
> > + if (err) {
> > + dev_err(&intf->dev,
> > + "Cannot get software infos, error %d\n", err);
> > + return err;
> > + }
> > +
> > + err = kvaser_usb_get_card_info(dev);
> > + if (err) {
> > + dev_err(&intf->dev,
> > + "Cannot get card infos, error %d\n", err);
> > + return err;
> > + }
> > +
> > + dev_dbg(&intf->dev, "Firmware version: %d.%d.%d\n",
> > + ((dev->fw_version >> 24) & 0xff),
> > + ((dev->fw_version >> 16) & 0xff),
> > + (dev->fw_version & 0xffff));
> > +
> > + for (i = 0; i < dev->nchannels; i++) {
> > + err = kvaser_usb_init_one(intf, id, i);
> > + if (err) {
> > + kvaser_usb_remove_interfaces(dev);
> > + return err;
> > + }
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static void kvaser_usb_disconnect(struct usb_interface *intf)
> > +{
> > + struct kvaser_usb *dev = usb_get_intfdata(intf);
> > +
> > + usb_set_intfdata(intf, NULL);
> > +
> > + if (!dev)
> > + return;
> > +
> > + kvaser_usb_remove_interfaces(dev);
> > +}
> > +
> > +static struct usb_driver kvaser_usb_driver = {
> > + .name = "kvaser_usb",
> > + .probe = kvaser_usb_probe,
> > + .disconnect = kvaser_usb_disconnect,
> > + .id_table = kvaser_usb_table
> ^^^
> nitpick, please add a "," there.
Ok.
> > +};
> >
> can you please add MODULE_DEVICE_TABLE(usb, kvaser_usb_table);
It is already present just after the kvaser_usb_table structure.
>
> > +module_usb_driver(kvaser_usb_driver);
> > +
> > +MODULE_AUTHOR("Olivier Sobrie <olivier@sobrie.be>");
> > +MODULE_DESCRIPTION("CAN driver for Kvaser CAN/USB devices");
> > +MODULE_LICENSE("GPL v2");
> >
>
> Marc
> --
> Pengutronix e.K. | Marc Kleine-Budde |
> Industrial Linux Solutions | Phone: +49-231-2826-924 |
> Vertretung West/Dortmund | Fax: +49-5121-206917-5555 |
> Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
>
Thank you,
--
Olivier
^ permalink raw reply
* Re: [PATCH 4/7] netprio_cgroup: reimplement priomap expansion
From: Daniel Wagner @ 2012-11-20 8:46 UTC (permalink / raw)
To: Tejun Heo
Cc: serge.hallyn-Z7WLFzj8eWMS+FvcfC7Uqw,
ebiederm-aS9lmoZGLiVWk0Htik3J/w, nhorman-2XuSBdqkA4R54TAoqtyWWQ,
tgraf-G/eBtMaohhA, davem-fT/PcQaiUtIeIZ0/mPfg9Q,
lizefan-hv44wF8Li93QT0dZR+AlfA, cgroups-u79uwXL29TY76Z2rM5mHXA,
containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1353400211-5182-5-git-send-email-tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Hi Tejun,
On 20.11.2012 09:30, Tejun Heo wrote:
> netprio kept track of the highest prioidx allocated and resized
> priomaps accordingly when necessary. This makes it necessary to keep
> track of prioidx allocation and may end up resizing on every new
> prioidx.
>
> Update extend_netdev_table() such that it takes @target_idx which the
> priomap should be able to accomodate. If the priomap is large enough,
> nothing happens; otherwise, the size is doubled until @target_idx can
> be accomodated.
>
> This makes max_prioidx and write_update_netdev_table() unnecessary.
> write_priomap() now calls extend_netdev_table() directly.
>
> Signed-off-by: Tejun Heo <tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> Acked-by: Neil Horman <nhorman-2XuSBdqkA4R54TAoqtyWWQ@public.gmane.org>
> ---
> net/core/netprio_cgroup.c | 56 ++++++++++++++++++++++++++++-------------------
> 1 file changed, 33 insertions(+), 23 deletions(-)
>
> diff --git a/net/core/netprio_cgroup.c b/net/core/netprio_cgroup.c
> index 92cc54c..569d83d 100644
> --- a/net/core/netprio_cgroup.c
> +++ b/net/core/netprio_cgroup.c
> @@ -27,11 +27,11 @@
>
> #include <linux/fdtable.h>
>
> +#define PRIOMAP_MIN_SZ 128
> #define PRIOIDX_SZ 128
>
> static unsigned long prioidx_map[PRIOIDX_SZ];
> static DEFINE_SPINLOCK(prioidx_map_lock);
> -static atomic_t max_prioidx = ATOMIC_INIT(0);
>
> static inline struct cgroup_netprio_state *cgrp_netprio_state(struct cgroup *cgrp)
> {
> @@ -51,8 +51,6 @@ static int get_prioidx(u32 *prio)
> return -ENOSPC;
> }
> set_bit(prioidx, prioidx_map);
> - if (atomic_read(&max_prioidx) < prioidx)
> - atomic_set(&max_prioidx, prioidx);
> spin_unlock_irqrestore(&prioidx_map_lock, flags);
> *prio = prioidx;
> return 0;
> @@ -67,15 +65,40 @@ static void put_prioidx(u32 idx)
> spin_unlock_irqrestore(&prioidx_map_lock, flags);
> }
>
> -static int extend_netdev_table(struct net_device *dev, u32 new_len)
> +/*
> + * Extend @dev->priomap so that it's large enough to accomodate
> + * @target_idx. @dev->priomap.priomap_len > @target_idx after successful
> + * return. Must be called under rtnl lock.
> + */
> +static int extend_netdev_table(struct net_device *dev, u32 target_idx)
> {
> - size_t new_size = sizeof(struct netprio_map) +
> - ((sizeof(u32) * new_len));
> - struct netprio_map *new = kzalloc(new_size, GFP_KERNEL);
> - struct netprio_map *old;
> + struct netprio_map *old, *new;
> + size_t new_sz, new_len;
>
> + /* is the existing priomap large enough? */
> old = rtnl_dereference(dev->priomap);
> + if (old && old->priomap_len > target_idx)
> + return 0;
> +
> + /*
> + * Determine the new size. Let's keep it power-of-two. We start
> + * from PRIOMAP_MIN_SZ and double it until it's large enough to
> + * accommodate @target_idx.
> + */
> + new_sz = PRIOMAP_MIN_SZ;
> + while (true) {
> + new_len = (new_sz - offsetof(struct netprio_map, priomap)) /
> + sizeof(new->priomap[0]);
> + if (new_len > target_idx)
> + break;
> + new_sz *= 2;
> + /* overflowed? */
> + if (WARN_ON(new_sz < PRIOMAP_MIN_SZ))
> + return -ENOSPC;
> + }
>
> + /* allocate & copy */
> + new = kzalloc(new_sz, GFP_KERNEL);
> if (!new) {
> pr_warn("Unable to alloc new priomap!\n");
> return -ENOMEM;
> @@ -87,26 +110,13 @@ static int extend_netdev_table(struct net_device *dev, u32 new_len)
>
> new->priomap_len = new_len;
>
> + /* install the new priomap */
> rcu_assign_pointer(dev->priomap, new);
> if (old)
> kfree_rcu(old, rcu);
> return 0;
> }
Okay, I might be just to stupid to see the beauty in what you are doing. So
please bear with me when I ask these question.
struct netprio_map {
struct rcu_head rcu;
struct netprio_aux *aux; /* auxiliary config array */
u32 priomap_len;
u32 priomap[];
};
Is there a specific reason why aux and priomap is handled differently? Couldn't you
just use same approach for both variables, e.g. re/allocating only them here and
leave the allocation struct netprio_map in cgrp_css_alloc()?
Also the algorithm to figure out the size of the array might be a bit too aggressive
in my opinion. So you always start at PRIOMAP_MIN_SIZE and then try to double
the size until target_idx fits. Wouldn't it make sense to start to look
for the new size beginning at old->priomap_len and then do the power-of-two
increase?
cheers,
daniel
^ permalink raw reply
* [Suggestion] net/netfilter: strcpy for timeout->name
From: Chen Gang @ 2012-11-20 8:47 UTC (permalink / raw)
To: Xue Ying, David Miller; +Cc: Shan Wei, Eric Dumazet, netdev
In-Reply-To: <50AB12EE.6050802@gmail.com>
Hello Xue Ying, David Miller:
Please help checking net/netfilter/nfnetlink_cttimeout.c:
I suggest, we use strncpy instead of strcpy at line 143.
just like we have already used strncmp at line 94.
after checking the calling work flow:
the length of nla_data(cda[CTA_TIMEOUT_NAME]) is not limited in server side.
one of calling work flows is:
netlink_unicast -> netlink_unicast_kernel -> nfnetlink_rcv -> netlink_rcv_skb
-> nfnetlink_rcv_msg -> cttimeout_new_timeout
thanks.
gchen.
70 static int
71 cttimeout_new_timeout(struct sock *ctnl, struct sk_buff *skb,
72 const struct nlmsghdr *nlh,
73 const struct nlattr * const cda[])
74 {
75 __u16 l3num;
76 __u8 l4num;
77 struct nf_conntrack_l4proto *l4proto;
78 struct ctnl_timeout *timeout, *matching = NULL;
79 struct net *net = sock_net(skb->sk);
80 char *name;
81 int ret;
82
83 if (!cda[CTA_TIMEOUT_NAME] ||
84 !cda[CTA_TIMEOUT_L3PROTO] ||
85 !cda[CTA_TIMEOUT_L4PROTO] ||
86 !cda[CTA_TIMEOUT_DATA])
87 return -EINVAL;
88
89 name = nla_data(cda[CTA_TIMEOUT_NAME]);
90 l3num = ntohs(nla_get_be16(cda[CTA_TIMEOUT_L3PROTO]));
91 l4num = nla_get_u8(cda[CTA_TIMEOUT_L4PROTO]);
92
93 list_for_each_entry(timeout, &cttimeout_list, head) {
94 if (strncmp(timeout->name, name, CTNL_TIMEOUT_NAME_MAX) != 0)
95 continue;
96
97 if (nlh->nlmsg_flags & NLM_F_EXCL)
98 return -EEXIST;
99
100 matching = timeout;
101 break;
102 }
103
104 l4proto = nf_ct_l4proto_find_get(l3num, l4num);
105
106 /* This protocol is not supportted, skip. */
107 if (l4proto->l4proto != l4num) {
108 ret = -EOPNOTSUPP;
109 goto err_proto_put;
110 }
111
112 if (matching) {
113 if (nlh->nlmsg_flags & NLM_F_REPLACE) {
114 /* You cannot replace one timeout policy by another of
115 * different kind, sorry.
116 */
117 if (matching->l3num != l3num ||
118 matching->l4proto->l4proto != l4num) {
119 ret = -EINVAL;
120 goto err_proto_put;
121 }
122
123 ret = ctnl_timeout_parse_policy(matching, l4proto, net,
124 cda[CTA_TIMEOUT_DATA]);
125 return ret;
126 }
127 ret = -EBUSY;
128 goto err_proto_put;
129 }
130
131 timeout = kzalloc(sizeof(struct ctnl_timeout) +
132 l4proto->ctnl_timeout.obj_size, GFP_KERNEL);
133 if (timeout == NULL) {
134 ret = -ENOMEM;
135 goto err_proto_put;
136 }
137
138 ret = ctnl_timeout_parse_policy(timeout, l4proto, net,
139 cda[CTA_TIMEOUT_DATA]);
140 if (ret < 0)
141 goto err;
142
143 strcpy(timeout->name, nla_data(cda[CTA_TIMEOUT_NAME]));
144 timeout->l3num = l3num;
145 timeout->l4proto = l4proto;
146 atomic_set(&timeout->refcnt, 1);
147 list_add_tail_rcu(&timeout->head, &cttimeout_list);
148
149 return 0;
150 err:
151 kfree(timeout);
152 err_proto_put:
153 nf_ct_l4proto_put(l4proto);
154 return ret;
155 }
156
^ permalink raw reply
* [RESEND PATCH net-next 1/1] sit: allow to configure 6rd tunnels via netlink
From: Nicolas Dichtel @ 2012-11-20 8:41 UTC (permalink / raw)
To: davem; +Cc: netdev, shemminger, Nicolas Dichtel
In-Reply-To: <20121120.033405.490869980095149376.davem@davemloft.net>
This patch add the support of 6RD tunnels management via netlink.
Note that netdev_state_change() is now called when 6RD parameters are updated.
6RD parameters are updated only if there is at least one 6RD attribute.
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
---
include/uapi/linux/if_tunnel.h | 4 ++
net/ipv6/sit.c | 149 ++++++++++++++++++++++++++++++++++-------
2 files changed, 128 insertions(+), 25 deletions(-)
diff --git a/include/uapi/linux/if_tunnel.h b/include/uapi/linux/if_tunnel.h
index 5ab0c8d..aee73d0 100644
--- a/include/uapi/linux/if_tunnel.h
+++ b/include/uapi/linux/if_tunnel.h
@@ -49,6 +49,10 @@ enum {
IFLA_IPTUN_FLAGS,
IFLA_IPTUN_PROTO,
IFLA_IPTUN_PMTUDISC,
+ IFLA_IPTUN_6RD_PREFIX,
+ IFLA_IPTUN_6RD_RELAY_PREFIX,
+ IFLA_IPTUN_6RD_PREFIXLEN,
+ IFLA_IPTUN_6RD_RELAY_PREFIXLEN,
__IFLA_IPTUN_MAX,
};
#define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1)
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index fee21c6..80cb382 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -936,6 +936,38 @@ static void ipip6_tunnel_update(struct ip_tunnel *t, struct ip_tunnel_parm *p)
netdev_state_change(t->dev);
}
+#ifdef CONFIG_IPV6_SIT_6RD
+static int ipip6_tunnel_update_6rd(struct ip_tunnel *t,
+ struct ip_tunnel_6rd *ip6rd)
+{
+ struct in6_addr prefix;
+ __be32 relay_prefix;
+
+ if (ip6rd->relay_prefixlen > 32 ||
+ ip6rd->prefixlen + (32 - ip6rd->relay_prefixlen) > 64)
+ return -EINVAL;
+
+ ipv6_addr_prefix(&prefix, &ip6rd->prefix, ip6rd->prefixlen);
+ if (!ipv6_addr_equal(&prefix, &ip6rd->prefix))
+ return -EINVAL;
+ if (ip6rd->relay_prefixlen)
+ relay_prefix = ip6rd->relay_prefix &
+ htonl(0xffffffffUL <<
+ (32 - ip6rd->relay_prefixlen));
+ else
+ relay_prefix = 0;
+ if (relay_prefix != ip6rd->relay_prefix)
+ return -EINVAL;
+
+ t->ip6rd.prefix = prefix;
+ t->ip6rd.relay_prefix = relay_prefix;
+ t->ip6rd.prefixlen = ip6rd->prefixlen;
+ t->ip6rd.relay_prefixlen = ip6rd->relay_prefixlen;
+ netdev_state_change(t->dev);
+ return 0;
+}
+#endif
+
static int
ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
{
@@ -1105,31 +1137,9 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
t = netdev_priv(dev);
if (cmd != SIOCDEL6RD) {
- struct in6_addr prefix;
- __be32 relay_prefix;
-
- err = -EINVAL;
- if (ip6rd.relay_prefixlen > 32 ||
- ip6rd.prefixlen + (32 - ip6rd.relay_prefixlen) > 64)
- goto done;
-
- ipv6_addr_prefix(&prefix, &ip6rd.prefix,
- ip6rd.prefixlen);
- if (!ipv6_addr_equal(&prefix, &ip6rd.prefix))
+ err = ipip6_tunnel_update_6rd(t, &ip6rd);
+ if (err < 0)
goto done;
- if (ip6rd.relay_prefixlen)
- relay_prefix = ip6rd.relay_prefix &
- htonl(0xffffffffUL <<
- (32 - ip6rd.relay_prefixlen));
- else
- relay_prefix = 0;
- if (relay_prefix != ip6rd.relay_prefix)
- goto done;
-
- t->ip6rd.prefix = prefix;
- t->ip6rd.relay_prefix = relay_prefix;
- t->ip6rd.prefixlen = ip6rd.prefixlen;
- t->ip6rd.relay_prefixlen = ip6rd.relay_prefixlen;
} else
ipip6_tunnel_clone_6rd(dev, sitn);
@@ -1261,11 +1271,53 @@ static void ipip6_netlink_parms(struct nlattr *data[],
parms->i_flags = nla_get_be16(data[IFLA_IPTUN_FLAGS]);
}
+#ifdef CONFIG_IPV6_SIT_6RD
+/* This function returns true when 6RD attributes are present in the nl msg */
+static bool ipip6_netlink_6rd_parms(struct nlattr *data[],
+ struct ip_tunnel_6rd *ip6rd)
+{
+ bool ret = false;
+ memset(ip6rd, 0, sizeof(*ip6rd));
+
+ if (!data)
+ return ret;
+
+ if (data[IFLA_IPTUN_6RD_PREFIX]) {
+ ret = true;
+ nla_memcpy(&ip6rd->prefix, data[IFLA_IPTUN_6RD_PREFIX],
+ sizeof(struct in6_addr));
+ }
+
+ if (data[IFLA_IPTUN_6RD_RELAY_PREFIX]) {
+ ret = true;
+ ip6rd->relay_prefix =
+ nla_get_be32(data[IFLA_IPTUN_6RD_RELAY_PREFIX]);
+ }
+
+ if (data[IFLA_IPTUN_6RD_PREFIXLEN]) {
+ ret = true;
+ ip6rd->prefixlen = nla_get_u16(data[IFLA_IPTUN_6RD_PREFIXLEN]);
+ }
+
+ if (data[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]) {
+ ret = true;
+ ip6rd->relay_prefixlen =
+ nla_get_u16(data[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]);
+ }
+
+ return ret;
+}
+#endif
+
static int ipip6_newlink(struct net *src_net, struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[])
{
struct net *net = dev_net(dev);
struct ip_tunnel *nt;
+#ifdef CONFIG_IPV6_SIT_6RD
+ struct ip_tunnel_6rd ip6rd;
+#endif
+ int err;
nt = netdev_priv(dev);
ipip6_netlink_parms(data, &nt->parms);
@@ -1273,7 +1325,16 @@ static int ipip6_newlink(struct net *src_net, struct net_device *dev,
if (ipip6_tunnel_locate(net, &nt->parms, 0))
return -EEXIST;
- return ipip6_tunnel_create(dev);
+ err = ipip6_tunnel_create(dev);
+ if (err < 0)
+ return err;
+
+#ifdef CONFIG_IPV6_SIT_6RD
+ if (ipip6_netlink_6rd_parms(data, &ip6rd))
+ err = ipip6_tunnel_update_6rd(nt, &ip6rd);
+#endif
+
+ return err;
}
static int ipip6_changelink(struct net_device *dev, struct nlattr *tb[],
@@ -1283,6 +1344,9 @@ static int ipip6_changelink(struct net_device *dev, struct nlattr *tb[],
struct ip_tunnel_parm p;
struct net *net = dev_net(dev);
struct sit_net *sitn = net_generic(net, sit_net_id);
+#ifdef CONFIG_IPV6_SIT_6RD
+ struct ip_tunnel_6rd ip6rd;
+#endif
if (dev == sitn->fb_tunnel_dev)
return -EINVAL;
@@ -1302,6 +1366,12 @@ static int ipip6_changelink(struct net_device *dev, struct nlattr *tb[],
t = netdev_priv(dev);
ipip6_tunnel_update(t, &p);
+
+#ifdef CONFIG_IPV6_SIT_6RD
+ if (ipip6_netlink_6rd_parms(data, &ip6rd))
+ return ipip6_tunnel_update_6rd(t, &ip6rd);
+#endif
+
return 0;
}
@@ -1322,6 +1392,16 @@ static size_t ipip6_get_size(const struct net_device *dev)
nla_total_size(1) +
/* IFLA_IPTUN_FLAGS */
nla_total_size(2) +
+#ifdef CONFIG_IPV6_SIT_6RD
+ /* IFLA_IPTUN_6RD_PREFIX */
+ nla_total_size(sizeof(struct in6_addr)) +
+ /* IFLA_IPTUN_6RD_RELAY_PREFIX */
+ nla_total_size(4) +
+ /* IFLA_IPTUN_6RD_PREFIXLEN */
+ nla_total_size(2) +
+ /* IFLA_IPTUN_6RD_RELAY_PREFIXLEN */
+ nla_total_size(2) +
+#endif
0;
}
@@ -1339,6 +1419,19 @@ static int ipip6_fill_info(struct sk_buff *skb, const struct net_device *dev)
!!(parm->iph.frag_off & htons(IP_DF))) ||
nla_put_be16(skb, IFLA_IPTUN_FLAGS, parm->i_flags))
goto nla_put_failure;
+
+#ifdef CONFIG_IPV6_SIT_6RD
+ if (nla_put(skb, IFLA_IPTUN_6RD_PREFIX, sizeof(struct in6_addr),
+ &tunnel->ip6rd.prefix) ||
+ nla_put_be32(skb, IFLA_IPTUN_6RD_RELAY_PREFIX,
+ tunnel->ip6rd.relay_prefix) ||
+ nla_put_u16(skb, IFLA_IPTUN_6RD_PREFIXLEN,
+ tunnel->ip6rd.prefixlen) ||
+ nla_put_u16(skb, IFLA_IPTUN_6RD_RELAY_PREFIXLEN,
+ tunnel->ip6rd.relay_prefixlen))
+ goto nla_put_failure;
+#endif
+
return 0;
nla_put_failure:
@@ -1353,6 +1446,12 @@ static const struct nla_policy ipip6_policy[IFLA_IPTUN_MAX + 1] = {
[IFLA_IPTUN_TOS] = { .type = NLA_U8 },
[IFLA_IPTUN_PMTUDISC] = { .type = NLA_U8 },
[IFLA_IPTUN_FLAGS] = { .type = NLA_U16 },
+#ifdef CONFIG_IPV6_SIT_6RD
+ [IFLA_IPTUN_6RD_PREFIX] = { .len = sizeof(struct in6_addr) },
+ [IFLA_IPTUN_6RD_RELAY_PREFIX] = { .type = NLA_U32 },
+ [IFLA_IPTUN_6RD_PREFIXLEN] = { .type = NLA_U16 },
+ [IFLA_IPTUN_6RD_RELAY_PREFIXLEN] = { .type = NLA_U16 },
+#endif
};
static struct rtnl_link_ops sit_link_ops __read_mostly = {
--
1.7.12
^ permalink raw reply related
* Re: [PATCH 3/7] netprio_cgroup: shorten variable names in extend_netdev_table()
From: Daniel Wagner @ 2012-11-20 8:37 UTC (permalink / raw)
To: Tejun Heo
Cc: nhorman-2XuSBdqkA4R54TAoqtyWWQ, netdev-u79uwXL29TY76Z2rM5mHXA,
containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
ebiederm-aS9lmoZGLiVWk0Htik3J/w, tgraf-G/eBtMaohhA,
cgroups-u79uwXL29TY76Z2rM5mHXA, davem-fT/PcQaiUtIeIZ0/mPfg9Q
In-Reply-To: <1353400211-5182-4-git-send-email-tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
On 20.11.2012 09:30, Tejun Heo wrote:
> The function is about to go through a rewrite. In preparation,
> shorten the variable names so that we don't repeat "priomap" so often.
>
> This patch is cosmetic.
>
> Signed-off-by: Tejun Heo <tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> Acked-by: Neil Horman <nhorman-2XuSBdqkA4R54TAoqtyWWQ@public.gmane.org>
Tested and Acked-by: Daniel Wagner <daniel.wagner-98C5kh4wR6ohFhg+JK9F0w@public.gmane.org>
^ permalink raw reply
* Re: [PATCH 2/7] netprio_cgroup: simplify write_priomap()
From: Daniel Wagner @ 2012-11-20 8:37 UTC (permalink / raw)
To: Tejun Heo
Cc: nhorman-2XuSBdqkA4R54TAoqtyWWQ, netdev-u79uwXL29TY76Z2rM5mHXA,
containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
ebiederm-aS9lmoZGLiVWk0Htik3J/w, tgraf-G/eBtMaohhA,
cgroups-u79uwXL29TY76Z2rM5mHXA, davem-fT/PcQaiUtIeIZ0/mPfg9Q
In-Reply-To: <1353400211-5182-3-git-send-email-tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
On 20.11.2012 09:30, Tejun Heo wrote:
> sscanf() doesn't bite.
>
> Signed-off-by: Tejun Heo <tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> Acked-by: Neil Horman <nhorman-2XuSBdqkA4R54TAoqtyWWQ@public.gmane.org>
Tested and Acked-by: Daniel Wagner <daniel.wagner-98C5kh4wR6ohFhg+JK9F0w@public.gmane.org>
^ permalink raw reply
* Re: [PATCH 1/7] netcls_cgroup: move config inheritance to ->css_online() and remove .broken_hierarchy marking
From: Daniel Wagner @ 2012-11-20 8:35 UTC (permalink / raw)
To: Tejun Heo
Cc: nhorman-2XuSBdqkA4R54TAoqtyWWQ, netdev-u79uwXL29TY76Z2rM5mHXA,
containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
ebiederm-aS9lmoZGLiVWk0Htik3J/w, tgraf-G/eBtMaohhA,
cgroups-u79uwXL29TY76Z2rM5mHXA, davem-fT/PcQaiUtIeIZ0/mPfg9Q
In-Reply-To: <1353400211-5182-2-git-send-email-tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
On 20.11.2012 09:30, Tejun Heo wrote:
> It turns out that we'll have to live with attributes which are
> inherited at cgroup creation time but not affected by further updates
> to the parent afterwards - such attributes are already in wide use
> e.g. for cpuset.
>
> So, there's nothing to do for netcls_cgroup for hierarchy support.
> Its current behavior - inherit only during creation - is good enough.
>
> Move config inheriting from ->css_alloc() to ->css_online() for
> consistency, which doesn't change behavior at all, and remove
> .broken_hierarchy marking.
>
> Signed-off-by: Tejun Heo <tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Not introducing the 'is_local' is a good thing.
Tested and Acked-by: Daniel Wagner <daniel.wagner-98C5kh4wR6ohFhg+JK9F0w@public.gmane.org>
^ permalink raw reply
* Re: [PATCH net-next 1/4] ipip: allow to deactivate the creation of fb dev
From: David Miller @ 2012-11-20 8:34 UTC (permalink / raw)
To: nicolas.dichtel; +Cc: shemminger, netdev
In-Reply-To: <50AB3F99.7070701@6wind.com>
From: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Date: Tue, 20 Nov 2012 09:30:17 +0100
> Le 20/11/2012 01:07, David Miller a écrit :
>> Why not put this aside and submit the other parts of your
>> patch set on their own, since those looked fine to me?
> Ok, no problem. I wanted to get feedback about this kind of idea, I
> understand the point.
>
> When you said "the other parts", you mean only patch 2/4 (sit: allow
> to configure 6rd tunnels via netlink) or 3/4 and 4/4 too?
> Because 3/4 and 4/4 are equivalent to this one.
I meant patch #2.
^ permalink raw reply
* Re: [Xen-devel] compound skb frag pages appearing in start_xmit
From: Stefan Bader @ 2012-11-20 8:30 UTC (permalink / raw)
To: Sander Eikelenboom
Cc: ANNIE LI, Ian Campbell, Eric Dumazet, netdev@vger.kernel.org,
Marcos E. Matsunaga, xen-devel, Konrad Rzeszutek Wilk,
Eric Dumazet
In-Reply-To: <1333495676.20121119164304@eikelenboom.it>
[-- Attachment #1: Type: text/plain, Size: 2248 bytes --]
On 19.11.2012 16:43, Sander Eikelenboom wrote:
>
> Thursday, November 15, 2012, 3:31:42 AM, you wrote:
>
>> On 2012-10-11 18:14, Ian Campbell wrote:
>>> On Thu, 2012-10-11 at 11:05 +0100, Eric Dumazet wrote:
>>>> On Thu, 2012-10-11 at 12:00 +0200, Sander Eikelenboom wrote:
>>>>
>>>>> Probably due to the BUG_ON from the patch below, i changed it into a WARN_ON.
>>>>> And i seem to hit it, but only in one of the guests at the moment and it triggers quite irregularly.
>>>> xennet_make_frags() is able to split the skb->head in multiple page-size
>>>> chunks.
>>>>
>>>> It should do the same for fragments
>>> Right, I just want to be reproduce the issue so I can know I've fixed it
>>> properly ;-)
>> Hi Ian,
>
>> I can reproduce this BUG_ON when running netperf/netserver test between
>> two domus running on the same dom0. The domu and dom0 all use v3.7-rc1.
>
>> When I tried to rebase my persistent grant netfront/netback patch on
>> latest kernel, netperf/netserver test never succeeded. I did some test
>> to find out that v3.6-rc7 works fine, but v3.7-rc1, v3.7-rc2 and
>> v3.7-rc4 does not succeed in netperf/netserver test. So I keep my
>> persistent grant patch only based on v3.4-rc3 now.
>
>> Konrad thought about commit 6a8ed462f16b8455eec5ae00eb6014159a6721f0 in
>> v3.7-rc1, and suggested me to test your debug patch in netfront. This
>> BUG_ON happens soon after running the netperf/netserver test case.
>
>> Thanks
>> Annie
>
> Is there any progression with this bug (rc6 is out the door, so the release of 3.7-final seems to be eminent and this bug completely cripples any networking with guests) ?
>
+1 on that. I was testing yesterday with a PVM domU running 3.7-rc5 on Xen 4.2
(but also reported from EC2 running Xen 3.4.3) c with one VCPU. I actually can
trigger it by just ssh'ing into the domU (from another machine) and then run
"find /". Output starts to stutter and then stops completely. When this happens
a new connection still can be made and as long as only shorter output is
generated the ssh connection is ok. From a dump taken it looks like user-space
is waiting in some select call (without any warnon I rather won't see the tx path).
-Stefan
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 897 bytes --]
^ permalink raw reply
* Re: [PATCH net-next 1/4] ipip: allow to deactivate the creation of fb dev
From: Nicolas Dichtel @ 2012-11-20 8:30 UTC (permalink / raw)
To: David Miller; +Cc: shemminger, netdev
In-Reply-To: <20121119.190753.856116050444408241.davem@davemloft.net>
Le 20/11/2012 01:07, David Miller a écrit :
> From: Nicolas Dichtel <nicolas.dichtel@6wind.com>
> Date: Fri, 16 Nov 2012 17:46:11 +0100
>
>> By default, the fb device is created, so there is no change if you
>> don't set explicitly setup_fb to 0.
>
>
> Nicolas, this idea is contentous to me too.
>
> Why not put this aside and submit the other parts of your
> patch set on their own, since those looked fine to me?
Ok, no problem. I wanted to get feedback about this kind of idea, I understand
the point.
When you said "the other parts", you mean only patch 2/4 (sit: allow to
configure 6rd tunnels via netlink) or 3/4 and 4/4 too?
Because 3/4 and 4/4 are equivalent to this one.
^ permalink raw reply
* [PATCH 7/7] netprio_cgroup: allow nesting and inherit config on cgroup creation
From: Tejun Heo @ 2012-11-20 8:30 UTC (permalink / raw)
To: daniel.wagner-98C5kh4wR6ohFhg+JK9F0w,
serge.hallyn-Z7WLFzj8eWMS+FvcfC7Uqw,
ebiederm-aS9lmoZGLiVWk0Htik3J/w, nhorman-2XuSBdqkA4R54TAoqtyWWQ,
tgraf-G/eBtMaohhA
Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Tejun Heo,
cgroups-u79uwXL29TY76Z2rM5mHXA, davem-fT/PcQaiUtIeIZ0/mPfg9Q
In-Reply-To: <1353400211-5182-1-git-send-email-tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Inherit netprio configuration from ->css_online(), allow nesting and
remove .broken_hierarchy marking. This makes netprio_cgroup's
behavior match netcls_cgroup's.
Note that this patch changes userland-visible behavior. Nesting is
allowed and the first level cgroups below the root cgroup behave
differently - they inherit priorities from the root cgroup on creation
instead of starting with 0. This is unfortunate but not doing so is
much crazier.
Signed-off-by: Tejun Heo <tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
---
Documentation/cgroups/net_prio.txt | 2 ++
net/core/netprio_cgroup.c | 42 ++++++++++++++++++++++----------------
2 files changed, 26 insertions(+), 18 deletions(-)
diff --git a/Documentation/cgroups/net_prio.txt b/Documentation/cgroups/net_prio.txt
index 01b3226..a82cbd2 100644
--- a/Documentation/cgroups/net_prio.txt
+++ b/Documentation/cgroups/net_prio.txt
@@ -51,3 +51,5 @@ One usage for the net_prio cgroup is with mqprio qdisc allowing application
traffic to be steered to hardware/driver based traffic classes. These mappings
can then be managed by administrators or other networking protocols such as
DCBX.
+
+A new net_prio cgroup inherits the parent's configuration.
diff --git a/net/core/netprio_cgroup.c b/net/core/netprio_cgroup.c
index b2af0d0..bde53da 100644
--- a/net/core/netprio_cgroup.c
+++ b/net/core/netprio_cgroup.c
@@ -136,9 +136,6 @@ static struct cgroup_subsys_state *cgrp_css_alloc(struct cgroup *cgrp)
{
struct cgroup_netprio_state *cs;
- if (cgrp->parent && cgrp->parent->id)
- return ERR_PTR(-EINVAL);
-
cs = kzalloc(sizeof(*cs), GFP_KERNEL);
if (!cs)
return ERR_PTR(-ENOMEM);
@@ -146,16 +143,34 @@ static struct cgroup_subsys_state *cgrp_css_alloc(struct cgroup *cgrp)
return &cs->css;
}
-static void cgrp_css_free(struct cgroup *cgrp)
+static int cgrp_css_online(struct cgroup *cgrp)
{
- struct cgroup_netprio_state *cs = cgrp_netprio_state(cgrp);
+ struct cgroup *parent = cgrp->parent;
struct net_device *dev;
+ int ret = 0;
+
+ if (!parent)
+ return 0;
rtnl_lock();
- for_each_netdev(&init_net, dev)
- WARN_ON_ONCE(netprio_set_prio(cgrp, dev, 0));
+ /*
+ * Inherit prios from the parent. As all prios are set during
+ * onlining, there is no need to clear them on offline.
+ */
+ for_each_netdev(&init_net, dev) {
+ u32 prio = netprio_prio(parent, dev);
+
+ ret = netprio_set_prio(cgrp, dev, prio);
+ if (ret)
+ break;
+ }
rtnl_unlock();
- kfree(cs);
+ return ret;
+}
+
+static void cgrp_css_free(struct cgroup *cgrp)
+{
+ kfree(cgrp_netprio_state(cgrp));
}
static u64 read_prioidx(struct cgroup *cgrp, struct cftype *cft)
@@ -237,21 +252,12 @@ static struct cftype ss_files[] = {
struct cgroup_subsys net_prio_subsys = {
.name = "net_prio",
.css_alloc = cgrp_css_alloc,
+ .css_online = cgrp_css_online,
.css_free = cgrp_css_free,
.attach = net_prio_attach,
.subsys_id = net_prio_subsys_id,
.base_cftypes = ss_files,
.module = THIS_MODULE,
-
- /*
- * net_prio has artificial limit on the number of cgroups and
- * disallows nesting making it impossible to co-mount it with other
- * hierarchical subsystems. Remove the artificially low PRIOIDX_SZ
- * limit and properly nest configuration such that children follow
- * their parents' configurations by default and are allowed to
- * override and remove the following.
- */
- .broken_hierarchy = true,
};
static int netprio_device_event(struct notifier_block *unused,
--
1.7.11.7
^ permalink raw reply related
* [PATCH 6/7] netprio_cgroup: implement netprio[_set]_prio() helpers
From: Tejun Heo @ 2012-11-20 8:30 UTC (permalink / raw)
To: daniel.wagner-98C5kh4wR6ohFhg+JK9F0w,
serge.hallyn-Z7WLFzj8eWMS+FvcfC7Uqw,
ebiederm-aS9lmoZGLiVWk0Htik3J/w, nhorman-2XuSBdqkA4R54TAoqtyWWQ,
tgraf-G/eBtMaohhA
Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Tejun Heo,
cgroups-u79uwXL29TY76Z2rM5mHXA, davem-fT/PcQaiUtIeIZ0/mPfg9Q
In-Reply-To: <1353400211-5182-1-git-send-email-tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Introduce two helpers - netprio_prio() and netprio_set_prio() - which
hide the details of priomap access and expansion. This will help
implementing hierarchy support.
Signed-off-by: Tejun Heo <tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Acked-by: Neil Horman <nhorman-2XuSBdqkA4R54TAoqtyWWQ@public.gmane.org>
---
net/core/netprio_cgroup.c | 72 ++++++++++++++++++++++++++++++++---------------
1 file changed, 50 insertions(+), 22 deletions(-)
diff --git a/net/core/netprio_cgroup.c b/net/core/netprio_cgroup.c
index 9409cdf..b2af0d0 100644
--- a/net/core/netprio_cgroup.c
+++ b/net/core/netprio_cgroup.c
@@ -87,6 +87,51 @@ static int extend_netdev_table(struct net_device *dev, u32 target_idx)
return 0;
}
+/**
+ * netprio_prio - return the effective netprio of a cgroup-net_device pair
+ * @cgrp: cgroup part of the target pair
+ * @dev: net_device part of the target pair
+ *
+ * Should be called under RCU read or rtnl lock.
+ */
+static u32 netprio_prio(struct cgroup *cgrp, struct net_device *dev)
+{
+ struct netprio_map *map = rcu_dereference_rtnl(dev->priomap);
+
+ if (map && cgrp->id < map->priomap_len)
+ return map->priomap[cgrp->id];
+ return 0;
+}
+
+/**
+ * netprio_set_prio - set netprio on a cgroup-net_device pair
+ * @cgrp: cgroup part of the target pair
+ * @dev: net_device part of the target pair
+ * @prio: prio to set
+ *
+ * Set netprio to @prio on @cgrp-@dev pair. Should be called under rtnl
+ * lock and may fail under memory pressure for non-zero @prio.
+ */
+static int netprio_set_prio(struct cgroup *cgrp, struct net_device *dev,
+ u32 prio)
+{
+ struct netprio_map *map;
+ int ret;
+
+ /* avoid extending priomap for zero writes */
+ map = rtnl_dereference(dev->priomap);
+ if (!prio && (!map || map->priomap_len <= cgrp->id))
+ return 0;
+
+ ret = extend_netdev_table(dev, cgrp->id);
+ if (ret)
+ return ret;
+
+ map = rtnl_dereference(dev->priomap);
+ map->priomap[cgrp->id] = prio;
+ return 0;
+}
+
static struct cgroup_subsys_state *cgrp_css_alloc(struct cgroup *cgrp)
{
struct cgroup_netprio_state *cs;
@@ -105,14 +150,10 @@ static void cgrp_css_free(struct cgroup *cgrp)
{
struct cgroup_netprio_state *cs = cgrp_netprio_state(cgrp);
struct net_device *dev;
- struct netprio_map *map;
rtnl_lock();
- for_each_netdev(&init_net, dev) {
- map = rtnl_dereference(dev->priomap);
- if (map && cgrp->id < map->priomap_len)
- map->priomap[cgrp->id] = 0;
- }
+ for_each_netdev(&init_net, dev)
+ WARN_ON_ONCE(netprio_set_prio(cgrp, dev, 0));
rtnl_unlock();
kfree(cs);
}
@@ -126,16 +167,10 @@ static int read_priomap(struct cgroup *cont, struct cftype *cft,
struct cgroup_map_cb *cb)
{
struct net_device *dev;
- u32 id = cont->id;
- u32 priority;
- struct netprio_map *map;
rcu_read_lock();
- for_each_netdev_rcu(&init_net, dev) {
- map = rcu_dereference(dev->priomap);
- priority = (map && id < map->priomap_len) ? map->priomap[id] : 0;
- cb->fill(cb, dev->name, priority);
- }
+ for_each_netdev_rcu(&init_net, dev)
+ cb->fill(cb, dev->name, netprio_prio(cont, dev));
rcu_read_unlock();
return 0;
}
@@ -145,7 +180,6 @@ static int write_priomap(struct cgroup *cgrp, struct cftype *cft,
{
char devname[IFNAMSIZ + 1];
struct net_device *dev;
- struct netprio_map *map;
u32 prio;
int ret;
@@ -158,14 +192,8 @@ static int write_priomap(struct cgroup *cgrp, struct cftype *cft,
rtnl_lock();
- ret = extend_netdev_table(dev, cgrp->id);
- if (ret)
- goto out_unlock;
+ ret = netprio_set_prio(cgrp, dev, prio);
- map = rtnl_dereference(dev->priomap);
- if (map)
- map->priomap[cgrp->id] = prio;
-out_unlock:
rtnl_unlock();
dev_put(dev);
return ret;
--
1.7.11.7
^ permalink raw reply related
* [PATCH 5/7] netprio_cgroup: use cgroup->id instead of cgroup_netprio_state->prioidx
From: Tejun Heo @ 2012-11-20 8:30 UTC (permalink / raw)
To: daniel.wagner-98C5kh4wR6ohFhg+JK9F0w,
serge.hallyn-Z7WLFzj8eWMS+FvcfC7Uqw,
ebiederm-aS9lmoZGLiVWk0Htik3J/w, nhorman-2XuSBdqkA4R54TAoqtyWWQ,
tgraf-G/eBtMaohhA
Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Tejun Heo,
cgroups-u79uwXL29TY76Z2rM5mHXA, davem-fT/PcQaiUtIeIZ0/mPfg9Q
In-Reply-To: <1353400211-5182-1-git-send-email-tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
With priomap expansion no longer depending on knowing max id
allocated, netprio_cgroup can use cgroup->id insted of cs->prioidx.
Drop prioidx alloc/free logic and convert all uses to cgroup->id.
* In cgrp_css_alloc(), parent->id test is moved above @cs allocation
to simplify error path.
* In cgrp_css_free(), @cs assignment is made initialization.
Signed-off-by: Tejun Heo <tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Acked-by: Neil Horman <nhorman-2XuSBdqkA4R54TAoqtyWWQ@public.gmane.org>
---
include/net/netprio_cgroup.h | 11 +++-----
net/core/netprio_cgroup.c | 65 ++++++++------------------------------------
2 files changed, 15 insertions(+), 61 deletions(-)
diff --git a/include/net/netprio_cgroup.h b/include/net/netprio_cgroup.h
index 2760f4f..1d04b6f 100644
--- a/include/net/netprio_cgroup.h
+++ b/include/net/netprio_cgroup.h
@@ -27,7 +27,6 @@ struct netprio_map {
struct cgroup_netprio_state {
struct cgroup_subsys_state css;
- u32 prioidx;
};
extern void sock_update_netprioidx(struct sock *sk, struct task_struct *task);
@@ -36,13 +35,12 @@ extern void sock_update_netprioidx(struct sock *sk, struct task_struct *task);
static inline u32 task_netprioidx(struct task_struct *p)
{
- struct cgroup_netprio_state *state;
+ struct cgroup_subsys_state *css;
u32 idx;
rcu_read_lock();
- state = container_of(task_subsys_state(p, net_prio_subsys_id),
- struct cgroup_netprio_state, css);
- idx = state->prioidx;
+ css = task_subsys_state(p, net_prio_subsys_id);
+ idx = css->cgroup->id;
rcu_read_unlock();
return idx;
}
@@ -57,8 +55,7 @@ static inline u32 task_netprioidx(struct task_struct *p)
rcu_read_lock();
css = task_subsys_state(p, net_prio_subsys_id);
if (css)
- idx = container_of(css,
- struct cgroup_netprio_state, css)->prioidx;
+ idx = css->cgroup->id;
rcu_read_unlock();
return idx;
}
diff --git a/net/core/netprio_cgroup.c b/net/core/netprio_cgroup.c
index 569d83d..9409cdf 100644
--- a/net/core/netprio_cgroup.c
+++ b/net/core/netprio_cgroup.c
@@ -28,10 +28,6 @@
#include <linux/fdtable.h>
#define PRIOMAP_MIN_SZ 128
-#define PRIOIDX_SZ 128
-
-static unsigned long prioidx_map[PRIOIDX_SZ];
-static DEFINE_SPINLOCK(prioidx_map_lock);
static inline struct cgroup_netprio_state *cgrp_netprio_state(struct cgroup *cgrp)
{
@@ -39,32 +35,6 @@ static inline struct cgroup_netprio_state *cgrp_netprio_state(struct cgroup *cgr
struct cgroup_netprio_state, css);
}
-static int get_prioidx(u32 *prio)
-{
- unsigned long flags;
- u32 prioidx;
-
- spin_lock_irqsave(&prioidx_map_lock, flags);
- prioidx = find_first_zero_bit(prioidx_map, sizeof(unsigned long) * PRIOIDX_SZ);
- if (prioidx == sizeof(unsigned long) * PRIOIDX_SZ) {
- spin_unlock_irqrestore(&prioidx_map_lock, flags);
- return -ENOSPC;
- }
- set_bit(prioidx, prioidx_map);
- spin_unlock_irqrestore(&prioidx_map_lock, flags);
- *prio = prioidx;
- return 0;
-}
-
-static void put_prioidx(u32 idx)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&prioidx_map_lock, flags);
- clear_bit(idx, prioidx_map);
- spin_unlock_irqrestore(&prioidx_map_lock, flags);
-}
-
/*
* Extend @dev->priomap so that it's large enough to accomodate
* @target_idx. @dev->priomap.priomap_len > @target_idx after successful
@@ -120,62 +90,50 @@ static int extend_netdev_table(struct net_device *dev, u32 target_idx)
static struct cgroup_subsys_state *cgrp_css_alloc(struct cgroup *cgrp)
{
struct cgroup_netprio_state *cs;
- int ret = -EINVAL;
+
+ if (cgrp->parent && cgrp->parent->id)
+ return ERR_PTR(-EINVAL);
cs = kzalloc(sizeof(*cs), GFP_KERNEL);
if (!cs)
return ERR_PTR(-ENOMEM);
- if (cgrp->parent && cgrp_netprio_state(cgrp->parent)->prioidx)
- goto out;
-
- ret = get_prioidx(&cs->prioidx);
- if (ret < 0) {
- pr_warn("No space in priority index array\n");
- goto out;
- }
-
return &cs->css;
-out:
- kfree(cs);
- return ERR_PTR(ret);
}
static void cgrp_css_free(struct cgroup *cgrp)
{
- struct cgroup_netprio_state *cs;
+ struct cgroup_netprio_state *cs = cgrp_netprio_state(cgrp);
struct net_device *dev;
struct netprio_map *map;
- cs = cgrp_netprio_state(cgrp);
rtnl_lock();
for_each_netdev(&init_net, dev) {
map = rtnl_dereference(dev->priomap);
- if (map && cs->prioidx < map->priomap_len)
- map->priomap[cs->prioidx] = 0;
+ if (map && cgrp->id < map->priomap_len)
+ map->priomap[cgrp->id] = 0;
}
rtnl_unlock();
- put_prioidx(cs->prioidx);
kfree(cs);
}
static u64 read_prioidx(struct cgroup *cgrp, struct cftype *cft)
{
- return (u64)cgrp_netprio_state(cgrp)->prioidx;
+ return cgrp->id;
}
static int read_priomap(struct cgroup *cont, struct cftype *cft,
struct cgroup_map_cb *cb)
{
struct net_device *dev;
- u32 prioidx = cgrp_netprio_state(cont)->prioidx;
+ u32 id = cont->id;
u32 priority;
struct netprio_map *map;
rcu_read_lock();
for_each_netdev_rcu(&init_net, dev) {
map = rcu_dereference(dev->priomap);
- priority = (map && prioidx < map->priomap_len) ? map->priomap[prioidx] : 0;
+ priority = (map && id < map->priomap_len) ? map->priomap[id] : 0;
cb->fill(cb, dev->name, priority);
}
rcu_read_unlock();
@@ -185,7 +143,6 @@ static int read_priomap(struct cgroup *cont, struct cftype *cft,
static int write_priomap(struct cgroup *cgrp, struct cftype *cft,
const char *buffer)
{
- u32 prioidx = cgrp_netprio_state(cgrp)->prioidx;
char devname[IFNAMSIZ + 1];
struct net_device *dev;
struct netprio_map *map;
@@ -201,13 +158,13 @@ static int write_priomap(struct cgroup *cgrp, struct cftype *cft,
rtnl_lock();
- ret = extend_netdev_table(dev, prioidx);
+ ret = extend_netdev_table(dev, cgrp->id);
if (ret)
goto out_unlock;
map = rtnl_dereference(dev->priomap);
if (map)
- map->priomap[prioidx] = prio;
+ map->priomap[cgrp->id] = prio;
out_unlock:
rtnl_unlock();
dev_put(dev);
--
1.7.11.7
^ permalink raw reply related
* [PATCH 4/7] netprio_cgroup: reimplement priomap expansion
From: Tejun Heo @ 2012-11-20 8:30 UTC (permalink / raw)
To: daniel.wagner-98C5kh4wR6ohFhg+JK9F0w,
serge.hallyn-Z7WLFzj8eWMS+FvcfC7Uqw,
ebiederm-aS9lmoZGLiVWk0Htik3J/w, nhorman-2XuSBdqkA4R54TAoqtyWWQ,
tgraf-G/eBtMaohhA
Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Tejun Heo,
cgroups-u79uwXL29TY76Z2rM5mHXA, davem-fT/PcQaiUtIeIZ0/mPfg9Q
In-Reply-To: <1353400211-5182-1-git-send-email-tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
netprio kept track of the highest prioidx allocated and resized
priomaps accordingly when necessary. This makes it necessary to keep
track of prioidx allocation and may end up resizing on every new
prioidx.
Update extend_netdev_table() such that it takes @target_idx which the
priomap should be able to accomodate. If the priomap is large enough,
nothing happens; otherwise, the size is doubled until @target_idx can
be accomodated.
This makes max_prioidx and write_update_netdev_table() unnecessary.
write_priomap() now calls extend_netdev_table() directly.
Signed-off-by: Tejun Heo <tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Acked-by: Neil Horman <nhorman-2XuSBdqkA4R54TAoqtyWWQ@public.gmane.org>
---
net/core/netprio_cgroup.c | 56 ++++++++++++++++++++++++++++-------------------
1 file changed, 33 insertions(+), 23 deletions(-)
diff --git a/net/core/netprio_cgroup.c b/net/core/netprio_cgroup.c
index 92cc54c..569d83d 100644
--- a/net/core/netprio_cgroup.c
+++ b/net/core/netprio_cgroup.c
@@ -27,11 +27,11 @@
#include <linux/fdtable.h>
+#define PRIOMAP_MIN_SZ 128
#define PRIOIDX_SZ 128
static unsigned long prioidx_map[PRIOIDX_SZ];
static DEFINE_SPINLOCK(prioidx_map_lock);
-static atomic_t max_prioidx = ATOMIC_INIT(0);
static inline struct cgroup_netprio_state *cgrp_netprio_state(struct cgroup *cgrp)
{
@@ -51,8 +51,6 @@ static int get_prioidx(u32 *prio)
return -ENOSPC;
}
set_bit(prioidx, prioidx_map);
- if (atomic_read(&max_prioidx) < prioidx)
- atomic_set(&max_prioidx, prioidx);
spin_unlock_irqrestore(&prioidx_map_lock, flags);
*prio = prioidx;
return 0;
@@ -67,15 +65,40 @@ static void put_prioidx(u32 idx)
spin_unlock_irqrestore(&prioidx_map_lock, flags);
}
-static int extend_netdev_table(struct net_device *dev, u32 new_len)
+/*
+ * Extend @dev->priomap so that it's large enough to accomodate
+ * @target_idx. @dev->priomap.priomap_len > @target_idx after successful
+ * return. Must be called under rtnl lock.
+ */
+static int extend_netdev_table(struct net_device *dev, u32 target_idx)
{
- size_t new_size = sizeof(struct netprio_map) +
- ((sizeof(u32) * new_len));
- struct netprio_map *new = kzalloc(new_size, GFP_KERNEL);
- struct netprio_map *old;
+ struct netprio_map *old, *new;
+ size_t new_sz, new_len;
+ /* is the existing priomap large enough? */
old = rtnl_dereference(dev->priomap);
+ if (old && old->priomap_len > target_idx)
+ return 0;
+
+ /*
+ * Determine the new size. Let's keep it power-of-two. We start
+ * from PRIOMAP_MIN_SZ and double it until it's large enough to
+ * accommodate @target_idx.
+ */
+ new_sz = PRIOMAP_MIN_SZ;
+ while (true) {
+ new_len = (new_sz - offsetof(struct netprio_map, priomap)) /
+ sizeof(new->priomap[0]);
+ if (new_len > target_idx)
+ break;
+ new_sz *= 2;
+ /* overflowed? */
+ if (WARN_ON(new_sz < PRIOMAP_MIN_SZ))
+ return -ENOSPC;
+ }
+ /* allocate & copy */
+ new = kzalloc(new_sz, GFP_KERNEL);
if (!new) {
pr_warn("Unable to alloc new priomap!\n");
return -ENOMEM;
@@ -87,26 +110,13 @@ static int extend_netdev_table(struct net_device *dev, u32 new_len)
new->priomap_len = new_len;
+ /* install the new priomap */
rcu_assign_pointer(dev->priomap, new);
if (old)
kfree_rcu(old, rcu);
return 0;
}
-static int write_update_netdev_table(struct net_device *dev)
-{
- int ret = 0;
- u32 max_len;
- struct netprio_map *map;
-
- max_len = atomic_read(&max_prioidx) + 1;
- map = rtnl_dereference(dev->priomap);
- if (!map || map->priomap_len < max_len)
- ret = extend_netdev_table(dev, max_len);
-
- return ret;
-}
-
static struct cgroup_subsys_state *cgrp_css_alloc(struct cgroup *cgrp)
{
struct cgroup_netprio_state *cs;
@@ -191,7 +201,7 @@ static int write_priomap(struct cgroup *cgrp, struct cftype *cft,
rtnl_lock();
- ret = write_update_netdev_table(dev);
+ ret = extend_netdev_table(dev, prioidx);
if (ret)
goto out_unlock;
--
1.7.11.7
^ permalink raw reply related
* [PATCH 3/7] netprio_cgroup: shorten variable names in extend_netdev_table()
From: Tejun Heo @ 2012-11-20 8:30 UTC (permalink / raw)
To: daniel.wagner-98C5kh4wR6ohFhg+JK9F0w,
serge.hallyn-Z7WLFzj8eWMS+FvcfC7Uqw,
ebiederm-aS9lmoZGLiVWk0Htik3J/w, nhorman-2XuSBdqkA4R54TAoqtyWWQ,
tgraf-G/eBtMaohhA
Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Tejun Heo,
cgroups-u79uwXL29TY76Z2rM5mHXA, davem-fT/PcQaiUtIeIZ0/mPfg9Q
In-Reply-To: <1353400211-5182-1-git-send-email-tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
The function is about to go through a rewrite. In preparation,
shorten the variable names so that we don't repeat "priomap" so often.
This patch is cosmetic.
Signed-off-by: Tejun Heo <tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Acked-by: Neil Horman <nhorman-2XuSBdqkA4R54TAoqtyWWQ@public.gmane.org>
---
net/core/netprio_cgroup.c | 23 +++++++++++------------
1 file changed, 11 insertions(+), 12 deletions(-)
diff --git a/net/core/netprio_cgroup.c b/net/core/netprio_cgroup.c
index 66d98da..92cc54c 100644
--- a/net/core/netprio_cgroup.c
+++ b/net/core/netprio_cgroup.c
@@ -71,26 +71,25 @@ static int extend_netdev_table(struct net_device *dev, u32 new_len)
{
size_t new_size = sizeof(struct netprio_map) +
((sizeof(u32) * new_len));
- struct netprio_map *new_priomap = kzalloc(new_size, GFP_KERNEL);
- struct netprio_map *old_priomap;
+ struct netprio_map *new = kzalloc(new_size, GFP_KERNEL);
+ struct netprio_map *old;
- old_priomap = rtnl_dereference(dev->priomap);
+ old = rtnl_dereference(dev->priomap);
- if (!new_priomap) {
+ if (!new) {
pr_warn("Unable to alloc new priomap!\n");
return -ENOMEM;
}
- if (old_priomap)
- memcpy(new_priomap->priomap, old_priomap->priomap,
- old_priomap->priomap_len *
- sizeof(old_priomap->priomap[0]));
+ if (old)
+ memcpy(new->priomap, old->priomap,
+ old->priomap_len * sizeof(old->priomap[0]));
- new_priomap->priomap_len = new_len;
+ new->priomap_len = new_len;
- rcu_assign_pointer(dev->priomap, new_priomap);
- if (old_priomap)
- kfree_rcu(old_priomap, rcu);
+ rcu_assign_pointer(dev->priomap, new);
+ if (old)
+ kfree_rcu(old, rcu);
return 0;
}
--
1.7.11.7
^ permalink raw reply related
* [PATCH 2/7] netprio_cgroup: simplify write_priomap()
From: Tejun Heo @ 2012-11-20 8:30 UTC (permalink / raw)
To: daniel.wagner-98C5kh4wR6ohFhg+JK9F0w,
serge.hallyn-Z7WLFzj8eWMS+FvcfC7Uqw,
ebiederm-aS9lmoZGLiVWk0Htik3J/w, nhorman-2XuSBdqkA4R54TAoqtyWWQ,
tgraf-G/eBtMaohhA
Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Tejun Heo,
cgroups-u79uwXL29TY76Z2rM5mHXA, davem-fT/PcQaiUtIeIZ0/mPfg9Q
In-Reply-To: <1353400211-5182-1-git-send-email-tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
sscanf() doesn't bite.
Signed-off-by: Tejun Heo <tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Acked-by: Neil Horman <nhorman-2XuSBdqkA4R54TAoqtyWWQ@public.gmane.org>
---
net/core/netprio_cgroup.c | 56 ++++++++++-------------------------------------
1 file changed, 11 insertions(+), 45 deletions(-)
diff --git a/net/core/netprio_cgroup.c b/net/core/netprio_cgroup.c
index f0b6b0d..66d98da 100644
--- a/net/core/netprio_cgroup.c
+++ b/net/core/netprio_cgroup.c
@@ -176,66 +176,32 @@ static int read_priomap(struct cgroup *cont, struct cftype *cft,
static int write_priomap(struct cgroup *cgrp, struct cftype *cft,
const char *buffer)
{
- char *devname = kstrdup(buffer, GFP_KERNEL);
- int ret = -EINVAL;
u32 prioidx = cgrp_netprio_state(cgrp)->prioidx;
- unsigned long priority;
- char *priostr;
+ char devname[IFNAMSIZ + 1];
struct net_device *dev;
struct netprio_map *map;
+ u32 prio;
+ int ret;
- if (!devname)
- return -ENOMEM;
-
- /*
- * Minimally sized valid priomap string
- */
- if (strlen(devname) < 3)
- goto out_free_devname;
-
- priostr = strstr(devname, " ");
- if (!priostr)
- goto out_free_devname;
-
- /*
- *Separate the devname from the associated priority
- *and advance the priostr pointer to the priority value
- */
- *priostr = '\0';
- priostr++;
-
- /*
- * If the priostr points to NULL, we're at the end of the passed
- * in string, and its not a valid write
- */
- if (*priostr == '\0')
- goto out_free_devname;
-
- ret = kstrtoul(priostr, 10, &priority);
- if (ret < 0)
- goto out_free_devname;
-
- ret = -ENODEV;
+ if (sscanf(buffer, "%"__stringify(IFNAMSIZ)"s %u", devname, &prio) != 2)
+ return -EINVAL;
dev = dev_get_by_name(&init_net, devname);
if (!dev)
- goto out_free_devname;
+ return -ENODEV;
rtnl_lock();
+
ret = write_update_netdev_table(dev);
- if (ret < 0)
- goto out_put_dev;
+ if (ret)
+ goto out_unlock;
map = rtnl_dereference(dev->priomap);
if (map)
- map->priomap[prioidx] = priority;
-
-out_put_dev:
+ map->priomap[prioidx] = prio;
+out_unlock:
rtnl_unlock();
dev_put(dev);
-
-out_free_devname:
- kfree(devname);
return ret;
}
--
1.7.11.7
^ permalink raw reply related
* [PATCH 1/7] netcls_cgroup: move config inheritance to ->css_online() and remove .broken_hierarchy marking
From: Tejun Heo @ 2012-11-20 8:30 UTC (permalink / raw)
To: daniel.wagner-98C5kh4wR6ohFhg+JK9F0w,
serge.hallyn-Z7WLFzj8eWMS+FvcfC7Uqw,
ebiederm-aS9lmoZGLiVWk0Htik3J/w, nhorman-2XuSBdqkA4R54TAoqtyWWQ,
tgraf-G/eBtMaohhA
Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Tejun Heo,
cgroups-u79uwXL29TY76Z2rM5mHXA, davem-fT/PcQaiUtIeIZ0/mPfg9Q
In-Reply-To: <1353400211-5182-1-git-send-email-tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
It turns out that we'll have to live with attributes which are
inherited at cgroup creation time but not affected by further updates
to the parent afterwards - such attributes are already in wide use
e.g. for cpuset.
So, there's nothing to do for netcls_cgroup for hierarchy support.
Its current behavior - inherit only during creation - is good enough.
Move config inheriting from ->css_alloc() to ->css_online() for
consistency, which doesn't change behavior at all, and remove
.broken_hierarchy marking.
Signed-off-by: Tejun Heo <tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
---
net/sched/cls_cgroup.c | 20 ++++++++------------
1 file changed, 8 insertions(+), 12 deletions(-)
diff --git a/net/sched/cls_cgroup.c b/net/sched/cls_cgroup.c
index 8cdc18e..31f06b6 100644
--- a/net/sched/cls_cgroup.c
+++ b/net/sched/cls_cgroup.c
@@ -41,11 +41,15 @@ static struct cgroup_subsys_state *cgrp_css_alloc(struct cgroup *cgrp)
cs = kzalloc(sizeof(*cs), GFP_KERNEL);
if (!cs)
return ERR_PTR(-ENOMEM);
+ return &cs->css;
+}
+static int cgrp_css_online(struct cgroup *cgrp)
+{
if (cgrp->parent)
- cs->classid = cgrp_cls_state(cgrp->parent)->classid;
-
- return &cs->css;
+ cgrp_cls_state(cgrp)->classid =
+ cgrp_cls_state(cgrp->parent)->classid;
+ return 0;
}
static void cgrp_css_free(struct cgroup *cgrp)
@@ -76,19 +80,11 @@ static struct cftype ss_files[] = {
struct cgroup_subsys net_cls_subsys = {
.name = "net_cls",
.css_alloc = cgrp_css_alloc,
+ .css_online = cgrp_css_online,
.css_free = cgrp_css_free,
.subsys_id = net_cls_subsys_id,
.base_cftypes = ss_files,
.module = THIS_MODULE,
-
- /*
- * While net_cls cgroup has the rudimentary hierarchy support of
- * inheriting the parent's classid on cgroup creation, it doesn't
- * properly propagates config changes in ancestors to their
- * descendents. A child should follow the parent's configuration
- * but be allowed to override it. Fix it and remove the following.
- */
- .broken_hierarchy = true,
};
struct cls_cgroup_head {
--
1.7.11.7
^ permalink raw reply related
* [PATCHSET REPOST v2 cgroup/for-3.8] netcls/prio_cgroup: update hierarchy support
From: Tejun Heo @ 2012-11-20 8:30 UTC (permalink / raw)
To: daniel.wagner-98C5kh4wR6ohFhg+JK9F0w,
serge.hallyn-Z7WLFzj8eWMS+FvcfC7Uqw,
ebiederm-aS9lmoZGLiVWk0Htik3J/w, nhorman-2XuSBdqkA4R54TAoqtyWWQ,
tgraf-G/eBtMaohhA
Cc: davem-fT/PcQaiUtIeIZ0/mPfg9Q, lizefan-hv44wF8Li93QT0dZR+AlfA,
cgroups-u79uwXL29TY76Z2rM5mHXA,
containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA
(Reposting w/ cc to netdev added as requested by David. Sorry about
the noise.)
Hello, guys.
This patchset replaces the following two patchsets.
[1] "[PATCHSET cgroup/for-3.8] netprio_cgroup: implement hierarchy support"
[2] "[PATCHSET cgroup/for-3.8] netcls_cgroup: implement hierarchy support"
It turns out that we'll have to live with attributes which are
inherited only while creating a new cgroup - such attributes are
already in wide use in cpuset, and there doesn't seem to be much point
in trying to implement fully hierarchical behavior on all attributes
especially as it requires an otherwise-unnecessary userland behavior
change on netcls_cgroup.
This patchset drop .broken_hierarchy from netcls_cgroup while
retaining the current behavior, and implements the same behavior on
netprio_cgroup.
0001-netcls_cgroup-move-config-inheritance-to-css_online-.patch
0002-netprio_cgroup-simplify-write_priomap.patch
0003-netprio_cgroup-shorten-variable-names-in-extend_netd.patch
0004-netprio_cgroup-reimplement-priomap-expansion.patch
0005-netprio_cgroup-use-cgroup-id-instead-of-cgroup_netpr.patch
0006-netprio_cgroup-implement-netprio-_set-_prio-helpers.patch
0007-netprio_cgroup-allow-nesting-and-inherit-config-on-c.patch
0001 drops .broken_hierarchy from netcls_cgroup.
0002-0006 prepare for inheritance implementation. These patches are
identical from the previous posting[1].
0007 implements inheritance on cgroup creation.
This patchset is on top of cgroup/for-3.8 0a950f65e1 ("cgroup: add
cgroup->id").
and available in the following git branch.
git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git review-cgroup-net-cls-prio-hierarchy
diffstat follows.
Documentation/cgroups/net_prio.txt | 2
include/net/netprio_cgroup.h | 11 -
net/core/netprio_cgroup.c | 254 ++++++++++++++++---------------------
net/sched/cls_cgroup.c | 20 +-
4 files changed, 124 insertions(+), 163 deletions(-)
Thanks.
--
tejun
[1] https://lkml.org/lkml/2012/11/16/514
[2] http://thread.gmane.org/gmane.linux.kernel.cgroups/5094
^ permalink raw reply
* Re: New ASIX USB3 product
From: Christian Riesch @ 2012-11-20 8:15 UTC (permalink / raw)
To: Jérôme Poulin; +Cc: netdev
In-Reply-To: <CALJXSJp+m7FewpW2i6wJoFAN0oGwao4-KjWuUX0F_dcE5vsoPQ@mail.gmail.com>
Jérôme,
On 2012-11-19 20:02, Jérôme Poulin wrote:
> I just bought a gigabit ethernet USB3 adapter, it is a StarTech
> USB31000S adapter and it does not seem to be un ASIX product database
> yet.
The AX88179 device is not yet supported by the mainline asix drivers.
You could try to use the driver from the ASIX website [1]. Or you could
compare this driver to the code in drivers/net/usb/a* and see if one of
these drivers would work for the AX88179 and add an entry for the
AX88179 in usb_device_id struct in asix_devices.c.
Regards, Christian
[1]
http://www.asix.com.tw/products.php?op=pItemdetail&PItemID=131;71;112&PLine=71
^ permalink raw reply
* Re: unable to handle paging request, arm, at aio/tcp code, only 3.6
From: Lluís Batlle i Rossell @ 2012-11-20 6:55 UTC (permalink / raw)
To: Eric Dumazet; +Cc: David Miller, netdev
In-Reply-To: <1353360858.10798.86.camel@edumazet-glaptop>
On Mon, Nov 19, 2012 at 01:34:18PM -0800, Eric Dumazet wrote:
> From: Eric Dumazet <edumazet@google.com>
>
> > Thanks for the report.
> >
> > I believe this is a regression of commit
> > 35ad9b9cf7d8a2e6259a0d24022e910adb6f3489
> > (ipv6: Add helper inet6_csk_update_pmtu().)
> >
> > I'll prepare a patch to fix this.
>
> Please try the following fix.
>
> Thanks !
Ok, I'm running it. Let's see if it crashes today.
Thank you!
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox