kernel: use bulk free in kfree_skb_list to improve performance
authorFelix Fietkau <nbd@nbd.name>
Sun, 24 Mar 2019 17:04:49 +0000 (18:04 +0100)
committerFelix Fietkau <nbd@nbd.name>
Mon, 12 Aug 2019 09:43:39 +0000 (11:43 +0200)
Signed-off-by: Felix Fietkau <nbd@nbd.name>
target/linux/generic/pending-4.14/650-net-use-bulk-free-in-kfree_skb_list.patch [new file with mode: 0644]
target/linux/generic/pending-4.19/650-net-use-bulk-free-in-kfree_skb_list.patch [new file with mode: 0644]

diff --git a/target/linux/generic/pending-4.14/650-net-use-bulk-free-in-kfree_skb_list.patch b/target/linux/generic/pending-4.14/650-net-use-bulk-free-in-kfree_skb_list.patch
new file mode 100644 (file)
index 0000000..1d1a643
--- /dev/null
@@ -0,0 +1,61 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sat, 23 Mar 2019 18:26:10 +0100
+Subject: [PATCH] net: use bulk free in kfree_skb_list
+
+Since we're freeing multiple skbs, we might as well use bulk free to save a
+few cycles. Use the same conditions for bulk free as in napi_consume_skb.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/core/skbuff.c
++++ b/net/core/skbuff.c
+@@ -666,12 +666,44 @@ EXPORT_SYMBOL(kfree_skb);
+ void kfree_skb_list(struct sk_buff *segs)
+ {
+-      while (segs) {
+-              struct sk_buff *next = segs->next;
++      struct sk_buff *next = segs;
++      void *skbs[16];
++      int n_skbs = 0;
+-              kfree_skb(segs);
+-              segs = next;
++      while ((segs = next) != NULL) {
++              next = segs->next;
++
++              if (segs->fclone != SKB_FCLONE_UNAVAILABLE) {
++                      kfree_skb(segs);
++                      continue;
++              }
++
++              if (!skb_unref(segs))
++                      continue;
++
++              trace_kfree_skb(segs, __builtin_return_address(0));
++
++              /* drop skb->head and call any destructors for packet */
++              skb_release_all(segs);
++
++#ifdef CONFIG_SLUB
++              /* SLUB writes into objects when freeing */
++              prefetchw(segs);
++#endif
++
++              skbs[n_skbs++] = segs;
++
++              if (n_skbs < ARRAY_SIZE(skbs))
++                      continue;
++
++              kmem_cache_free_bulk(skbuff_head_cache, n_skbs, skbs);
++              n_skbs = 0;
+       }
++
++      if (!n_skbs)
++              return;
++
++      kmem_cache_free_bulk(skbuff_head_cache, n_skbs, skbs);
+ }
+ EXPORT_SYMBOL(kfree_skb_list);
diff --git a/target/linux/generic/pending-4.19/650-net-use-bulk-free-in-kfree_skb_list.patch b/target/linux/generic/pending-4.19/650-net-use-bulk-free-in-kfree_skb_list.patch
new file mode 100644 (file)
index 0000000..1d1a643
--- /dev/null
@@ -0,0 +1,61 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sat, 23 Mar 2019 18:26:10 +0100
+Subject: [PATCH] net: use bulk free in kfree_skb_list
+
+Since we're freeing multiple skbs, we might as well use bulk free to save a
+few cycles. Use the same conditions for bulk free as in napi_consume_skb.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/core/skbuff.c
++++ b/net/core/skbuff.c
+@@ -666,12 +666,44 @@ EXPORT_SYMBOL(kfree_skb);
+ void kfree_skb_list(struct sk_buff *segs)
+ {
+-      while (segs) {
+-              struct sk_buff *next = segs->next;
++      struct sk_buff *next = segs;
++      void *skbs[16];
++      int n_skbs = 0;
+-              kfree_skb(segs);
+-              segs = next;
++      while ((segs = next) != NULL) {
++              next = segs->next;
++
++              if (segs->fclone != SKB_FCLONE_UNAVAILABLE) {
++                      kfree_skb(segs);
++                      continue;
++              }
++
++              if (!skb_unref(segs))
++                      continue;
++
++              trace_kfree_skb(segs, __builtin_return_address(0));
++
++              /* drop skb->head and call any destructors for packet */
++              skb_release_all(segs);
++
++#ifdef CONFIG_SLUB
++              /* SLUB writes into objects when freeing */
++              prefetchw(segs);
++#endif
++
++              skbs[n_skbs++] = segs;
++
++              if (n_skbs < ARRAY_SIZE(skbs))
++                      continue;
++
++              kmem_cache_free_bulk(skbuff_head_cache, n_skbs, skbs);
++              n_skbs = 0;
+       }
++
++      if (!n_skbs)
++              return;
++
++      kmem_cache_free_bulk(skbuff_head_cache, n_skbs, skbs);
+ }
+ EXPORT_SYMBOL(kfree_skb_list);