* Re: [PATCH 0/2] adding tracepoints to vhost
From: Stefan Hajnoczi @ 2012-04-10 12:54 UTC (permalink / raw)
To: Michael S. Tsirkin; +Cc: kvm, netdev, linux-kernel, virtualization
In-Reply-To: <20120410124250.GB29808@redhat.com>
On Tue, Apr 10, 2012 at 1:42 PM, Michael S. Tsirkin <mst@redhat.com> wrote:
> On Tue, Apr 10, 2012 at 12:40:50PM +0100, Stefan Hajnoczi wrote:
>> On Tue, Apr 10, 2012 at 3:58 AM, Jason Wang <jasowang@redhat.com> wrote:
>> > To help in vhost analyzing, the following series adding basic tracepoints to
>> > vhost. Operations of both virtqueues and vhost works were traced in current
>> > implementation, net code were untouched. A top-like satistics displaying script
>> > were introduced to help the troubleshooting.
>> >
>> > TODO:
>> > - net specific tracepoints?
>> >
>> > ---
>> >
>> > Jason Wang (2):
>> > vhost: basic tracepoints
>> > tools: virtio: add a top-like utility for displaying vhost satistics
>> >
>> >
>> > drivers/vhost/trace.h | 153 ++++++++++++++++++++
>> > drivers/vhost/vhost.c | 17 ++
>> > tools/virtio/vhost_stat | 360 +++++++++++++++++++++++++++++++++++++++++++++++
>> > 3 files changed, 528 insertions(+), 2 deletions(-)
>> > create mode 100644 drivers/vhost/trace.h
>> > create mode 100755 tools/virtio/vhost_stat
>>
>> Perhaps this can replace the vhost log feature? I'm not sure if
>> tracepoints support the right data types but it seems like vhost
>> debugging could be done using tracing with less code.
>>
>> Stefan
>
> vhost log is not a debugging tool, it logs memory accesses for
> migration.
Thanks. I totally misunderstood its purpose.
Stefan
^ permalink raw reply
* Re: [PATCH 0/2] adding tracepoints to vhost
From: Zhi Yong Wu @ 2012-04-10 13:10 UTC (permalink / raw)
To: Michael S. Tsirkin; +Cc: virtualization, linux-kernel, kvm, netdev
In-Reply-To: <20120410124250.GB29808@redhat.com>
On Tue, Apr 10, 2012 at 8:42 PM, Michael S. Tsirkin <mst@redhat.com> wrote:
> On Tue, Apr 10, 2012 at 12:40:50PM +0100, Stefan Hajnoczi wrote:
>> On Tue, Apr 10, 2012 at 3:58 AM, Jason Wang <jasowang@redhat.com> wrote:
>> > To help in vhost analyzing, the following series adding basic tracepoints to
>> > vhost. Operations of both virtqueues and vhost works were traced in current
>> > implementation, net code were untouched. A top-like satistics displaying script
>> > were introduced to help the troubleshooting.
>> >
>> > TODO:
>> > - net specific tracepoints?
>> >
>> > ---
>> >
>> > Jason Wang (2):
>> > vhost: basic tracepoints
>> > tools: virtio: add a top-like utility for displaying vhost satistics
>> >
>> >
>> > drivers/vhost/trace.h | 153 ++++++++++++++++++++
>> > drivers/vhost/vhost.c | 17 ++
>> > tools/virtio/vhost_stat | 360 +++++++++++++++++++++++++++++++++++++++++++++++
>> > 3 files changed, 528 insertions(+), 2 deletions(-)
>> > create mode 100644 drivers/vhost/trace.h
>> > create mode 100755 tools/virtio/vhost_stat
>>
>> Perhaps this can replace the vhost log feature? I'm not sure if
>> tracepoints support the right data types but it seems like vhost
>> debugging could be done using tracing with less code.
>>
>> Stefan
>
> vhost log is not a debugging tool, it logs memory accesses for
> migration.
Great, it is very appreciated if there's some docs about this
> _______________________________________________
> Virtualization mailing list
> Virtualization@lists.linux-foundation.org
> https://lists.linuxfoundation.org/mailman/listinfo/virtualization
--
Regards,
Zhi Yong Wu
^ permalink raw reply
* Re: linux-next: build failure after merge of the final tree (net-next tree related)
From: David Miller @ 2012-04-10 13:26 UTC (permalink / raw)
To: sfr; +Cc: netdev, linux-next, linux-kernel, msink, schwidefsky,
heiko.carstens
In-Reply-To: <20120410152923.15aee4df478d819f167cd4af@canb.auug.org.au>
From: Stephen Rothwell <sfr@canb.auug.org.au>
Date: Tue, 10 Apr 2012 15:29:23 +1000
> After merging the final tree, today's linux-next build (s390 allmodconfig)
> failed like this:
I just checked in the following which will hopefully cure this,
thanks:
--------------------
wiznet: Fix Kconfig dependencies.
Both drivers need to depend upon HAS_IOMEM, otherwise we
get a build failure on platforms like S390.
All the driver specific config options need to depend upon
the drivers themselves.
Reported-by: Stephen Rothwell <sfr@canb.auug.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/ethernet/wiznet/Kconfig | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/drivers/net/ethernet/wiznet/Kconfig b/drivers/net/ethernet/wiznet/Kconfig
index 2bb383c..c8291bf 100644
--- a/drivers/net/ethernet/wiznet/Kconfig
+++ b/drivers/net/ethernet/wiznet/Kconfig
@@ -19,6 +19,7 @@ if NET_VENDOR_WIZNET
config WIZNET_W5100
tristate "WIZnet W5100 Ethernet support"
+ depends on HAS_IOMEM
---help---
Support for WIZnet W5100 chips.
@@ -31,6 +32,7 @@ config WIZNET_W5100
config WIZNET_W5300
tristate "WIZnet W5300 Ethernet support"
+ depends on HAS_IOMEM
---help---
Support for WIZnet W5300 chips.
@@ -43,6 +45,7 @@ config WIZNET_W5300
choice
prompt "WIZnet interface mode"
+ depends on WIZNET_W5100 || WIZNET_W5300
default WIZNET_BUS_ANY
config WIZNET_BUS_DIRECT
@@ -69,6 +72,7 @@ endchoice
config WIZNET_TX_FLOW
bool "Use transmit flow control"
+ depends on WIZNET_W5100 || WIZNET_W5300
default y
help
This enables transmit flow control for WIZnet chips.
--
1.7.7.6
^ permalink raw reply related
* Re: [net-next PATCH v1 7/7] macvlan: add FDB bridge ops and new macvlan mode
From: John Fastabend @ 2012-04-10 13:27 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: roprabhu, stephen.hemminger, davem, hadi, bhutchings,
jeffrey.t.kirsher, netdev, gregory.v.rose, krkumar2, sri
In-Reply-To: <20120410080916.GB26540@redhat.com>
On 4/10/2012 1:09 AM, Michael S. Tsirkin wrote:
> On Mon, Apr 09, 2012 at 03:00:54PM -0700, John Fastabend wrote:
>> This adds a new macvlan mode MACVLAN_PASSTHRU_NOPROMISC
>> this mode acts the same as the original passthru mode _except_
>> it does not set promiscuous mode on the lowerdev. Because the
>> lowerdev is not put in promiscuous mode any unicast or multicast
>> addresses the device should receive must be explicitely added
>> with the FDB bridge ops. In many use cases the management stack
>> will know the mac addresses needed (maybe negotiated via EVB/VDP)
>> or may require only receiving known "good" mac addresses. This
>> mode with the FDB ops supports this usage model.
>
>
> Looks good to me. Some questions below:
>
>> This patch is a result of Roopa Prabhu's work. Follow up
>> patches are needed for VEPA and VEB macvlan modes.
>
> And bridge too?
>
Yes I called this mode VEB here but this is defined in if_link.h
as IFLA_MACVLAN_MODE_BRIDGE. From a IEEE point of view I think
the macvlan bridge mode acts more like a 802.1Q VEB then a 802.1d
bridge.
> Also, my understanding is that other modes won't need a flag
> like this since they don't put the device in promisc mode initially,
> so no assumptions are broken if we require all addresses
> to be declared, right?
>
correct. But requires extra work to the hash table so the forwarding
works correctly.
> A final question: I think we'll later add a macvlan mode
> that does not flood all multicasts. This would change behaviour
> in an incompatible way so we'll probably need yet another
> flag. Would it make sense to combine this functionality
> with nopromisc so we have less modes to support?
>
For VEPA and bridge modes this makes sense to me. If you want
the flood behavior you can create it by adding the addr to all
the devices or just to a subset of them to get the non-flooding
capabilities.
.John
^ permalink raw reply
* Re: axienet driver copyrights
From: David Miller @ 2012-04-10 13:41 UTC (permalink / raw)
To: monstr; +Cc: ariane.keller, daniel.borkmann, netdev, john.williams, linnj
In-Reply-To: <4F84164C.6000702@monstr.eu>
From: Michal Simek <monstr@monstr.eu>
Date: Tue, 10 Apr 2012 13:15:24 +0200
> David: Would it be possible to ping me everytime when there is any
> patch
> around xilinx ethernet controller.
This is a completely unreasonable request, sorry. The burdon is on
you to watch carefully the netdev list for patches you are interested
in.
^ permalink raw reply
* Re: net: more accurate skb truesize - regression on Microblaze
From: David Miller @ 2012-04-10 13:43 UTC (permalink / raw)
To: monstr; +Cc: eric.dumazet, netdev, john.williams
In-Reply-To: <4F841BB9.2030209@monstr.eu>
From: Michal Simek <monstr@monstr.eu>
Date: Tue, 10 Apr 2012 13:38:33 +0200
> There is long history for ll_temac and axi emac drivers. and if you
> compare
> them they are very similar with similar bugs.
> In our distribution we are using older ll_temac driver where this is
> fixed.
> Performance is much higher if you allocate buffers for actual mtu.
You place an enormous burdon upon us when you ask us to analyze your
performance problems and bugs when using out of tree drivers. Please
do not do this.
^ permalink raw reply
* Re: [PATCH 0/2] adding tracepoints to vhost
From: Michael S. Tsirkin @ 2012-04-10 13:45 UTC (permalink / raw)
To: Zhi Yong Wu; +Cc: virtualization, linux-kernel, kvm, netdev
In-Reply-To: <CAEH94Li0==w=AUKd5WCPMcqxLh=+N6bKttOwrE8y-xuOyPt_QA@mail.gmail.com>
On Tue, Apr 10, 2012 at 09:10:48PM +0800, Zhi Yong Wu wrote:
> >> Perhaps this can replace the vhost log feature? I'm not sure if
> >> tracepoints support the right data types but it seems like vhost
> >> debugging could be done using tracing with less code.
> >>
> >> Stefan
> >
> > vhost log is not a debugging tool, it logs memory accesses for
> > migration.
> Great, it is very appreciated if there's some docs about this
About what? vhost logging? See the comment near the
definition of VHOST_SET_LOG_BASE in vhost.h
> > _______________________________________________
> > Virtualization mailing list
> > Virtualization@lists.linux-foundation.org
> > https://lists.linuxfoundation.org/mailman/listinfo/virtualization
>
>
>
> --
> Regards,
>
> Zhi Yong Wu
^ permalink raw reply
* Re: [net-next PATCH v1 7/7] macvlan: add FDB bridge ops and new macvlan mode
From: John Fastabend @ 2012-04-10 13:50 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: roprabhu, stephen.hemminger, davem, hadi, bhutchings,
jeffrey.t.kirsher, netdev, gregory.v.rose, krkumar2, sri
In-Reply-To: <20120410081418.GC26540@redhat.com>
On 4/10/2012 1:14 AM, Michael S. Tsirkin wrote:
> On Tue, Apr 10, 2012 at 11:09:16AM +0300, Michael S. Tsirkin wrote:
>> On Mon, Apr 09, 2012 at 03:00:54PM -0700, John Fastabend wrote:
>>> This adds a new macvlan mode MACVLAN_PASSTHRU_NOPROMISC
>>> this mode acts the same as the original passthru mode _except_
>>> it does not set promiscuous mode on the lowerdev. Because the
>>> lowerdev is not put in promiscuous mode any unicast or multicast
>>> addresses the device should receive must be explicitely added
>>> with the FDB bridge ops. In many use cases the management stack
>>> will know the mac addresses needed (maybe negotiated via EVB/VDP)
>>> or may require only receiving known "good" mac addresses. This
>>> mode with the FDB ops supports this usage model.
>>
>>
>> Looks good to me. Some questions below:
>>
>>> This patch is a result of Roopa Prabhu's work. Follow up
>>> patches are needed for VEPA and VEB macvlan modes.
>>
>> And bridge too?
>>
>> Also, my understanding is that other modes won't need a flag
>> like this since they don't put the device in promisc mode initially,
>> so no assumptions are broken if we require all addresses
>> to be declared, right?
>>
>> A final question: I think we'll later add a macvlan mode
>> that does not flood all multicasts. This would change behaviour
>> in an incompatible way so we'll probably need yet another
>> flag. Would it make sense to combine this functionality
>> with nopromisc so we have less modes to support?
>
> One other question I forgot:
>
[...]
>>>
>>> @@ -344,12 +346,15 @@ static int macvlan_stop(struct net_device *dev)
>>> struct macvlan_dev *vlan = netdev_priv(dev);
>>> struct net_device *lowerdev = vlan->lowerdev;
>>>
>>> + dev_uc_unsync(lowerdev, dev);
>>> + dev_mc_unsync(lowerdev, dev);
>>> +
>>> if (vlan->port->passthru) {
>>> - dev_set_promiscuity(lowerdev, -1);
>>> + if (vlan->mode == MACVLAN_MODE_PASSTHRU)
>>> + dev_set_promiscuity(lowerdev, 1);
>>> goto hash_del;
>>> }
>>>
>>> - dev_mc_unsync(lowerdev, dev);
>>> if (dev->flags & IFF_ALLMULTI)
>>> dev_set_allmulti(lowerdev, -1);
>>>
>>> @@ -399,10 +404,11 @@ static void macvlan_change_rx_flags(struct net_device *dev, int change)
>>> dev_set_allmulti(lowerdev, dev->flags & IFF_ALLMULTI ? 1 : -1);
>
> In the new mode, do we want to have promisc on lowerdev follow whatever
> is set on the macvlan, like we do for allmulti?
> I'm not sure at this point - what do others think?
>
Just to enumerate why you would need this: (1) socket set with
PACKET_MR_MULTICAST and (2) something like mrouted is running
on the macvlan (3) maybe some case I missed?
Don't you need CAP_NET_RAW to set these though anyways? So I
wouldn't think it would be a problem. I assume if a user has
CAP_NET_RAW or UUID 0 they really should be able to set this
up.
.John
^ permalink raw reply
* Re: [PATCH] net: orphan queued skbs if device tx can stall
From: Eric Dumazet @ 2012-04-10 13:52 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: netdev, linux-kernel, David S. Miller, Jamal Hadi Salim,
Stephen Hemminger, Jason Wang, Neil Horman, Jiri Pirko,
Jeff Kirsher, Michał Mirosław, Ben Hutchings,
Herbert Xu
In-Reply-To: <20120410124151.GA29808@redhat.com>
On Tue, 2012-04-10 at 15:41 +0300, Michael S. Tsirkin wrote:
> I think it's a bad interface too but it's in a userspace ABI
> now so I suspect we are stuck with it for now. We can try deprecating
> but we can't just drop it.
>
By the way, skb orphaning should already be done in skb_orphan_try(),
not sure why its done again in tun_net_xmit(). Note we perform orphaning
right before giving skb to device on premise it'll be sent (and freed)
in a reasonable amount of time.
With following patch, no more qdisc on top of tun device, yet user can
change the limit (I would be curious to know if anybody changes tun
txqueuelen and why)
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index bb8c72c..c4a00cf 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -379,6 +379,7 @@ static int tun_net_close(struct net_device *dev)
static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct tun_struct *tun = netdev_priv(dev);
+ int limit;
tun_debug(KERN_INFO, tun, "tun_net_xmit %d\n", skb->len);
@@ -396,7 +397,8 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
sk_filter(tun->socket.sk, skb))
goto drop;
- if (skb_queue_len(&tun->socket.sk->sk_receive_queue) >= dev->tx_queue_len) {
+ limit = dev->tx_queue_len ? : TUN_READQ_SIZE;
+ if (skb_queue_len(&tun->socket.sk->sk_receive_queue) >= limit) {
if (!(tun->flags & TUN_ONE_QUEUE)) {
/* Normal queueing mode. */
/* Packet scheduler handles dropping of further packets. */
@@ -521,7 +523,7 @@ static void tun_net_init(struct net_device *dev)
/* Zero header length */
dev->type = ARPHRD_NONE;
dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
- dev->tx_queue_len = TUN_READQ_SIZE; /* We prefer our own queue length */
+ dev->tx_queue_len = 0;
break;
case TUN_TAP_DEV:
@@ -532,7 +534,7 @@ static void tun_net_init(struct net_device *dev)
eth_hw_addr_random(dev);
- dev->tx_queue_len = TUN_READQ_SIZE; /* We prefer our own queue length */
+ dev->tx_queue_len = 0;
break;
}
}
^ permalink raw reply related
* Re: net: more accurate skb truesize - regression on Microblaze
From: David Miller @ 2012-04-10 13:52 UTC (permalink / raw)
To: monstr; +Cc: eric.dumazet, netdev, john.williams
In-Reply-To: <CAHTX3dLRR09_QaA2BzmbCVAUVVGvr_P3s2d1KEgPLMYGGVzrpA@mail.gmail.com>
From: Michal Simek <monstr@monstr.eu>
Date: Tue, 10 Apr 2012 15:49:17 +0200
> I reported problem with performance regression on the same drvier
> between one kernel version and the newer version. Even with pointer
> to specific patch which I have identified as source of the problem.
> It has nothing to do with performance of driver itself because
> identified patch directly points to generic network code not to
> mainline driver and performance problem in it.
The size and attributes of the SKBs allocated is a clear important
variable in this bug, and you've just described how the SKBs allocated
are of completely different sizes in the driver you're using compared
to the one in the tree.
You were very fortunate that Eric was able to track down the cause
even with this unknown variable, but in other cases this can lead to
wild goose chases which waste developer time.
So, again, please do not do this in the future, reproduce your
problems with upstream sources only.
^ permalink raw reply
* Re: [net-next PATCH v1 7/7] macvlan: add FDB bridge ops and new macvlan mode
From: Michael S. Tsirkin @ 2012-04-10 13:43 UTC (permalink / raw)
To: John Fastabend
Cc: roprabhu, stephen.hemminger, davem, hadi, bhutchings,
jeffrey.t.kirsher, netdev, gregory.v.rose, krkumar2, sri
In-Reply-To: <4F843544.8060209@intel.com>
On Tue, Apr 10, 2012 at 06:27:32AM -0700, John Fastabend wrote:
> On 4/10/2012 1:09 AM, Michael S. Tsirkin wrote:
> > On Mon, Apr 09, 2012 at 03:00:54PM -0700, John Fastabend wrote:
> >> This adds a new macvlan mode MACVLAN_PASSTHRU_NOPROMISC
> >> this mode acts the same as the original passthru mode _except_
> >> it does not set promiscuous mode on the lowerdev. Because the
> >> lowerdev is not put in promiscuous mode any unicast or multicast
> >> addresses the device should receive must be explicitely added
> >> with the FDB bridge ops. In many use cases the management stack
> >> will know the mac addresses needed (maybe negotiated via EVB/VDP)
> >> or may require only receiving known "good" mac addresses. This
> >> mode with the FDB ops supports this usage model.
> >
> >
> > Looks good to me. Some questions below:
> >
> >> This patch is a result of Roopa Prabhu's work. Follow up
> >> patches are needed for VEPA and VEB macvlan modes.
> >
> > And bridge too?
> >
>
> Yes I called this mode VEB here but this is defined in if_link.h
> as IFLA_MACVLAN_MODE_BRIDGE. From a IEEE point of view I think
> the macvlan bridge mode acts more like a 802.1Q VEB then a 802.1d
> bridge.
grep didn't find IFLA_MACVLAN_MODE_BRIDGE - which kernel
are you looking at?
> > Also, my understanding is that other modes won't need a flag
> > like this since they don't put the device in promisc mode initially,
> > so no assumptions are broken if we require all addresses
> > to be declared, right?
> >
>
> correct. But requires extra work to the hash table so the forwarding
> works correctly.
>
> > A final question: I think we'll later add a macvlan mode
> > that does not flood all multicasts. This would change behaviour
> > in an incompatible way so we'll probably need yet another
> > flag. Would it make sense to combine this functionality
> > with nopromisc so we have less modes to support?
> >
>
> For VEPA and bridge modes this makes sense to me.
Hmm okay, but this would mean we should convert
MACVLAN_MODE_PASSTHRU_NOPROMISC to something
that can combined with all modes. E.g.
MACVLAN_MODE_BRIDGE | MACVLAN_MODE_FLAG_XXXXX
and document that it does not promise to flood
multicast.
> If you want
> the flood behavior you can create it by adding the addr to all
> the devices or just to a subset of them to get the non-flooding
> capabilities.
>
> .John
BTW we seem to try to flood in pass-through too, not sure why.
--
MST
^ permalink raw reply
* Re: [PATCH] net: orphan queued skbs if device tx can stall
From: Michael S. Tsirkin @ 2012-04-10 14:10 UTC (permalink / raw)
To: Eric Dumazet
Cc: netdev, linux-kernel, David S. Miller, Jamal Hadi Salim,
Stephen Hemminger, Jason Wang, Neil Horman, Jiri Pirko,
Jeff Kirsher, Michał Mirosław, Ben Hutchings,
Herbert Xu
In-Reply-To: <1334065929.5300.40.camel@edumazet-glaptop>
On Tue, Apr 10, 2012 at 03:52:09PM +0200, Eric Dumazet wrote:
> On Tue, 2012-04-10 at 15:41 +0300, Michael S. Tsirkin wrote:
>
> > I think it's a bad interface too but it's in a userspace ABI
> > now so I suspect we are stuck with it for now. We can try deprecating
> > but we can't just drop it.
> >
>
> By the way, skb orphaning should already be done in skb_orphan_try(),
> not sure why its done again in tun_net_xmit().
I think it's for when some tx flags are set.
> Note we perform orphaning right before giving skb to device on premise
> it'll be sent (and freed) in a reasonable amount of time.
Right. No way to ensure this with tun :(
> With following patch, no more qdisc on top of tun device,
I'll test this, thanks.
> yet user can
> change the limit
Question: if tun is moved between namespaces after tx queue len
is changed, will it get a queueing qdisc then?
If yes we need some other hack to address that ...
> (I would be curious to know if anybody changes tun
> txqueuelen and why)
>
> diff --git a/drivers/net/tun.c b/drivers/net/tun.c
> index bb8c72c..c4a00cf 100644
> --- a/drivers/net/tun.c
> +++ b/drivers/net/tun.c
> @@ -379,6 +379,7 @@ static int tun_net_close(struct net_device *dev)
> static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
> {
> struct tun_struct *tun = netdev_priv(dev);
> + int limit;
>
> tun_debug(KERN_INFO, tun, "tun_net_xmit %d\n", skb->len);
>
> @@ -396,7 +397,8 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
> sk_filter(tun->socket.sk, skb))
> goto drop;
>
> - if (skb_queue_len(&tun->socket.sk->sk_receive_queue) >= dev->tx_queue_len) {
> + limit = dev->tx_queue_len ? : TUN_READQ_SIZE;
> + if (skb_queue_len(&tun->socket.sk->sk_receive_queue) >= limit) {
> if (!(tun->flags & TUN_ONE_QUEUE)) {
> /* Normal queueing mode. */
> /* Packet scheduler handles dropping of further packets. */
> @@ -521,7 +523,7 @@ static void tun_net_init(struct net_device *dev)
> /* Zero header length */
> dev->type = ARPHRD_NONE;
> dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
> - dev->tx_queue_len = TUN_READQ_SIZE; /* We prefer our own queue length */
> + dev->tx_queue_len = 0;
> break;
>
> case TUN_TAP_DEV:
> @@ -532,7 +534,7 @@ static void tun_net_init(struct net_device *dev)
>
> eth_hw_addr_random(dev);
>
> - dev->tx_queue_len = TUN_READQ_SIZE; /* We prefer our own queue length */
> + dev->tx_queue_len = 0;
> break;
> }
> }
>
^ permalink raw reply
* Re: net: more accurate skb truesize - regression on Microblaze
From: David Miller @ 2012-04-10 14:14 UTC (permalink / raw)
To: monstr; +Cc: eric.dumazet, netdev, john.williams
In-Reply-To: <CAHTX3dLz9+A48u6ckGiDytBkyMrvgV0Zi3xfnt4RBmoagJbndA@mail.gmail.com>
From: Michal Simek <monstr@monstr.eu>
Date: Tue, 10 Apr 2012 16:04:18 +0200
> I didn't report problem on any private held driver. I think you have
> misunderstand our later discussion about ll_temac driver where are
> some problems which at least
Thanks for the clarification.
^ permalink raw reply
* Re: [net-next PATCH v1 7/7] macvlan: add FDB bridge ops and new macvlan mode
From: John Fastabend @ 2012-04-10 14:25 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: roprabhu, stephen.hemminger, davem, hadi, bhutchings,
jeffrey.t.kirsher, netdev, gregory.v.rose, krkumar2, sri
In-Reply-To: <20120410134321.GB18899@redhat.com>
On 4/10/2012 6:43 AM, Michael S. Tsirkin wrote:
> On Tue, Apr 10, 2012 at 06:27:32AM -0700, John Fastabend wrote:
>> On 4/10/2012 1:09 AM, Michael S. Tsirkin wrote:
>>> On Mon, Apr 09, 2012 at 03:00:54PM -0700, John Fastabend wrote:
>>>> This adds a new macvlan mode MACVLAN_PASSTHRU_NOPROMISC
>>>> this mode acts the same as the original passthru mode _except_
>>>> it does not set promiscuous mode on the lowerdev. Because the
>>>> lowerdev is not put in promiscuous mode any unicast or multicast
>>>> addresses the device should receive must be explicitely added
>>>> with the FDB bridge ops. In many use cases the management stack
>>>> will know the mac addresses needed (maybe negotiated via EVB/VDP)
>>>> or may require only receiving known "good" mac addresses. This
>>>> mode with the FDB ops supports this usage model.
>>>
>>>
>>> Looks good to me. Some questions below:
>>>
>>>> This patch is a result of Roopa Prabhu's work. Follow up
>>>> patches are needed for VEPA and VEB macvlan modes.
>>>
>>> And bridge too?
>>>
>>
>> Yes I called this mode VEB here but this is defined in if_link.h
>> as IFLA_MACVLAN_MODE_BRIDGE. From a IEEE point of view I think
>> the macvlan bridge mode acts more like a 802.1Q VEB then a 802.1d
>> bridge.
>
> grep didn't find IFLA_MACVLAN_MODE_BRIDGE - which kernel
> are you looking at?
grr sorry typo MACVLAN_MODE_BRIDGE in if_link.h
>
>>> Also, my understanding is that other modes won't need a flag
>>> like this since they don't put the device in promisc mode initially,
>>> so no assumptions are broken if we require all addresses
>>> to be declared, right?
>>>
>>
>> correct. But requires extra work to the hash table so the forwarding
>> works correctly.
>>
>>> A final question: I think we'll later add a macvlan mode
>>> that does not flood all multicasts. This would change behaviour
>>> in an incompatible way so we'll probably need yet another
>>> flag. Would it make sense to combine this functionality
>>> with nopromisc so we have less modes to support?
>>>
>>
>> For VEPA and bridge modes this makes sense to me.
>
> Hmm okay, but this would mean we should convert
> MACVLAN_MODE_PASSTHRU_NOPROMISC to something
> that can combined with all modes. E.g.
> MACVLAN_MODE_BRIDGE | MACVLAN_MODE_FLAG_XXXXX
>
> and document that it does not promise to flood
> multicast.
>
How about changing MACVLAN_MODE_PASSTHRU_NOPROMISC -> MACVLAN_MODE_NOPORMISC
for this patch. Then a follow on series can rework bridge
and VEPA to use it as well.
>> If you want
>> the flood behavior you can create it by adding the addr to all
>> the devices or just to a subset of them to get the non-flooding
>> capabilities.
>>
>> .John
>
> BTW we seem to try to flood in pass-through too, not sure why.
>
Suppose your looking at macvlan_handle_frame()? It does
seem unneeded.
.John
^ permalink raw reply
* [PATCH v4 0/10] skb paged fragment destructors
From: Ian Campbell @ 2012-04-10 14:26 UTC (permalink / raw)
To: netdev
Cc: David Miller, Eric Dumazet, Michael S. Tsirkin, Wei Liu,
David VomLehn, Bart Van Assche, xen-devel, Ian Campbell
I think this is v4, but I've sort of lost count, sorry that it's taken
me so long to get back to this stuff.
The following series makes use of the skb fragment API (which is in 3.2
+) to add a per-paged-fragment destructor callback. This can be used by
creators of skbs who are interested in the lifecycle of the pages
included in that skb after they have handed it off to the network stack.
The mail at [0] contains some more background and rationale but
basically the completed series will allow entities which inject pages
into the networking stack to receive a notification when the stack has
really finished with those pages (i.e. including retransmissions,
clones, pull-ups etc) and not just when the original skb is finished
with, which is beneficial to many subsystems which wish to inject pages
into the network stack without giving up full ownership of those page's
lifecycle. It implements something broadly along the lines of what was
described in [1].
I have also included a patch to the RPC subsystem which uses this API to
fix the bug which I describe at [2].
I've also had some interest from David VemLehn and Bart Van Assche
regarding using this functionality in the context of vmsplice and iSCSI
targets respectively (I think).
Changes since last time:
* Added skb_orphan_frags API for the use of recipients of SKBs who
may hold onto the SKB for a long time (this is analogous to
skb_orphan). This was pointed out by Michael. The TUN driver is
currently the only user.
* I can't for the life of me get anything to actually hit
this code path. I've been trying with an NFS server
running in a Xen HVM domain with emulated (e.g. tap)
networking and a client in domain 0, using the NFS fix
in this series which generates SKBs with destructors
set, so far -- nothing. I suspect that lack of TSO/GSO
etc on the TAP interface is causing the frags to be
copied to normal pages during skb_segment().
* Various fixups related to the change of alignment/padding in
shinfo, in particular to build_skb as pointed out by Eric.
* Tweaked ordering of shinfo members to ensure that all hotpath
variables up to and including the first frag fit within (and are
aligned to) a single 64 byte cache line. (Eric again)
I ran a monothread UDP benchmark (similar to that described by Eric in
e52fcb2462ac) and don't see any difference in pps throughput, it was
~810,000 pps both before and after.
Cheers,
Ian.
[0] http://marc.info/?l=linux-netdev&m=131072801125521&w=2
[1] http://marc.info/?l=linux-netdev&m=130925719513084&w=2
[2] http://marc.info/?l=linux-nfs&m=122424132729720&w=2
^ permalink raw reply
* [PATCH 09/10] net: add paged frag destructor support to kernel_sendpage.
From: Ian Campbell @ 2012-04-10 14:26 UTC (permalink / raw)
To: netdev-u79uwXL29TY76Z2rM5mHXA
Cc: David Miller, Eric Dumazet, Michael S. Tsirkin, Wei Liu,
xen-devel-GuqFBffKawuEi8DpZVb4nw, Ian Campbell, Alexey Kuznetsov,
Pekka Savola (ipv6), James Morris, Hideaki YOSHIFUJI,
Patrick McHardy, Trond Myklebust, Greg Kroah-Hartman,
drbd-user-cunTk1MwBs8qoQakbn7OcQ,
devel-gWbeCf7V1WCQmaza687I9mD2FQJk+8+b,
cluster-devel-H+wXaHxf7aLQT0dZR+AlfA,
ocfs2-devel-N0ozoZBvEnrZJqsBc5GL+g,
ceph-devel-u79uwXL29TY76Z2rM5mHXA,
rds-devel-N0ozoZBvEnrZJqsBc5GL+g,
linux-nfs-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1334067965.5394.22.camel-o4Be2W7LfRlXesXXhkcM7miJhflN2719@public.gmane.org>
This requires adding a new argument to various sendpage hooks up and down the
stack. At the moment this parameter is always NULL.
Signed-off-by: Ian Campbell <ian.campbell-Sxgqhf6Nn4DQT0dZR+AlfA@public.gmane.org>
Cc: "David S. Miller" <davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
Cc: Alexey Kuznetsov <kuznet-v/Mj1YrvjDBInbfyfbPRSQ@public.gmane.org>
Cc: "Pekka Savola (ipv6)" <pekkas-UjJjq++bwZ7HOG6cAo2yLw@public.gmane.org>
Cc: James Morris <jmorris-gx6/JNMH7DfYtjvyW6yDsg@public.gmane.org>
Cc: Hideaki YOSHIFUJI <yoshfuji-VfPWfsRibaP+Ru+s062T9g@public.gmane.org>
Cc: Patrick McHardy <kaber-dcUjhNyLwpNeoWH0uzbU5w@public.gmane.org>
Cc: Trond Myklebust <Trond.Myklebust-HgOvQuBEEgTQT0dZR+AlfA@public.gmane.org>
Cc: Greg Kroah-Hartman <gregkh-l3A5Bk7waGM@public.gmane.org>
Cc: drbd-user-cunTk1MwBs8qoQakbn7OcQ@public.gmane.org
Cc: devel-gWbeCf7V1WCQmaza687I9mD2FQJk+8+b@public.gmane.org
Cc: cluster-devel-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org
Cc: ocfs2-devel-N0ozoZBvEnrZJqsBc5GL+g@public.gmane.org
Cc: netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Cc: ceph-devel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Cc: rds-devel-N0ozoZBvEnrZJqsBc5GL+g@public.gmane.org
Cc: linux-nfs-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
---
drivers/block/drbd/drbd_main.c | 1 +
drivers/scsi/iscsi_tcp.c | 4 ++--
drivers/scsi/iscsi_tcp.h | 3 ++-
drivers/target/iscsi/iscsi_target_util.c | 3 ++-
fs/dlm/lowcomms.c | 4 ++--
fs/ocfs2/cluster/tcp.c | 1 +
include/linux/net.h | 6 +++++-
include/net/inet_common.h | 4 +++-
include/net/ip.h | 4 +++-
include/net/sock.h | 8 +++++---
include/net/tcp.h | 4 +++-
net/ceph/messenger.c | 2 +-
net/core/sock.c | 6 +++++-
net/ipv4/af_inet.c | 9 ++++++---
net/ipv4/ip_output.c | 6 ++++--
net/ipv4/tcp.c | 24 +++++++++++++++---------
net/ipv4/udp.c | 11 ++++++-----
net/ipv4/udp_impl.h | 5 +++--
net/rds/tcp_send.c | 1 +
net/socket.c | 11 +++++++----
net/sunrpc/svcsock.c | 6 +++---
net/sunrpc/xprtsock.c | 2 +-
22 files changed, 81 insertions(+), 44 deletions(-)
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c
index 211fc44..e70ba0c 100644
--- a/drivers/block/drbd/drbd_main.c
+++ b/drivers/block/drbd/drbd_main.c
@@ -2584,6 +2584,7 @@ static int _drbd_send_page(struct drbd_conf *mdev, struct page *page,
set_fs(KERNEL_DS);
do {
sent = mdev->data.socket->ops->sendpage(mdev->data.socket, page,
+ NULL,
offset, len,
msg_flags);
if (sent == -EAGAIN) {
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index 453a740..df9f7dd 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -284,8 +284,8 @@ static int iscsi_sw_tcp_xmit_segment(struct iscsi_tcp_conn *tcp_conn,
if (!segment->data) {
sg = segment->sg;
offset += segment->sg_offset + sg->offset;
- r = tcp_sw_conn->sendpage(sk, sg_page(sg), offset,
- copy, flags);
+ r = tcp_sw_conn->sendpage(sk, sg_page(sg), NULL,
+ offset, copy, flags);
} else {
struct msghdr msg = { .msg_flags = flags };
struct kvec iov = {
diff --git a/drivers/scsi/iscsi_tcp.h b/drivers/scsi/iscsi_tcp.h
index 666fe09..1e23265 100644
--- a/drivers/scsi/iscsi_tcp.h
+++ b/drivers/scsi/iscsi_tcp.h
@@ -52,7 +52,8 @@ struct iscsi_sw_tcp_conn {
uint32_t sendpage_failures_cnt;
uint32_t discontiguous_hdr_cnt;
- ssize_t (*sendpage)(struct socket *, struct page *, int, size_t, int);
+ ssize_t (*sendpage)(struct socket *, struct page *,
+ struct skb_frag_destructor *, int, size_t, int);
};
struct iscsi_sw_tcp_host {
diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c
index 4eba86d..d876dae 100644
--- a/drivers/target/iscsi/iscsi_target_util.c
+++ b/drivers/target/iscsi/iscsi_target_util.c
@@ -1323,7 +1323,8 @@ send_hdr:
u32 sub_len = min_t(u32, data_len, space);
send_pg:
tx_sent = conn->sock->ops->sendpage(conn->sock,
- sg_page(sg), sg->offset + offset, sub_len, 0);
+ sg_page(sg), NULL,
+ sg->offset + offset, sub_len, 0);
if (tx_sent != sub_len) {
if (tx_sent == -EAGAIN) {
pr_err("tcp_sendpage() returned"
diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c
index 133ef6d..0673cea 100644
--- a/fs/dlm/lowcomms.c
+++ b/fs/dlm/lowcomms.c
@@ -1336,8 +1336,8 @@ static void send_to_sock(struct connection *con)
ret = 0;
if (len) {
- ret = kernel_sendpage(con->sock, e->page, offset, len,
- msg_flags);
+ ret = kernel_sendpage(con->sock, e->page, NULL,
+ offset, len, msg_flags);
if (ret == -EAGAIN || ret == 0) {
if (ret == -EAGAIN &&
test_bit(SOCK_ASYNC_NOSPACE, &con->sock->flags) &&
diff --git a/fs/ocfs2/cluster/tcp.c b/fs/ocfs2/cluster/tcp.c
index 044e7b5..e13851e 100644
--- a/fs/ocfs2/cluster/tcp.c
+++ b/fs/ocfs2/cluster/tcp.c
@@ -983,6 +983,7 @@ static void o2net_sendpage(struct o2net_sock_container *sc,
mutex_lock(&sc->sc_send_lock);
ret = sc->sc_sock->ops->sendpage(sc->sc_sock,
virt_to_page(kmalloced_virt),
+ NULL,
(long)kmalloced_virt & ~PAGE_MASK,
size, MSG_DONTWAIT);
mutex_unlock(&sc->sc_send_lock);
diff --git a/include/linux/net.h b/include/linux/net.h
index be60c7f..d9b0d648 100644
--- a/include/linux/net.h
+++ b/include/linux/net.h
@@ -157,6 +157,7 @@ struct kiocb;
struct sockaddr;
struct msghdr;
struct module;
+struct skb_frag_destructor;
struct proto_ops {
int family;
@@ -203,6 +204,7 @@ struct proto_ops {
int (*mmap) (struct file *file, struct socket *sock,
struct vm_area_struct * vma);
ssize_t (*sendpage) (struct socket *sock, struct page *page,
+ struct skb_frag_destructor *destroy,
int offset, size_t size, int flags);
ssize_t (*splice_read)(struct socket *sock, loff_t *ppos,
struct pipe_inode_info *pipe, size_t len, unsigned int flags);
@@ -274,7 +276,9 @@ extern int kernel_getsockopt(struct socket *sock, int level, int optname,
char *optval, int *optlen);
extern int kernel_setsockopt(struct socket *sock, int level, int optname,
char *optval, unsigned int optlen);
-extern int kernel_sendpage(struct socket *sock, struct page *page, int offset,
+extern int kernel_sendpage(struct socket *sock, struct page *page,
+ struct skb_frag_destructor *destroy,
+ int offset,
size_t size, int flags);
extern int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg);
extern int kernel_sock_shutdown(struct socket *sock,
diff --git a/include/net/inet_common.h b/include/net/inet_common.h
index 22fac98..91cd8d0 100644
--- a/include/net/inet_common.h
+++ b/include/net/inet_common.h
@@ -21,7 +21,9 @@ extern int inet_dgram_connect(struct socket *sock, struct sockaddr * uaddr,
extern int inet_accept(struct socket *sock, struct socket *newsock, int flags);
extern int inet_sendmsg(struct kiocb *iocb, struct socket *sock,
struct msghdr *msg, size_t size);
-extern ssize_t inet_sendpage(struct socket *sock, struct page *page, int offset,
+extern ssize_t inet_sendpage(struct socket *sock, struct page *page,
+ struct skb_frag_destructor *frag,
+ int offset,
size_t size, int flags);
extern int inet_recvmsg(struct kiocb *iocb, struct socket *sock,
struct msghdr *msg, size_t size, int flags);
diff --git a/include/net/ip.h b/include/net/ip.h
index b53d65f..6bf9926 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -114,7 +114,9 @@ extern int ip_append_data(struct sock *sk, struct flowi4 *fl4,
struct rtable **rt,
unsigned int flags);
extern int ip_generic_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb);
-extern ssize_t ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page,
+extern ssize_t ip_append_page(struct sock *sk, struct flowi4 *fl4,
+ struct page *page,
+ struct skb_frag_destructor *destroy,
int offset, size_t size, int flags);
extern struct sk_buff *__ip_make_skb(struct sock *sk,
struct flowi4 *fl4,
diff --git a/include/net/sock.h b/include/net/sock.h
index a6ba1f8..c927997 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -834,6 +834,7 @@ struct proto {
size_t len, int noblock, int flags,
int *addr_len);
int (*sendpage)(struct sock *sk, struct page *page,
+ struct skb_frag_destructor *destroy,
int offset, size_t size, int flags);
int (*bind)(struct sock *sk,
struct sockaddr *uaddr, int addr_len);
@@ -1452,9 +1453,10 @@ extern int sock_no_mmap(struct file *file,
struct socket *sock,
struct vm_area_struct *vma);
extern ssize_t sock_no_sendpage(struct socket *sock,
- struct page *page,
- int offset, size_t size,
- int flags);
+ struct page *page,
+ struct skb_frag_destructor *destroy,
+ int offset, size_t size,
+ int flags);
/*
* Functions to fill in entries in struct proto_ops when a protocol
diff --git a/include/net/tcp.h b/include/net/tcp.h
index f75a04d..7536266 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -331,7 +331,9 @@ extern void *tcp_v4_tw_get_peer(struct sock *sk);
extern int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw);
extern int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
size_t size);
-extern int tcp_sendpage(struct sock *sk, struct page *page, int offset,
+extern int tcp_sendpage(struct sock *sk, struct page *page,
+ struct skb_frag_destructor *destroy,
+ int offset,
size_t size, int flags);
extern int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg);
extern int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c
index ad5b708..69f049b 100644
--- a/net/ceph/messenger.c
+++ b/net/ceph/messenger.c
@@ -851,7 +851,7 @@ static int write_partial_msg_pages(struct ceph_connection *con)
cpu_to_le32(crc32c(tmpcrc, base, len));
con->out_msg_pos.did_page_crc = 1;
}
- ret = kernel_sendpage(con->sock, page,
+ ret = kernel_sendpage(con->sock, page, NULL,
con->out_msg_pos.page_pos + page_shift,
len,
MSG_DONTWAIT | MSG_NOSIGNAL |
diff --git a/net/core/sock.c b/net/core/sock.c
index 9be6d0d..f56fc8c 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1965,7 +1965,9 @@ int sock_no_mmap(struct file *file, struct socket *sock, struct vm_area_struct *
}
EXPORT_SYMBOL(sock_no_mmap);
-ssize_t sock_no_sendpage(struct socket *sock, struct page *page, int offset, size_t size, int flags)
+ssize_t sock_no_sendpage(struct socket *sock, struct page *page,
+ struct skb_frag_destructor *destroy,
+ int offset, size_t size, int flags)
{
ssize_t res;
struct msghdr msg = {.msg_flags = flags};
@@ -1975,6 +1977,8 @@ ssize_t sock_no_sendpage(struct socket *sock, struct page *page, int offset, siz
iov.iov_len = size;
res = kernel_sendmsg(sock, &msg, &iov, 1, size);
kunmap(page);
+ /* kernel_sendmsg copies so we can destroy immediately */
+ skb_frag_destructor_unref(destroy);
return res;
}
EXPORT_SYMBOL(sock_no_sendpage);
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index fdf49fd..e55a6e1 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -748,7 +748,9 @@ int inet_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
}
EXPORT_SYMBOL(inet_sendmsg);
-ssize_t inet_sendpage(struct socket *sock, struct page *page, int offset,
+ssize_t inet_sendpage(struct socket *sock, struct page *page,
+ struct skb_frag_destructor *destroy,
+ int offset,
size_t size, int flags)
{
struct sock *sk = sock->sk;
@@ -761,8 +763,9 @@ ssize_t inet_sendpage(struct socket *sock, struct page *page, int offset,
return -EAGAIN;
if (sk->sk_prot->sendpage)
- return sk->sk_prot->sendpage(sk, page, offset, size, flags);
- return sock_no_sendpage(sock, page, offset, size, flags);
+ return sk->sk_prot->sendpage(sk, page, destroy,
+ offset, size, flags);
+ return sock_no_sendpage(sock, page, destroy, offset, size, flags);
}
EXPORT_SYMBOL(inet_sendpage);
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 9e4eca6..2ce0b8e 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -1130,6 +1130,7 @@ int ip_append_data(struct sock *sk, struct flowi4 *fl4,
}
ssize_t ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page,
+ struct skb_frag_destructor *destroy,
int offset, size_t size, int flags)
{
struct inet_sock *inet = inet_sk(sk);
@@ -1243,11 +1244,12 @@ ssize_t ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page,
i = skb_shinfo(skb)->nr_frags;
if (len > size)
len = size;
- if (skb_can_coalesce(skb, i, page, NULL, offset)) {
+ if (skb_can_coalesce(skb, i, page, destroy, offset)) {
skb_frag_size_add(&skb_shinfo(skb)->frags[i-1], len);
} else if (i < MAX_SKB_FRAGS) {
- get_page(page);
skb_fill_page_desc(skb, i, page, offset, len);
+ skb_frag_set_destructor(skb, i, destroy);
+ skb_frag_ref(skb, i);
} else {
err = -EMSGSIZE;
goto error;
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index b1612e9..89d4db0 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -757,8 +757,11 @@ static int tcp_send_mss(struct sock *sk, int *size_goal, int flags)
return mss_now;
}
-static ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffset,
- size_t psize, int flags)
+static ssize_t do_tcp_sendpages(struct sock *sk,
+ struct page **pages,
+ struct skb_frag_destructor *destroy,
+ int poffset,
+ size_t psize, int flags)
{
struct tcp_sock *tp = tcp_sk(sk);
int mss_now, size_goal;
@@ -804,7 +807,7 @@ new_segment:
copy = size;
i = skb_shinfo(skb)->nr_frags;
- can_coalesce = skb_can_coalesce(skb, i, page, NULL, offset);
+ can_coalesce = skb_can_coalesce(skb, i, page, destroy, offset);
if (!can_coalesce && i >= MAX_SKB_FRAGS) {
tcp_mark_push(tp, skb);
goto new_segment;
@@ -815,8 +818,9 @@ new_segment:
if (can_coalesce) {
skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy);
} else {
- get_page(page);
skb_fill_page_desc(skb, i, page, offset, copy);
+ skb_frag_set_destructor(skb, i, destroy);
+ skb_frag_ref(skb, i);
}
skb->len += copy;
@@ -871,18 +875,20 @@ out_err:
return sk_stream_error(sk, flags, err);
}
-int tcp_sendpage(struct sock *sk, struct page *page, int offset,
- size_t size, int flags)
+int tcp_sendpage(struct sock *sk, struct page *page,
+ struct skb_frag_destructor *destroy,
+ int offset, size_t size, int flags)
{
ssize_t res;
if (!(sk->sk_route_caps & NETIF_F_SG) ||
!(sk->sk_route_caps & NETIF_F_ALL_CSUM))
- return sock_no_sendpage(sk->sk_socket, page, offset, size,
- flags);
+ return sock_no_sendpage(sk->sk_socket, page, destroy,
+ offset, size, flags);
lock_sock(sk);
- res = do_tcp_sendpages(sk, &page, offset, size, flags);
+ res = do_tcp_sendpages(sk, &page, destroy,
+ offset, size, flags);
release_sock(sk);
return res;
}
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index d6f5fee..f9038e4 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -1032,8 +1032,9 @@ do_confirm:
}
EXPORT_SYMBOL(udp_sendmsg);
-int udp_sendpage(struct sock *sk, struct page *page, int offset,
- size_t size, int flags)
+int udp_sendpage(struct sock *sk, struct page *page,
+ struct skb_frag_destructor *destroy,
+ int offset, size_t size, int flags)
{
struct inet_sock *inet = inet_sk(sk);
struct udp_sock *up = udp_sk(sk);
@@ -1061,11 +1062,11 @@ int udp_sendpage(struct sock *sk, struct page *page, int offset,
}
ret = ip_append_page(sk, &inet->cork.fl.u.ip4,
- page, offset, size, flags);
+ page, destroy, offset, size, flags);
if (ret == -EOPNOTSUPP) {
release_sock(sk);
- return sock_no_sendpage(sk->sk_socket, page, offset,
- size, flags);
+ return sock_no_sendpage(sk->sk_socket, page, destroy,
+ offset, size, flags);
}
if (ret < 0) {
udp_flush_pending_frames(sk);
diff --git a/net/ipv4/udp_impl.h b/net/ipv4/udp_impl.h
index aaad650..4923d82 100644
--- a/net/ipv4/udp_impl.h
+++ b/net/ipv4/udp_impl.h
@@ -23,8 +23,9 @@ extern int compat_udp_getsockopt(struct sock *sk, int level, int optname,
#endif
extern int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
size_t len, int noblock, int flags, int *addr_len);
-extern int udp_sendpage(struct sock *sk, struct page *page, int offset,
- size_t size, int flags);
+extern int udp_sendpage(struct sock *sk, struct page *page,
+ struct skb_frag_destructor *destroy,
+ int offset, size_t size, int flags);
extern int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb);
extern void udp_destroy_sock(struct sock *sk);
diff --git a/net/rds/tcp_send.c b/net/rds/tcp_send.c
index 1b4fd68..71503ad 100644
--- a/net/rds/tcp_send.c
+++ b/net/rds/tcp_send.c
@@ -119,6 +119,7 @@ int rds_tcp_xmit(struct rds_connection *conn, struct rds_message *rm,
while (sg < rm->data.op_nents) {
ret = tc->t_sock->ops->sendpage(tc->t_sock,
sg_page(&rm->data.op_sg[sg]),
+ NULL,
rm->data.op_sg[sg].offset + off,
rm->data.op_sg[sg].length - off,
MSG_DONTWAIT|MSG_NOSIGNAL);
diff --git a/net/socket.c b/net/socket.c
index 12a48d8..d0c0d8d 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -815,7 +815,7 @@ static ssize_t sock_sendpage(struct file *file, struct page *page,
if (more)
flags |= MSG_MORE;
- return kernel_sendpage(sock, page, offset, size, flags);
+ return kernel_sendpage(sock, page, NULL, offset, size, flags);
}
static ssize_t sock_splice_read(struct file *file, loff_t *ppos,
@@ -3350,15 +3350,18 @@ int kernel_setsockopt(struct socket *sock, int level, int optname,
}
EXPORT_SYMBOL(kernel_setsockopt);
-int kernel_sendpage(struct socket *sock, struct page *page, int offset,
+int kernel_sendpage(struct socket *sock, struct page *page,
+ struct skb_frag_destructor *destroy,
+ int offset,
size_t size, int flags)
{
sock_update_classid(sock->sk);
if (sock->ops->sendpage)
- return sock->ops->sendpage(sock, page, offset, size, flags);
+ return sock->ops->sendpage(sock, page, destroy,
+ offset, size, flags);
- return sock_no_sendpage(sock, page, offset, size, flags);
+ return sock_no_sendpage(sock, page, destroy, offset, size, flags);
}
EXPORT_SYMBOL(kernel_sendpage);
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 40ae884..706305b 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -185,7 +185,7 @@ int svc_send_common(struct socket *sock, struct xdr_buf *xdr,
/* send head */
if (slen == xdr->head[0].iov_len)
flags = 0;
- len = kernel_sendpage(sock, headpage, headoffset,
+ len = kernel_sendpage(sock, headpage, NULL, headoffset,
xdr->head[0].iov_len, flags);
if (len != xdr->head[0].iov_len)
goto out;
@@ -198,7 +198,7 @@ int svc_send_common(struct socket *sock, struct xdr_buf *xdr,
while (pglen > 0) {
if (slen == size)
flags = 0;
- result = kernel_sendpage(sock, *ppage, base, size, flags);
+ result = kernel_sendpage(sock, *ppage, NULL, base, size, flags);
if (result > 0)
len += result;
if (result != size)
@@ -212,7 +212,7 @@ int svc_send_common(struct socket *sock, struct xdr_buf *xdr,
/* send tail */
if (xdr->tail[0].iov_len) {
- result = kernel_sendpage(sock, tailpage, tailoffset,
+ result = kernel_sendpage(sock, tailpage, NULL, tailoffset,
xdr->tail[0].iov_len, 0);
if (result > 0)
len += result;
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index 92bc518..f05082b 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -408,7 +408,7 @@ static int xs_send_pagedata(struct socket *sock, struct xdr_buf *xdr, unsigned i
remainder -= len;
if (remainder != 0 || more)
flags |= MSG_MORE;
- err = sock->ops->sendpage(sock, *ppage, base, len, flags);
+ err = sock->ops->sendpage(sock, *ppage, NULL, base, len, flags);
if (remainder == 0 || err != len)
break;
sent += err;
--
1.7.2.5
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH 10/10] sunrpc: use SKB fragment destructors to delay completion until page is released by network stack.
From: Ian Campbell @ 2012-04-10 14:26 UTC (permalink / raw)
To: netdev-u79uwXL29TY76Z2rM5mHXA
Cc: David Miller, Eric Dumazet, Michael S. Tsirkin, Wei Liu,
xen-devel-GuqFBffKawuEi8DpZVb4nw, Ian Campbell, Neil Brown,
J. Bruce Fields, linux-nfs-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1334067965.5394.22.camel-o4Be2W7LfRlXesXXhkcM7miJhflN2719@public.gmane.org>
This prevents an issue where an ACK is delayed, a retransmit is queued (either
at the RPC or TCP level) and the ACK arrives before the retransmission hits the
wire. If this happens to an NFS WRITE RPC then the write() system call
completes and the userspace process can continue, potentially modifying data
referenced by the retransmission before the retransmission occurs.
Signed-off-by: Ian Campbell <ian.campbell-Sxgqhf6Nn4DQT0dZR+AlfA@public.gmane.org>
Acked-by: Trond Myklebust <Trond.Myklebust-HgOvQuBEEgTQT0dZR+AlfA@public.gmane.org>
Cc: "David S. Miller" <davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
Cc: Neil Brown <neilb-l3A5Bk7waGM@public.gmane.org>
Cc: "J. Bruce Fields" <bfields-uC3wQj2KruNg9hUCZPvPmw@public.gmane.org>
Cc: linux-nfs-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Cc: netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
---
include/linux/sunrpc/xdr.h | 2 ++
include/linux/sunrpc/xprt.h | 5 ++++-
net/sunrpc/clnt.c | 27 ++++++++++++++++++++++-----
net/sunrpc/svcsock.c | 3 ++-
net/sunrpc/xprt.c | 12 ++++++++++++
net/sunrpc/xprtsock.c | 3 ++-
6 files changed, 44 insertions(+), 8 deletions(-)
diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h
index af70af3..ff1b121 100644
--- a/include/linux/sunrpc/xdr.h
+++ b/include/linux/sunrpc/xdr.h
@@ -16,6 +16,7 @@
#include <asm/byteorder.h>
#include <asm/unaligned.h>
#include <linux/scatterlist.h>
+#include <linux/skbuff.h>
/*
* Buffer adjustment
@@ -57,6 +58,7 @@ struct xdr_buf {
tail[1]; /* Appended after page data */
struct page ** pages; /* Array of contiguous pages */
+ struct skb_frag_destructor *destructor;
unsigned int page_base, /* Start of page data */
page_len, /* Length of page data */
flags; /* Flags for data disposition */
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
index 77d278d..e8d3f18 100644
--- a/include/linux/sunrpc/xprt.h
+++ b/include/linux/sunrpc/xprt.h
@@ -92,7 +92,10 @@ struct rpc_rqst {
/* A cookie used to track the
state of the transport
connection */
-
+ struct skb_frag_destructor destructor; /* SKB paged fragment
+ * destructor for
+ * transmitted pages*/
+
/*
* Partial send handling
*/
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 7a4cb5f..4e94e2a 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -62,6 +62,7 @@ static void call_reserve(struct rpc_task *task);
static void call_reserveresult(struct rpc_task *task);
static void call_allocate(struct rpc_task *task);
static void call_decode(struct rpc_task *task);
+static void call_complete(struct rpc_task *task);
static void call_bind(struct rpc_task *task);
static void call_bind_status(struct rpc_task *task);
static void call_transmit(struct rpc_task *task);
@@ -1417,6 +1418,8 @@ rpc_xdr_encode(struct rpc_task *task)
(char *)req->rq_buffer + req->rq_callsize,
req->rq_rcvsize);
+ req->rq_snd_buf.destructor = &req->destructor;
+
p = rpc_encode_header(task);
if (p == NULL) {
printk(KERN_INFO "RPC: couldn't encode RPC header, exit EIO\n");
@@ -1582,6 +1585,7 @@ call_connect_status(struct rpc_task *task)
static void
call_transmit(struct rpc_task *task)
{
+ struct rpc_rqst *req = task->tk_rqstp;
dprint_status(task);
task->tk_action = call_status;
@@ -1615,8 +1619,8 @@ call_transmit(struct rpc_task *task)
call_transmit_status(task);
if (rpc_reply_expected(task))
return;
- task->tk_action = rpc_exit_task;
- rpc_wake_up_queued_task(&task->tk_xprt->pending, task);
+ task->tk_action = call_complete;
+ skb_frag_destructor_unref(&req->destructor);
}
/*
@@ -1689,7 +1693,8 @@ call_bc_transmit(struct rpc_task *task)
return;
}
- task->tk_action = rpc_exit_task;
+ task->tk_action = call_complete;
+ skb_frag_destructor_unref(&req->destructor);
if (task->tk_status < 0) {
printk(KERN_NOTICE "RPC: Could not send backchannel reply "
"error: %d\n", task->tk_status);
@@ -1729,7 +1734,6 @@ call_bc_transmit(struct rpc_task *task)
"error: %d\n", task->tk_status);
break;
}
- rpc_wake_up_queued_task(&req->rq_xprt->pending, task);
}
#endif /* CONFIG_SUNRPC_BACKCHANNEL */
@@ -1907,12 +1911,14 @@ call_decode(struct rpc_task *task)
return;
}
- task->tk_action = rpc_exit_task;
+ task->tk_action = call_complete;
if (decode) {
task->tk_status = rpcauth_unwrap_resp(task, decode, req, p,
task->tk_msg.rpc_resp);
}
+ rpc_sleep_on(&req->rq_xprt->pending, task, NULL);
+ skb_frag_destructor_unref(&req->destructor);
dprintk("RPC: %5u call_decode result %d\n", task->tk_pid,
task->tk_status);
return;
@@ -1927,6 +1933,17 @@ out_retry:
}
}
+/*
+ * 8. Wait for pages to be released by the network stack.
+ */
+static void
+call_complete(struct rpc_task *task)
+{
+ dprintk("RPC: %5u call_complete result %d\n",
+ task->tk_pid, task->tk_status);
+ task->tk_action = rpc_exit_task;
+}
+
static __be32 *
rpc_encode_header(struct rpc_task *task)
{
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 706305b..efa95df 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -198,7 +198,8 @@ int svc_send_common(struct socket *sock, struct xdr_buf *xdr,
while (pglen > 0) {
if (slen == size)
flags = 0;
- result = kernel_sendpage(sock, *ppage, NULL, base, size, flags);
+ result = kernel_sendpage(sock, *ppage, xdr->destructor,
+ base, size, flags);
if (result > 0)
len += result;
if (result != size)
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index 0cbcd1a..a252759 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -1108,6 +1108,16 @@ static inline void xprt_init_xid(struct rpc_xprt *xprt)
xprt->xid = net_random();
}
+static int xprt_complete_skb_pages(struct skb_frag_destructor *destroy)
+{
+ struct rpc_rqst *req =
+ container_of(destroy, struct rpc_rqst, destructor);
+
+ dprintk("RPC: %5u completing skb pages\n", req->rq_task->tk_pid);
+ rpc_wake_up_queued_task(&req->rq_xprt->pending, req->rq_task);
+ return 0;
+}
+
static void xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt)
{
struct rpc_rqst *req = task->tk_rqstp;
@@ -1120,6 +1130,8 @@ static void xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt)
req->rq_xid = xprt_alloc_xid(xprt);
req->rq_release_snd_buf = NULL;
xprt_reset_majortimeo(req);
+ atomic_set(&req->destructor.ref, 1);
+ req->destructor.destroy = &xprt_complete_skb_pages;
dprintk("RPC: %5u reserved req %p xid %08x\n", task->tk_pid,
req, ntohl(req->rq_xid));
}
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index f05082b..b6ee8b7 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -408,7 +408,8 @@ static int xs_send_pagedata(struct socket *sock, struct xdr_buf *xdr, unsigned i
remainder -= len;
if (remainder != 0 || more)
flags |= MSG_MORE;
- err = sock->ops->sendpage(sock, *ppage, NULL, base, len, flags);
+ err = sock->ops->sendpage(sock, *ppage, xdr->destructor,
+ base, len, flags);
if (remainder == 0 || err != len)
break;
sent += err;
--
1.7.2.5
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* Re: [PATCH] pppoatm: Fix excessive queue bloat
From: chas williams - CONTRACTOR @ 2012-04-10 14:26 UTC (permalink / raw)
To: David Woodhouse; +Cc: netdev, David Miller, paulus, Eric Dumazet
In-Reply-To: <1333914837.31812.57.camel@shinybook.infradead.org>
On Sun, 08 Apr 2012 21:53:57 +0200
David Woodhouse <dwmw2@infradead.org> wrote:
> Seriously, this gets *much* easier if we just ditch the checks against
> sk_sndbuf. We just wake up whenever decrementing ->inflight from zero.
> Can I?
i dont know. on a 'low' speed connection like queuing 2 packets might
be enough to keep something busy but imagine an interace like oc3 or
oc12. i dont know anything running pppoatm on such an interface but it
seems like just dropping sk_sndbuf isnt right either.
sk_sndbuf is per vcc and that isnt right either since the transmit
limit is actually the atm device's transmit queue depth. in your case,
since you are only using a single vcc, this problem does somewhat map
to a sk_sndbuf. but sk_sndbuf counts bytes and not entries in a queue
which is typically the limit imposed by the hardware.
it makes me wonder if we dont need to add another stub to the atm
driver interface to check if the device can transmit instead of 'can we
queue on the vcc'. atm_may_send() then would be changed to check to see
if a transmit queue entry is available and there is sk_sndbuf queue
space. if a driver doesnt have this stub to check for queue space,
atm_may_send() can just assume there is a queue entry and we get the
previous default behavior. what is the "queue depth" of your atm
device's transmit queue?
yes, the vcc->sk_sndbuf should be MAX(vcc->sk_sndbuf, pppoatm->MTU) but
since people dont often change the sk_sndbuf i guess no one has run
into this issue. pppoatm (et al) should enforce this limit though.
^ permalink raw reply
* [PATCH 03/10] chelsio: use SKB_WITH_OVERHEAD
From: Ian Campbell @ 2012-04-10 14:26 UTC (permalink / raw)
To: netdev
Cc: David Miller, Eric Dumazet, Michael S. Tsirkin, Wei Liu,
xen-devel, Ian Campbell, Divy Le Ray
In-Reply-To: <1334067965.5394.22.camel@zakaz.uk.xensource.com>
Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
Cc: Divy Le Ray <divy@chelsio.com>
---
drivers/net/ethernet/chelsio/cxgb/sge.c | 3 +--
drivers/net/ethernet/chelsio/cxgb3/sge.c | 6 +++---
2 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/chelsio/cxgb/sge.c b/drivers/net/ethernet/chelsio/cxgb/sge.c
index 47a8435..52373db 100644
--- a/drivers/net/ethernet/chelsio/cxgb/sge.c
+++ b/drivers/net/ethernet/chelsio/cxgb/sge.c
@@ -599,8 +599,7 @@ static int alloc_rx_resources(struct sge *sge, struct sge_params *p)
sizeof(struct cpl_rx_data) +
sge->freelQ[!sge->jumbo_fl].dma_offset;
- size = (16 * 1024) -
- SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+ size = SKB_WITH_OVERHEAD(16 * 1024);
sge->freelQ[sge->jumbo_fl].rx_buffer_size = size;
diff --git a/drivers/net/ethernet/chelsio/cxgb3/sge.c b/drivers/net/ethernet/chelsio/cxgb3/sge.c
index cfb60e1..b804470 100644
--- a/drivers/net/ethernet/chelsio/cxgb3/sge.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/sge.c
@@ -3043,7 +3043,7 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports,
q->fl[1].buf_size = FL1_PG_CHUNK_SIZE;
#else
q->fl[1].buf_size = is_offload(adapter) ?
- (16 * 1024) - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) :
+ SKB_WITH_OVERHEAD(16 * 1024) :
MAX_FRAME_SIZE + 2 + sizeof(struct cpl_rx_pkt);
#endif
@@ -3282,8 +3282,8 @@ void t3_sge_prep(struct adapter *adap, struct sge_params *p)
{
int i;
- p->max_pkt_size = (16 * 1024) - sizeof(struct cpl_rx_data) -
- SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+ p->max_pkt_size =
+ SKB_WITH_OVERHEAD((16*1024) - sizeof(struct cpl_rx_data));
for (i = 0; i < SGE_QSETS; ++i) {
struct qset_params *q = p->qset + i;
--
1.7.2.5
^ permalink raw reply related
* [PATCH 05/10] net: move destructor_arg to the front of sk_buff.
From: Ian Campbell @ 2012-04-10 14:26 UTC (permalink / raw)
To: netdev
Cc: David Miller, Eric Dumazet, Michael S. Tsirkin, Wei Liu,
xen-devel, Ian Campbell
In-Reply-To: <1334067965.5394.22.camel@zakaz.uk.xensource.com>
As of the previous patch we align the end (rather than the start) of the struct
to a cache line and so, with 32 and 64 byte cache lines and the shinfo size
increase from the next patch, the first 8 bytes of the struct end up on a
different cache line to the rest of it so make sure it is something relatively
unimportant to avoid hitting an extra cache line on hot operations such as
kfree_skb.
Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Eric Dumazet <eric.dumazet@gmail.com>
---
include/linux/skbuff.h | 15 ++++++++++-----
net/core/skbuff.c | 5 ++++-
2 files changed, 14 insertions(+), 6 deletions(-)
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 0ad6a46..f0ae39c 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -265,6 +265,15 @@ struct ubuf_info {
* the end of the header data, ie. at skb->end.
*/
struct skb_shared_info {
+ /* Intermediate layers must ensure that destructor_arg
+ * remains valid until skb destructor */
+ void *destructor_arg;
+
+ /*
+ * Warning: all fields from here until dataref are cleared in
+ * __alloc_skb()
+ *
+ */
unsigned char nr_frags;
__u8 tx_flags;
unsigned short gso_size;
@@ -276,14 +285,10 @@ struct skb_shared_info {
__be32 ip6_frag_id;
/*
- * Warning : all fields before dataref are cleared in __alloc_skb()
+ * Warning: all fields before dataref are cleared in __alloc_skb()
*/
atomic_t dataref;
- /* Intermediate layers must ensure that destructor_arg
- * remains valid until skb destructor */
- void * destructor_arg;
-
/* must be last field, see pskb_expand_head() */
skb_frag_t frags[MAX_SKB_FRAGS];
};
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index d4e139e..b8a41d6 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -214,7 +214,10 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
/* make sure we initialize shinfo sequentially */
shinfo = skb_shinfo(skb);
- memset(shinfo, 0, offsetof(struct skb_shared_info, dataref));
+
+ memset(&shinfo->nr_frags, 0,
+ offsetof(struct skb_shared_info, dataref)
+ - offsetof(struct skb_shared_info, nr_frags));
atomic_set(&shinfo->dataref, 1);
kmemcheck_annotate_variable(shinfo->destructor_arg);
--
1.7.2.5
^ permalink raw reply related
* [PATCH 06/10] net: add support for per-paged-fragment destructors
From: Ian Campbell @ 2012-04-10 14:26 UTC (permalink / raw)
To: netdev
Cc: David Miller, Eric Dumazet, Michael S. Tsirkin, Wei Liu,
xen-devel, Ian Campbell, Michał Mirosław
In-Reply-To: <1334067965.5394.22.camel@zakaz.uk.xensource.com>
Entities which care about the complete lifecycle of pages which they inject
into the network stack via an skb paged fragment can choose to set this
destructor in order to receive a callback when the stack is really finished
with a page (including all clones, retransmits, pull-ups etc etc).
This destructor will always be propagated alongside the struct page when
copying skb_frag_t->page. This is the reason I chose to embed the destructor in
a "struct { } page" within the skb_frag_t, rather than as a separate field,
since it allows existing code which propagates ->frags[N].page to Just
Work(tm).
When the destructor is present the page reference counting is done slightly
differently. No references are held by the network stack on the struct page (it
is up to the caller to manage this as necessary) instead the network stack will
track references via the count embedded in the destructor structure. When this
reference count reaches zero then the destructor will be called and the caller
can take the necesary steps to release the page (i.e. release the struct page
reference itself).
The intention is that callers can use this callback to delay completion to
_their_ callers until the network stack has completely released the page, in
order to prevent use-after-free or modification of data pages which are still
in use by the stack.
It is allowable (indeed expected) for a caller to share a single destructor
instance between multiple pages injected into the stack e.g. a group of pages
included in a single higher level operation might share a destructor which is
used to complete that higher level operation.
With this change and the previous two changes to shinfo alignment and field
orderring it is now the case tyhat on a 64 bit system with 64 byte cache lines,
everything from nr_frags until the end of frags[0] is on the same cacheline.
Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Eric Dumazet <eric.dumazet@gmail.com>
Cc: "Michał Mirosław" <mirq-linux@rere.qmqm.pl>
Cc: netdev@vger.kernel.org
---
include/linux/skbuff.h | 43 +++++++++++++++++++++++++++++++++++++++++++
net/core/skbuff.c | 17 +++++++++++++++++
2 files changed, 60 insertions(+), 0 deletions(-)
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index f0ae39c..6ac283e 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -166,9 +166,15 @@ struct sk_buff;
typedef struct skb_frag_struct skb_frag_t;
+struct skb_frag_destructor {
+ atomic_t ref;
+ int (*destroy)(struct skb_frag_destructor *destructor);
+};
+
struct skb_frag_struct {
struct {
struct page *p;
+ struct skb_frag_destructor *destructor;
} page;
#if (BITS_PER_LONG > 32) || (PAGE_SIZE >= 65536)
__u32 page_offset;
@@ -1221,6 +1227,31 @@ static inline int skb_pagelen(const struct sk_buff *skb)
}
/**
+ * skb_frag_set_destructor - set destructor for a paged fragment
+ * @skb: buffer containing fragment to be initialised
+ * @i: paged fragment index to initialise
+ * @destroy: the destructor to use for this fragment
+ *
+ * Sets @destroy as the destructor to be called when all references to
+ * the frag @i in @skb (tracked over skb_clone, retransmit, pull-ups,
+ * etc) are released.
+ *
+ * When a destructor is set then reference counting is performed on
+ * @destroy->ref. When the ref reaches zero then @destroy->destroy
+ * will be called. The caller is responsible for holding and managing
+ * any other references (such a the struct page reference count).
+ *
+ * This function must be called before any use of skb_frag_ref() or
+ * skb_frag_unref().
+ */
+static inline void skb_frag_set_destructor(struct sk_buff *skb, int i,
+ struct skb_frag_destructor *destroy)
+{
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ frag->page.destructor = destroy;
+}
+
+/**
* __skb_fill_page_desc - initialise a paged fragment in an skb
* @skb: buffer containing fragment to be initialised
* @i: paged fragment index to initialise
@@ -1239,6 +1270,7 @@ static inline void __skb_fill_page_desc(struct sk_buff *skb, int i,
skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
frag->page.p = page;
+ frag->page.destructor = NULL;
frag->page_offset = off;
skb_frag_size_set(frag, size);
}
@@ -1743,6 +1775,9 @@ static inline struct page *skb_frag_page(const skb_frag_t *frag)
return frag->page.p;
}
+extern void skb_frag_destructor_ref(struct skb_frag_destructor *destroy);
+extern void skb_frag_destructor_unref(struct skb_frag_destructor *destroy);
+
/**
* __skb_frag_ref - take an addition reference on a paged fragment.
* @frag: the paged fragment
@@ -1751,6 +1786,10 @@ static inline struct page *skb_frag_page(const skb_frag_t *frag)
*/
static inline void __skb_frag_ref(skb_frag_t *frag)
{
+ if (unlikely(frag->page.destructor)) {
+ skb_frag_destructor_ref(frag->page.destructor);
+ return;
+ }
get_page(skb_frag_page(frag));
}
@@ -1774,6 +1813,10 @@ static inline void skb_frag_ref(struct sk_buff *skb, int f)
*/
static inline void __skb_frag_unref(skb_frag_t *frag)
{
+ if (unlikely(frag->page.destructor)) {
+ skb_frag_destructor_unref(frag->page.destructor);
+ return;
+ }
put_page(skb_frag_page(frag));
}
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index b8a41d6..9ec88ce 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -349,6 +349,23 @@ struct sk_buff *dev_alloc_skb(unsigned int length)
}
EXPORT_SYMBOL(dev_alloc_skb);
+void skb_frag_destructor_ref(struct skb_frag_destructor *destroy)
+{
+ BUG_ON(destroy == NULL);
+ atomic_inc(&destroy->ref);
+}
+EXPORT_SYMBOL(skb_frag_destructor_ref);
+
+void skb_frag_destructor_unref(struct skb_frag_destructor *destroy)
+{
+ if (destroy == NULL)
+ return;
+
+ if (atomic_dec_and_test(&destroy->ref))
+ destroy->destroy(destroy);
+}
+EXPORT_SYMBOL(skb_frag_destructor_unref);
+
static void skb_drop_list(struct sk_buff **listp)
{
struct sk_buff *list = *listp;
--
1.7.2.5
^ permalink raw reply related
* [PATCH 08/10] net: add skb_orphan_frags to copy aside frags with destructors
From: Ian Campbell @ 2012-04-10 14:26 UTC (permalink / raw)
To: netdev
Cc: David Miller, Eric Dumazet, Michael S. Tsirkin, Wei Liu,
xen-devel, Ian Campbell
In-Reply-To: <1334067965.5394.22.camel@zakaz.uk.xensource.com>
This should be used by drivers which need to hold on to an skb for an extended
(perhaps unbounded) period of time. e.g. the tun driver which relies on
userspace consuming the skb.
Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
Cc: mst@redhat.com
---
drivers/net/tun.c | 1 +
include/linux/skbuff.h | 11 ++++++++
net/core/skbuff.c | 67 ++++++++++++++++++++++++++++++++++-------------
3 files changed, 60 insertions(+), 19 deletions(-)
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 74d7f76..b20789e 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -416,6 +416,7 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
/* Orphan the skb - required as we might hang on to it
* for indefinite time. */
skb_orphan(skb);
+ skb_orphan_frags(skb, GFP_KERNEL);
/* Enqueue packet */
skb_queue_tail(&tun->socket.sk->sk_receive_queue, skb);
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 8593ac2..77145f0 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -1688,6 +1688,17 @@ static inline void skb_orphan(struct sk_buff *skb)
}
/**
+ * skb_orphan_frags - orphan the frags contained in a buffer
+ * @skb: buffer to orphan frags from
+ * @gfp_mask: allocation mask for replacement pages
+ *
+ * For each frag in the SKB which has a destructor (i.e. has an
+ * owner) create a copy of that frag and release the original
+ * page by calling the destructor.
+ */
+extern int skb_orphan_frags(struct sk_buff *skb, gfp_t gfp_mask);
+
+/**
* __skb_queue_purge - empty a list
* @list: list to empty
*
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index e63a4a6..d0a1603 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -688,31 +688,25 @@ struct sk_buff *skb_morph(struct sk_buff *dst, struct sk_buff *src)
}
EXPORT_SYMBOL_GPL(skb_morph);
-/* skb_copy_ubufs - copy userspace skb frags buffers to kernel
- * @skb: the skb to modify
- * @gfp_mask: allocation priority
- *
- * This must be called on SKBTX_DEV_ZEROCOPY skb.
- * It will copy all frags into kernel and drop the reference
- * to userspace pages.
- *
- * If this function is called from an interrupt gfp_mask() must be
- * %GFP_ATOMIC.
- *
- * Returns 0 on success or a negative error code on failure
- * to allocate kernel memory to copy to.
+/*
+ * If uarg != NULL copy and replace all frags.
+ * If uarg == NULL then only copy and replace those which have a destructor
+ * pointer.
*/
-int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask)
+static int skb_copy_frags(struct sk_buff *skb, gfp_t gfp_mask,
+ struct ubuf_info *uarg)
{
int i;
int num_frags = skb_shinfo(skb)->nr_frags;
struct page *page, *head = NULL;
- struct ubuf_info *uarg = skb_shinfo(skb)->destructor_arg;
for (i = 0; i < num_frags; i++) {
u8 *vaddr;
skb_frag_t *f = &skb_shinfo(skb)->frags[i];
+ if (!uarg && !f->page.destructor)
+ continue;
+
page = alloc_page(GFP_ATOMIC);
if (!page) {
while (head) {
@@ -730,11 +724,16 @@ int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask)
head = page;
}
- /* skb frags release userspace buffers */
- for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
+ /* skb frags release buffers */
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+ skb_frag_t *f = &skb_shinfo(skb)->frags[i];
+ if (!uarg && !f->page.destructor)
+ continue;
skb_frag_unref(skb, i);
+ }
- uarg->callback(uarg);
+ if (uarg)
+ uarg->callback(uarg);
/* skb frags point to kernel buffers */
for (i = skb_shinfo(skb)->nr_frags; i > 0; i--) {
@@ -743,10 +742,40 @@ int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask)
head = (struct page *)head->private;
}
- skb_shinfo(skb)->tx_flags &= ~SKBTX_DEV_ZEROCOPY;
return 0;
}
+/* skb_copy_ubufs - copy userspace skb frags buffers to kernel
+ * @skb: the skb to modify
+ * @gfp_mask: allocation priority
+ *
+ * This must be called on SKBTX_DEV_ZEROCOPY skb.
+ * It will copy all frags into kernel and drop the reference
+ * to userspace pages.
+ *
+ * If this function is called from an interrupt gfp_mask() must be
+ * %GFP_ATOMIC.
+ *
+ * Returns 0 on success or a negative error code on failure
+ * to allocate kernel memory to copy to.
+ */
+int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask)
+{
+ struct ubuf_info *uarg = skb_shinfo(skb)->destructor_arg;
+ int rc;
+
+ rc = skb_copy_frags(skb, gfp_mask, uarg);
+
+ if (rc == 0)
+ skb_shinfo(skb)->tx_flags &= ~SKBTX_DEV_ZEROCOPY;
+
+ return rc;
+}
+
+int skb_orphan_frags(struct sk_buff *skb, gfp_t gfp_mask)
+{
+ return skb_copy_frags(skb, gfp_mask, NULL);
+}
/**
* skb_clone - duplicate an sk_buff
--
1.7.2.5
^ permalink raw reply related
* [PATCH 01/10] net: add and use SKB_ALLOCSIZE
From: Ian Campbell @ 2012-04-10 14:26 UTC (permalink / raw)
To: netdev
Cc: David Miller, Eric Dumazet, Michael S. Tsirkin, Wei Liu,
xen-devel, Ian Campbell
In-Reply-To: <1334067965.5394.22.camel@zakaz.uk.xensource.com>
This gives the allocation size required for an skb containing X bytes of data
Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
---
drivers/net/ethernet/broadcom/bnx2.c | 7 +++----
drivers/net/ethernet/broadcom/bnx2x/bnx2x.h | 3 +--
drivers/net/ethernet/broadcom/tg3.c | 3 +--
include/linux/skbuff.h | 12 ++++++++++++
net/core/skbuff.c | 8 +-------
5 files changed, 18 insertions(+), 15 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c
index 8297e28..dede71f 100644
--- a/drivers/net/ethernet/broadcom/bnx2.c
+++ b/drivers/net/ethernet/broadcom/bnx2.c
@@ -5321,8 +5321,7 @@ bnx2_set_rx_ring_size(struct bnx2 *bp, u32 size)
/* 8 for CRC and VLAN */
rx_size = bp->dev->mtu + ETH_HLEN + BNX2_RX_OFFSET + 8;
- rx_space = SKB_DATA_ALIGN(rx_size + BNX2_RX_ALIGN) + NET_SKB_PAD +
- SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+ rx_space = SKB_ALLOCSIZE(rx_size + BNX2_RX_ALIGN) + NET_SKB_PAD;
bp->rx_copy_thresh = BNX2_RX_COPY_THRESH;
bp->rx_pg_ring_size = 0;
@@ -5345,8 +5344,8 @@ bnx2_set_rx_ring_size(struct bnx2 *bp, u32 size)
bp->rx_buf_use_size = rx_size;
/* hw alignment + build_skb() overhead*/
- bp->rx_buf_size = SKB_DATA_ALIGN(bp->rx_buf_use_size + BNX2_RX_ALIGN) +
- NET_SKB_PAD + SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+ bp->rx_buf_size = SKB_ALLOCSIZE(bp->rx_buf_use_size + BNX2_RX_ALIGN) +
+ NET_SKB_PAD;
bp->rx_jumbo_thresh = rx_size - BNX2_RX_OFFSET;
bp->rx_ring_size = size;
bp->rx_max_ring = bnx2_find_max_ring(size, MAX_RX_RINGS);
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
index e37161f..12f2ceb 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
@@ -1229,8 +1229,7 @@ struct bnx2x {
#define BNX2X_FW_RX_ALIGN_START (1UL << BNX2X_RX_ALIGN_SHIFT)
#define BNX2X_FW_RX_ALIGN_END \
- max(1UL << BNX2X_RX_ALIGN_SHIFT, \
- SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
+ max(1UL << BNX2X_RX_ALIGN_SHIFT, SKB_ALLOCSIZE(0))
#define BNX2X_PXP_DRAM_ALIGN (BNX2X_RX_ALIGN_SHIFT - 5)
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index 7b71387..4d4b063 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -5672,8 +5672,7 @@ static int tg3_alloc_rx_data(struct tg3 *tp, struct tg3_rx_prodring_set *tpr,
* Callers depend upon this behavior and assume that
* we leave everything unchanged if we fail.
*/
- skb_size = SKB_DATA_ALIGN(data_size + TG3_RX_OFFSET(tp)) +
- SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+ skb_size = SKB_ALLOCSIZE(data_size + TG3_RX_OFFSET(tp));
data = kmalloc(skb_size, GFP_ATOMIC);
if (!data)
return -ENOMEM;
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 192250b..fbc92b2 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -41,8 +41,20 @@
#define SKB_DATA_ALIGN(X) (((X) + (SMP_CACHE_BYTES - 1)) & \
~(SMP_CACHE_BYTES - 1))
+/* maximum data size which can fit into an allocation of X bytes */
#define SKB_WITH_OVERHEAD(X) \
((X) - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
+/*
+ * minimum allocation size required for an skb containing X bytes of data
+ *
+ * We do our best to align skb_shared_info on a separate cache
+ * line. It usually works because kmalloc(X > SMP_CACHE_BYTES) gives
+ * aligned memory blocks, unless SLUB/SLAB debug is enabled. Both
+ * skb->head and skb_shared_info are cache line aligned.
+ */
+#define SKB_ALLOCSIZE(X) \
+ (SKB_DATA_ALIGN((X)) + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
+
#define SKB_MAX_ORDER(X, ORDER) \
SKB_WITH_OVERHEAD((PAGE_SIZE << (ORDER)) - (X))
#define SKB_MAX_HEAD(X) (SKB_MAX_ORDER((X), 0))
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index a690cae..59a1ecb 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -184,13 +184,7 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
goto out;
prefetchw(skb);
- /* We do our best to align skb_shared_info on a separate cache
- * line. It usually works because kmalloc(X > SMP_CACHE_BYTES) gives
- * aligned memory blocks, unless SLUB/SLAB debug is enabled.
- * Both skb->head and skb_shared_info are cache line aligned.
- */
- size = SKB_DATA_ALIGN(size);
- size += SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+ size = SKB_ALLOCSIZE(size);
data = kmalloc_node_track_caller(size, gfp_mask, node);
if (!data)
goto nodata;
--
1.7.2.5
^ permalink raw reply related
* [PATCH 02/10] net: Use SKB_WITH_OVERHEAD in build_skb
From: Ian Campbell @ 2012-04-10 14:26 UTC (permalink / raw)
To: netdev
Cc: David Miller, Eric Dumazet, Michael S. Tsirkin, Wei Liu,
xen-devel, Ian Campbell
In-Reply-To: <1334067965.5394.22.camel@zakaz.uk.xensource.com>
Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
---
net/core/skbuff.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 59a1ecb..d4e139e 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -264,7 +264,7 @@ struct sk_buff *build_skb(void *data)
if (!skb)
return NULL;
- size = ksize(data) - SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+ size = SKB_WITH_OVERHEAD(ksize(data));
memset(skb, 0, offsetof(struct sk_buff, tail));
skb->truesize = SKB_TRUESIZE(size);
--
1.7.2.5
^ permalink raw reply related
* [PATCH 07/10] net: only allow paged fragments with the same destructor to be coalesced.
From: Ian Campbell @ 2012-04-10 14:26 UTC (permalink / raw)
To: netdev
Cc: David Miller, Eric Dumazet, Michael S. Tsirkin, Wei Liu,
xen-devel, Ian Campbell, Alexey Kuznetsov, Pekka Savola (ipv6),
James Morris, Hideaki YOSHIFUJI, Patrick McHardy,
Michał Mirosław
In-Reply-To: <1334067965.5394.22.camel@zakaz.uk.xensource.com>
Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
Cc: "Pekka Savola (ipv6)" <pekkas@netcore.fi>
Cc: James Morris <jmorris@namei.org>
Cc: Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org>
Cc: Patrick McHardy <kaber@trash.net>
Cc: Eric Dumazet <eric.dumazet@gmail.com>
Cc: "Michał Mirosław" <mirq-linux@rere.qmqm.pl>
Cc: netdev@vger.kernel.org
---
include/linux/skbuff.h | 7 +++++--
net/core/skbuff.c | 1 +
net/ipv4/ip_output.c | 2 +-
net/ipv4/tcp.c | 4 ++--
4 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 6ac283e..8593ac2 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -2014,13 +2014,16 @@ static inline int skb_add_data(struct sk_buff *skb,
}
static inline int skb_can_coalesce(struct sk_buff *skb, int i,
- const struct page *page, int off)
+ const struct page *page,
+ const struct skb_frag_destructor *destroy,
+ int off)
{
if (i) {
const struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i - 1];
return page == skb_frag_page(frag) &&
- off == frag->page_offset + skb_frag_size(frag);
+ off == frag->page_offset + skb_frag_size(frag) &&
+ frag->page.destructor == destroy;
}
return 0;
}
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 9ec88ce..e63a4a6 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -2323,6 +2323,7 @@ int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen)
*/
if (!to ||
!skb_can_coalesce(tgt, to, skb_frag_page(fragfrom),
+ fragfrom->page.destructor,
fragfrom->page_offset)) {
merge = -1;
} else {
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index ff302bd..9e4eca6 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -1243,7 +1243,7 @@ ssize_t ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page,
i = skb_shinfo(skb)->nr_frags;
if (len > size)
len = size;
- if (skb_can_coalesce(skb, i, page, offset)) {
+ if (skb_can_coalesce(skb, i, page, NULL, offset)) {
skb_frag_size_add(&skb_shinfo(skb)->frags[i-1], len);
} else if (i < MAX_SKB_FRAGS) {
get_page(page);
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index cfd7edd..b1612e9 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -804,7 +804,7 @@ new_segment:
copy = size;
i = skb_shinfo(skb)->nr_frags;
- can_coalesce = skb_can_coalesce(skb, i, page, offset);
+ can_coalesce = skb_can_coalesce(skb, i, page, NULL, offset);
if (!can_coalesce && i >= MAX_SKB_FRAGS) {
tcp_mark_push(tp, skb);
goto new_segment;
@@ -1013,7 +1013,7 @@ new_segment:
off = sk->sk_sndmsg_off;
- if (skb_can_coalesce(skb, i, page, off) &&
+ if (skb_can_coalesce(skb, i, page, NULL, off) &&
off != PAGE_SIZE) {
/* We can extend the last page
* fragment. */
--
1.7.2.5
^ permalink raw reply related
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