summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaolo Abeni <pabeni@redhat.com>2026-07-17 12:09:18 +0200
committerPaolo Abeni <pabeni@redhat.com>2026-07-17 12:09:18 +0200
commit5c655dfd9823c2e0edf3f477637e2a05fc077fc2 (patch)
tree1f6cd026c3e2107a212095db15d16392c66d934b
parentf6f3b36c15ed44de1fbb44e645e4fae8c4a4453e (diff)
parent49e03ca58334cd46dfd9267ced0ff91dcae2c451 (diff)
downloadlinux-next-5c655dfd9823c2e0edf3f477637e2a05fc077fc2.tar.gz
linux-next-5c655dfd9823c2e0edf3f477637e2a05fc077fc2.zip
Merge branch 'netconsole-stop-charging-netpoll-users-for-netconsole-only-data'
Breno Leitao says: ==================== netconsole: stop charging netpoll users for netconsole-only data This work continue to untangle netconsole and netpoll, improving memory usage for netpoll users that are not netconsole. struct netpoll is shared by every netpoll consumer in the tree: bonding, bridge, team, vlan, macvlan, dsa and netconsole. The non- netconsole users only need a per-port handle that lets them transmit SKBs. Yet struct netpoll has accumulated a pile of fields that exist only to serve netconsole's printk path: - skb_pool / refill_wq: the fallback skb pool find_skb() falls back on when alloc_skb() returns NULL, plus the workqueue that refills it. - local_port / remote_port / remote_mac: the source and destination UDP ports and the destination ethernet address used to build outgoing log packets. Every netpoll user that allocates a struct netpoll pays for all of these fields, even though it never queues a single skb on the pool, never sends a UDP frame and never looks at any of the addressing. Move this netconsole-only state out of the shared struct into struct netconsole_target, where its only consumer already lives. After the series every passive netpoll consumer drops sizeof(sk_buff_head) + sizeof(work_struct) + 2 * sizeof(u16) + ETH_ALEN bytes per port (plus padding), and struct netpoll keeps only what belongs to the generic poll/transmit abstraction or what netpoll core still reads itself. Follow-ups ---------- local_ip, remote_ip and ipv6 are still in struct netpoll. Moving the addressing additionally requires relocating netpoll_setup() -- whose only caller is netconsole -- and its IPv4/IPv6 helpers, so it is left for a follow-up to keep this series focused on a single responsibility transfer. This is pure code motion with no functional change. The pre-existing target/device teardown races reported against v1 have since been fixed independently (as suggested by Jakub) and are already in the tree, so, re-posting this one. ==================== Link: https://patch.msgid.link/20260710-netconsole_move_more-v3-0-6f63f76b28bc@debian.org Signed-off-by: Paolo Abeni <pabeni@redhat.com>
-rw-r--r--drivers/net/netconsole.c199
-rw-r--r--include/linux/netpoll.h18
-rw-r--r--net/core/netpoll.c51
3 files changed, 152 insertions, 116 deletions
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index c1812a98365b..49b2243a20b2 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -61,6 +61,19 @@ MODULE_IMPORT_NS("NETDEV_INTERNAL");
#define MAX_USERDATA_ITEMS 256
#define MAX_PRINT_CHUNK 1000
+/*
+ * Sizing for the per-target fallback skb pool consulted by find_skb()
+ * when its GFP_ATOMIC allocation fails so messages still get out under
+ * memory pressure.
+ */
+#define MAX_UDP_CHUNK 1460
+#define MAX_SKBS 32
+#define MAX_SKB_SIZE \
+ (sizeof(struct ethhdr) + \
+ sizeof(struct iphdr) + \
+ sizeof(struct udphdr) + \
+ MAX_UDP_CHUNK)
+
static char config[MAX_PARAM_LENGTH];
module_param_string(netconsole, config, MAX_PARAM_LENGTH, 0);
MODULE_PARM_DESC(netconsole, " netconsole=[src-port]@[src-ip]/[dev],[tgt-port]@<tgt-ip>/[tgt-macaddr]");
@@ -162,14 +175,19 @@ enum target_state {
* @np: The netpoll structure for this target.
* Contains the other userspace visible parameters:
* dev_name (read-write)
- * local_port (read-write)
- * remote_port (read-write)
* local_ip (read-write)
* remote_ip (read-write)
* local_mac (read-only)
- * remote_mac (read-write)
+ * @local_port: Source UDP port of the target (read-write).
+ * @remote_port: Destination UDP port of the target (read-write).
+ * @remote_mac: Destination ethernet address of the target (read-write).
* @buf: The buffer used to send the full msg to the network stack
* @resume_wq: Workqueue to resume deactivated target
+ * @skb_pool: Per-target fallback skb pool consulted by find_skb() when
+ * its GFP_ATOMIC allocation fails. Lifetime brackets a
+ * successful netpoll_setup() / netpoll_cleanup() pair on @np.
+ * @refill_wq: Work item that asynchronously tops @skb_pool back up to
+ * MAX_SKBS after find_skb() drains an entry.
*/
struct netconsole_target {
struct list_head list;
@@ -190,11 +208,15 @@ struct netconsole_target {
bool extended;
bool release;
struct netpoll np;
+ u16 local_port, remote_port;
+ u8 remote_mac[ETH_ALEN];
/* protected by target_list_lock; +1 gives scnprintf() room for its
* NUL terminator so a full MAX_PRINT_CHUNK payload is not truncated
*/
char buf[MAX_PRINT_CHUNK + 1];
struct work_struct resume_wq;
+ struct sk_buff_head skb_pool;
+ struct work_struct refill_wq;
};
#ifdef CONFIG_NETCONSOLE_DYNAMIC
@@ -292,11 +314,56 @@ static void netcons_release_dev(struct netconsole_target *nt)
memset(&nt->np.dev_name, 0, IFNAMSIZ);
}
+static void refill_skbs(struct netconsole_target *nt)
+{
+ struct sk_buff_head *skb_pool = &nt->skb_pool;
+ struct sk_buff *skb;
+
+ while (READ_ONCE(skb_pool->qlen) < MAX_SKBS) {
+ skb = alloc_skb(MAX_SKB_SIZE, GFP_ATOMIC | __GFP_NOWARN);
+ if (!skb)
+ break;
+
+ skb_queue_tail(skb_pool, skb);
+ }
+}
+
+static void refill_skbs_work_handler(struct work_struct *work)
+{
+ struct netconsole_target *nt =
+ container_of(work, struct netconsole_target, refill_wq);
+
+ refill_skbs(nt);
+}
+
+/* Seed the per-target skb pool that find_skb() falls back to. The queue
+ * head and refill work are set up once in alloc_and_init(); this only
+ * (re)fills the pool. Pair with netconsole_skb_pool_flush().
+ */
+static void netconsole_skb_pool_init(struct netconsole_target *nt)
+{
+ refill_skbs(nt);
+}
+
+static void netconsole_skb_pool_flush(struct netconsole_target *nt)
+{
+ cancel_work_sync(&nt->refill_wq);
+ skb_queue_purge_reason(&nt->skb_pool, SKB_CONSUMED);
+}
+
/* Attempts to resume logging to a deactivated target. */
static void resume_target(struct netconsole_target *nt)
{
+ /* Initialise the skb pool before netpoll_setup() makes nt->np.dev
+ * visible to target_list walkers (e.g. netconsole_netdev_event),
+ * which otherwise may move the target to the cleanup list and
+ * call netconsole_skb_pool_flush() on uninitialised state.
+ */
+ netconsole_skb_pool_init(nt);
+
if (netpoll_setup(&nt->np)) {
/* netpoll fails setup once, do not try again. */
+ netconsole_skb_pool_flush(nt);
nt->state = STATE_DISABLED;
return;
}
@@ -358,6 +425,7 @@ static void process_resume_target(struct work_struct *work)
rtnl_lock();
if (nt->state == STATE_ENABLED && nt->np.dev &&
nt->np.dev->reg_state != NETREG_REGISTERED) {
+ netconsole_skb_pool_flush(nt);
netcons_release_dev(nt);
nt->state = STATE_DISABLED;
}
@@ -393,11 +461,14 @@ static struct netconsole_target *alloc_and_init(void)
nt->np.name = "netconsole";
strscpy(nt->np.dev_name, "eth0", IFNAMSIZ);
- nt->np.local_port = 6665;
- nt->np.remote_port = 6666;
- eth_broadcast_addr(nt->np.remote_mac);
+ nt->local_port = 6665;
+ nt->remote_port = 6666;
+ eth_broadcast_addr(nt->remote_mac);
nt->state = STATE_DISABLED;
INIT_WORK(&nt->resume_wq, process_resume_target);
+ /* Set up the skb pool primitives once; enabling only refills it. */
+ skb_queue_head_init(&nt->skb_pool);
+ INIT_WORK(&nt->refill_wq, refill_skbs_work_handler);
return nt;
}
@@ -417,6 +488,7 @@ static void netconsole_process_cleanups_core(void)
list_for_each_entry_safe(nt, tmp, &target_cleanup_list, list) {
/* all entries in the cleanup_list needs to be disabled */
WARN_ON_ONCE(nt->state == STATE_ENABLED);
+ netconsole_skb_pool_flush(nt);
netcons_release_dev(nt);
/* moved the cleaned target to target_list. Need to hold both
* locks
@@ -429,21 +501,23 @@ static void netconsole_process_cleanups_core(void)
mutex_unlock(&target_cleanup_list_lock);
}
-static void netconsole_print_banner(struct netpoll *np)
+static void netconsole_print_banner(struct netconsole_target *nt)
{
- np_info(np, "local port %d\n", np->local_port);
+ struct netpoll *np = &nt->np;
+
+ np_info(np, "local port %d\n", nt->local_port);
if (np->ipv6)
np_info(np, "local IPv6 address %pI6c\n", &np->local_ip.in6);
else
np_info(np, "local IPv4 address %pI4\n", &np->local_ip.ip);
np_info(np, "interface name '%s'\n", np->dev_name);
np_info(np, "local ethernet address '%pM'\n", np->dev_mac);
- np_info(np, "remote port %d\n", np->remote_port);
+ np_info(np, "remote port %d\n", nt->remote_port);
if (np->ipv6)
np_info(np, "remote IPv6 address %pI6c\n", &np->remote_ip.in6);
else
np_info(np, "remote IPv4 address %pI4\n", &np->remote_ip.ip);
- np_info(np, "remote ethernet address %pM\n", np->remote_mac);
+ np_info(np, "remote ethernet address %pM\n", nt->remote_mac);
}
/* Parse the string and populate the `inet_addr` union. Return 0 if IPv4 is
@@ -561,12 +635,12 @@ static ssize_t dev_name_show(struct config_item *item, char *buf)
static ssize_t local_port_show(struct config_item *item, char *buf)
{
- return sysfs_emit(buf, "%d\n", to_target(item)->np.local_port);
+ return sysfs_emit(buf, "%d\n", to_target(item)->local_port);
}
static ssize_t remote_port_show(struct config_item *item, char *buf)
{
- return sysfs_emit(buf, "%d\n", to_target(item)->np.remote_port);
+ return sysfs_emit(buf, "%d\n", to_target(item)->remote_port);
}
static ssize_t local_ip_show(struct config_item *item, char *buf)
@@ -599,7 +673,7 @@ static ssize_t local_mac_show(struct config_item *item, char *buf)
static ssize_t remote_mac_show(struct config_item *item, char *buf)
{
- return sysfs_emit(buf, "%pM\n", to_target(item)->np.remote_mac);
+ return sysfs_emit(buf, "%pM\n", to_target(item)->remote_mac);
}
static ssize_t transmit_errors_show(struct config_item *item, char *buf)
@@ -756,11 +830,21 @@ static ssize_t enabled_store(struct config_item *item,
* Skip netconsole_parser_cmdline() -- all the attributes are
* already configured via configfs. Just print them out.
*/
- netconsole_print_banner(&nt->np);
+ netconsole_print_banner(nt);
+
+ /* Initialise the skb pool before netpoll_setup() so the pool
+ * is valid as soon as nt->np.dev becomes visible to
+ * target_list walkers (netconsole_netdev_event), which would
+ * otherwise call netconsole_skb_pool_flush() on uninitialised
+ * state.
+ */
+ netconsole_skb_pool_init(nt);
ret = netpoll_setup(&nt->np);
- if (ret)
+ if (ret) {
+ netconsole_skb_pool_flush(nt);
goto out_unlock;
+ }
nt->state = STATE_ENABLED;
pr_info("network logging started\n");
@@ -885,7 +969,7 @@ static ssize_t local_port_store(struct config_item *item, const char *buf,
goto out_unlock;
}
- ret = kstrtou16(buf, 10, &nt->np.local_port);
+ ret = kstrtou16(buf, 10, &nt->local_port);
if (ret < 0)
goto out_unlock;
ret = count;
@@ -907,7 +991,7 @@ static ssize_t remote_port_store(struct config_item *item,
goto out_unlock;
}
- ret = kstrtou16(buf, 10, &nt->np.remote_port);
+ ret = kstrtou16(buf, 10, &nt->remote_port);
if (ret < 0)
goto out_unlock;
ret = count;
@@ -994,7 +1078,7 @@ static ssize_t remote_mac_store(struct config_item *item, const char *buf,
goto out_unlock;
if (buf[MAC_ADDR_STR_LEN] && buf[MAC_ADDR_STR_LEN] != '\n')
goto out_unlock;
- memcpy(nt->np.remote_mac, remote_mac, ETH_ALEN);
+ memcpy(nt->remote_mac, remote_mac, ETH_ALEN);
ret = count;
out_unlock:
@@ -1481,15 +1565,15 @@ static void drop_netconsole_target(struct config_group *group,
mutex_lock(&target_cleanup_list_lock);
spin_lock_irqsave(&target_list_lock, flags);
- /* A STATE_DEACTIVATED target may have been moved to
- * target_cleanup_list by netconsole_netdev_event() but not yet
- * processed by netconsole_process_cleanups_core(). Unlinking it below
- * hides it from the cleanup worker, so this path has to clean it up
- * itself. Record that the target still owns a netpoll before the
- * state is downgraded.
+ /* A target moved to target_cleanup_list by netconsole_netdev_event()
+ * but not yet processed still owns a netpoll; unlinking it below hides
+ * it from the cleanup worker, so this path must tear it down itself.
+ * This covers NETDEV_UNREGISTER (STATE_DEACTIVATED) and
+ * NETDEV_RELEASE / NETDEV_JOIN (STATE_DISABLED); key off nt->np.dev,
+ * which stays set until the netpoll is cleaned up.
*/
needs_cleanup = nt->state == STATE_ENABLED ||
- nt->state == STATE_DEACTIVATED;
+ nt->state == STATE_DEACTIVATED || nt->np.dev;
/* Disable deactivated target to prevent races between resume attempt
* and target removal.
*/
@@ -1514,8 +1598,10 @@ static void drop_netconsole_target(struct config_group *group,
* netpoll_cleanup() is idempotent (it skips when np->dev is NULL), so
* it is safe even if the cleanup worker already tore the netpoll down.
*/
- if (needs_cleanup)
+ if (needs_cleanup) {
+ netconsole_skb_pool_flush(nt);
netpoll_cleanup(&nt->np);
+ }
config_item_put(&nt->group.cg_item);
}
@@ -1706,7 +1792,7 @@ static struct notifier_block netconsole_netdev_notifier = {
* pool locks and is therefore not NMI-safe. Skip the refill when called
* from NMI context; the next non-NMI caller will top the pool back up.
*/
-static struct sk_buff *netcons_skb_pop(struct netpoll *np, int len)
+static struct sk_buff *netcons_skb_pop(struct netconsole_target *nt, int len)
{
struct sk_buff *skb;
@@ -1718,19 +1804,21 @@ static struct sk_buff *netcons_skb_pop(struct netpoll *np, int len)
if (!in_nmi())
net_warn_ratelimited("netconsole: dropping message, requested skb len %d exceeds pool buffer size %zu on %s\n",
len, (size_t)MAX_SKB_SIZE,
- np->dev->name);
+ nt->np.dev->name);
return NULL;
}
- skb = skb_dequeue(&np->skb_pool);
+ skb = skb_dequeue(&nt->skb_pool);
if (!in_nmi())
- schedule_work(&np->refill_wq);
+ schedule_work(&nt->refill_wq);
return skb;
}
-static struct sk_buff *find_skb(struct netpoll *np, int len, int reserve)
+static struct sk_buff *find_skb(struct netconsole_target *nt, int len,
+ int reserve)
{
+ struct netpoll *np = &nt->np;
int count = 0;
struct sk_buff *skb;
@@ -1739,7 +1827,7 @@ repeat:
skb = alloc_skb(len, GFP_ATOMIC | __GFP_NOWARN);
if (!skb)
- skb = netcons_skb_pop(np, len);
+ skb = netcons_skb_pop(nt, len);
if (!skb) {
if (++count < 10) {
@@ -1779,8 +1867,9 @@ static void netpoll_udp_checksum(struct netpoll *np, struct sk_buff *skb,
udph->check = CSUM_MANGLED_0;
}
-static void push_udp(struct netpoll *np, struct sk_buff *skb, int len)
+static void push_udp(struct netconsole_target *nt, struct sk_buff *skb, int len)
{
+ struct netpoll *np = &nt->np;
struct udphdr *udph;
int udp_len;
@@ -1790,21 +1879,22 @@ static void push_udp(struct netpoll *np, struct sk_buff *skb, int len)
skb_reset_transport_header(skb);
udph = udp_hdr(skb);
- udph->source = htons(np->local_port);
- udph->dest = htons(np->remote_port);
+ udph->source = htons(nt->local_port);
+ udph->dest = htons(nt->remote_port);
udph->len = htons(udp_len);
netpoll_udp_checksum(np, skb, len);
}
-static void push_eth(struct netpoll *np, struct sk_buff *skb)
+static void push_eth(struct netconsole_target *nt, struct sk_buff *skb)
{
+ struct netpoll *np = &nt->np;
struct ethhdr *eth;
eth = skb_push(skb, ETH_HLEN);
skb_reset_mac_header(skb);
ether_addr_copy(eth->h_source, np->dev->dev_addr);
- ether_addr_copy(eth->h_dest, np->remote_mac);
+ ether_addr_copy(eth->h_dest, nt->remote_mac);
if (np->ipv6)
eth->h_proto = htons(ETH_P_IPV6);
else
@@ -1861,8 +1951,10 @@ static void push_ipv6(struct netpoll *np, struct sk_buff *skb, int len)
skb->protocol = htons(ETH_P_IPV6);
}
-static int netpoll_send_udp(struct netpoll *np, const char *msg, int len)
+static int netpoll_send_udp(struct netconsole_target *nt, const char *msg,
+ int len)
{
+ struct netpoll *np = &nt->np;
int total_len, ip_len, udp_len;
struct sk_buff *skb;
@@ -1877,7 +1969,7 @@ static int netpoll_send_udp(struct netpoll *np, const char *msg, int len)
total_len = ip_len + LL_RESERVED_SPACE(np->dev);
- skb = find_skb(np, total_len + np->dev->needed_tailroom,
+ skb = find_skb(nt, total_len + np->dev->needed_tailroom,
total_len - len);
if (!skb)
return -ENOMEM;
@@ -1885,12 +1977,12 @@ static int netpoll_send_udp(struct netpoll *np, const char *msg, int len)
skb_copy_to_linear_data(skb, msg, len);
skb_put(skb, len);
- push_udp(np, skb, len);
+ push_udp(nt, skb, len);
if (np->ipv6)
push_ipv6(np, skb, len);
else
push_ipv4(np, skb, len);
- push_eth(np, skb);
+ push_eth(nt, skb);
skb->dev = np->dev;
return (int)netpoll_send_skb(np, skb);
@@ -1908,7 +2000,7 @@ static int netpoll_send_udp(struct netpoll *np, const char *msg, int len)
*/
static void send_udp(struct netconsole_target *nt, const char *msg, int len)
{
- int result = netpoll_send_udp(&nt->np, msg, len);
+ int result = netpoll_send_udp(nt, msg, len);
if (IS_ENABLED(CONFIG_NETCONSOLE_DYNAMIC)) {
if (result == NET_XMIT_DROP) {
@@ -2203,8 +2295,9 @@ __releases(&target_list_lock)
spin_unlock_irqrestore(&target_list_lock, flags);
}
-static int netconsole_parser_cmdline(struct netpoll *np, char *opt)
+static int netconsole_parser_cmdline(struct netconsole_target *nt, char *opt)
{
+ struct netpoll *np = &nt->np;
bool ipversion_set = false;
char *cur = opt;
char *delim;
@@ -2215,7 +2308,7 @@ static int netconsole_parser_cmdline(struct netpoll *np, char *opt)
if (!delim)
goto parse_failed;
*delim = 0;
- if (kstrtou16(cur, 10, &np->local_port))
+ if (kstrtou16(cur, 10, &nt->local_port))
goto parse_failed;
cur = delim;
}
@@ -2262,7 +2355,7 @@ static int netconsole_parser_cmdline(struct netpoll *np, char *opt)
*delim = 0;
if (*cur == ' ' || *cur == '\t')
np_info(np, "warning: whitespace is not allowed\n");
- if (kstrtou16(cur, 10, &np->remote_port))
+ if (kstrtou16(cur, 10, &nt->remote_port))
goto parse_failed;
cur = delim;
}
@@ -2284,11 +2377,11 @@ static int netconsole_parser_cmdline(struct netpoll *np, char *opt)
if (*cur != 0) {
/* MAC address */
- if (!mac_pton(cur, np->remote_mac))
+ if (!mac_pton(cur, nt->remote_mac))
goto parse_failed;
}
- netconsole_print_banner(np);
+ netconsole_print_banner(nt);
return 0;
@@ -2326,14 +2419,22 @@ static struct netconsole_target *alloc_param_target(char *target_config,
}
/* Parse parameters and setup netpoll */
- err = netconsole_parser_cmdline(&nt->np, target_config);
+ err = netconsole_parser_cmdline(nt, target_config);
if (err)
goto fail;
+ /* Initialise the skb pool before netpoll_setup() so the pool is
+ * valid as soon as nt->np.dev becomes visible. The target is not
+ * yet on target_list, so a netdev event cannot reach it here, but
+ * mirror the configfs path for symmetry.
+ */
+ netconsole_skb_pool_init(nt);
+
err = netpoll_setup(&nt->np);
if (err) {
pr_err("Not enabling netconsole for %s%d. Netpoll setup failed\n",
NETCONSOLE_PARAM_TARGET_PREFIX, cmdline_count);
+ netconsole_skb_pool_flush(nt);
if (!IS_ENABLED(CONFIG_NETCONSOLE_DYNAMIC))
/* only fail if dynamic reconfiguration is set,
* otherwise, keep the target in the list, but disabled.
@@ -2355,6 +2456,8 @@ fail:
static void free_param_target(struct netconsole_target *nt)
{
cancel_work_sync(&nt->resume_wq);
+ if (nt->state == STATE_ENABLED)
+ netconsole_skb_pool_flush(nt);
netpoll_cleanup(&nt->np);
#ifdef CONFIG_NETCONSOLE_DYNAMIC
kfree(nt->userdata);
diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
index 88f7daa8560e..79315461a7b1 100644
--- a/include/linux/netpoll.h
+++ b/include/linux/netpoll.h
@@ -21,20 +21,6 @@ union inet_addr {
struct in6_addr in6;
};
-/*
- * Maximum payload netpoll's preallocated skb pool can carry. Keep this in
- * sync with the buffer size used by refill_skbs() in net/core/netpoll.c;
- * callers (e.g. netconsole) use it to detect requests the pool can never
- * satisfy and avoid dequeuing a pooled skb that would later trip
- * skb_over_panic() in skb_put().
- */
-#define MAX_UDP_CHUNK 1460
-#define MAX_SKB_SIZE \
- (sizeof(struct ethhdr) + \
- sizeof(struct iphdr) + \
- sizeof(struct udphdr) + \
- MAX_UDP_CHUNK)
-
struct netpoll {
struct net_device *dev;
netdevice_tracker dev_tracker;
@@ -49,10 +35,6 @@ struct netpoll {
union inet_addr local_ip, remote_ip;
bool ipv6;
- u16 local_port, remote_port;
- u8 remote_mac[ETH_ALEN];
- struct sk_buff_head skb_pool;
- struct work_struct refill_wq;
};
#define np_info(np, fmt, ...) \
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index aed415d3cd74..f8da1048ea3a 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -36,12 +36,6 @@
#include <trace/events/napi.h>
#include <linux/kconfig.h>
-/*
- * We maintain a small pool of fully-sized skbs, to make sure the
- * message gets out even in extreme OOM situations.
- */
-
-#define MAX_SKBS 32
#define USEC_PER_POLL 50
static unsigned int carrier_timeout = 4;
@@ -213,22 +207,6 @@ void netpoll_poll_enable(struct net_device *dev)
up(&ni->dev_lock);
}
-static void refill_skbs(struct netpoll *np)
-{
- struct sk_buff_head *skb_pool;
- struct sk_buff *skb;
-
- skb_pool = &np->skb_pool;
-
- while (READ_ONCE(skb_pool->qlen) < MAX_SKBS) {
- skb = alloc_skb(MAX_SKB_SIZE, GFP_ATOMIC | __GFP_NOWARN);
- if (!skb)
- break;
-
- skb_queue_tail(skb_pool, skb);
- }
-}
-
void netpoll_zap_completion_queue(void)
{
unsigned long flags;
@@ -351,32 +329,12 @@ netdev_tx_t netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)
}
EXPORT_SYMBOL(netpoll_send_skb);
-static void skb_pool_flush(struct netpoll *np)
-{
- struct sk_buff_head *skb_pool;
-
- cancel_work_sync(&np->refill_wq);
- skb_pool = &np->skb_pool;
- skb_queue_purge_reason(skb_pool, SKB_CONSUMED);
-}
-
-static void refill_skbs_work_handler(struct work_struct *work)
-{
- struct netpoll *np =
- container_of(work, struct netpoll, refill_wq);
-
- refill_skbs(np);
-}
-
int __netpoll_setup(struct netpoll *np, struct net_device *ndev)
{
struct netpoll_info *npinfo;
const struct net_device_ops *ops;
int err;
- skb_queue_head_init(&np->skb_pool);
- INIT_WORK(&np->refill_wq, refill_skbs_work_handler);
-
if (ndev->priv_flags & IFF_DISABLE_NETPOLL) {
np_err(np, "%s doesn't support polling, aborting\n",
ndev->name);
@@ -411,9 +369,6 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev)
np->dev = ndev;
strscpy(np->dev_name, ndev->name, IFNAMSIZ);
- /* fill up the skb queue */
- refill_skbs(np);
-
/* last thing to do is link it to the net device structure */
rcu_assign_pointer(ndev->npinfo, npinfo);
@@ -603,7 +558,7 @@ int netpoll_setup(struct netpoll *np)
err = __netpoll_setup(np, ndev);
if (err)
- goto flush;
+ goto put;
rtnl_unlock();
/* Make sure all NAPI polls which started before dev->npinfo
@@ -614,8 +569,6 @@ int netpoll_setup(struct netpoll *np)
return 0;
-flush:
- skb_pool_flush(np);
put:
DEBUG_NET_WARN_ON_ONCE(np->dev);
if (ip_overwritten)
@@ -659,8 +612,6 @@ static void __netpoll_cleanup(struct netpoll *np)
disable_delayed_work_sync(&npinfo->tx_work);
call_rcu(&npinfo->rcu, rcu_cleanup_netpoll_info);
}
-
- skb_pool_flush(np);
}
void __netpoll_free(struct netpoll *np)