Below patch wasn't even compile tested.  I'm not involved with network
drivers anymore, so my personal interest is fairly low.  But since I
firmly believe in the advantages and feasibility of interrupt-less TX,
there should at least be an ugly broken patch to flame about.  Go for
it, tell me how stupid I am!

Jörn

-- 
The competent programmer is fully aware of the strictly limited size of
his own skull; therefore he approaches the programming task in full
humility, and among other things he avoids clever tricks like the plague. 
-- Edsger W. Dijkstra

Add a kfree_skb_keepdata - a variant that will not free the data buffer.
This can be used for interrupt-less TX.  After TX is initiated, the data
buffer belongs to the hardware and cannot be freed until the hardware is
handing control back to the host cpu.  This is normally done in the TX
interrupt, which we want to avoid.

With this function, the skb can be freed immediatly after canding control
over the data buffer to the hardware, while keeping the data buffer itself
for a (possibly very long) while.  Data buffer needs to be freed seperately
afterwards.

Signed-off-by: Jörn Engel <[EMAIL PROTECTED]>
---

 include/linux/skbuff.h |   13 ++++++++++++-
 net/core/skbuff.c      |   27 ++++++++++++++++++++++-----
 2 files changed, 34 insertions(+), 6 deletions(-)

--- kfree_skb/include/linux/skbuff.h~kfree_skb_nodata   2006-02-22 
08:36:29.000000000 +0100
+++ kfree_skb/include/linux/skbuff.h    2006-02-22 09:15:55.000000000 +0100
@@ -307,6 +307,7 @@ struct sk_buff {
 #include <asm/system.h>
 
 extern void           __kfree_skb(struct sk_buff *skb);
+extern void           ____kfree_skb(struct sk_buff *skb, int free_data);
 extern struct sk_buff *__alloc_skb(unsigned int size,
                                   gfp_t priority, int fclone);
 static inline struct sk_buff *alloc_skb(unsigned int size,
@@ -324,7 +325,6 @@ static inline struct sk_buff *alloc_skb_
 extern struct sk_buff *alloc_skb_from_cache(kmem_cache_t *cp,
                                            unsigned int size,
                                            gfp_t priority);
-extern void           kfree_skbmem(struct sk_buff *skb);
 extern struct sk_buff *skb_clone(struct sk_buff *skb,
                                 gfp_t priority);
 extern struct sk_buff *skb_copy(const struct sk_buff *skb,
@@ -423,6 +423,17 @@ static inline void kfree_skb(struct sk_b
        __kfree_skb(skb);
 }
 
+static inline void kfree_skb_keepdata(struct sk_buff *skb)
+{
+       if (unlikely(!skb))
+               return;
+       if (likely(atomic_read(&skb->users) == 1))
+               smp_rmb();
+       else if (likely(!atomic_dec_and_test(&skb->users)))
+               return;
+       ____kfree_skb(skb, 0);
+}
+
 /**
  *     skb_cloned - is the buffer a clone
  *     @skb: buffer to check
--- kfree_skb/net/core/skbuff.c~kfree_skb_nodata        2005-11-14 
12:20:52.000000000 +0100
+++ kfree_skb/net/core/skbuff.c 2006-02-22 09:14:15.000000000 +0100
@@ -283,12 +283,13 @@ void skb_release_data(struct sk_buff *sk
 /*
  *     Free an skbuff by memory without cleaning the state.
  */
-void kfree_skbmem(struct sk_buff *skb)
+static void kfree_skbmem(struct sk_buff *skb, int free_data)
 {
        struct sk_buff *other;
        atomic_t *fclone_ref;
 
-       skb_release_data(skb);
+       if (likely(free_data))
+               skb_release_data(skb);
        switch (skb->fclone) {
        case SKB_FCLONE_UNAVAILABLE:
                kmem_cache_free(skbuff_head_cache, skb);
@@ -316,15 +317,16 @@ void kfree_skbmem(struct sk_buff *skb)
 }
 
 /**
- *     __kfree_skb - private function
+ *     ____kfree_skb - private function
  *     @skb: buffer
+ *     @free_data: 0 don't free skb->data, 1 free skb->data
  *
  *     Free an sk_buff. Release anything attached to the buffer.
  *     Clean the state. This is an internal helper function. Users should
  *     always call kfree_skb
  */
 
-void __kfree_skb(struct sk_buff *skb)
+void ____kfree_skb(struct sk_buff *skb, int free_data)
 {
        dst_release(skb->dst);
 #ifdef CONFIG_XFRM
@@ -351,7 +353,21 @@ void __kfree_skb(struct sk_buff *skb)
 #endif
 #endif
 
-       kfree_skbmem(skb);
+       kfree_skbmem(skb, free_data);
+}
+
+/**
+ *     __kfree_skb - private function
+ *     @skb: buffer
+ *
+ *     Free an sk_buff. Release anything attached to the buffer.
+ *     Clean the state. This is an internal helper function. Users should
+ *     always call kfree_skb
+ */
+
+void __kfree_skb(struct sk_buff *skb)
+{
+       ____kfree_skb(skb, 1);
 }
 
 /**
@@ -1806,6 +1822,7 @@ void __init skb_init(void)
 }
 
 EXPORT_SYMBOL(___pskb_trim);
+EXPORT_SYMBOL(____kfree_skb);
 EXPORT_SYMBOL(__kfree_skb);
 EXPORT_SYMBOL(__pskb_pull_tail);
 EXPORT_SYMBOL(__alloc_skb);
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to