From: Jeremy Fitzhardinge <jeremy@goop.org>
To: Herbert Xu <herbert@gondor.apana.org.au>,
David Miller <davem@davemloft.net>
Cc: NetDev <netdev@vger.kernel.org>
Subject: [PATCH RFC] net: add alloc_skb_mustcopy() to make clone copy
Date: Tue, 20 Oct 2009 15:19:18 +0900 [thread overview]
Message-ID: <4ADD5666.9090409@goop.org> (raw)
[ RFC only ]
When doing network IO on behalf of guests, a Xen dom0 kernel gets granted
pages from guests. These pages cannot be released normally, so we must
handle releasing them specially, which can do with a skb_destructor.
This is complicated by the fact that the lifetime of an skb's
frags can be extended via cloning. To address this, this patch adds
alloc_skb_mustcopy() which allocates an skb with fclone==SKB_MUST_COPY.
If skb_clone() sees an skb with this set, it simply calls skb_copy
instead so that there are no aliases to the granted pages.
/* Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com> */
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index f2c69a2..830203f 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -228,6 +228,7 @@ enum {
SKB_FCLONE_UNAVAILABLE,
SKB_FCLONE_ORIG,
SKB_FCLONE_CLONE,
+ SKB_MUST_COPY,
};
enum {
@@ -449,13 +450,19 @@ extern struct sk_buff *__alloc_skb(unsigned int size,
static inline struct sk_buff *alloc_skb(unsigned int size,
gfp_t priority)
{
- return __alloc_skb(size, priority, 0, -1);
+ return __alloc_skb(size, priority, SKB_FCLONE_UNAVAILABLE, -1);
}
static inline struct sk_buff *alloc_skb_fclone(unsigned int size,
gfp_t priority)
{
- return __alloc_skb(size, priority, 1, -1);
+ return __alloc_skb(size, priority, SKB_FCLONE_ORIG, -1);
+}
+
+static inline struct sk_buff *alloc_skb_mustcopy(unsigned int size,
+ gfp_t priority)
+{
+ return __alloc_skb(size, priority, SKB_MUST_COPY, -1);
}
extern int skb_recycle_check(struct sk_buff *skb, int skb_size);
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 9e0597d..b130fab 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -177,7 +177,9 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
struct sk_buff *skb;
u8 *data;
- cache = fclone ? skbuff_fclone_cache : skbuff_head_cache;
+ cache = skbuff_head_cache;
+ if (fclone == SKB_FCLONE_ORIG)
+ cache = skbuff_fclone_cache;
/* Get the HEAD */
skb = kmem_cache_alloc_node(cache, gfp_mask & ~__GFP_DMA, node);
@@ -220,13 +222,13 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
skb_frag_list_init(skb);
memset(&shinfo->hwtstamps, 0, sizeof(shinfo->hwtstamps));
- if (fclone) {
+ skb->fclone = fclone;
+ if (fclone == SKB_FCLONE_ORIG) {
struct sk_buff *child = skb + 1;
atomic_t *fclone_ref = (atomic_t *) (child + 1);
kmemcheck_annotate_bitfield(child, flags1);
kmemcheck_annotate_bitfield(child, flags2);
- skb->fclone = SKB_FCLONE_ORIG;
atomic_set(fclone_ref, 1);
child->fclone = SKB_FCLONE_UNAVAILABLE;
@@ -259,7 +261,8 @@ struct sk_buff *__netdev_alloc_skb(struct net_device *dev,
int node = dev->dev.parent ? dev_to_node(dev->dev.parent) : -1;
struct sk_buff *skb;
- skb = __alloc_skb(length + NET_SKB_PAD, gfp_mask, 0, node);
+ skb = __alloc_skb(length + NET_SKB_PAD, gfp_mask,
+ SKB_FCLONE_UNAVAILABLE, node);
if (likely(skb)) {
skb_reserve(skb, NET_SKB_PAD);
skb->dev = dev;
@@ -364,6 +367,7 @@ static void kfree_skbmem(struct sk_buff *skb)
switch (skb->fclone) {
case SKB_FCLONE_UNAVAILABLE:
+ case SKB_MUST_COPY:
kmem_cache_free(skbuff_head_cache, skb);
break;
@@ -493,7 +497,9 @@ int skb_recycle_check(struct sk_buff *skb, int skb_size)
{
struct skb_shared_info *shinfo;
- if (skb_is_nonlinear(skb) || skb->fclone != SKB_FCLONE_UNAVAILABLE)
+ if (skb_is_nonlinear(skb) ||
+ skb->fclone == SKB_FCLONE_ORIG ||
+ skb->fclone == SKB_FCLONE_CLONE)
return 0;
skb_size = SKB_DATA_ALIGN(skb_size + NET_SKB_PAD);
@@ -640,6 +646,8 @@ struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask)
atomic_t *fclone_ref = (atomic_t *) (n + 1);
n->fclone = SKB_FCLONE_CLONE;
atomic_inc(fclone_ref);
+ } else if (skb->fclone == SKB_MUST_COPY) {
+ return skb_copy(skb, gfp_mask);
} else {
n = kmem_cache_alloc(skbuff_head_cache, gfp_mask);
if (!n)
next reply other threads:[~2009-10-20 6:19 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-10-20 6:19 Jeremy Fitzhardinge [this message]
2009-10-20 7:52 ` [PATCH RFC] net: add alloc_skb_mustcopy() to make clone copy David Miller
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4ADD5666.9090409@goop.org \
--to=jeremy@goop.org \
--cc=davem@davemloft.net \
--cc=herbert@gondor.apana.org.au \
--cc=netdev@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).