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