Re: [PATCH 0/4] skb paged fragment destructors
From: Ian Campbell <hidden>
Date: 2011-11-17 14:45:23
On Wed, 2011-11-09 at 17:49 +0000, Eric Dumazet wrote:
Le mercredi 09 novembre 2011 à 15:01 +0000, Ian Campbell a écrit :quoted
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. I think these have all been posted before, but have been backed up behind the skb fragment API. 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 presented this work at LPC in September and there was a question/concern raised (by Jesse Brandenburg IIRC) regarding the overhead of adding this extra field per fragment. If I understand correctly it seems that in the there have been performance regressions in the past with allocations outgrowing one allocation size bucket and therefore using the next. The change in datastructure size resulting from this series is: BEFORE AFTER AMD64: sizeof(struct skb_frag_struct) = 16 24 sizeof(struct skb_shared_info) = 344 488Thats a real problem, because 488 is soo big. (its even rounded to 512 bytes) Now, on x86, a half page (2048 bytes) wont be big enough to contain a typical frame (MTU=1500) NET_SKB_PAD (64) + 1500 + 14 + 512 > 2048
Am I right that it's not so much a case of fitting into half a page but more like not wasting nearly half a page if you end up requiring a 4096 byte allocation? (This is probably splitting hairs, I'm really just curious)
Even if we dont round 488 to 512, (no cache align skb_shared_info) we have a problem. NET_SKB_PAD (64) + 1500 + 14 + 488 > 2048 Why not using a low order bit to mark 'page' being a pointer to
I've given this a go but it makes the patches to the user of this facility quite nasty (or at least it does for the sunrpc/NFS case). I'm going to plug at it a bit more and see if I can't make it look cleaner but I was starting to wonder about alternative approaches. One idea was split the allocation of the data and the shinfo. Since shinfo is a fixed size it would be easy to have a specific cache for them. Does this sound even vaguely plausible?
struct skb_frag_page_desc {
struct page *p;
atomic_t ref;
int (*destroy)(void *data);
/* void *data; */ /* no need, see container_of() */
It turns out that container_of is not so useful here as the users
typically has a list of pages not a single page and hence has a list of
destructors too. What you actually need is the container of the pointer
to that list, IYSWIM, which you can't get at given only a pointer to an
element of the list. So you end up doing
struct subsys_page_desc {
struct subsys_container *container;
struct sbk_frag_page_desc;
}
*container here is basically the same as the void * so you might as well
include it in the base datastructure.
Ian.
};
struct skb_frag_struct {
struct {
union {
struct page *p; /* low order bit not set */
struct skb_frag_page_desc *skbpage; /* low order bit set */
};
} page;
...