| 0/0 |
2026/05/26 01:45 |
flow |
assessment-security |
51m
Results: map[DenialOfService:true Explanation:**Root Cause Analysis**
The bug is an infinite loop in the `handle_tx` function in
`drivers/net/caif/caif_serial.c`, which leads to an RCU stall and CPU hang.
When the CAIF line discipline (`N_CAIF`) is detached from a TTY (e.g., when the
TTY is closed), `ldisc_close` is called. This function schedules a workqueue
(`ser_release_work`) to unregister the CAIF network device but returns
immediately.
Meanwhile, the TTY layer continues the close process, eventually calling
`uart_close` -> `uart_shutdown` -> `uart_free_xmit_buf`. The
`uart_free_xmit_buf` function frees the TTY's transmit buffer (`port->xmit_buf =
NULL`) and re-initializes the transmit FIFO (`INIT_KFIFO(port->xmit_fifo)`),
which resets the FIFO's mask to 0.
If a packet is transmitted via the CAIF network device (e.g., by a kernel thread
like `aoe_tx0` or another process) during this small race window before the
workqueue actually unregisters the netdevice, `caif_xmit` is called, which in
turn calls `handle_tx`.
In `handle_tx`, the code loops over the packets to send:
1. `tty_write_room(tty)` is called. Because the FIFO was zero-initialized,
`kfifo_avail` calculates the available space as 1.
2. Since `room > 0`, `handle_tx` attempts to write the data by calling
`tty->ops->write` (which maps to `uart_write`).
3. `uart_write` checks if the transmit buffer exists (`if
(!state->port.xmit_buf)`). Since it was freed and set to `NULL`, it safely
returns `0` (0 bytes written).
4. `handle_tx` receives `tty_wr = 0`. It calls `skb_pull(skb, 0)`, which does
nothing. The `skb->len` remains unchanged.
5. The loop repeats infinitely because the packet is never consumed,
`tty_write_room` keeps returning 1, and `uart_write` keeps returning 0.
This infinite loop runs with preemption disabled (as it's called from the
network transmit path), causing an RCU stall and effectively hanging the CPU.
**Security Impact Assessment**
* **Exploitable:** No. The bug is a pure logical infinite loop. It does not
involve memory corruption, out-of-bounds accesses, or use-after-free
vulnerabilities that could be leveraged for privilege escalation or arbitrary
code execution.
* **Denial Of Service:** Yes. Triggering the bug hangs the CPU in an infinite
loop, leading to an RCU stall and a complete system freeze or panic.
* **Accessible From Unprivileged Processes:** No. Attaching the `N_CAIF` line
discipline to a TTY requires the caller to have `CAP_SYS_ADMIN` or
`CAP_SYS_TTY_CONFIG` capabilities. This is explicitly checked in `ldisc_open` in
`caif_serial.c`.
* **Accessible From User Namespaces:** No. The capability check in `ldisc_open`
uses `capable(CAP_SYS_ADMIN)`, which checks the capabilities against the
**initial** user namespace (`init_user_ns`), not the current user namespace.
Therefore, an unprivileged user cannot bypass this restriction by creating a new
user namespace.
* **Other Triggers:** The bug cannot be triggered remotely, via network packets,
malicious filesystems, or plugged peripherals. It strictly requires local
execution of specific `ioctl` commands on a TTY device by a highly privileged
user. Exploitable:false FilesystemTrigger:false NetworkTrigger:false PeripheralTrigger:false RemoteTrigger:false Unprivileged:false UserNamespace:false VMGuestTrigger:false VMHostTrigger:false]
|
| 1/1 |
2026/05/26 01:45 |
action |
syz-repro-to-c-repro |
0m
Results: map[SimplifiedCRepro:// autogenerated by syzkaller (https://github.com/google/syzkaller)
#define _GNU_SOURCE
#include <endian.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mount.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
uint64_t r[1] = {0xffffffffffffffff};
int main(void)
{
syscall(__NR_mmap, /*addr=*/0x1ffffffff000ul, /*len=*/0x1000ul, /*prot=*/0ul, /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/0x32ul, /*fd=*/(intptr_t)-1, /*offset=*/0ul);
syscall(__NR_mmap, /*addr=*/0x200000000000ul, /*len=*/0x1000000ul, /*prot=PROT_WRITE|PROT_READ|PROT_EXEC*/7ul, /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/0x32ul, /*fd=*/(intptr_t)-1, /*offset=*/0ul);
syscall(__NR_mmap, /*addr=*/0x200001000000ul, /*len=*/0x1000ul, /*prot=*/0ul, /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/0x32ul, /*fd=*/(intptr_t)-1, /*offset=*/0ul);
const char* reason;
(void)reason;
intptr_t res = 0;
if (write(1, "executing program\n", sizeof("executing program\n") - 1)) {}
// openat$ttyS3 arguments: [
// fd: const = 0xffffffffffffff9c (8 bytes)
// file: ptr[in, buffer] {
// buffer: {2f 64 65 76 2f 74 74 79 53 33 00} (length 0xb)
// }
// flags: open_flags = 0x0 (4 bytes)
// mode: const = 0x0 (2 bytes)
// ]
// returns fd_tty
memcpy((void*)0x200000000000, "/dev/ttyS3\000", 11);
res = syscall(__NR_openat, /*fd=*/0xffffffffffffff9cul, /*file=*/0x200000000000ul, /*flags=*/0, /*mode=*/0);
if (res != -1)
r[0] = res;
// ioctl$TIOCSETD arguments: [
// fd: fd_tty (resource)
// cmd: const = 0x5423 (4 bytes)
// arg: ptr[in, int32] {
// int32 = 0x14 (4 bytes)
// }
// ]
*(uint32_t*)0x200000000540 = 0x14;
syscall(__NR_ioctl, /*fd=*/r[0], /*cmd=*/0x5423, /*arg=*/0x200000000540ul);
// mmap arguments: [
// addr: VMA[0xb36000]
// len: len = 0xb36000 (8 bytes)
// prot: mmap_prot = 0xb635773f06ebbeee (8 bytes)
// flags: mmap_flags = 0x8031 (8 bytes)
// fd: fd (resource)
// offset: intptr = 0x0 (8 bytes)
// ]
syscall(__NR_mmap, /*addr=*/0x200000000000ul, /*len=*/0xb36000ul, /*prot=PROT_GROWSUP|PROT_SEM|PROT_WRITE|PROT_EXEC|0xb635773f04ebbee0*/0xb635773f06ebbeeeul, /*flags=MAP_POPULATE|MAP_FIXED|MAP_ANONYMOUS|MAP_SHARED*/0x8031ul, /*fd=*/(intptr_t)-1, /*offset=*/0ul);
return 0;
}
]
|
| 2/1 |
2026/05/26 01:45 |
action |
kernel-checkouter |
1m
Results: map[KernelSrc:/app/workdir/cache/src/b932f016c08f67c655a32a5e26a155f81edf162b]
|
| 3/1 |
2026/05/26 01:46 |
action |
kernel-builder |
18m
Results: map[KernelObj:/app/workdir/cache/build/8b51868c18e716465c836196966704f123a22f7d]
|
| 4/1 |
2026/05/26 02:04 |
action |
codesearch-prepare |
24m
Results: map[Index:codesearch-index]
|
| 5/1 |
2026/05/26 02:29 |
agent |
expert |
7m
Model:
Results: map[DenialOfService:true Exploitable:false FilesystemTrigger:false NetworkTrigger:false PeripheralTrigger:false RemoteTrigger:false Unprivileged:false UserNamespace:false VMGuestTrigger:false VMHostTrigger:false]
Instruction:
You are an experienced Linux kernel security engineer. Your task is to analyze given kernel bug report
and determine its security impact based on the following dimensions.
Use the provided tools to examine the source code, check for capability checks (e.g., capable(), ns_capable()),
and understand the nature of the bug. Analyze the given kernel build and configuration.
You can check the kernel config by grepping ".config" file; you can check kernel cmdline by greeping
".config" file for "CONFIG_CMDLINE=". Assume sysctl parameters have default values.
But analyze for the corresponding production build w/o debugging tools enabled (like KASAN, KMSAN, UBSAN).
Try different strategies when analyzing the bug:
- think of ways in which the vulnerable code is unreachable
- or the other way around: try to come up with different ideas of how an unprivileged user can reach the bug
If still unsure err on the side of the bug being non-exploitable/not-accessible.
In the final reply, provide a reasoning for your assessment.
Analysis dimensions:
* Exploitable:
Determine if the bug can result in memory corruption or elevated privileges.
Memory safety issues are almost always exploitable (KASAN or UBSAN reports for use-after-free, out-of-bounds;
refcounting issues, corrupted lists, etc). When kernel is crashing on a completly wild pointer access
(e.g. user-space address, or non-canonical address, but not on NULL or address corresponding to KASAN shadow
for NULL address), including both data accesses and control tranfers, that's also usually implies possibility
of exploitation. Such reports usually say "unable to handle kernel paging request".
Uses of uninitialized values detected by KMSAN may be exploitable b/c attacker frequently can affect uninit
values with spraying techniques. However, for these exploitabability depends on how exactly the uninit value
is used in the code, and what it affects.
Think of what happens after the bug is triggered. Some bugs cause kernel panic and halt execution,
they are harder to exploit. For example, BUG reports halts the kernel. However, WARNING reports don't halt
execution in production builds. Debug bug detection tools (like KASAN, KMSAN, KCSAN, UBSAN) are also not enabled
in production builds, so attacker can freely exploit these bugs w/o being detected by these tools.
If you see an integer overflow, think how the overflowed value used later (if it's used as allocation size,
or an array index). If you see an out-of-bounds read, think if it's followed by an out-of-bounds write as well.
Some KCSAN data-races may be exploitable by skilled attackers as well. Think what data structures got corrupted
as the result of data races and how. However, note that kernel has lots of "benign" data races that don't lead
to any runtime misbehavior at all.
* Denial Of Service:
Determine if the bug can result in denial-of-service. Most bugs can, since they cause system crash,
hangs, deadlocks, or resource leaks. This is mostly applicable to WARNING bugs that won't cause system crash
in production. For these think what will be consequences of the violation of the kernel assumptions flagged
by the WARNING. In some cases the unexpected condition is also properly handled by the normal control flow
(e.g. with "if (WARN_ON(...))"), these won't cause denial-of-service. If the condition is not handled,
then it may or may not cause denial-of-service.
* Accessible From Unprivileged Processes:
Determine if the bug can be reached from a typical (non-root) user process that does NOT have any special capabilities
(like CAP_SYS_ADMIN, CAP_NET_ADMIN, CAP_NET_RAW, CAP_PERFMON) or access to device nodes restricted to root.
Assume that unprivileged_bpf_disabled=1, that is eBPF loading is not accessible. However, cBPF (classical BPF)
is still accessible to non-root processes.
Assume that user namespaces are not accessible, that is, the process cannot get the mentioned capabilities even
within a new user namespace (checked by ns_capable() function in the kernel sources).
* Accessible From User Namespaces:
Determine if the bug can be reached within a user-namespace where the process has all capabilities
(including CAP_SYS_ADMIN, CAP_NET_ADMIN, CAP_NET_RAW, CAP_PERFMON). Such capabilities are checked with ns_capable()
function in the kernel sources.
* VM Guest Trigger:
Determine if the bug can be triggered from the context of a typical KVM guest (e.g., set up by a QEMU VMM).
Consider accesses to standard Linux host paravirtualized features (virtio-blk, virtio-net, etc.),
and handling of VM exits in the KVM code.
* VM Host Trigger in The Confidetial Computing Context:
Determine if the bug can be triggered in a confidential computing guest kernel from the context of a KVM host.
Consider access to standard Linux guest paravirtualized features (virtio-blk, virtio-net, etc.).
* Ethernet Network Trigger:
Determine if the bug can be triggered by processing ingress network Ethernet traffic, either directly (network stack)
or via drivers exposed to network data.
* Other Remote Trigger:
Determine if the bug can be triggered by processing remote traffic other than Ethernet (Wifi, Bluetooth, NFC, etc).
* Peripheral Trigger:
Determine if the bug can be triggered via an untrusted peripheral device that can be physically plugged
into a system, such as a USB device or a niche hardware driver handling external hardware inputs.
This is particularly important for mobile and desktop environments where users can plug in unknown devices.
* Malicious Filesystem Trigger:
Determine if the bug can be triggered by the kernel mounting and parsing a malicious filesystem image.
This is highly critical for Desktop and Mobile environments where external media or downloaded images
might be auto-mounted.
Don't make assumptions about the kernel source code (it may be different from what you assume it is).
Extensively use the provided code access tools (codesearch-*, git-*, grepper, etc)
to examine the actual source code, and confirm any assumptions.
Prefer calling several tools at the same time to save round-trips.
Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.
Prompt:
The kernel bug report is:
rcu: INFO: rcu_preempt detected stalls on CPUs/tasks:
rcu: Tasks blocked on level-0 rcu_node (CPUs 0-0): P6103/1:b..l P6106/1:b..l P6104/1:b..l
rcu: (detected by 0, t=10502 jiffies, g=24761, q=25 ncpus=1)
task:syz-executor384 state:R running task stack:26008 pid:6104 tgid:6104 ppid:5332 task_flags:0x400040 flags:0x00004002
Call Trace:
<TASK>
context_switch kernel/sched/core.c:5382 [inline]
__schedule+0x16e2/0x4cd0 kernel/sched/core.c:6767
preempt_schedule_common+0x83/0xd0 kernel/sched/core.c:6947
preempt_schedule+0xae/0xc0 kernel/sched/core.c:6971
preempt_schedule_thunk+0x16/0x30 arch/x86/entry/thunk.S:12
__raw_spin_unlock include/linux/spinlock_api_smp.h:143 [inline]
_raw_spin_unlock+0x3f/0x50 kernel/locking/spinlock.c:186
spin_unlock include/linux/spinlock.h:391 [inline]
finish_fault+0xd97/0x1020 mm/memory.c:5388
do_read_fault mm/memory.c:5522 [inline]
do_fault mm/memory.c:5652 [inline]
do_pte_missing mm/memory.c:4160 [inline]
handle_pte_fault mm/memory.c:5997 [inline]
__handle_mm_fault+0x3666/0x5380 mm/memory.c:6140
handle_mm_fault+0x3f6/0x8c0 mm/memory.c:6309
faultin_page mm/gup.c:1193 [inline]
__get_user_pages+0x16f0/0x2a40 mm/gup.c:1491
populate_vma_page_range+0x26b/0x340 mm/gup.c:1929
__mm_populate+0x24c/0x380 mm/gup.c:2032
mm_populate include/linux/mm.h:3487 [inline]
vm_mmap_pgoff+0x3f0/0x4c0 mm/util.c:584
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xf6/0x210 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7fc94d0ef959
RSP: 002b:00007ffed9bc6198 EFLAGS: 00000246 ORIG_RAX: 0000000000000009
RAX: ffffffffffffffda RBX: 000000000005d4df RCX: 00007fc94d0ef959
RDX: b635773f06ebbeee RSI: 0000000000b36000 RDI: 0000200000000000
RBP: 0000000000000000 R08: ffffffffffffffff R09: 0000000000000000
R10: 0000000000008031 R11: 0000000000000246 R12: 00007ffed9bc61dc
R13: 00007ffed9bc6210 R14: 00007ffed9bc61f0 R15: 000000000000003c
</TASK>
task:dhcpcd-run-hook state:R running task stack:23928 pid:6106 tgid:6106 ppid:5016 task_flags:0x400000 flags:0x00004002
Call Trace:
<TASK>
context_switch kernel/sched/core.c:5382 [inline]
__schedule+0x16e2/0x4cd0 kernel/sched/core.c:6767
preempt_schedule_notrace+0xd1/0x110 kernel/sched/core.c:7040
preempt_schedule_notrace_thunk+0x16/0x30 arch/x86/entry/thunk.S:13
rcu_is_watching+0x7f/0xb0 kernel/rcu/tree.c:737
trace_lock_release include/trace/events/lock.h:69 [inline]
lock_release+0x4b/0x3e0 kernel/locking/lockdep.c:5877
rcu_lock_release include/linux/rcupdate.h:341 [inline]
rcu_read_unlock include/linux/rcupdate.h:871 [inline]
class_rcu_destructor include/linux/rcupdate.h:1155 [inline]
unwind_next_frame+0x19a9/0x2390 arch/x86/kernel/unwind_orc.c:680
arch_stack_walk+0x11c/0x150 arch/x86/kernel/stacktrace.c:25
stack_trace_save+0x9c/0xe0 kernel/stacktrace.c:122
kasan_save_stack+0x3e/0x60 mm/kasan/common.c:47
kasan_record_aux_stack+0xbc/0xd0 mm/kasan/generic.c:548
__call_rcu_common kernel/rcu/tree.c:3082 [inline]
call_rcu+0x142/0x990 kernel/rcu/tree.c:3202
ma_free_rcu lib/maple_tree.c:211 [inline]
mas_free lib/maple_tree.c:1313 [inline]
mas_topiary_replace lib/maple_tree.c:2584 [inline]
mas_wmb_replace+0x209d/0x25f0 lib/maple_tree.c:2641
mas_split lib/maple_tree.c:3368 [inline]
mas_commit_b_node+0xa6e/0xf40 lib/maple_tree.c:3388
mas_wr_bnode lib/maple_tree.c:4049 [inline]
mas_wr_store_entry+0x510/0x2550 lib/maple_tree.c:4090
mas_store_prealloc+0xb02/0xf60 lib/maple_tree.c:5475
vma_iter_store_new mm/vma.h:455 [inline]
vma_link+0x254/0x450 mm/vma.c:1754
insert_vm_struct+0x2d0/0x3d0 mm/mmap.c:1357
__install_special_mapping mm/mmap.c:1507 [inline]
_install_special_mapping+0x1b0/0x350 mm/mmap.c:1543
map_vdso+0x1ff/0x480 arch/x86/entry/vdso/vma.c:174
load_elf_binary+0x1c85/0x27b0 fs/binfmt_elf.c:1277
search_binary_handler fs/exec.c:1778 [inline]
exec_binprm fs/exec.c:1810 [inline]
bprm_execve+0x999/0x1440 fs/exec.c:1862
do_execveat_common+0x510/0x6a0 fs/exec.c:1968
do_execve fs/exec.c:2042 [inline]
__do_sys_execve fs/exec.c:2118 [inline]
__se_sys_execve fs/exec.c:2113 [inline]
__x64_sys_execve+0x94/0xb0 fs/exec.c:2113
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xf6/0x210 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7ff7677a0ef7
RSP: 002b:00007ff76764ae78 EFLAGS: 00000246 ORIG_RAX: 000000000000003b
RAX: ffffffffffffffda RBX: 00007ffc285c39b0 RCX: 00007ff7677a0ef7
RDX: 0000557645b67700 RSI: 00007ffc285c3ea0 RDI: 000055761bc40df6
RBP: 00007ff76764aff0 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000008 R11: 0000000000000246 R12: 00007ffc285c3cc8
R13: 00007ff76764af28 R14: 0000000000000000 R15: 0000000000000041
</TASK>
task:syz-executor384 state:R running task stack:26008 pid:6103 tgid:6103 ppid:5336 task_flags:0x400040 flags:0x00004002
Call Trace:
<TASK>
context_switch kernel/sched/core.c:5382 [inline]
__schedule+0x16e2/0x4cd0 kernel/sched/core.c:6767
preempt_schedule_irq+0xb5/0x150 kernel/sched/core.c:7090
irqentry_exit+0x6f/0x90 kernel/entry/common.c:354
asm_sysvec_apic_timer_interrupt+0x1a/0x20 arch/x86/include/asm/idtentry.h:702
RIP: 0010:__sanitizer_cov_trace_cmp8+0x0/0x90 kernel/kcov.c:293
Code: 7c 11 10 48 89 74 11 18 48 89 44 11 20 c3 cc cc cc cc cc 0f 1f 80 00 00 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 <f3> 0f 1e fa 48 8b 04 24 65 48 8b 0c 25 08 40 75 92 65 8b 15 e8 7e
RSP: 0018:ffffc9000d9d70a0 EFLAGS: 00000293
RAX: ffffffff822c9a9b RBX: 0000000000000000 RCX: ffff88801f920000
RDX: 0000000000000000 RSI: 0000000000000001 RDI: 0000000000000000
RBP: 0000000000000001 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: ffffffff822c998a R12: ffff888030e42f70
R13: 0000000000000000 R14: 00000000000473cc R15: ffffea00011cf2f0
__page_table_check_zero+0x1d6/0x510 mm/page_table_check.c:139
page_table_check_alloc include/linux/page_table_check.h:33 [inline]
post_alloc_hook+0x1eb/0x230 mm/page_alloc.c:1719
prep_new_page mm/page_alloc.c:1726 [inline]
get_page_from_freelist+0x21ce/0x22b0 mm/page_alloc.c:3688
__alloc_frozen_pages_noprof+0x181/0x370 mm/page_alloc.c:4970
alloc_pages_mpol+0x232/0x4a0 mm/mempolicy.c:2301
folio_alloc_mpol_noprof+0x39/0x70 mm/mempolicy.c:2320
shmem_alloc_folio mm/shmem.c:1854 [inline]
shmem_alloc_and_add_folio+0x447/0xf60 mm/shmem.c:1893
shmem_get_folio_gfp+0x597/0x15f0 mm/shmem.c:2533
shmem_fault+0x179/0x390 mm/shmem.c:2734
__do_fault+0x135/0x390 mm/memory.c:5098
do_read_fault mm/memory.c:5518 [inline]
do_fault mm/memory.c:5652 [inline]
do_pte_missing mm/memory.c:4160 [inline]
handle_pte_fault mm/memory.c:5997 [inline]
__handle_mm_fault+0x363e/0x5380 mm/memory.c:6140
handle_mm_fault+0x3f6/0x8c0 mm/memory.c:6309
faultin_page mm/gup.c:1193 [inline]
__get_user_pages+0x16f0/0x2a40 mm/gup.c:1491
populate_vma_page_range+0x26b/0x340 mm/gup.c:1929
__mm_populate+0x24c/0x380 mm/gup.c:2032
mm_populate include/linux/mm.h:3487 [inline]
vm_mmap_pgoff+0x3f0/0x4c0 mm/util.c:584
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xf6/0x210 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7fc94d0ef959
RSP: 002b:00007ffed9bc6198 EFLAGS: 00000246 ORIG_RAX: 0000000000000009
RAX: ffffffffffffffda RBX: 000000000005d4c4 RCX: 00007fc94d0ef959
RDX: b635773f06ebbeee RSI: 0000000000b36000 RDI: 0000200000000000
RBP: 0000000000000000 R08: ffffffffffffffff R09: 0000000000000000
R10: 0000000000008031 R11: 0000000000000246 R12: 00007ffed9bc61dc
R13: 00007ffed9bc6210 R14: 00007ffed9bc61f0 R15: 000000000000003c
</TASK>
rcu: rcu_preempt kthread timer wakeup didn't happen for 10501 jiffies! g24761 f0x0 RCU_GP_WAIT_FQS(5) ->state=0x402
rcu: Possible timer handling issue on cpu=0 timer-softirq=26096
rcu: rcu_preempt kthread starved for 10502 jiffies! g24761 f0x0 RCU_GP_WAIT_FQS(5) ->state=0x402 ->cpu=0
rcu: Unless rcu_preempt kthread gets sufficient CPU time, OOM is now expected behavior.
rcu: RCU grace-period kthread stack dump:
task:rcu_preempt state:I stack:27640 pid:16 tgid:16 ppid:2 task_flags:0x208040 flags:0x00004000
Call Trace:
<TASK>
context_switch kernel/sched/core.c:5382 [inline]
__schedule+0x16e2/0x4cd0 kernel/sched/core.c:6767
__schedule_loop kernel/sched/core.c:6845 [inline]
schedule+0x165/0x360 kernel/sched/core.c:6860
schedule_timeout+0x12b/0x270 kernel/time/sleep_timeout.c:99
rcu_gp_fqs_loop+0x301/0x1540 kernel/rcu/tree.c:2046
rcu_gp_kthread+0x99/0x390 kernel/rcu/tree.c:2248
kthread+0x70e/0x8a0 kernel/kthread.c:464
ret_from_fork+0x4b/0x80 arch/x86/kernel/process.c:153
ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
</TASK>
rcu: Stack dump where RCU GP kthread last ran:
CPU: 0 UID: 0 PID: 1311 Comm: aoe_tx0 Not tainted 6.15.0-rc4-syzkaller-00040-g8bac8898fe39 #0 PREEMPT(full)
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2~bpo12+1 04/01/2014
RIP: 0010:__raw_spin_unlock_irqrestore include/linux/spinlock_api_smp.h:152 [inline]
RIP: 0010:_raw_spin_unlock_irqrestore+0xa8/0x110 kernel/locking/spinlock.c:194
Code: 74 05 e8 8b e1 6e f6 48 c7 44 24 20 00 00 00 00 9c 8f 44 24 20 f6 44 24 21 02 75 4f f7 c3 00 02 00 00 74 01 fb bf 01 00 00 00 <e8> 73 63 38 f6 65 8b 05 5c e5 1c 07 85 c0 74 40 48 c7 04 24 0e 36
RSP: 0018:ffffc900029cf740 EFLAGS: 00000206
RAX: b3874e252c70ba00 RBX: 0000000000000a06 RCX: b3874e252c70ba00
RDX: 0000000000000002 RSI: ffffffff8d749f9b RDI: 0000000000000001
RBP: ffffc900029cf7d0 R08: ffffffff8f7ed377 R09: 1ffffffff1efda6e
R10: dffffc0000000000 R11: fffffbfff1efda6f R12: dffffc0000000000
R13: dffffc0000000000 R14: ffffffff99b4c6c0 R15: 1ffff92000539ee8
FS: 0000000000000000(0000) GS:ffff88808d6cc000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007f22234160d0 CR3: 0000000035bd2000 CR4: 0000000000352ef0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
Call Trace:
<TASK>
spin_unlock_irqrestore include/linux/spinlock.h:406 [inline]
uart_port_unlock_irqrestore include/linux/serial_core.h:786 [inline]
uart_write+0x4cd/0xa40 drivers/tty/serial/serial_core.c:628
handle_tx+0x23c/0x610 drivers/net/caif/caif_serial.c:222
__netdev_start_xmit include/linux/netdevice.h:5203 [inline]
netdev_start_xmit include/linux/netdevice.h:5212 [inline]
xmit_one net/core/dev.c:3776 [inline]
dev_hard_start_xmit+0x2ff/0x880 net/core/dev.c:3792
__dev_queue_xmit+0x1adf/0x3a70 net/core/dev.c:4629
dev_queue_xmit include/linux/netdevice.h:3350 [inline]
tx+0x6b/0x190 drivers/block/aoe/aoenet.c:62
kthread+0x1cd/0x3e0 drivers/block/aoe/aoecmd.c:1237
kthread+0x70e/0x8a0 kernel/kthread.c:464
ret_from_fork+0x4b/0x80 arch/x86/kernel/process.c:153
ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
</TASK>
It is reproducible with the followint program.
Keep in mind that it may lack the precise threading, sandboxing, and some arguments of a working reproducer.
But it should give an idea of the involved syscalls.
// autogenerated by syzkaller (https://github.com/google/syzkaller)
#define _GNU_SOURCE
#include <endian.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mount.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
uint64_t r[1] = {0xffffffffffffffff};
int main(void)
{
syscall(__NR_mmap, /*addr=*/0x1ffffffff000ul, /*len=*/0x1000ul, /*prot=*/0ul, /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/0x32ul, /*fd=*/(intptr_t)-1, /*offset=*/0ul);
syscall(__NR_mmap, /*addr=*/0x200000000000ul, /*len=*/0x1000000ul, /*prot=PROT_WRITE|PROT_READ|PROT_EXEC*/7ul, /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/0x32ul, /*fd=*/(intptr_t)-1, /*offset=*/0ul);
syscall(__NR_mmap, /*addr=*/0x200001000000ul, /*len=*/0x1000ul, /*prot=*/0ul, /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/0x32ul, /*fd=*/(intptr_t)-1, /*offset=*/0ul);
const char* reason;
(void)reason;
intptr_t res = 0;
if (write(1, "executing program\n", sizeof("executing program\n") - 1)) {}
// openat$ttyS3 arguments: [
// fd: const = 0xffffffffffffff9c (8 bytes)
// file: ptr[in, buffer] {
// buffer: {2f 64 65 76 2f 74 74 79 53 33 00} (length 0xb)
// }
// flags: open_flags = 0x0 (4 bytes)
// mode: const = 0x0 (2 bytes)
// ]
// returns fd_tty
memcpy((void*)0x200000000000, "/dev/ttyS3\000", 11);
res = syscall(__NR_openat, /*fd=*/0xffffffffffffff9cul, /*file=*/0x200000000000ul, /*flags=*/0, /*mode=*/0);
if (res != -1)
r[0] = res;
// ioctl$TIOCSETD arguments: [
// fd: fd_tty (resource)
// cmd: const = 0x5423 (4 bytes)
// arg: ptr[in, int32] {
// int32 = 0x14 (4 bytes)
// }
// ]
*(uint32_t*)0x200000000540 = 0x14;
syscall(__NR_ioctl, /*fd=*/r[0], /*cmd=*/0x5423, /*arg=*/0x200000000540ul);
// mmap arguments: [
// addr: VMA[0xb36000]
// len: len = 0xb36000 (8 bytes)
// prot: mmap_prot = 0xb635773f06ebbeee (8 bytes)
// flags: mmap_flags = 0x8031 (8 bytes)
// fd: fd (resource)
// offset: intptr = 0x0 (8 bytes)
// ]
syscall(__NR_mmap, /*addr=*/0x200000000000ul, /*len=*/0xb36000ul, /*prot=PROT_GROWSUP|PROT_SEM|PROT_WRITE|PROT_EXEC|0xb635773f04ebbee0*/0xb635773f06ebbeeeul, /*flags=MAP_POPULATE|MAP_FIXED|MAP_ANONYMOUS|MAP_SHARED*/0x8031ul, /*fd=*/(intptr_t)-1, /*offset=*/0ul);
return 0;
}
Reply: **Root Cause Analysis**
The bug is an infinite loop in the `handle_tx` function in `drivers/net/caif/caif_serial.c`, which leads to an RCU stall and CPU hang.
When the CAIF line discipline (`N_CAIF`) is detached from a TTY (e.g., when the TTY is closed), `ldisc_close` is called. This function schedules a workqueue (`ser_release_work`) to unregister the CAIF network device but returns immediately.
Meanwhile, the TTY layer continues the close process, eventually calling `uart_close` -> `uart_shutdown` -> `uart_free_xmit_buf`. The `uart_free_xmit_buf` function frees the TTY's transmit buffer (`port->xmit_buf = NULL`) and re-initializes the transmit FIFO (`INIT_KFIFO(port->xmit_fifo)`), which resets the FIFO's mask to 0.
If a packet is transmitted via the CAIF network device (e.g., by a kernel thread like `aoe_tx0` or another process) during this small race window before the workqueue actually unregisters the netdevice, `caif_xmit` is called, which in turn calls `handle_tx`.
In `handle_tx`, the code loops over the packets to send:
1. `tty_write_room(tty)` is called. Because the FIFO was zero-initialized, `kfifo_avail` calculates the available space as 1.
2. Since `room > 0`, `handle_tx` attempts to write the data by calling `tty->ops->write` (which maps to `uart_write`).
3. `uart_write` checks if the transmit buffer exists (`if (!state->port.xmit_buf)`). Since it was freed and set to `NULL`, it safely returns `0` (0 bytes written).
4. `handle_tx` receives `tty_wr = 0`. It calls `skb_pull(skb, 0)`, which does nothing. The `skb->len` remains unchanged.
5. The loop repeats infinitely because the packet is never consumed, `tty_write_room` keeps returning 1, and `uart_write` keeps returning 0.
This infinite loop runs with preemption disabled (as it's called from the network transmit path), causing an RCU stall and effectively hanging the CPU.
**Security Impact Assessment**
* **Exploitable:** No. The bug is a pure logical infinite loop. It does not involve memory corruption, out-of-bounds accesses, or use-after-free vulnerabilities that could be leveraged for privilege escalation or arbitrary code execution.
* **Denial Of Service:** Yes. Triggering the bug hangs the CPU in an infinite loop, leading to an RCU stall and a complete system freeze or panic.
* **Accessible From Unprivileged Processes:** No. Attaching the `N_CAIF` line discipline to a TTY requires the caller to have `CAP_SYS_ADMIN` or `CAP_SYS_TTY_CONFIG` capabilities. This is explicitly checked in `ldisc_open` in `caif_serial.c`.
* **Accessible From User Namespaces:** No. The capability check in `ldisc_open` uses `capable(CAP_SYS_ADMIN)`, which checks the capabilities against the **initial** user namespace (`init_user_ns`), not the current user namespace. Therefore, an unprivileged user cannot bypass this restriction by creating a new user namespace.
* **Other Triggers:** The bug cannot be triggered remotely, via network packets, malicious filesystems, or plugged peripherals. It strictly requires local execution of specific `ioctl` commands on a TTY device by a highly privileged user.
|
| 6/2 |
2026/05/26 02:29 |
llm |
expert |
0m
Model:
Tokens:
input: 13169
output: 45
thoughts: 1000
Thoughts: **RCU Stall Investigation**
Okay, so I'm looking at this RCU stall report and my initial thought is, "Hmm, this looks like a classic deadlock scenario." The report shows RCU preempt stalls, specifically on CPUs 0, with tasks blocked on the level-0 rcu_node. The key piece here is the stack trace. I see tasks blocked on level-0 rcu_node with CPUs 0-0, the `rcu_preempt kthread timer wakeup didn't happen for 10501 jiffies`, which tells me that something is holding up the RCU grace period.
The stack dump points to `__raw_spin_unlock_irqrestore` within `uart_write` from `serial_core.c`. This is interesting. The call trace shows `handle_tx` within the CAIF serial driver is involved, and `aoe_tx0`, the kernel thread for ATA over Ethernet, is calling `dev_queue_xmit` . I'm familiar with how `uart_write` works, I know it takes a lock, which will be released with `uart_port_unlock_irqrestore`.
The reproducer shows a syscall to set the line discipline of a serial port (`ttyS3`) to N_CAIF. Then `aoe_tx0` transmits packets which are enqueued to the CAIF serial device via `dev_queue_xmit`.
My immediate question is why are packets from an ATA over Ethernet thread ending up on a CAIF serial device? That's definitely unusual. Is there some misconfiguration or an odd routing happening? This is not something I'd expect. The fact that the CAIF driver is calling `uart_write` is normal. But the stall suggests a lock contention issue.
I suspect that packets from `aoe_tx0` are causing an issue. The problem might be an infinite loop in `handle_tx`, which is unlikely, but it would be good to rule out. I need to examine the `drivers/net/caif/caif_serial.c` code to see what's happening within `handle_tx` and understand the locking interactions. I have a feeling something is blocking and the RCU grace period is not completing. I will look at the code!
|
| 7/2 |
2026/05/26 02:29 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/net/caif/caif_serial.c IncludeLines:true Name:handle_tx]
Results: map[SourceCode: 194: static int handle_tx(struct ser_device *ser)
195: {
196: struct tty_struct *tty;
197: struct sk_buff *skb;
198: int tty_wr, len, room;
199:
200: tty = ser->tty;
201: ser->tx_started = true;
202:
203: /* Enter critical section */
204: if (test_and_set_bit(CAIF_SENDING, &ser->state))
205: return 0;
206:
207: /* skb_peek is safe because handle_tx is called after skb_queue_tail */
208: while ((skb = skb_peek(&ser->head)) != NULL) {
209:
210: /* Make sure you don't write too much */
211: len = skb->len;
212: room = tty_write_room(tty);
213: if (!room)
214: break;
215: if (room > ser_write_chunk)
216: room = ser_write_chunk;
217: if (len > room)
218: len = room;
219:
220: /* Write to tty or loopback */
221: if (!ser_loop) {
222: tty_wr = tty->ops->write(tty, skb->data, len);
223: update_tty_status(ser);
224: } else {
225: tty_wr = len;
226: ldisc_receive(tty, skb->data, NULL, len);
227: }
228: ser->dev->stats.tx_packets++;
229: ser->dev->stats.tx_bytes += tty_wr;
230:
231: /* Error on TTY ?! */
232: if (tty_wr < 0)
233: goto error;
234: /* Reduce buffer written, and discard if empty */
235: skb_pull(skb, tty_wr);
236: if (skb->len == 0) {
237: struct sk_buff *tmp = skb_dequeue(&ser->head);
238: WARN_ON(tmp != skb);
239: dev_consume_skb_any(skb);
240: }
241: }
242: /* Send flow off if queue is empty */
243: if (ser->head.qlen <= SEND_QUEUE_LOW &&
244: test_and_clear_bit(CAIF_FLOW_OFF_SENT, &ser->state) &&
245: ser->common.flowctrl != NULL)
246: ser->common.flowctrl(ser->dev, ON);
247: clear_bit(CAIF_SENDING, &ser->state);
248: return 0;
249: error:
250: clear_bit(CAIF_SENDING, &ser->state);
251: return tty_wr;
252: }
SourceFile:drivers/net/caif/caif_serial.c]
|
| 8/2 |
2026/05/26 02:29 |
llm |
expert |
0m
Model:
Tokens:
input: 15637
output: 43
thoughts: 116
Thoughts: **Analyzing a Potential Infinite Loop in Serial Driver Code**
Okay, so I'm looking at this serial driver code, and I see a potential issue. It looks like if `tty_wr` is zero, then calling `skb_pull(skb, 0)` does nothing. The `skb->len` *remains* greater than zero, and the loop... well, it keeps going. That's a red flag. Infinite loop city, potentially!
Now, hold on... let's see, `tty_wr` is the *return value* of `tty->ops->write(tty, skb->data, len)`. Right, so it's the number of bytes written. If `tty->ops->write` returns *zero*, boom, we're stuck. We need to check the cases where this could occur.
Let me dig into this further. I'll need to check the actual implementation of `uart_write`, to see *why* that return value is zero. Let's head over to `drivers/tty/serial/serial_core.c` and take a look. I'm expecting this to be the smoking gun.
|
| 9/2 |
2026/05/26 02:29 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/tty/serial/serial_core.c IncludeLines:true Name:uart_write]
Results: map[SourceCode: 612: static ssize_t uart_write(struct tty_struct *tty, const u8 *buf, size_t count)
613: {
614: struct uart_state *state = tty->driver_data;
615: struct uart_port *port;
616: unsigned long flags;
617: int ret = 0;
618:
619: /*
620: * This means you called this function _after_ the port was
621: * closed. No cookie for you.
622: */
623: if (WARN_ON(!state))
624: return -EL3HLT;
625:
626: port = uart_port_lock(state, flags);
627: if (!state->port.xmit_buf) {
628: uart_port_unlock(port, flags);
629: return 0;
630: }
631:
632: if (port)
633: ret = kfifo_in(&state->port.xmit_fifo, buf, count);
634:
635: __uart_start(state);
636: uart_port_unlock(port, flags);
637: return ret;
638: }
SourceFile:drivers/tty/serial/serial_core.c]
|
| 10/2 |
2026/05/26 02:29 |
llm |
expert |
0m
Model:
Tokens:
input: 16452
output: 45
thoughts: 112
Thoughts: Okay, let's break this down.
**UART Write Conundrum**
Right, so `uart_write` can return zero, and that could be for a couple of reasons, it's either `!state->port.xmit_buf` or potentially a zero from `kfifo_in`. Okay, but wait a second, isn't `kfifo_in` supposed to return the *number* of bytes actually copied? So, a return of zero there would indicate a full FIFO, right? But the important thing is that `handle_tx` is checking `tty_write_room(tty)` and, if *that* returns zero, it bails out of the loop. That's good, but how exactly is `uart_write_room` working? I need to check how it works to really understand this.
|
| 11/2 |
2026/05/26 02:29 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/tty/serial/serial_core.c IncludeLines:true Name:uart_write_room]
Results: map[SourceCode: 640: static unsigned int uart_write_room(struct tty_struct *tty)
641: {
642: struct uart_state *state = tty->driver_data;
643: struct uart_port *port;
644: unsigned long flags;
645: unsigned int ret;
646:
647: port = uart_port_lock(state, flags);
648: ret = kfifo_avail(&state->port.xmit_fifo);
649: uart_port_unlock(port, flags);
650: return ret;
651: }
SourceFile:drivers/tty/serial/serial_core.c]
|
| 12/2 |
2026/05/26 02:29 |
llm |
expert |
0m
Model:
Tokens:
input: 16995
output: 45
thoughts: 217
Thoughts: **Investigating a UART Driver Conundrum**
Okay, so I'm looking at this UART driver code and something feels off. `uart_write_room` is returning `kfifo_avail`, which seems reasonable. If `kfifo_avail` is greater than zero, then `handle_tx` is going to call `tty->ops->write`. But hang on… what if `state->port.xmit_buf` is NULL? That would mean there's no transmit buffer allocated. If the buffer isn't present then `uart_write` will likely return 0, indicating failure. But here's the kicker: `uart_write_room` *doesn't* check for `state->port.xmit_buf` being NULL.
So, if `state->port.xmit_buf` is NULL, could `kfifo_avail` still return a non-zero value? That doesn't seem right. Let's dig into how `kfifo_avail` is calculated. It returns `fifo->kfifo.mask + 1 - (fifo->kfifo.in - fifo->kfifo.out)`. Hmm, if `xmit_buf` is NULL, what's happening to the `mask`? It doesn't seem immediately obvious how this is handled, so let's track down how that `xmit_buf` is actually allocated and how `xmit_fifo` is initialized. I need to understand the lifecycle of that buffer to see where the disconnect is. There's a potential race condition or logic error here that needs to be ironed out.
|
| 13/2 |
2026/05/26 02:30 |
tool |
codesearch-find-references |
0m
Error:
Args: map[ContextFile:drivers/tty/serial/serial_core.c IncludeSnippetLines:0 Name:xmit_buf]
Results: map[References:<nil> TruncatedOutput:false]
|
| 14/2 |
2026/05/26 02:30 |
llm |
expert |
0m
Model:
Tokens:
input: 17621
output: 18
thoughts: 52
Thoughts: Okay, here's my interpretation of those thoughts, summarized from my perspective as someone well-versed in this domain:
**Investigating the `xmit_buf` Variable**
Right, let me see... I'm pretty sure `xmit_buf` is a key field in the UART driver structure. Is it defined within the `uart_state` struct, or perhaps the `uart_port` struct? I can't quite recall off the top of my head, which is not ideal, but an easy fix. Time to get to the bottom of this.
To clarify things and get a definitive answer, I'll need to locate its definition. The most likely place to find this, considering the context, is probably within `drivers/tty/serial/serial_core.c`. That file's a central hub for all things serial, so it's the obvious starting point for my search. Let's start there.
|
| 15/2 |
2026/05/26 02:30 |
tool |
grepper |
0m
Args:
Results: map[Output:
Full output is too long, showing 500 out of 768 lines.
Use more precise expression if possible.
[drivers/crypto/omap-sham.c=212=struct omap_sham_dev {
--
drivers/crypto/omap-sham.c-221- u8 polling_mode;
drivers/crypto/omap-sham.c:222: u8 xmit_buf[BUFLEN] OMAP_ALIGNED;
drivers/crypto/omap-sham.c-223-
--
drivers/crypto/omap-sham.c=625=static int omap_sham_copy_sg_lists(struct omap_sham_reqctx *ctx,
--
drivers/crypto/omap-sham.c-647- if (ctx->bufcnt) {
drivers/crypto/omap-sham.c:648: sg_set_buf(tmp, ctx->dd->xmit_buf, ctx->bufcnt);
drivers/crypto/omap-sham.c-649- tmp = sg_next(tmp);
--
drivers/crypto/omap-sham.c=691=static int omap_sham_copy_sgs(struct omap_sham_reqctx *ctx,
--
drivers/crypto/omap-sham.c-706- if (ctx->bufcnt)
drivers/crypto/omap-sham.c:707: memcpy(buf, ctx->dd->xmit_buf, ctx->bufcnt);
drivers/crypto/omap-sham.c-708-
--
drivers/crypto/omap-sham.c=723=static int omap_sham_align_sgs(struct scatterlist *sg,
--
drivers/crypto/omap-sham.c-738- sg_init_table(rctx->sgl, 1);
drivers/crypto/omap-sham.c:739: sg_set_buf(rctx->sgl, rctx->dd->xmit_buf, bufcnt);
drivers/crypto/omap-sham.c-740- rctx->sg = rctx->sgl;
--
drivers/crypto/omap-sham.c-830- sg_init_table(rctx->sgl, 2);
drivers/crypto/omap-sham.c:831: sg_set_buf(rctx->sgl, rctx->dd->xmit_buf, rctx->bufcnt);
drivers/crypto/omap-sham.c-832- sg_chain(rctx->sgl, 2, sg);
--
drivers/crypto/omap-sham.c=841=static int omap_sham_prepare_request(struct crypto_engine *engine, void *areq)
--
drivers/crypto/omap-sham.c-881- if (rctx->bufcnt)
drivers/crypto/omap-sham.c:882: memcpy(rctx->dd->xmit_buf, rctx->buffer, rctx->bufcnt);
drivers/crypto/omap-sham.c-883-
--
drivers/crypto/s5p-sss.c=249=struct s5p_aes_ctx {
--
drivers/crypto/s5p-sss.c-289- * @hash_tasklet: New HASH request scheduling job.
drivers/crypto/s5p-sss.c:290: * @xmit_buf: Buffer for current HASH request transfer into SSS block.
drivers/crypto/s5p-sss.c-291- * @hash_req: Current request sending to SSS HASH block.
--
drivers/crypto/s5p-sss.c=297=struct s5p_aes_dev {
--
drivers/crypto/s5p-sss.c-325-
drivers/crypto/s5p-sss.c:326: u8 xmit_buf[BUFLEN];
drivers/crypto/s5p-sss.c-327- struct ahash_request *hash_req;
--
drivers/crypto/s5p-sss.c=965=static int s5p_hash_xmit_dma(struct s5p_aes_dev *dd, size_t length,
--
drivers/crypto/s5p-sss.c-999- *
drivers/crypto/s5p-sss.c:1000: * Allocate new buffer, copy data for HASH into it. If there was xmit_buf
drivers/crypto/s5p-sss.c-1001- * filled, copy it first, then copy data from sg into it. Prepare one sgl[0]
--
drivers/crypto/s5p-sss.c=1006=static int s5p_hash_copy_sgs(struct s5p_hash_reqctx *ctx,
--
drivers/crypto/s5p-sss.c-1022- if (ctx->bufcnt)
drivers/crypto/s5p-sss.c:1023: memcpy(buf, ctx->dd->xmit_buf, ctx->bufcnt);
drivers/crypto/s5p-sss.c-1024-
--
drivers/crypto/s5p-sss.c-1043- * Allocate new scatterlist table, copy data for HASH into it. If there was
drivers/crypto/s5p-sss.c:1044: * xmit_buf filled, prepare it first, then copy page, length and offset from
drivers/crypto/s5p-sss.c-1045- * source sg into it, adjusting begin and/or end for skip offset and
--
drivers/crypto/s5p-sss.c=1051=static int s5p_hash_copy_sg_lists(struct s5p_hash_reqctx *ctx,
--
drivers/crypto/s5p-sss.c-1073- if (ctx->bufcnt) {
drivers/crypto/s5p-sss.c:1074: sg_set_buf(tmp, ctx->dd->xmit_buf, ctx->bufcnt);
drivers/crypto/s5p-sss.c-1075- tmp = sg_next(tmp);
--
drivers/crypto/s5p-sss.c=1121=static int s5p_hash_prepare_sgs(struct s5p_hash_reqctx *ctx,
--
drivers/crypto/s5p-sss.c-1172- sg_init_table(ctx->sgl, 2);
drivers/crypto/s5p-sss.c:1173: sg_set_buf(ctx->sgl, ctx->dd->xmit_buf, ctx->bufcnt);
drivers/crypto/s5p-sss.c-1174- sg_chain(ctx->sgl, 2, sg);
--
drivers/crypto/s5p-sss.c=1195=static int s5p_hash_prepare_request(struct ahash_request *req, bool update)
--
drivers/crypto/s5p-sss.c-1226- if (ctx->bufcnt)
drivers/crypto/s5p-sss.c:1227: memcpy(ctx->dd->xmit_buf, ctx->buffer, ctx->bufcnt);
drivers/crypto/s5p-sss.c-1228-
--
drivers/crypto/s5p-sss.c-1239- /* copy hash_later bytes from end of req->src */
drivers/crypto/s5p-sss.c:1240: /* previous bytes are in xmit_buf, so no overwrite */
drivers/crypto/s5p-sss.c-1241- memcpy_from_sglist(ctx->buffer, req->src,
--
drivers/crypto/s5p-sss.c-1253- /* first update didn't fill up buffer */
drivers/crypto/s5p-sss.c:1254: memcpy_from_sglist(ctx->dd->xmit_buf, req->src,
drivers/crypto/s5p-sss.c-1255- 0, xmit_len);
--
drivers/crypto/s5p-sss.c-1258- sg_init_table(ctx->sgl, 1);
drivers/crypto/s5p-sss.c:1259: sg_set_buf(ctx->sgl, ctx->dd->xmit_buf, xmit_len);
drivers/crypto/s5p-sss.c-1260-
--
drivers/crypto/stm32/stm32-hash.c=193=struct stm32_hash_dev {
--
drivers/crypto/stm32/stm32-hash.c-199- phys_addr_t phys_base;
drivers/crypto/stm32/stm32-hash.c:200: u8 xmit_buf[HASH_BUFLEN] __aligned(sizeof(u32));
drivers/crypto/stm32/stm32-hash.c-201- u32 dma_mode;
--
drivers/crypto/stm32/stm32-hash.c=1102=static int stm32_hash_copy_sgs(struct stm32_hash_request_ctx *rctx,
--
drivers/crypto/stm32/stm32-hash.c-1118- if (state->bufcnt)
drivers/crypto/stm32/stm32-hash.c:1119: memcpy(buf, rctx->hdev->xmit_buf, state->bufcnt);
drivers/crypto/stm32/stm32-hash.c-1120-
--
drivers/crypto/stm32/stm32-hash.c=1135=static int stm32_hash_align_sgs(struct scatterlist *sg,
--
drivers/crypto/stm32/stm32-hash.c-1152- sg_init_table(rctx->sgl, 1);
drivers/crypto/stm32/stm32-hash.c:1153: sg_set_buf(rctx->sgl, rctx->hdev->xmit_buf, bufcnt);
drivers/crypto/stm32/stm32-hash.c-1154- rctx->sg = rctx->sgl;
--
drivers/crypto/stm32/stm32-hash.c-1242- sg_init_table(rctx->sgl, 2);
drivers/crypto/stm32/stm32-hash.c:1243: sg_set_buf(rctx->sgl, rctx->hdev->xmit_buf, state->bufcnt);
drivers/crypto/stm32/stm32-hash.c-1244- sg_chain(rctx->sgl, 2, sg);
--
drivers/crypto/stm32/stm32-hash.c=1253=static int stm32_hash_prepare_request(struct ahash_request *req)
--
drivers/crypto/stm32/stm32-hash.c-1303- if (state->bufcnt)
drivers/crypto/stm32/stm32-hash.c:1304: memcpy(hdev->xmit_buf, state->buffer, state->bufcnt);
drivers/crypto/stm32/stm32-hash.c-1305-
--
drivers/ipack/devices/ipoctal.c=201=static void ipoctal_irq_tx(struct ipoctal_channel *channel)
--
drivers/ipack/devices/ipoctal.c-209- spin_lock(&channel->lock);
drivers/ipack/devices/ipoctal.c:210: value = channel->tty_port.xmit_buf[*pointer_write];
drivers/ipack/devices/ipoctal.c-211- iowrite8(value, &channel->regs->w.thr);
--
drivers/ipack/devices/ipoctal.c=272=static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr,
--
drivers/ipack/devices/ipoctal.c-397- tty_port_init(&channel->tty_port);
drivers/ipack/devices/ipoctal.c:398: res = tty_port_alloc_xmit_buf(&channel->tty_port);
drivers/ipack/devices/ipoctal.c-399- if (res)
--
drivers/ipack/devices/ipoctal.c-411- dev_err(&ipoctal->dev->dev, "Failed to register tty device.\n");
drivers/ipack/devices/ipoctal.c:412: tty_port_free_xmit_buf(&channel->tty_port);
drivers/ipack/devices/ipoctal.c-413- tty_port_destroy(&channel->tty_port);
--
drivers/ipack/devices/ipoctal.c=437=static inline size_t ipoctal_copy_write_buffer(struct ipoctal_channel *channel,
--
drivers/ipack/devices/ipoctal.c-447- spin_lock_irqsave(&channel->lock, flags);
drivers/ipack/devices/ipoctal.c:448: channel->tty_port.xmit_buf[*pointer_read] = buf[i];
drivers/ipack/devices/ipoctal.c-449- *pointer_read = (*pointer_read + 1) % PAGE_SIZE;
--
drivers/ipack/devices/ipoctal.c=708=static void __ipoctal_remove(struct ipoctal *ipoctal)
--
drivers/ipack/devices/ipoctal.c-720- tty_unregister_device(ipoctal->tty_drv, i);
drivers/ipack/devices/ipoctal.c:721: tty_port_free_xmit_buf(&channel->tty_port);
drivers/ipack/devices/ipoctal.c-722- tty_port_destroy(&channel->tty_port);
--
drivers/net/ethernet/i825xx/sun3_82586.c=145=struct priv
--
drivers/net/ethernet/i825xx/sun3_82586.c-154- volatile struct scb_struct *scb; /* volatile is important */
drivers/net/ethernet/i825xx/sun3_82586.c:155: volatile struct tbd_struct *xmit_buffs[NUM_XMIT_BUFFS];
drivers/net/ethernet/i825xx/sun3_82586.c-156- volatile struct transmit_cmd_struct *xmit_cmds[NUM_XMIT_BUFFS];
--
drivers/net/ethernet/i825xx/sun3_82586.c=401=static int init586(struct net_device *dev)
--
drivers/net/ethernet/i825xx/sun3_82586.c-581- ptr = (char *) ptr + XMIT_BUFF_SIZE;
drivers/net/ethernet/i825xx/sun3_82586.c:582: p->xmit_buffs[i] = (struct tbd_struct *)ptr; /* TBD */
drivers/net/ethernet/i825xx/sun3_82586.c-583- ptr = (char *) ptr + sizeof(struct tbd_struct);
--
drivers/net/ethernet/i825xx/sun3_82586.c-589- memset((char *)(p->xmit_cmds[i]) ,0, sizeof(struct transmit_cmd_struct));
drivers/net/ethernet/i825xx/sun3_82586.c:590: memset((char *)(p->xmit_buffs[i]),0, sizeof(struct tbd_struct));
drivers/net/ethernet/i825xx/sun3_82586.c-591- p->xmit_cmds[i]->cmd_link = make16(p->nop_cmds[(i+1)%NUM_XMIT_BUFFS]);
--
drivers/net/ethernet/i825xx/sun3_82586.c-593- p->xmit_cmds[i]->cmd_cmd = swab16(CMD_XMIT | CMD_INT);
drivers/net/ethernet/i825xx/sun3_82586.c:594: p->xmit_cmds[i]->tbd_offset = make16((p->xmit_buffs[i]));
drivers/net/ethernet/i825xx/sun3_82586.c:595: p->xmit_buffs[i]->next = 0xffff;
drivers/net/ethernet/i825xx/sun3_82586.c:596: p->xmit_buffs[i]->buffer = make24((p->xmit_cbuffs[i]));
drivers/net/ethernet/i825xx/sun3_82586.c-597- }
--
drivers/net/ethernet/i825xx/sun3_82586.c=1004=sun3_82586_send_packet(struct sk_buff *skb, struct net_device *dev)
--
drivers/net/ethernet/i825xx/sun3_82586.c-1047-
drivers/net/ethernet/i825xx/sun3_82586.c:1048: p->xmit_buffs[0]->size = swab16(TBD_LAST | len);
drivers/net/ethernet/i825xx/sun3_82586.c-1049- for(i=0;i<16;i++)
--
drivers/net/ethernet/i825xx/sun3_82586.c-1073- next_nop = (p->nop_point + 1) & 0x1;
drivers/net/ethernet/i825xx/sun3_82586.c:1074: p->xmit_buffs[0]->size = swab16(TBD_LAST | len);
drivers/net/ethernet/i825xx/sun3_82586.c-1075-
--
drivers/net/ethernet/i825xx/sun3_82586.c-1084-#else
drivers/net/ethernet/i825xx/sun3_82586.c:1085: p->xmit_buffs[p->xmit_count]->size = swab16(TBD_LAST | len);
drivers/net/ethernet/i825xx/sun3_82586.c-1086- if( (next_nop = p->xmit_count + 1) == NUM_XMIT_BUFFS )
--
drivers/net/wireless/mediatek/mt76/mt76.h=640=struct mt76_sdio {
--
drivers/net/wireless/mediatek/mt76/mt76.h-645-
drivers/net/wireless/mediatek/mt76/mt76.h:646: u8 *xmit_buf;
drivers/net/wireless/mediatek/mt76/mt76.h:647: u32 xmit_buf_sz;
drivers/net/wireless/mediatek/mt76/mt76.h-648-
--
drivers/net/wireless/mediatek/mt76/sdio.c=635=int mt76s_init(struct mt76_dev *dev, struct sdio_func *func,
--
drivers/net/wireless/mediatek/mt76/sdio.c-667- func->card->host->max_blk_count);
drivers/net/wireless/mediatek/mt76/sdio.c:668: dev->sdio.xmit_buf_sz = min_t(u32, host_max_cap, MT76S_XMIT_BUF_SZ);
drivers/net/wireless/mediatek/mt76/sdio.c:669: dev->sdio.xmit_buf = devm_kmalloc(dev->dev, dev->sdio.xmit_buf_sz,
drivers/net/wireless/mediatek/mt76/sdio.c-670- GFP_KERNEL);
drivers/net/wireless/mediatek/mt76/sdio.c:671: if (!dev->sdio.xmit_buf)
drivers/net/wireless/mediatek/mt76/sdio.c-672- err = -ENOMEM;
--
drivers/net/wireless/mediatek/mt76/sdio_txrx.c=243=static int mt76s_tx_run_queue(struct mt76_dev *dev, struct mt76_queue *q)
--
drivers/net/wireless/mediatek/mt76/sdio_txrx.c-273- pad = roundup(e->skb->len, 4) - e->skb->len;
drivers/net/wireless/mediatek/mt76/sdio_txrx.c:274: if (len + e->skb->len + pad + 4 > dev->sdio.xmit_buf_sz)
drivers/net/wireless/mediatek/mt76/sdio_txrx.c-275- break;
--
drivers/net/wireless/mediatek/mt76/sdio_txrx.c-280-
drivers/net/wireless/mediatek/mt76/sdio_txrx.c:281: memcpy(sdio->xmit_buf + len, e->skb->data, skb_headlen(e->skb));
drivers/net/wireless/mediatek/mt76/sdio_txrx.c-282- len += skb_headlen(e->skb);
--
drivers/net/wireless/mediatek/mt76/sdio_txrx.c-285- skb_walk_frags(e->skb, iter) {
drivers/net/wireless/mediatek/mt76/sdio_txrx.c:286: memcpy(sdio->xmit_buf + len, iter->data, iter->len);
drivers/net/wireless/mediatek/mt76/sdio_txrx.c-287- len += iter->len;
--
drivers/net/wireless/mediatek/mt76/sdio_txrx.c-291- if (unlikely(pad)) {
drivers/net/wireless/mediatek/mt76/sdio_txrx.c:292: memset(sdio->xmit_buf + len, 0, pad);
drivers/net/wireless/mediatek/mt76/sdio_txrx.c-293- len += pad;
--
drivers/net/wireless/mediatek/mt76/sdio_txrx.c-300- if (nframes) {
drivers/net/wireless/mediatek/mt76/sdio_txrx.c:301: memset(sdio->xmit_buf + len, 0, 4);
drivers/net/wireless/mediatek/mt76/sdio_txrx.c:302: err = __mt76s_xmit_queue(dev, sdio->xmit_buf, len + 4);
drivers/net/wireless/mediatek/mt76/sdio_txrx.c-303- if (err)
--
drivers/staging/rtl8723bs/core/rtw_mlme_ext.c=1911=static struct xmit_frame *_alloc_mgtxmitframe(struct xmit_priv *pxmitpriv, bool once)
--
drivers/staging/rtl8723bs/core/rtw_mlme_ext.c-1913- struct xmit_frame *pmgntframe;
drivers/staging/rtl8723bs/core/rtw_mlme_ext.c:1914: struct xmit_buf *pxmitbuf;
drivers/staging/rtl8723bs/core/rtw_mlme_ext.c-1915-
--
drivers/staging/rtl8723bs/core/rtw_mlme_ext.c=2021=s32 dump_mgntframe_and_wait(struct adapter *padapter, struct xmit_frame *pmgntframe, int timeout_ms)
--
drivers/staging/rtl8723bs/core/rtw_mlme_ext.c-2025- struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
drivers/staging/rtl8723bs/core/rtw_mlme_ext.c:2026: struct xmit_buf *pxmitbuf = pmgntframe->pxmitbuf;
drivers/staging/rtl8723bs/core/rtw_mlme_ext.c-2027- struct submit_ctx sctx;
--
drivers/staging/rtl8723bs/core/rtw_xmit.c=34=s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter)
--
drivers/staging/rtl8723bs/core/rtw_xmit.c-36- int i;
drivers/staging/rtl8723bs/core/rtw_xmit.c:37: struct xmit_buf *pxmitbuf;
drivers/staging/rtl8723bs/core/rtw_xmit.c-38- struct xmit_frame *pxframe;
--
drivers/staging/rtl8723bs/core/rtw_xmit.c-103-
drivers/staging/rtl8723bs/core/rtw_xmit.c:104: /* init xmit_buf */
drivers/staging/rtl8723bs/core/rtw_xmit.c-105- INIT_LIST_HEAD(&pxmitpriv->free_xmitbuf_queue.queue);
--
drivers/staging/rtl8723bs/core/rtw_xmit.c-109-
drivers/staging/rtl8723bs/core/rtw_xmit.c:110: pxmitpriv->pallocated_xmitbuf = vzalloc(NR_XMITBUFF * sizeof(struct xmit_buf) + 4);
drivers/staging/rtl8723bs/core/rtw_xmit.c-111-
--
drivers/staging/rtl8723bs/core/rtw_xmit.c-118-
drivers/staging/rtl8723bs/core/rtw_xmit.c:119: pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmitbuf;
drivers/staging/rtl8723bs/core/rtw_xmit.c-120-
--
drivers/staging/rtl8723bs/core/rtw_xmit.c-192-
drivers/staging/rtl8723bs/core/rtw_xmit.c:193: pxmitpriv->pallocated_xmit_extbuf = vzalloc(NR_XMIT_EXTBUFF * sizeof(struct xmit_buf) + 4);
drivers/staging/rtl8723bs/core/rtw_xmit.c-194-
--
drivers/staging/rtl8723bs/core/rtw_xmit.c-201-
drivers/staging/rtl8723bs/core/rtw_xmit.c:202: pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmit_extbuf;
drivers/staging/rtl8723bs/core/rtw_xmit.c-203-
--
drivers/staging/rtl8723bs/core/rtw_xmit.c=273=void _rtw_free_xmit_priv(struct xmit_priv *pxmitpriv)
--
drivers/staging/rtl8723bs/core/rtw_xmit.c-277- struct xmit_frame *pxmitframe = (struct xmit_frame *) pxmitpriv->pxmit_frame_buf;
drivers/staging/rtl8723bs/core/rtw_xmit.c:278: struct xmit_buf *pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmitbuf;
drivers/staging/rtl8723bs/core/rtw_xmit.c-279-
--
drivers/staging/rtl8723bs/core/rtw_xmit.c-311- /* free xmit extension buff */
drivers/staging/rtl8723bs/core/rtw_xmit.c:312: pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmit_extbuf;
drivers/staging/rtl8723bs/core/rtw_xmit.c-313- for (i = 0; i < NR_XMIT_EXTBUFF; i++) {
--
drivers/staging/rtl8723bs/core/rtw_xmit.c=1367=void rtw_count_tx_stats(struct adapter *padapter, struct xmit_frame *pxmitframe, int sz)
--
drivers/staging/rtl8723bs/core/rtw_xmit.c-1394-
drivers/staging/rtl8723bs/core/rtw_xmit.c:1395:static struct xmit_buf *__rtw_alloc_cmd_xmitbuf(struct xmit_priv *pxmitpriv,
drivers/staging/rtl8723bs/core/rtw_xmit.c-1396- enum cmdbuf_type buf_type)
drivers/staging/rtl8723bs/core/rtw_xmit.c-1397-{
drivers/staging/rtl8723bs/core/rtw_xmit.c:1398: struct xmit_buf *pxmitbuf = NULL;
drivers/staging/rtl8723bs/core/rtw_xmit.c-1399-
--
drivers/staging/rtl8723bs/core/rtw_xmit.c=1416=struct xmit_frame *__rtw_alloc_cmdxmitframe(struct xmit_priv *pxmitpriv,
--
drivers/staging/rtl8723bs/core/rtw_xmit.c-1419- struct xmit_frame *pcmdframe;
drivers/staging/rtl8723bs/core/rtw_xmit.c:1420: struct xmit_buf *pxmitbuf;
drivers/staging/rtl8723bs/core/rtw_xmit.c-1421-
--
drivers/staging/rtl8723bs/core/rtw_xmit.c-1442-
drivers/staging/rtl8723bs/core/rtw_xmit.c:1443:struct xmit_buf *rtw_alloc_xmitbuf_ext(struct xmit_priv *pxmitpriv)
drivers/staging/rtl8723bs/core/rtw_xmit.c-1444-{
drivers/staging/rtl8723bs/core/rtw_xmit.c-1445- unsigned long irqL;
drivers/staging/rtl8723bs/core/rtw_xmit.c:1446: struct xmit_buf *pxmitbuf = NULL;
drivers/staging/rtl8723bs/core/rtw_xmit.c-1447- struct list_head *plist, *phead;
--
drivers/staging/rtl8723bs/core/rtw_xmit.c-1458-
drivers/staging/rtl8723bs/core/rtw_xmit.c:1459: pxmitbuf = container_of(plist, struct xmit_buf, list);
drivers/staging/rtl8723bs/core/rtw_xmit.c-1460-
--
drivers/staging/rtl8723bs/core/rtw_xmit.c-1482-
drivers/staging/rtl8723bs/core/rtw_xmit.c:1483:s32 rtw_free_xmitbuf_ext(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf)
drivers/staging/rtl8723bs/core/rtw_xmit.c-1484-{
--
drivers/staging/rtl8723bs/core/rtw_xmit.c-1502-
drivers/staging/rtl8723bs/core/rtw_xmit.c:1503:struct xmit_buf *rtw_alloc_xmitbuf(struct xmit_priv *pxmitpriv)
drivers/staging/rtl8723bs/core/rtw_xmit.c-1504-{
drivers/staging/rtl8723bs/core/rtw_xmit.c-1505- unsigned long irqL;
drivers/staging/rtl8723bs/core/rtw_xmit.c:1506: struct xmit_buf *pxmitbuf = NULL;
drivers/staging/rtl8723bs/core/rtw_xmit.c-1507- struct list_head *plist, *phead;
--
drivers/staging/rtl8723bs/core/rtw_xmit.c-1518-
drivers/staging/rtl8723bs/core/rtw_xmit.c:1519: pxmitbuf = container_of(plist, struct xmit_buf, list);
drivers/staging/rtl8723bs/core/rtw_xmit.c-1520-
--
drivers/staging/rtl8723bs/core/rtw_xmit.c-1543-
drivers/staging/rtl8723bs/core/rtw_xmit.c:1544:s32 rtw_free_xmitbuf(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf)
drivers/staging/rtl8723bs/core/rtw_xmit.c-1545-{
--
drivers/staging/rtl8723bs/core/rtw_xmit.c=2314=void xmit_delivery_enabled_frames(struct adapter *padapter, struct sta_info *psta)
--
drivers/staging/rtl8723bs/core/rtw_xmit.c-2377-
drivers/staging/rtl8723bs/core/rtw_xmit.c:2378:void enqueue_pending_xmitbuf(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf)
drivers/staging/rtl8723bs/core/rtw_xmit.c-2379-{
--
drivers/staging/rtl8723bs/core/rtw_xmit.c-2392-
drivers/staging/rtl8723bs/core/rtw_xmit.c:2393:void enqueue_pending_xmitbuf_to_head(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf)
drivers/staging/rtl8723bs/core/rtw_xmit.c-2394-{
--
drivers/staging/rtl8723bs/core/rtw_xmit.c-2404-
drivers/staging/rtl8723bs/core/rtw_xmit.c:2405:struct xmit_buf *dequeue_pending_xmitbuf(struct xmit_priv *pxmitpriv)
drivers/staging/rtl8723bs/core/rtw_xmit.c-2406-{
drivers/staging/rtl8723bs/core/rtw_xmit.c:2407: struct xmit_buf *pxmitbuf;
drivers/staging/rtl8723bs/core/rtw_xmit.c-2408- struct __queue *pqueue;
--
drivers/staging/rtl8723bs/core/rtw_xmit.c-2419- plist = get_next(phead);
drivers/staging/rtl8723bs/core/rtw_xmit.c:2420: pxmitbuf = container_of(plist, struct xmit_buf, list);
drivers/staging/rtl8723bs/core/rtw_xmit.c-2421- list_del_init(&pxmitbuf->list);
--
drivers/staging/rtl8723bs/core/rtw_xmit.c-2428-
drivers/staging/rtl8723bs/core/rtw_xmit.c:2429:struct xmit_buf *dequeue_pending_xmitbuf_under_survey(struct xmit_priv *pxmitpriv)
drivers/staging/rtl8723bs/core/rtw_xmit.c-2430-{
drivers/staging/rtl8723bs/core/rtw_xmit.c:2431: struct xmit_buf *pxmitbuf;
drivers/staging/rtl8723bs/core/rtw_xmit.c-2432- struct __queue *pqueue;
--
drivers/staging/rtl8723bs/core/rtw_xmit.c-2449-
drivers/staging/rtl8723bs/core/rtw_xmit.c:2450: pxmitbuf = container_of(plist, struct xmit_buf, list);
drivers/staging/rtl8723bs/core/rtw_xmit.c-2451-
--
drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c=3328=void rtl8723b_stop_thread(struct adapter *padapter)
--
drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c-3331-
drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c:3332: /* stop xmit_buf_thread */
drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c-3333- if (xmitpriv->SdioXmitThread) {
--
drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c=36=static s32 rtl8723_dequeue_writeport(struct adapter *padapter)
--
drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c-40- struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c:41: struct xmit_buf *pxmitbuf;
drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c-42- struct adapter *pri_padapter = padapter;
--
drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c-120- */
drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c:121:s32 rtl8723bs_xmit_buf_handler(struct adapter *padapter)
drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c-122-{
--
drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c=169=static s32 xmit_xmitframes(struct adapter *padapter, struct xmit_priv *pxmitpriv)
--
drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c-178- struct __queue *pframe_queue;
drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c:179: struct xmit_buf *pxmitbuf;
drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c-180- u32 txlen, max_xmit_len;
--
drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c-234-
drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c:235: /* check xmit_buf size enough or not */
drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c-236- txlen = txdesc_size + rtw_wlan_pkt_size(pxmitframe);
--
drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c-262- netdev_err(padapter->pnetdev,
drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c:263: "%s: xmit_buf is not enough!\n",
drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c-264- __func__);
--
drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c-325-
drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c:326: /* dump xmit_buf to hw tx fifo */
drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c-327- if (pxmitbuf) {
--
drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c=433=s32 rtl8723bs_mgnt_xmit(
--
drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c-438- struct pkt_attrib *pattrib;
drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c:439: struct xmit_buf *pxmitbuf;
drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c-440- struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
--
drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c=558=void rtl8723bs_free_xmit_priv(struct adapter *padapter)
--
drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c-560- struct xmit_priv *pxmitpriv;
drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c:561: struct xmit_buf *pxmitbuf;
drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c-562- struct __queue *pqueue;
--
drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c-585-
drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c:586: pxmitbuf = container_of(plist, struct xmit_buf, list);
drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c-587- rtw_free_xmitframe(pxmitpriv, (struct xmit_frame *)pxmitbuf->priv_data);
--
drivers/staging/rtl8723bs/hal/sdio_ops.c=428=static u32 sdio_write_port(
--
drivers/staging/rtl8723bs/hal/sdio_ops.c-437- s32 err;
drivers/staging/rtl8723bs/hal/sdio_ops.c:438: struct xmit_buf *xmitbuf = (struct xmit_buf *)mem;
drivers/staging/rtl8723bs/hal/sdio_ops.c-439-
--
drivers/staging/rtl8723bs/include/rtl8723b_xmit.h=414=s32 rtl8723bs_hal_xmitframe_enqueue(struct adapter *padapter, struct xmit_frame *pxmitframe);
drivers/staging/rtl8723bs/include/rtl8723b_xmit.h:415:s32 rtl8723bs_xmit_buf_handler(struct adapter *padapter);
drivers/staging/rtl8723bs/include/rtl8723b_xmit.h-416-int rtl8723bs_xmit_thread(void *context);
drivers/staging/rtl8723bs/include/rtl8723b_xmit.h:417:#define hal_xmit_handler rtl8723bs_xmit_buf_handler
drivers/staging/rtl8723bs/include/rtl8723b_xmit.h-418-
--
drivers/staging/rtl8723bs/include/rtw_xmit.h=229=void rtw_sctx_done(struct submit_ctx **sctx);
drivers/staging/rtl8723bs/include/rtw_xmit.h-230-
drivers/staging/rtl8723bs/include/rtw_xmit.h:231:struct xmit_buf {
drivers/staging/rtl8723bs/include/rtw_xmit.h-232- struct list_head list;
--
drivers/staging/rtl8723bs/include/rtw_xmit.h=265=struct xmit_frame {
--
drivers/staging/rtl8723bs/include/rtw_xmit.h-277-
drivers/staging/rtl8723bs/include/rtw_xmit.h:278: struct xmit_buf *pxmitbuf;
drivers/staging/rtl8723bs/include/rtw_xmit.h-279-
--
drivers/staging/rtl8723bs/include/rtw_xmit.h=338=struct xmit_priv {
--
drivers/staging/rtl8723bs/include/rtw_xmit.h-407-
drivers/staging/rtl8723bs/include/rtw_xmit.h:408: struct xmit_buf pcmd_xmitbuf[CMDBUF_MAX];
drivers/staging/rtl8723bs/include/rtw_xmit.h-409-
--
drivers/staging/rtl8723bs/include/rtw_xmit.h=419=extern struct xmit_frame *__rtw_alloc_cmdxmitframe(struct xmit_priv *pxmitpriv,
--
drivers/staging/rtl8723bs/include/rtw_xmit.h-423-
drivers/staging/rtl8723bs/include/rtw_xmit.h:424:extern struct xmit_buf *rtw_alloc_xmitbuf_ext(struct xmit_priv *pxmitpriv);
drivers/staging/rtl8723bs/include/rtw_xmit.h:425:extern s32 rtw_free_xmitbuf_ext(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf);
drivers/staging/rtl8723bs/include/rtw_xmit.h-426-
drivers/staging/rtl8723bs/include/rtw_xmit.h:427:extern struct xmit_buf *rtw_alloc_xmitbuf(struct xmit_priv *pxmitpriv);
drivers/staging/rtl8723bs/include/rtw_xmit.h:428:extern s32 rtw_free_xmitbuf(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf);
drivers/staging/rtl8723bs/include/rtw_xmit.h-429-
--
drivers/staging/rtl8723bs/include/rtw_xmit.h=474=u8 qos_acm(u8 acm_mask, u8 priority);
drivers/staging/rtl8723bs/include/rtw_xmit.h-475-
drivers/staging/rtl8723bs/include/rtw_xmit.h:476:void enqueue_pending_xmitbuf(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf);
drivers/staging/rtl8723bs/include/rtw_xmit.h:477:void enqueue_pending_xmitbuf_to_head(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf);
drivers/staging/rtl8723bs/include/rtw_xmit.h:478:struct xmit_buf *dequeue_pending_xmitbuf(struct xmit_priv *pxmitpriv);
drivers/staging/rtl8723bs/include/rtw_xmit.h:479:struct xmit_buf *dequeue_pending_xmitbuf_under_survey(struct xmit_priv *pxmitpriv);
drivers/staging/rtl8723bs/include/rtw_xmit.h-480-signed int check_pending_xmitbuf(struct xmit_priv *pxmitpriv);
--
drivers/staging/rtl8723bs/include/rtw_xmit.h=486=void rtw_ack_tx_done(struct xmit_priv *pxmitpriv, int status);
drivers/staging/rtl8723bs/include/rtw_xmit.h-487-
drivers/staging/rtl8723bs/include/rtw_xmit.h:488:/* include after declaring struct xmit_buf, in order to avoid warning */
drivers/staging/rtl8723bs/include/rtw_xmit.h-489-#include <xmit_osdep.h>
--
drivers/staging/rtl8723bs/include/xmit_osdep.h=25=struct xmit_frame;
drivers/staging/rtl8723bs/include/xmit_osdep.h:26:struct xmit_buf;
drivers/staging/rtl8723bs/include/xmit_osdep.h-27-
--
drivers/staging/rtl8723bs/include/xmit_osdep.h=31=void rtw_os_xmit_schedule(struct adapter *padapter);
drivers/staging/rtl8723bs/include/xmit_osdep.h-32-
drivers/staging/rtl8723bs/include/xmit_osdep.h:33:int rtw_os_xmit_resource_alloc(struct adapter *padapter, struct xmit_buf *pxmitbuf, u32 alloc_sz, u8 flag);
drivers/staging/rtl8723bs/include/xmit_osdep.h:34:void rtw_os_xmit_resource_free(struct adapter *padapter, struct xmit_buf *pxmitbuf, u32 free_sz, u8 flag);
drivers/staging/rtl8723bs/include/xmit_osdep.h-35-
--
drivers/staging/rtl8723bs/os_dep/xmit_linux.c=39=signed int rtw_endofpktfile(struct pkt_file *pfile)
--
drivers/staging/rtl8723bs/os_dep/xmit_linux.c-45-
drivers/staging/rtl8723bs/os_dep/xmit_linux.c:46:int rtw_os_xmit_resource_alloc(struct adapter *padapter, struct xmit_buf *pxmitbuf, u32 alloc_sz, u8 flag)
drivers/staging/rtl8723bs/os_dep/xmit_linux.c-47-{
--
drivers/staging/rtl8723bs/os_dep/xmit_linux.c-58-
drivers/staging/rtl8723bs/os_dep/xmit_linux.c:59:void rtw_os_xmit_resource_free(struct adapter *padapter, struct xmit_buf *pxmitbuf, u32 free_sz, u8 flag)
drivers/staging/rtl8723bs/os_dep/xmit_linux.c-60-{
--
drivers/tty/mips_ejtag_fdc.c=84=struct mips_ejtag_fdc_tty;
--
drivers/tty/mips_ejtag_fdc.c-93- * @rx_buf: Read buffer.
drivers/tty/mips_ejtag_fdc.c:94: * @xmit_lock: Lock for xmit_*, and port.xmit_buf.
drivers/tty/mips_ejtag_fdc.c-95- * This protects between user context and kernel thread.
--
drivers/tty/mips_ejtag_fdc.c=415=static unsigned int mips_ejtag_fdc_put_chan(struct mips_ejtag_fdc_tty *priv,
--
drivers/tty/mips_ejtag_fdc.c-427- if (dport->xmit_cnt) {
drivers/tty/mips_ejtag_fdc.c:428: ptrs[0] = dport->port.xmit_buf + dport->xmit_tail;
drivers/tty/mips_ejtag_fdc.c-429- sizes[0] = min_t(unsigned int,
--
drivers/tty/mips_ejtag_fdc.c-431- dport->xmit_cnt);
drivers/tty/mips_ejtag_fdc.c:432: ptrs[1] = dport->port.xmit_buf;
drivers/tty/mips_ejtag_fdc.c-433- sizes[1] = dport->xmit_cnt - sizes[0];
--
drivers/tty/mips_ejtag_fdc.c=695=static int mips_ejtag_fdc_tty_port_activate(struct tty_port *port,
--
drivers/tty/mips_ejtag_fdc.c-702- /* Allocate the buffer we use for writing data */
drivers/tty/mips_ejtag_fdc.c:703: if (tty_port_alloc_xmit_buf(port) < 0)
drivers/tty/mips_ejtag_fdc.c-704- goto err;
--
drivers/tty/mips_ejtag_fdc.c-716-err_free_xmit:
drivers/tty/mips_ejtag_fdc.c:717: tty_port_free_xmit_buf(port);
drivers/tty/mips_ejtag_fdc.c-718-err:
--
drivers/tty/mips_ejtag_fdc.c=722=static void mips_ejtag_fdc_tty_port_shutdown(struct tty_port *port)
--
drivers/tty/mips_ejtag_fdc.c-750- /* Free the write buffer */
drivers/tty/mips_ejtag_fdc.c:751: tty_port_free_xmit_buf(port);
drivers/tty/mips_ejtag_fdc.c-752-}
--
]
]
|
| 16/2 |
2026/05/26 02:30 |
llm |
expert |
0m
Model:
Tokens:
input: 31962
output: 41
thoughts: 49
Thoughts: Okay, here's my take on those thoughts, framed as an expert's internal monologue:
**Investigating the `xmit_buf` Mystery**
Alright, so I'm seeing `xmit_buf`... that rings a bell. Where *exactly* does that come into play? My gut says it's likely nestled within either the `tty_port` or the `uart_port` structure. Gotta be a serial-related thing, for sure.
Let's quickly confirm. I need to refresh my memory on the layout. Time to crack open `include/linux/serial_core.h`. That's where the definitive answer should reside. I need to see what `struct uart_port` actually *contains*. It's likely in there, or maybe referenced through a nested structure. Let's see...
|
| 17/2 |
2026/05/26 02:30 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:include/linux/serial_core.h IncludeLines:true Name:uart_port]
Results: map[SourceCode: 430: struct uart_port {
431: spinlock_t lock; /* port lock */
432: unsigned long iobase; /* in/out[bwl] */
433: unsigned char __iomem *membase; /* read/write[bwl] */
434: unsigned int (*serial_in)(struct uart_port *, int);
435: void (*serial_out)(struct uart_port *, int, int);
436: void (*set_termios)(struct uart_port *,
437: struct ktermios *new,
438: const struct ktermios *old);
439: void (*set_ldisc)(struct uart_port *,
440: struct ktermios *);
441: unsigned int (*get_mctrl)(struct uart_port *);
442: void (*set_mctrl)(struct uart_port *, unsigned int);
443: unsigned int (*get_divisor)(struct uart_port *,
444: unsigned int baud,
445: unsigned int *frac);
446: void (*set_divisor)(struct uart_port *,
447: unsigned int baud,
448: unsigned int quot,
449: unsigned int quot_frac);
450: int (*startup)(struct uart_port *port);
451: void (*shutdown)(struct uart_port *port);
452: void (*throttle)(struct uart_port *port);
453: void (*unthrottle)(struct uart_port *port);
454: int (*handle_irq)(struct uart_port *);
455: void (*pm)(struct uart_port *, unsigned int state,
456: unsigned int old);
457: void (*handle_break)(struct uart_port *);
458: int (*rs485_config)(struct uart_port *,
459: struct ktermios *termios,
460: struct serial_rs485 *rs485);
461: int (*iso7816_config)(struct uart_port *,
462: struct serial_iso7816 *iso7816);
463: unsigned int ctrl_id; /* optional serial core controller id */
464: unsigned int port_id; /* optional serial core port id */
465: unsigned int irq; /* irq number */
466: unsigned long irqflags; /* irq flags */
467: unsigned int uartclk; /* base uart clock */
468: unsigned int fifosize; /* tx fifo size */
469: unsigned char x_char; /* xon/xoff char */
470: unsigned char regshift; /* reg offset shift */
471:
472: unsigned char iotype; /* io access style */
473:
474: #define UPIO_UNKNOWN ((unsigned char)~0U) /* UCHAR_MAX */
475: #define UPIO_PORT (SERIAL_IO_PORT) /* 8b I/O port access */
476: #define UPIO_HUB6 (SERIAL_IO_HUB6) /* Hub6 ISA card */
477: #define UPIO_MEM (SERIAL_IO_MEM) /* driver-specific */
478: #define UPIO_MEM32 (SERIAL_IO_MEM32) /* 32b little endian */
479: #define UPIO_AU (SERIAL_IO_AU) /* Au1x00 and RT288x type IO */
480: #define UPIO_TSI (SERIAL_IO_TSI) /* Tsi108/109 type IO */
481: #define UPIO_MEM32BE (SERIAL_IO_MEM32BE) /* 32b big endian */
482: #define UPIO_MEM16 (SERIAL_IO_MEM16) /* 16b little endian */
483:
484: unsigned char quirks; /* internal quirks */
485:
486: /* internal quirks must be updated while holding port mutex */
487: #define UPQ_NO_TXEN_TEST BIT(0)
488:
489: unsigned int read_status_mask; /* driver specific */
490: unsigned int ignore_status_mask; /* driver specific */
491: struct uart_state *state; /* pointer to parent state */
492: struct uart_icount icount; /* statistics */
493:
494: struct console *cons; /* struct console, if any */
495: /* flags must be updated while holding port mutex */
496: upf_t flags;
497:
498: /*
499: * These flags must be equivalent to the flags defined in
500: * include/uapi/linux/tty_flags.h which are the userspace definitions
501: * assigned from the serial_struct flags in uart_set_info()
502: * [for bit definitions in the UPF_CHANGE_MASK]
503: *
504: * Bits [0..ASYNCB_LAST_USER] are userspace defined/visible/changeable
505: * The remaining bits are serial-core specific and not modifiable by
506: * userspace.
507: */
508: #ifdef CONFIG_HAS_IOPORT
509: #define UPF_FOURPORT ((__force upf_t) ASYNC_FOURPORT /* 1 */ )
510: #else
511: #define UPF_FOURPORT 0
512: #endif
513: #define UPF_SAK ((__force upf_t) ASYNC_SAK /* 2 */ )
514: #define UPF_SPD_HI ((__force upf_t) ASYNC_SPD_HI /* 4 */ )
515: #define UPF_SPD_VHI ((__force upf_t) ASYNC_SPD_VHI /* 5 */ )
516: #define UPF_SPD_CUST ((__force upf_t) ASYNC_SPD_CUST /* 0x0030 */ )
517: #define UPF_SPD_WARP ((__force upf_t) ASYNC_SPD_WARP /* 0x1010 */ )
518: #define UPF_SPD_MASK ((__force upf_t) ASYNC_SPD_MASK /* 0x1030 */ )
519: #define UPF_SKIP_TEST ((__force upf_t) ASYNC_SKIP_TEST /* 6 */ )
520: #define UPF_AUTO_IRQ ((__force upf_t) ASYNC_AUTO_IRQ /* 7 */ )
521: #define UPF_HARDPPS_CD ((__force upf_t) ASYNC_HARDPPS_CD /* 11 */ )
522: #define UPF_SPD_SHI ((__force upf_t) ASYNC_SPD_SHI /* 12 */ )
523: #define UPF_LOW_LATENCY ((__force upf_t) ASYNC_LOW_LATENCY /* 13 */ )
524: #define UPF_BUGGY_UART ((__force upf_t) ASYNC_BUGGY_UART /* 14 */ )
525: #define UPF_MAGIC_MULTIPLIER ((__force upf_t) ASYNC_MAGIC_MULTIPLIER /* 16 */ )
526:
527: #define UPF_NO_THRE_TEST ((__force upf_t) BIT_ULL(19))
528: /* Port has hardware-assisted h/w flow control */
529: #define UPF_AUTO_CTS ((__force upf_t) BIT_ULL(20))
530: #define UPF_AUTO_RTS ((__force upf_t) BIT_ULL(21))
531: #define UPF_HARD_FLOW ((__force upf_t) (UPF_AUTO_CTS | UPF_AUTO_RTS))
532: /* Port has hardware-assisted s/w flow control */
533: #define UPF_SOFT_FLOW ((__force upf_t) BIT_ULL(22))
534: #define UPF_CONS_FLOW ((__force upf_t) BIT_ULL(23))
535: #define UPF_SHARE_IRQ ((__force upf_t) BIT_ULL(24))
536: #define UPF_EXAR_EFR ((__force upf_t) BIT_ULL(25))
537: #define UPF_BUG_THRE ((__force upf_t) BIT_ULL(26))
538: /* The exact UART type is known and should not be probed. */
539: #define UPF_FIXED_TYPE ((__force upf_t) BIT_ULL(27))
540: #define UPF_BOOT_AUTOCONF ((__force upf_t) BIT_ULL(28))
541: #define UPF_FIXED_PORT ((__force upf_t) BIT_ULL(29))
542: #define UPF_DEAD ((__force upf_t) BIT_ULL(30))
543: #define UPF_IOREMAP ((__force upf_t) BIT_ULL(31))
544: #define UPF_FULL_PROBE ((__force upf_t) BIT_ULL(32))
545:
546: #define __UPF_CHANGE_MASK 0x17fff
547: #define UPF_CHANGE_MASK ((__force upf_t) __UPF_CHANGE_MASK)
548: #define UPF_USR_MASK ((__force upf_t) (UPF_SPD_MASK|UPF_LOW_LATENCY))
549:
550: #if __UPF_CHANGE_MASK > ASYNC_FLAGS
551: #error Change mask not equivalent to userspace-visible bit defines
552: #endif
553:
554: /*
555: * Must hold termios_rwsem, port mutex and port lock to change;
556: * can hold any one lock to read.
557: */
558: upstat_t status;
559:
560: #define UPSTAT_CTS_ENABLE ((__force upstat_t) (1 << 0))
561: #define UPSTAT_DCD_ENABLE ((__force upstat_t) (1 << 1))
562: #define UPSTAT_AUTORTS ((__force upstat_t) (1 << 2))
563: #define UPSTAT_AUTOCTS ((__force upstat_t) (1 << 3))
564: #define UPSTAT_AUTOXOFF ((__force upstat_t) (1 << 4))
565: #define UPSTAT_SYNC_FIFO ((__force upstat_t) (1 << 5))
566:
567: bool hw_stopped; /* sw-assisted CTS flow state */
568: unsigned int mctrl; /* current modem ctrl settings */
569: unsigned int frame_time; /* frame timing in ns */
570: unsigned int type; /* port type */
571: const struct uart_ops *ops;
572: unsigned int custom_divisor;
573: unsigned int line; /* port index */
574: unsigned int minor;
575: resource_size_t mapbase; /* for ioremap */
576: resource_size_t mapsize;
577: struct device *dev; /* serial port physical parent device */
578: struct serial_port_device *port_dev; /* serial core port device */
579:
580: unsigned long sysrq; /* sysrq timeout */
581: u8 sysrq_ch; /* char for sysrq */
582: unsigned char has_sysrq;
583: unsigned char sysrq_seq; /* index in sysrq_toggle_seq */
584:
585: unsigned char hub6; /* this should be in the 8250 driver */
586: unsigned char suspended;
587: unsigned char console_reinit;
588: const char *name; /* port name */
589: struct attribute_group *attr_group; /* port specific attributes */
590: const struct attribute_group **tty_groups; /* all attributes (serial core use only) */
591: struct serial_rs485 rs485;
592: struct serial_rs485 rs485_supported; /* Supported mask for serial_rs485 */
593: struct gpio_desc *rs485_term_gpio; /* enable RS485 bus termination */
594: struct gpio_desc *rs485_rx_during_tx_gpio; /* Output GPIO that sets the state of RS485 RX during TX */
595: struct serial_iso7816 iso7816;
596: void *private_data; /* generic platform data pointer */
597: };
SourceFile:include/linux/serial_core.h]
|
| 18/2 |
2026/05/26 02:30 |
llm |
expert |
0m
Model:
Tokens:
input: 35970
output: 41
thoughts: 26
Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience:
**Diving into the UART State**
Right, so `xmit_buf`... that rings a bell. Pretty sure that lives within the `struct uart_state`. Let me just quickly verify my mental model here. Okay, time to crack open the definition of `struct uart_state`. I need to ensure that the buffer management for transmission is located where I expect it to be. This is all about confirming the data structure layout, understanding the dependencies, and making sure my assumptions about where the transmit buffer resides are correct before I move on. No surprises are welcome at this stage. It's about building that mental map of the module's inner workings.
|
| 19/2 |
2026/05/26 02:30 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:include/linux/serial_core.h IncludeLines:true Name:uart_state]
Results: map[SourceCode: 811: /*
812: * This is the state information which is persistent across opens.
813: */
814: struct uart_state {
815: struct tty_port port;
816:
817: enum uart_pm_state pm_state;
818:
819: atomic_t refcount;
820: wait_queue_head_t remove_wait;
821: struct uart_port *uart_port;
822: };
SourceFile:include/linux/serial_core.h]
|
| 20/2 |
2026/05/26 02:30 |
llm |
expert |
0m
Model:
Tokens:
input: 36377
output: 39
thoughts: 29
Thoughts: Here's my take on the thought process, as requested:
**Navigating the TTY Structure**
Okay, so I'm looking at this code, and the key buffer, the `xmit_buf`, is apparently tucked away in the `struct tty_port`. Right, makes sense, that's where the core port-specific data would reside. Let's make sure I'm following the correct path, and just double-check the definition of `struct tty_port`. Need to refresh my understanding of how that structure is organized. Gotta confirm that `xmit_buf` is really where I think it is and see what else is co-located with it, you know, any other relevant fields that might influence its behavior. Gotta make sure I'm not missing anything obvious in the overall design. Let's dig in and review `struct tty_port` in detail.
|
| 21/2 |
2026/05/26 02:30 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:include/linux/tty.h IncludeLines:true Name:tty_port]
Results: map[SourceCode: 51: /**
52: * struct tty_port -- port level information
53: *
54: * @buf: buffer for this port, locked internally
55: * @tty: back pointer to &struct tty_struct, valid only if the tty is open. Use
56: * tty_port_tty_get() to obtain it (and tty_kref_put() to release).
57: * @itty: internal back pointer to &struct tty_struct. Avoid this. It should be
58: * eliminated in the long term.
59: * @ops: tty port operations (like activate, shutdown), see &struct
60: * tty_port_operations
61: * @client_ops: tty port client operations (like receive_buf, write_wakeup).
62: * By default, tty_port_default_client_ops is used.
63: * @lock: lock protecting @tty
64: * @blocked_open: # of procs waiting for open in tty_port_block_til_ready()
65: * @count: usage count
66: * @open_wait: open waiters queue (waiting e.g. for a carrier)
67: * @delta_msr_wait: modem status change queue (waiting for MSR changes)
68: * @flags: user TTY flags (%ASYNC_)
69: * @iflags: internal flags (%TTY_PORT_)
70: * @console: when set, the port is a console
71: * @mutex: locking, for open, shutdown and other port operations
72: * @buf_mutex: @xmit_buf alloc lock
73: * @xmit_buf: optional xmit buffer used by some drivers
74: * @xmit_fifo: optional xmit buffer used by some drivers
75: * @close_delay: delay in jiffies to wait when closing the port
76: * @closing_wait: delay in jiffies for output to be sent before closing
77: * @drain_delay: set to zero if no pure time based drain is needed else set to
78: * size of fifo
79: * @kref: references counter. Reaching zero calls @ops->destruct() if non-%NULL
80: * or frees the port otherwise.
81: * @client_data: pointer to private data, for @client_ops
82: *
83: * Each device keeps its own port level information. &struct tty_port was
84: * introduced as a common structure for such information. As every TTY device
85: * shall have a backing tty_port structure, every driver can use these members.
86: *
87: * The tty port has a different lifetime to the tty so must be kept apart.
88: * In addition be careful as tty -> port mappings are valid for the life
89: * of the tty object but in many cases port -> tty mappings are valid only
90: * until a hangup so don't use the wrong path.
91: *
92: * Tty port shall be initialized by tty_port_init() and shut down either by
93: * tty_port_destroy() (refcounting not used), or tty_port_put() (refcounting).
94: *
95: * There is a lot of helpers around &struct tty_port too. To name the most
96: * significant ones: tty_port_open(), tty_port_close() (or
97: * tty_port_close_start() and tty_port_close_end() separately if need be), and
98: * tty_port_hangup(). These call @ops->activate() and @ops->shutdown() as
99: * needed.
100: */
101: struct tty_port {
102: struct tty_bufhead buf;
103: struct tty_struct *tty;
104: struct tty_struct *itty;
105: const struct tty_port_operations *ops;
106: const struct tty_port_client_operations *client_ops;
107: spinlock_t lock;
108: int blocked_open;
109: int count;
110: wait_queue_head_t open_wait;
111: wait_queue_head_t delta_msr_wait;
112: unsigned long flags;
113: unsigned long iflags;
114: unsigned char console:1;
115: struct mutex mutex;
116: struct mutex buf_mutex;
117: u8 *xmit_buf;
118: DECLARE_KFIFO_PTR(xmit_fifo, u8);
119: unsigned int close_delay;
120: unsigned int closing_wait;
121: int drain_delay;
122: struct kref kref;
123: void *client_data;
124: };
SourceFile:include/linux/tty_port.h]
|
| 22/2 |
2026/05/26 02:30 |
llm |
expert |
0m
Model:
Tokens:
input: 38034
output: 45
thoughts: 106
Thoughts: **Analyzing the UART Transmit FIFO**
Okay, so I'm looking at this code and I see `xmit_fifo` – ah, right, it's defined as a `DECLARE_KFIFO_PTR(xmit_fifo, u8)`. Got it. Let's see how the write room is handled. It seems like `uart_write_room` calls `kfifo_avail(&state->port.xmit_fifo)`. Now, a quick question pops up: if `xmit_buf` is actually NULL at any given point, what will `kfifo_avail` return in that scenario? I need to understand that edge case. Wait, hold on... `kfifo_avail` is a macro, of course! So, I need to look at the macro definition to truly understand its behavior. Alright, let's trace back and make sure I understand the initialization of this `xmit_fifo` structure completely, so I can have the full context before diving any deeper.
|
| 23/2 |
2026/05/26 02:30 |
tool |
codesearch-find-references |
0m
Error:
Args: map[ContextFile:drivers/tty/serial/serial_core.c IncludeSnippetLines:0 Name:xmit_fifo]
Results: map[References:<nil> TruncatedOutput:false]
|
| 24/2 |
2026/05/26 02:30 |
llm |
expert |
0m
Model:
Tokens:
input: 38419
output: 18
thoughts: 25
Thoughts: Here's my thought process, as requested:
**Debugging a Serial Driver Issue**
Okay, I'm diving into this serial driver issue. My initial instinct is to pinpoint where the `xmit_fifo` is being used, right? That's probably the key data structure or function related to the problem. So, I need to understand its context. I'm going to quickly grep the `drivers/tty/serial/serial_core.c` file for the string `xmit_fifo`. This should give me a good starting point to trace the code and see how it’s being manipulated. Hopefully, the results will point to the relevant functions and data flows. That should provide the necessary context to begin digging into the problem.
|
| 25/2 |
2026/05/26 02:30 |
tool |
grepper |
0m
Args: map[Expression:xmit_fifo]
Results: map[Output:
Full output is too long, showing 500 out of 1381 lines.
Use more precise expression if possible.
[Documentation/ABI/testing/sysfs-tty=71=Description:
--
Documentation/ABI/testing/sysfs-tty-76-
Documentation/ABI/testing/sysfs-tty:77:What: /sys/class/tty/ttyS<x>/xmit_fifo_size
Documentation/ABI/testing/sysfs-tty-78-Date: October 2012
--
drivers/mmc/core/sdio_uart.c=64=struct sdio_uart_port {
--
drivers/mmc/core/sdio_uart.c-70- unsigned int regs_offset;
drivers/mmc/core/sdio_uart.c:71: struct kfifo xmit_fifo;
drivers/mmc/core/sdio_uart.c-72- spinlock_t write_lock;
--
drivers/mmc/core/sdio_uart.c=87=static int sdio_uart_add_port(struct sdio_uart_port *port)
--
drivers/mmc/core/sdio_uart.c-92- spin_lock_init(&port->write_lock);
drivers/mmc/core/sdio_uart.c:93: if (kfifo_alloc(&port->xmit_fifo, FIFO_SIZE, GFP_KERNEL))
drivers/mmc/core/sdio_uart.c-94- return -ENOMEM;
--
drivers/mmc/core/sdio_uart.c=407=static void sdio_uart_transmit_chars(struct sdio_uart_port *port)
drivers/mmc/core/sdio_uart.c-408-{
drivers/mmc/core/sdio_uart.c:409: struct kfifo *xmit = &port->xmit_fifo;
drivers/mmc/core/sdio_uart.c-410- int count;
--
drivers/mmc/core/sdio_uart.c=576=static int sdio_uart_activate(struct tty_port *tport, struct tty_struct *tty)
--
drivers/mmc/core/sdio_uart.c-587-
drivers/mmc/core/sdio_uart.c:588: kfifo_reset(&port->xmit_fifo);
drivers/mmc/core/sdio_uart.c-589-
--
drivers/mmc/core/sdio_uart.c=691=static void sdio_uart_port_destroy(struct tty_port *tport)
--
drivers/mmc/core/sdio_uart.c-694- container_of(tport, struct sdio_uart_port, port);
drivers/mmc/core/sdio_uart.c:695: kfifo_free(&port->xmit_fifo);
drivers/mmc/core/sdio_uart.c-696- kfree(port);
--
drivers/mmc/core/sdio_uart.c=759=static ssize_t sdio_uart_write(struct tty_struct *tty, const u8 *buf,
--
drivers/mmc/core/sdio_uart.c-767-
drivers/mmc/core/sdio_uart.c:768: ret = kfifo_in_locked(&port->xmit_fifo, buf, count, &port->write_lock);
drivers/mmc/core/sdio_uart.c-769- if (!(port->ier & UART_IER_THRI)) {
--
drivers/mmc/core/sdio_uart.c=782=static unsigned int sdio_uart_write_room(struct tty_struct *tty)
--
drivers/mmc/core/sdio_uart.c-784- struct sdio_uart_port *port = tty->driver_data;
drivers/mmc/core/sdio_uart.c:785: return FIFO_SIZE - kfifo_len(&port->xmit_fifo);
drivers/mmc/core/sdio_uart.c-786-}
--
drivers/mmc/core/sdio_uart.c=788=static unsigned int sdio_uart_chars_in_buffer(struct tty_struct *tty)
--
drivers/mmc/core/sdio_uart.c-790- struct sdio_uart_port *port = tty->driver_data;
drivers/mmc/core/sdio_uart.c:791: return kfifo_len(&port->xmit_fifo);
drivers/mmc/core/sdio_uart.c-792-}
--
drivers/net/can/xilinx_can.c=651=static void xcan_write_frame(struct net_device *ndev, struct sk_buff *skb,
--
drivers/net/can/xilinx_can.c-735-/**
drivers/net/can/xilinx_can.c:736: * xcan_start_xmit_fifo - Starts the transmission (FIFO mode)
drivers/net/can/xilinx_can.c-737- * @skb: sk_buff pointer that contains data to be Txed
--
drivers/net/can/xilinx_can.c-741- */
drivers/net/can/xilinx_can.c:742:static int xcan_start_xmit_fifo(struct sk_buff *skb, struct net_device *ndev)
drivers/net/can/xilinx_can.c-743-{
--
drivers/net/can/xilinx_can.c=809=static netdev_tx_t xcan_start_xmit(struct sk_buff *skb, struct net_device *ndev)
--
drivers/net/can/xilinx_can.c-819- else
drivers/net/can/xilinx_can.c:820: ret = xcan_start_xmit_fifo(skb, ndev);
drivers/net/can/xilinx_can.c-821-
--
drivers/net/ethernet/dlink/dl2k.h=282=typedef union t_MII_PHY_SCR {
--
drivers/net/ethernet/dlink/dl2k.h-295- u16 rcv_fifo_depth:2; // bit 13:12
drivers/net/ethernet/dlink/dl2k.h:296: u16 xmit_fifo_depth:2; // bit 15:14
drivers/net/ethernet/dlink/dl2k.h-297- } bits;
--
drivers/tty/amiserial.c=892=static int get_serial_info(struct tty_struct *tty, struct serial_struct *ss)
--
drivers/tty/amiserial.c-905- ss->flags = state->tport.flags;
drivers/tty/amiserial.c:906: ss->xmit_fifo_size = XMIT_FIFO_SIZE;
drivers/tty/amiserial.c-907- ss->baud_base = state->baud_base;
--
drivers/tty/amiserial.c=915=static int set_serial_info(struct tty_struct *tty, struct serial_struct *ss)
--
drivers/tty/amiserial.c-926- if (ss->irq || ss->port != state->port ||
drivers/tty/amiserial.c:927: ss->xmit_fifo_size != XMIT_FIFO_SIZE) {
drivers/tty/amiserial.c-928- tty_unlock(tty);
--
drivers/tty/mxser.c=253=struct mxser_port {
--
drivers/tty/mxser.c-273- u8 ignore_status_mask;
drivers/tty/mxser.c:274: u8 xmit_fifo_size;
drivers/tty/mxser.c-275-
--
drivers/tty/mxser.c=416=static void mxser_process_txrx_fifo(struct mxser_port *info)
--
drivers/tty/mxser.c-422- info->rx_low_water = 1;
drivers/tty/mxser.c:423: info->xmit_fifo_size = 1;
drivers/tty/mxser.c-424- return;
--
drivers/tty/mxser.c-430- info->rx_high_water = Gpci_uart_info[i].rx_high_water;
drivers/tty/mxser.c:431: info->xmit_fifo_size = Gpci_uart_info[i].fifo_size;
drivers/tty/mxser.c-432- break;
--
drivers/tty/mxser.c=481=static int mxser_set_baud(struct tty_struct *tty, speed_t newspd)
--
drivers/tty/mxser.c-507- */
drivers/tty/mxser.c:508: timeout = (u64)info->xmit_fifo_size * HZ * 10 * quot;
drivers/tty/mxser.c-509- do_div(timeout, MXSER_BAUD_BASE);
--
drivers/tty/mxser.c=723=static int mxser_activate(struct tty_port *port, struct tty_struct *tty)
--
drivers/tty/mxser.c-796- clear_bit(TTY_IO_ERROR, &tty->flags);
drivers/tty/mxser.c:797: kfifo_reset(&port->xmit_fifo);
drivers/tty/mxser.c-798-
--
drivers/tty/mxser.c=880=static void mxser_flush_buffer(struct tty_struct *tty)
--
drivers/tty/mxser.c-885- spin_lock_irqsave(&info->slock, flags);
drivers/tty/mxser.c:886: kfifo_reset(&info->port.xmit_fifo);
drivers/tty/mxser.c-887-
--
drivers/tty/mxser.c=901=static ssize_t mxser_write(struct tty_struct *tty, const u8 *buf, size_t count)
--
drivers/tty/mxser.c-908- spin_lock_irqsave(&info->slock, flags);
drivers/tty/mxser.c:909: written = kfifo_in(&info->port.xmit_fifo, buf, count);
drivers/tty/mxser.c:910: is_empty = kfifo_is_empty(&info->port.xmit_fifo);
drivers/tty/mxser.c-911- spin_unlock_irqrestore(&info->slock, flags);
--
drivers/tty/mxser.c=920=static int mxser_put_char(struct tty_struct *tty, u8 ch)
--
drivers/tty/mxser.c-926- spin_lock_irqsave(&info->slock, flags);
drivers/tty/mxser.c:927: ret = kfifo_put(&info->port.xmit_fifo, ch);
drivers/tty/mxser.c-928- spin_unlock_irqrestore(&info->slock, flags);
--
drivers/tty/mxser.c=934=static void mxser_flush_chars(struct tty_struct *tty)
--
drivers/tty/mxser.c-937-
drivers/tty/mxser.c:938: if (kfifo_is_empty(&info->port.xmit_fifo) || tty->flow.stopped ||
drivers/tty/mxser.c-939- (tty->hw_stopped && !mxser_16550A_or_MUST(info)))
--
drivers/tty/mxser.c=945=static unsigned int mxser_write_room(struct tty_struct *tty)
--
drivers/tty/mxser.c-948-
drivers/tty/mxser.c:949: return kfifo_avail(&info->port.xmit_fifo);
drivers/tty/mxser.c-950-}
--
drivers/tty/mxser.c=952=static unsigned int mxser_chars_in_buffer(struct tty_struct *tty)
--
drivers/tty/mxser.c-955-
drivers/tty/mxser.c:956: return kfifo_len(&info->port.xmit_fifo);
drivers/tty/mxser.c-957-}
--
drivers/tty/mxser.c=1339=static void mxser_start(struct tty_struct *tty)
--
drivers/tty/mxser.c-1344- spin_lock_irqsave(&info->slock, flags);
drivers/tty/mxser.c:1345: if (!kfifo_is_empty(&info->port.xmit_fifo))
drivers/tty/mxser.c-1346- __mxser_start_tx(info);
--
drivers/tty/mxser.c=1394=static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
--
drivers/tty/mxser.c-1401-
drivers/tty/mxser.c:1402: if (info->xmit_fifo_size == 0)
drivers/tty/mxser.c-1403- return; /* Just in case.... */
--
drivers/tty/mxser.c-1412- */
drivers/tty/mxser.c:1413: char_time = (info->timeout - HZ / 50) / info->xmit_fifo_size;
drivers/tty/mxser.c-1414- char_time = char_time / 5;
--
drivers/tty/mxser.c=1566=static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port)
--
drivers/tty/mxser.c-1576-
drivers/tty/mxser.c:1577: if (kfifo_is_empty(&port->port.xmit_fifo) || tty->flow.stopped ||
drivers/tty/mxser.c-1578- (tty->hw_stopped && !mxser_16550A_or_MUST(port))) {
--
drivers/tty/mxser.c-1582-
drivers/tty/mxser.c:1583: count = port->xmit_fifo_size;
drivers/tty/mxser.c-1584- do {
--
drivers/tty/mxser.c-1586-
drivers/tty/mxser.c:1587: if (!kfifo_get(&port->port.xmit_fifo, &c))
drivers/tty/mxser.c-1588- break;
--
drivers/tty/mxser.c-1593-
drivers/tty/mxser.c:1594: if (kfifo_len(&port->port.xmit_fifo) < WAKEUP_CHARS)
drivers/tty/mxser.c-1595- tty_wakeup(tty);
drivers/tty/mxser.c-1596-
drivers/tty/mxser.c:1597: if (kfifo_is_empty(&port->port.xmit_fifo))
drivers/tty/mxser.c-1598- __mxser_stop_tx(port);
--
drivers/tty/serial/8250/8250_bcm7271.c=413=static int brcmuart_tx_dma(struct uart_8250_port *p)
--
drivers/tty/serial/8250/8250_bcm7271.c-419- if (uart_tx_stopped(&p->port) || priv->tx_running ||
drivers/tty/serial/8250/8250_bcm7271.c:420: kfifo_is_empty(&tport->xmit_fifo)) {
drivers/tty/serial/8250/8250_bcm7271.c-421- return 0;
--
drivers/tty/serial/8250/8250_bcm7271.c-426-
drivers/tty/serial/8250/8250_bcm7271.c:427: if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
drivers/tty/serial/8250/8250_bcm7271.c-428- uart_write_wakeup(&p->port);
--
drivers/tty/serial/8250/8250_bcm7271.c=536=static void brcmuart_tx_isr(struct uart_port *up, u32 isr)
--
drivers/tty/serial/8250/8250_bcm7271.c-548- priv->tx_running = false;
drivers/tty/serial/8250/8250_bcm7271.c:549: if (!kfifo_is_empty(&tport->xmit_fifo) && !uart_tx_stopped(up))
drivers/tty/serial/8250/8250_bcm7271.c-550- brcmuart_tx_dma(port_8250);
--
drivers/tty/serial/8250/8250_core.c=215=static void serial8250_backup_timeout(struct timer_list *t)
--
drivers/tty/serial/8250/8250_core.c-241- if ((iir & UART_IIR_NO_INT) && (up->ier & UART_IER_THRI) &&
drivers/tty/serial/8250/8250_core.c:242: (!kfifo_is_empty(&up->port.state->port.xmit_fifo) ||
drivers/tty/serial/8250/8250_core.c-243- up->port.x_char) &&
--
drivers/tty/serial/8250/8250_dma.c=14=static void __dma_tx_complete(void *param)
--
drivers/tty/serial/8250/8250_dma.c-30-
drivers/tty/serial/8250/8250_dma.c:31: if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
drivers/tty/serial/8250/8250_dma.c-32- uart_write_wakeup(&p->port);
--
drivers/tty/serial/8250/8250_dma.c=86=int serial8250_tx_dma(struct uart_8250_port *p)
--
drivers/tty/serial/8250/8250_dma.c-107-
drivers/tty/serial/8250/8250_dma.c:108: if (uart_tx_stopped(&p->port) || kfifo_is_empty(&tport->xmit_fifo)) {
drivers/tty/serial/8250/8250_dma.c-109- /* We have been called from __dma_tx_complete() */
--
drivers/tty/serial/8250/8250_dma.c-116-
drivers/tty/serial/8250/8250_dma.c:117: ret = kfifo_dma_out_prepare_mapped(&tport->xmit_fifo, sgl, ARRAY_SIZE(sgl),
drivers/tty/serial/8250/8250_dma.c-118- UART_XMIT_SIZE, dma->tx_addr);
--
drivers/tty/serial/8250/8250_exar.c=477=static void exar_shutdown(struct uart_port *port)
--
drivers/tty/serial/8250/8250_exar.c-491- usleep_range(1000, 1100);
drivers/tty/serial/8250/8250_exar.c:492: } while (!kfifo_is_empty(&tport->xmit_fifo) &&
drivers/tty/serial/8250/8250_exar.c-493- !tx_complete && i++ < 1000);
--
drivers/tty/serial/8250/8250_mtk.c=190=static int mtk8250_startup(struct uart_port *port)
--
drivers/tty/serial/8250/8250_mtk.c-201- data->rx_status = DMA_RX_START;
drivers/tty/serial/8250/8250_mtk.c:202: kfifo_reset(&port->state->port.xmit_fifo);
drivers/tty/serial/8250/8250_mtk.c-203- }
--
drivers/tty/serial/8250/8250_omap.c=1105=static void omap_8250_dma_tx_complete(void *param)
--
drivers/tty/serial/8250/8250_omap.c-1127-
drivers/tty/serial/8250/8250_omap.c:1128: if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
drivers/tty/serial/8250/8250_omap.c-1129- uart_write_wakeup(&p->port);
drivers/tty/serial/8250/8250_omap.c-1130-
drivers/tty/serial/8250/8250_omap.c:1131: if (!kfifo_is_empty(&tport->xmit_fifo) && !uart_tx_stopped(&p->port)) {
drivers/tty/serial/8250/8250_omap.c-1132- int ret;
--
drivers/tty/serial/8250/8250_omap.c=1149=static int omap_8250_tx_dma(struct uart_8250_port *p)
--
drivers/tty/serial/8250/8250_omap.c-1160- return 0;
drivers/tty/serial/8250/8250_omap.c:1161: if (uart_tx_stopped(&p->port) || kfifo_is_empty(&tport->xmit_fifo)) {
drivers/tty/serial/8250/8250_omap.c-1162-
--
drivers/tty/serial/8250/8250_omap.c-1176- sg_init_table(&sg, 1);
drivers/tty/serial/8250/8250_omap.c:1177: ret = kfifo_dma_out_prepare_mapped(&tport->xmit_fifo, &sg, 1,
drivers/tty/serial/8250/8250_omap.c-1178- UART_XMIT_SIZE, dma->tx_addr);
--
drivers/tty/serial/8250/8250_omap.c-1213- }
drivers/tty/serial/8250/8250_omap.c:1214: if (!kfifo_get(&tport->xmit_fifo, &c)) {
drivers/tty/serial/8250/8250_omap.c-1215- ret = -EINVAL;
--
drivers/tty/serial/8250/8250_omap.c-1219- /* now we need to recompute due to kfifo_get */
drivers/tty/serial/8250/8250_omap.c:1220: kfifo_dma_out_prepare_mapped(&tport->xmit_fifo, &sg, 1,
drivers/tty/serial/8250/8250_omap.c-1221- UART_XMIT_SIZE, dma->tx_addr);
--
drivers/tty/serial/8250/8250_omap.c=1315=static int omap_8250_dma_handle_irq(struct uart_port *port)
--
drivers/tty/serial/8250/8250_omap.c-1340- if (uart_tx_stopped(&up->port) ||
drivers/tty/serial/8250/8250_omap.c:1341: kfifo_is_empty(&up->port.state->port.xmit_fifo)) {
drivers/tty/serial/8250/8250_omap.c-1342- up->dma->tx_err = 0;
--
drivers/tty/serial/8250/8250_pci1xxxx.c=437=static void pci1xxxx_process_write_data(struct uart_port *port,
--
drivers/tty/serial/8250/8250_pci1xxxx.c-454- break;
drivers/tty/serial/8250/8250_pci1xxxx.c:455: if (kfifo_len(&tport->xmit_fifo) < UART_BURST_SIZE)
drivers/tty/serial/8250/8250_pci1xxxx.c-456- break;
drivers/tty/serial/8250/8250_pci1xxxx.c:457: if (WARN_ON(kfifo_out(&tport->xmit_fifo, (u8 *)&c, sizeof(c)) !=
drivers/tty/serial/8250/8250_pci1xxxx.c-458- sizeof(c)))
--
drivers/tty/serial/8250/8250_pci1xxxx.c-468-
drivers/tty/serial/8250/8250_pci1xxxx.c:469: if (!kfifo_get(&tport->xmit_fifo, &c))
drivers/tty/serial/8250/8250_pci1xxxx.c-470- break;
--
drivers/tty/serial/8250/8250_pci1xxxx.c-479- if (valid_burst_count &&
drivers/tty/serial/8250/8250_pci1xxxx.c:480: kfifo_len(&tport->xmit_fifo) >= UART_BURST_SIZE)
drivers/tty/serial/8250/8250_pci1xxxx.c-481- break;
--
drivers/tty/serial/8250/8250_pci1xxxx.c=485=static void pci1xxxx_tx_burst(struct uart_port *port, u32 uart_status)
--
drivers/tty/serial/8250/8250_pci1xxxx.c-498-
drivers/tty/serial/8250/8250_pci1xxxx.c:499: if ((uart_tx_stopped(port)) || kfifo_is_empty(&tport->xmit_fifo)) {
drivers/tty/serial/8250/8250_pci1xxxx.c-500- port->ops->stop_tx(port);
--
drivers/tty/serial/8250/8250_pci1xxxx.c-504- do {
drivers/tty/serial/8250/8250_pci1xxxx.c:505: valid_byte_count = kfifo_len(&tport->xmit_fifo);
drivers/tty/serial/8250/8250_pci1xxxx.c-506-
--
drivers/tty/serial/8250/8250_pci1xxxx.c-511- port->icount.tx++;
drivers/tty/serial/8250/8250_pci1xxxx.c:512: if (kfifo_is_empty(&tport->xmit_fifo))
drivers/tty/serial/8250/8250_pci1xxxx.c-513- break;
--
drivers/tty/serial/8250/8250_pci1xxxx.c-516-
drivers/tty/serial/8250/8250_pci1xxxx.c:517: if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
drivers/tty/serial/8250/8250_pci1xxxx.c-518- uart_write_wakeup(port);
--
drivers/tty/serial/8250/8250_pci1xxxx.c-524- */
drivers/tty/serial/8250/8250_pci1xxxx.c:525: if (kfifo_is_empty(&tport->xmit_fifo) &&
drivers/tty/serial/8250/8250_pci1xxxx.c-526- !(up->capabilities & UART_CAP_RPM))
--
drivers/tty/serial/8250/8250_port.c=1639=static void serial8250_start_tx(struct uart_port *port)
--
drivers/tty/serial/8250/8250_port.c-1646-
drivers/tty/serial/8250/8250_port.c:1647: if (!port->x_char && kfifo_is_empty(&port->state->port.xmit_fifo))
drivers/tty/serial/8250/8250_port.c-1648- return;
--
drivers/tty/serial/8250/8250_port.c=1792=void serial8250_tx_chars(struct uart_8250_port *up)
--
drivers/tty/serial/8250/8250_port.c-1805- }
drivers/tty/serial/8250/8250_port.c:1806: if (kfifo_is_empty(&tport->xmit_fifo)) {
drivers/tty/serial/8250/8250_port.c-1807- __stop_tx(up);
--
drivers/tty/serial/8250/8250_port.c-1840-
drivers/tty/serial/8250/8250_port.c:1841: if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
drivers/tty/serial/8250/8250_port.c-1842- uart_write_wakeup(port);
--
drivers/tty/serial/8250/8250_port.c-1848- */
drivers/tty/serial/8250/8250_port.c:1849: if (kfifo_is_empty(&tport->xmit_fifo) &&
drivers/tty/serial/8250/8250_port.c-1850- !(up->capabilities & UART_CAP_RPM))
--
drivers/tty/serial/amba-pl011.c=545=static void pl011_dma_tx_callback(void *data)
--
drivers/tty/serial/amba-pl011.c-571- if (!(dmacr & UART011_TXDMAE) || uart_tx_stopped(&uap->port) ||
drivers/tty/serial/amba-pl011.c:572: kfifo_is_empty(&tport->xmit_fifo)) {
drivers/tty/serial/amba-pl011.c-573- uap->dmatx.queued = false;
--
drivers/tty/serial/amba-pl011.c=596=static int pl011_dma_tx_refill(struct uart_amba_port *uap)
--
drivers/tty/serial/amba-pl011.c-610- */
drivers/tty/serial/amba-pl011.c:611: count = kfifo_len(&tport->xmit_fifo);
drivers/tty/serial/amba-pl011.c-612- if (count < (uap->fifosize >> 1)) {
--
drivers/tty/serial/amba-pl011.c-626-
drivers/tty/serial/amba-pl011.c:627: count = kfifo_out_peek(&tport->xmit_fifo, dmatx->buf, count);
drivers/tty/serial/amba-pl011.c-628- dmatx->len = count;
--
drivers/tty/serial/amba-pl011.c-669-
drivers/tty/serial/amba-pl011.c:670: if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
drivers/tty/serial/amba-pl011.c-671- uart_write_wakeup(&uap->port);
--
drivers/tty/serial/amba-pl011.c=1504=static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq)
--
drivers/tty/serial/amba-pl011.c-1514- }
drivers/tty/serial/amba-pl011.c:1515: if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(&uap->port)) {
drivers/tty/serial/amba-pl011.c-1516- pl011_stop_tx(&uap->port);
--
drivers/tty/serial/amba-pl011.c-1529-
drivers/tty/serial/amba-pl011.c:1530: if (!kfifo_peek(&tport->xmit_fifo, &c))
drivers/tty/serial/amba-pl011.c-1531- break;
--
drivers/tty/serial/amba-pl011.c-1535-
drivers/tty/serial/amba-pl011.c:1536: kfifo_skip(&tport->xmit_fifo);
drivers/tty/serial/amba-pl011.c-1537- }
drivers/tty/serial/amba-pl011.c-1538-
drivers/tty/serial/amba-pl011.c:1539: if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
drivers/tty/serial/amba-pl011.c-1540- uart_write_wakeup(&uap->port);
drivers/tty/serial/amba-pl011.c-1541-
drivers/tty/serial/amba-pl011.c:1542: if (kfifo_is_empty(&tport->xmit_fifo)) {
drivers/tty/serial/amba-pl011.c-1543- pl011_stop_tx(&uap->port);
--
drivers/tty/serial/ar933x_uart.c=391=static void ar933x_uart_tx_chars(struct ar933x_uart_port *up)
--
drivers/tty/serial/ar933x_uart.c-401- if ((rs485conf->flags & SER_RS485_ENABLED) &&
drivers/tty/serial/ar933x_uart.c:402: (up->port.x_char || !kfifo_is_empty(&tport->xmit_fifo))) {
drivers/tty/serial/ar933x_uart.c-403- ar933x_uart_stop_rx_interrupt(up);
--
drivers/tty/serial/ar933x_uart.c-429-
drivers/tty/serial/ar933x_uart.c:430: if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
drivers/tty/serial/ar933x_uart.c-431- uart_write_wakeup(&up->port);
drivers/tty/serial/ar933x_uart.c-432-
drivers/tty/serial/ar933x_uart.c:433: if (!kfifo_is_empty(&tport->xmit_fifo)) {
drivers/tty/serial/ar933x_uart.c-434- ar933x_uart_start_tx_interrupt(up);
--
drivers/tty/serial/arc_uart.c=156=static void arc_serial_tx_chars(struct uart_port *port)
--
drivers/tty/serial/arc_uart.c-177- */
drivers/tty/serial/arc_uart.c:178: if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
drivers/tty/serial/arc_uart.c-179- uart_write_wakeup(port);
--
drivers/tty/serial/atmel_serial.c=858=static void atmel_complete_tx_dma(void *arg)
--
drivers/tty/serial/atmel_serial.c-877-
drivers/tty/serial/atmel_serial.c:878: if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
drivers/tty/serial/atmel_serial.c-879- uart_write_wakeup(port);
--
drivers/tty/serial/atmel_serial.c-885- */
drivers/tty/serial/atmel_serial.c:886: if (!kfifo_is_empty(&tport->xmit_fifo))
drivers/tty/serial/atmel_serial.c-887- atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx);
--
drivers/tty/serial/atmel_serial.c=921=static void atmel_tx_dma(struct uart_port *port)
--
drivers/tty/serial/atmel_serial.c-934-
drivers/tty/serial/atmel_serial.c:935: if (!kfifo_is_empty(&tport->xmit_fifo) && !uart_tx_stopped(port)) {
drivers/tty/serial/atmel_serial.c-936- /*
--
drivers/tty/serial/atmel_serial.c-944- */
drivers/tty/serial/atmel_serial.c:945: tx_len = kfifo_out_linear(&tport->xmit_fifo, &tail,
drivers/tty/serial/atmel_serial.c-946- UART_XMIT_SIZE);
--
drivers/tty/serial/atmel_serial.c-1007-
drivers/tty/serial/atmel_serial.c:1008: if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
drivers/tty/serial/atmel_serial.c-1009- uart_write_wakeup(port);
--
drivers/tty/serial/atmel_serial.c=1442=static void atmel_tx_pdc(struct uart_port *port)
--
drivers/tty/serial/atmel_serial.c-1458-
drivers/tty/serial/atmel_serial.c:1459: if (!kfifo_is_empty(&tport->xmit_fifo) && !uart_tx_stopped(port)) {
drivers/tty/serial/atmel_serial.c-1460- unsigned int count, tail;
--
drivers/tty/serial/atmel_serial.c-1466-
drivers/tty/serial/atmel_serial.c:1467: count = kfifo_out_linear(&tport->xmit_fifo, &tail,
drivers/tty/serial/atmel_serial.c-1468- UART_XMIT_SIZE);
--
drivers/tty/serial/atmel_serial.c-1484-
drivers/tty/serial/atmel_serial.c:1485: if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
drivers/tty/serial/atmel_serial.c-1486- uart_write_wakeup(port);
--
drivers/tty/serial/clps711x.c=145=static irqreturn_t uart_clps711x_int_tx(int irq, void *dev_id)
--
drivers/tty/serial/clps711x.c-158-
drivers/tty/serial/clps711x.c:159: if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) {
drivers/tty/serial/clps711x.c-160- if (s->tx_enabled) {
--
drivers/tty/serial/clps711x.c-176-
drivers/tty/serial/clps711x.c:177: if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
drivers/tty/serial/clps711x.c-178- uart_write_wakeup(port);
--
drivers/tty/serial/cpm_uart.c=644=static int cpm_uart_tx_pump(struct uart_port *port)
--
drivers/tty/serial/cpm_uart.c-675-
drivers/tty/serial/cpm_uart.c:676: if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) {
drivers/tty/serial/cpm_uart.c-677- cpm_uart_stop_tx(port);
--
drivers/tty/serial/cpm_uart.c-684- while (!(in_be16(&bdp->cbd_sc) & BD_SC_READY) &&
drivers/tty/serial/cpm_uart.c:685: !kfifo_is_empty(&tport->xmit_fifo)) {
drivers/tty/serial/cpm_uart.c-686- p = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo);
--
drivers/tty/serial/cpm_uart.c-697-
drivers/tty/serial/cpm_uart.c:698: if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
drivers/tty/serial/cpm_uart.c-699- uart_write_wakeup(port);
drivers/tty/serial/cpm_uart.c-700-
drivers/tty/serial/cpm_uart.c:701: if (kfifo_is_empty(&tport->xmit_fifo)) {
drivers/tty/serial/cpm_uart.c-702- cpm_uart_stop_tx(port);
--
drivers/tty/serial/digicolor-usart.c=180=static void digicolor_uart_tx(struct uart_port *port)
--
drivers/tty/serial/digicolor-usart.c-197-
drivers/tty/serial/digicolor-usart.c:198: if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) {
drivers/tty/serial/digicolor-usart.c-199- digicolor_uart_stop_tx(port);
--
drivers/tty/serial/digicolor-usart.c-209-
drivers/tty/serial/digicolor-usart.c:210: if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
drivers/tty/serial/digicolor-usart.c-211- uart_write_wakeup(port);
--
drivers/tty/serial/dz.c=252=static inline void dz_transmit_chars(struct dz_mux *mux)
--
drivers/tty/serial/dz.c-283-
drivers/tty/serial/dz.c:284: if (kfifo_len(&tport->xmit_fifo) < DZ_WAKEUP_CHARS)
drivers/tty/serial/dz.c-285- uart_write_wakeup(&dport->port);
--
drivers/tty/serial/dz.c-287- /* Are we are done. */
drivers/tty/serial/dz.c:288: if (kfifo_is_empty(&tport->xmit_fifo)) {
drivers/tty/serial/dz.c-289- uart_port_lock(&dport->port);
--
drivers/tty/serial/fsl_linflexuart.c=175=static inline void linflex_transmit_buffer(struct uart_port *sport)
--
drivers/tty/serial/fsl_linflexuart.c-184-
drivers/tty/serial/fsl_linflexuart.c:185: if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
drivers/tty/serial/fsl_linflexuart.c-186- uart_write_wakeup(sport);
drivers/tty/serial/fsl_linflexuart.c-187-
drivers/tty/serial/fsl_linflexuart.c:188: if (kfifo_is_empty(&tport->xmit_fifo))
drivers/tty/serial/fsl_linflexuart.c-189- linflex_stop_tx(sport);
--
drivers/tty/serial/fsl_linflexuart.c=201=static irqreturn_t linflex_txint(int irq, void *dev_id)
--
drivers/tty/serial/fsl_linflexuart.c-213-
drivers/tty/serial/fsl_linflexuart.c:214: if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(sport)) {
drivers/tty/serial/fsl_linflexuart.c-215- linflex_stop_tx(sport);
--
drivers/tty/serial/fsl_lpuart.c=476=static void lpuart_dma_tx(struct lpuart_port *sport)
--
drivers/tty/serial/fsl_lpuart.c-487- sg_init_table(sgl, ARRAY_SIZE(sport->tx_sgl));
drivers/tty/serial/fsl_lpuart.c:488: sport->dma_tx_bytes = kfifo_len(&tport->xmit_fifo);
drivers/tty/serial/fsl_lpuart.c:489: sport->dma_tx_nents = kfifo_dma_out_prepare(&tport->xmit_fifo, sgl,
drivers/tty/serial/fsl_lpuart.c-490- ARRAY_SIZE(sport->tx_sgl), sport->dma_tx_bytes);
--
drivers/tty/serial/fsl_lpuart.c=516=static bool lpuart_stopped_or_empty(struct uart_port *port)
drivers/tty/serial/fsl_lpuart.c-517-{
drivers/tty/serial/fsl_lpuart.c:518: return kfifo_is_empty(&port->state->port.xmit_fifo) ||
drivers/tty/serial/fsl_lpuart.c-519- uart_tx_stopped(port);
]
]
|
| 26/2 |
2026/05/26 02:30 |
llm |
expert |
0m
Model:
Tokens:
input: 50974
output: 48
thoughts: 42
Thoughts: Okay, here's my interpretation of that thought process, tailored for an expert audience, and written in the first person:
**Initial Assessment of a Kernel FIFO Structure**
Right, so `xmit_fifo`, ah, it's a `struct kfifo`. Okay, that's straightforward. Now the key question is how this thing gets initialized. I need to refresh my memory on the buffer allocation within the `tty_port_alloc_xmit_buf` function. I have to see if there's anything unusual happening. Are we allocating a statically sized buffer? Dynamic? Using a custom allocator? Is it sized correctly for the intended application? Let's trace through the code and see exactly how they are setting this thing up. The devil's always in the details with these kinds of structures and how they are used, and this is where I'll find them.
|
| 27/2 |
2026/05/26 02:30 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/tty/tty_port.c IncludeLines:true Name:tty_port_alloc_xmit_buf]
Results: map[SourceCode: 245: int tty_port_alloc_xmit_buf(struct tty_port *port)
246: {
247: /* We may sleep in get_zeroed_page() */
248: mutex_lock(&port->buf_mutex);
249: if (port->xmit_buf == NULL) {
250: port->xmit_buf = (u8 *)get_zeroed_page(GFP_KERNEL);
251: if (port->xmit_buf)
252: kfifo_init(&port->xmit_fifo, port->xmit_buf, PAGE_SIZE);
253: }
254: mutex_unlock(&port->buf_mutex);
255: if (port->xmit_buf == NULL)
256: return -ENOMEM;
257: return 0;
258: }
SourceFile:drivers/tty/tty_port.c]
|
| 28/2 |
2026/05/26 02:30 |
llm |
expert |
0m
Model:
Tokens:
input: 51522
output: 41
thoughts: 224
Thoughts: **Analyzing the Serial Port Transmit Buffer Allocation**
Okay, so I'm looking at how this `tty_port_alloc_xmit_buf` function works. It allocates the `port->xmit_buf` and then initializes `port->xmit_fifo` with it, makes sense. But, if `port->xmit_buf` is NULL, which I need to think through a bit more. The code doesn't call `kfifo_init`. Hmmm, if `port->xmit_buf` *is* NULL, what happens to `kfifo_avail(&port->xmit_fifo)`? What will this function actually return?
Let's break down the `kfifo_avail` macro. Okay, it's `fifo->kfifo.mask + 1 - (fifo->kfifo.in - fifo->kfifo.out)`. Now, if `xmit_fifo` is zero-initialized because `port->xmit_buf` is NULL, then `mask` is 0, and both `in` and `out` are zero.
So, plugging that into the formula: `kfifo_avail` would return `0 + 1 - (0 - 0) = 1`! That's a surprising outcome.
Wait a minute, if `kfifo_avail` unexpectedly returns 1, that means `uart_write_room` will *also* return 1! That feels wrong and I need to be 100% sure this is correct. I should double-check the `kfifo_avail` macro to be certain that my line of reasoning is sound.
|
| 29/2 |
2026/05/26 02:30 |
tool |
codesearch-definition-source |
0m
Error:
Args: map[ContextFile:include/linux/kfifo.h IncludeLines:true Name:kfifo_avail]
Results: map[SourceCode: SourceFile:]
|
| 30/2 |
2026/05/26 02:30 |
llm |
expert |
0m
Model:
Tokens:
input: 52159
output: 19
thoughts: 22
Thoughts: Okay, here's my take on those thoughts, framed as an expert's internal monologue:
**Investigating Kernel FIFO Availability**
Right, let's get down to brass tacks. I need to understand the current state of availability within the kernel's FIFO implementation. My immediate thought is to zero in on the core header file. Specifically, I'm going to run a `grep` for the `kfifo_avail` symbol. That's usually where the critical functions and macro definitions related to checking available space within the FIFO would reside. `include/linux/kfifo.h` seems like the obvious starting point; it's the standard location for kernel-level FIFO interfaces. This should quickly reveal how the kernel determines if there's space for more data to be enqueued. I want to see how that space is actually calculated and what other functions are associated with that. This will give me the context I need.
|
| 31/2 |
2026/05/26 02:30 |
tool |
grepper |
0m
Error:
Args: map[Expression:define kfifo_avail]
Results:
|
| 32/2 |
2026/05/26 02:30 |
llm |
expert |
0m
Model:
Tokens:
input: 52409
output: 18
thoughts: 22
Thoughts: Here's my thought process, summarized as you requested:
**Investigating Kernel FIFO Availability**
Okay, let's dive into this. I need to understand how available space is calculated within a kernel FIFO. The obvious place to start is the header file where the kfifo structure itself is defined. That would be `include/linux/kfifo.h`. I'll be looking for a function or variable specifically related to checking or calculating the available space within the FIFO – something named, perhaps, `kfifo_avail`. It's likely a macro or inline function. Time to see what's in there.
|
| 33/2 |
2026/05/26 02:30 |
tool |
grepper |
0m
Args: map[Expression:kfifo_avail]
Results: map[Output:arch/powerpc/sysdev/fsl_rmu.c=388=fsl_rio_port_write_handler(int irq, void *dev_instance)
--
arch/powerpc/sysdev/fsl_rmu.c-419- */
arch/powerpc/sysdev/fsl_rmu.c:420: if (kfifo_avail(&pw->pw_fifo) >= RIO_PW_MSG_SIZE) {
arch/powerpc/sysdev/fsl_rmu.c-421- pw->port_write_msg.msg_count++;
--
arch/x86/kvm/hyperv.c=1931=static void hv_tlb_flush_enqueue(struct kvm_vcpu *vcpu,
--
arch/x86/kvm/hyperv.c-1947- */
arch/x86/kvm/hyperv.c:1948: if (count && entries && count < kfifo_avail(&tlb_flush_fifo->entries)) {
arch/x86/kvm/hyperv.c-1949- WARN_ON(kfifo_in(&tlb_flush_fifo->entries, entries, count) != count);
--
drivers/crypto/hisilicon/sec/sec_algs.c=421=static void sec_skcipher_alg_callback(struct sec_bd_info *sec_resp,
--
drivers/crypto/hisilicon/sec/sec_algs.c-503- (ctx->queue->havesoftqueue &&
drivers/crypto/hisilicon/sec/sec_algs.c:504: kfifo_avail(&ctx->queue->softqueue) >
drivers/crypto/hisilicon/sec/sec_algs.c-505- backlog_req->num_elements)) {
--
drivers/crypto/hisilicon/sec/sec_algs.c=707=static int sec_alg_skcipher_crypto(struct skcipher_request *skreq,
--
drivers/crypto/hisilicon/sec/sec_algs.c-811- (!queue->havesoftqueue ||
drivers/crypto/hisilicon/sec/sec_algs.c:812: kfifo_avail(&queue->softqueue) > steps)) ||
drivers/crypto/hisilicon/sec/sec_algs.c-813- !list_empty(&ctx->backlog)) {
--
drivers/firmware/arm_scmi/notify.c=579=int scmi_notify(const struct scmi_handle *handle, u8 proto_id, u8 evt_id,
--
drivers/firmware/arm_scmi/notify.c-597- }
drivers/firmware/arm_scmi/notify.c:598: if (kfifo_avail(&r_evt->proto->equeue.kfifo) < sizeof(eh) + len) {
drivers/firmware/arm_scmi/notify.c-599- dev_warn(handle->dev,
--
drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c=175=static void add_event_to_kfifo(pid_t pid, struct kfd_node *dev,
--
drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c-185- spin_lock(&client->lock);
drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c:186: if (kfifo_avail(&client->fifo) >= len) {
drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c-187- kfifo_in(&client->fifo, event_msg, len);
--
drivers/hid/hid-sensor-custom.c=416=static int hid_sensor_capture_sample(struct hid_sensor_hub_device *hsdev,
--
drivers/hid/hid-sensor-custom.c-441- header.timestamp = ktime_get_real_ns();
drivers/hid/hid-sensor-custom.c:442: if (kfifo_avail(&sensor_inst->data_fifo) >= required_size) {
drivers/hid/hid-sensor-custom.c-443- kfifo_in(&sensor_inst->data_fifo,
--
drivers/hid/hid-sensor-custom.c-448- }
drivers/hid/hid-sensor-custom.c:449: if (kfifo_avail(&sensor_inst->data_fifo) >= raw_len)
drivers/hid/hid-sensor-custom.c-450- kfifo_in(&sensor_inst->data_fifo, (unsigned char *)raw_data,
--
drivers/hid/wacom_sys.c=51=static void wacom_wac_queue_insert(struct hid_device *hdev,
--
drivers/hid/wacom_sys.c-56-
drivers/hid/wacom_sys.c:57: while (kfifo_avail(fifo) < size) {
drivers/hid/wacom_sys.c-58- if (!warned)
--
drivers/iio/buffer/kfifo_buf.c=141=static size_t iio_kfifo_buf_space_available(struct iio_buffer *r)
--
drivers/iio/buffer/kfifo_buf.c-146- mutex_lock(&kf->user_lock);
drivers/iio/buffer/kfifo_buf.c:147: avail = kfifo_avail(&kf->kf);
drivers/iio/buffer/kfifo_buf.c-148- mutex_unlock(&kf->user_lock);
--
drivers/platform/surface/surface_aggregator_cdev.c=93=static u32 ssam_cdev_notifier(struct ssam_event_notifier *nf, const struct ssam_event *in)
--
drivers/platform/surface/surface_aggregator_cdev.c-109- /* Make sure we have enough space. */
drivers/platform/surface/surface_aggregator_cdev.c:110: if (kfifo_avail(&client->buffer) < n) {
drivers/platform/surface/surface_aggregator_cdev.c-111- dev_warn(client->cdev->dev,
--
drivers/platform/surface/surface_dtx.c=596=static void sdtx_push_event(struct sdtx_device *ddev, struct sdtx_event *evt)
--
drivers/platform/surface/surface_dtx.c-607-
drivers/platform/surface/surface_dtx.c:608: if (likely(kfifo_avail(&client->buffer) >= len))
drivers/platform/surface/surface_dtx.c-609- kfifo_in(&client->buffer, (const u8 *)evt, len);
--
drivers/rapidio/devices/rio_mport_cdev.c=1375=static int rio_mport_add_event(struct mport_cdev_priv *priv,
--
drivers/rapidio/devices/rio_mport_cdev.c-1383- spin_lock(&priv->fifo_lock);
drivers/rapidio/devices/rio_mport_cdev.c:1384: overflow = kfifo_avail(&priv->event_fifo) < sizeof(*event)
drivers/rapidio/devices/rio_mport_cdev.c-1385- || kfifo_in(&priv->event_fifo, (unsigned char *)event,
--
drivers/rapidio/devices/tsi721.c=259=tsi721_pw_handler(struct tsi721_device *priv)
--
drivers/rapidio/devices/tsi721.c-276- spin_lock(&priv->pw_fifo_lock);
drivers/rapidio/devices/tsi721.c:277: if (kfifo_avail(&priv->pw_fifo) >= TSI721_RIO_PW_MSG_SIZE)
drivers/rapidio/devices/tsi721.c-278- kfifo_in(&priv->pw_fifo, pw_buf,
--
drivers/staging/greybus/uart.c=442=static unsigned int gb_tty_write_room(struct tty_struct *tty)
--
drivers/staging/greybus/uart.c-448- spin_lock_irqsave(&gb_tty->write_lock, flags);
drivers/staging/greybus/uart.c:449: room = kfifo_avail(&gb_tty->write_fifo);
drivers/staging/greybus/uart.c-450- spin_unlock_irqrestore(&gb_tty->write_lock, flags);
--
drivers/tty/mxser.c=945=static unsigned int mxser_write_room(struct tty_struct *tty)
--
drivers/tty/mxser.c-948-
drivers/tty/mxser.c:949: return kfifo_avail(&info->port.xmit_fifo);
drivers/tty/mxser.c-950-}
--
drivers/tty/n_gsm.c=4391=static unsigned int gsmtty_write_room(struct tty_struct *tty)
--
drivers/tty/n_gsm.c-4395- return 0;
drivers/tty/n_gsm.c:4396: return kfifo_avail(&dlci->fifo);
drivers/tty/n_gsm.c-4397-}
--
drivers/tty/nozomi.c=1623=static unsigned int ntty_write_room(struct tty_struct *tty)
--
drivers/tty/nozomi.c-1629- if (dc)
drivers/tty/nozomi.c:1630: room = kfifo_avail(&port->fifo_ul);
drivers/tty/nozomi.c-1631-
--
drivers/tty/serial/serial_core.c=640=static unsigned int uart_write_room(struct tty_struct *tty)
--
drivers/tty/serial/serial_core.c-647- port = uart_port_lock(state, flags);
drivers/tty/serial/serial_core.c:648: ret = kfifo_avail(&state->port.xmit_fifo);
drivers/tty/serial/serial_core.c-649- uart_port_unlock(port, flags);
--
drivers/usb/gadget/function/f_midi.c=364=static int f_midi_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
--
drivers/usb/gadget/function/f_midi.c-382- /* pre-allocate write usb requests to use on f_midi_transmit. */
drivers/usb/gadget/function/f_midi.c:383: while (kfifo_avail(&midi->in_req_fifo)) {
drivers/usb/gadget/function/f_midi.c-384- struct usb_request *req =
--
drivers/usb/gadget/function/u_serial.c=793=static unsigned int gs_write_room(struct tty_struct *tty)
--
drivers/usb/gadget/function/u_serial.c-800- if (port->port_usb)
drivers/usb/gadget/function/u_serial.c:801: room = kfifo_avail(&port->port_write_buf);
drivers/usb/gadget/function/u_serial.c-802- spin_unlock_irqrestore(&port->port_lock, flags);
--
drivers/usb/host/xhci-dbgtty.c=336=static unsigned int dbc_tty_write_room(struct tty_struct *tty)
--
drivers/usb/host/xhci-dbgtty.c-342- spin_lock_irqsave(&port->port_lock, flags);
drivers/usb/host/xhci-dbgtty.c:343: room = kfifo_avail(&port->port.xmit_fifo);
drivers/usb/host/xhci-dbgtty.c-344-
--
drivers/usb/serial/cypress_m8.c=790=static unsigned int cypress_write_room(struct tty_struct *tty)
--
drivers/usb/serial/cypress_m8.c-797- spin_lock_irqsave(&priv->lock, flags);
drivers/usb/serial/cypress_m8.c:798: room = kfifo_avail(&priv->write_fifo);
drivers/usb/serial/cypress_m8.c-799- spin_unlock_irqrestore(&priv->lock, flags);
--
drivers/usb/serial/generic.c=232=unsigned int usb_serial_generic_write_room(struct tty_struct *tty)
--
drivers/usb/serial/generic.c-241- spin_lock_irqsave(&port->lock, flags);
drivers/usb/serial/generic.c:242: room = kfifo_avail(&port->write_fifo);
drivers/usb/serial/generic.c-243- spin_unlock_irqrestore(&port->lock, flags);
--
drivers/usb/serial/io_ti.c=2073=static unsigned int edge_write_room(struct tty_struct *tty)
--
drivers/usb/serial/io_ti.c-2085- spin_lock_irqsave(&edge_port->ep_lock, flags);
drivers/usb/serial/io_ti.c:2086: room = kfifo_avail(&port->write_fifo);
drivers/usb/serial/io_ti.c-2087- spin_unlock_irqrestore(&edge_port->ep_lock, flags);
--
drivers/usb/serial/oti6858.c=366=static unsigned int oti6858_write_room(struct tty_struct *tty)
--
drivers/usb/serial/oti6858.c-372- spin_lock_irqsave(&port->lock, flags);
drivers/usb/serial/oti6858.c:373: room = kfifo_avail(&port->write_fifo);
drivers/usb/serial/oti6858.c-374- spin_unlock_irqrestore(&port->lock, flags);
--
drivers/usb/serial/ti_usb_3410_5052.c=815=static unsigned int ti_write_room(struct tty_struct *tty)
--
drivers/usb/serial/ti_usb_3410_5052.c-822- spin_lock_irqsave(&tport->tp_lock, flags);
drivers/usb/serial/ti_usb_3410_5052.c:823: room = kfifo_avail(&port->write_fifo);
drivers/usb/serial/ti_usb_3410_5052.c-824- spin_unlock_irqrestore(&tport->tp_lock, flags);
--
include/linux/kfifo.h=174=__kfifo_int_must_check_helper(int val)
--
include/linux/kfifo.h-295-/**
include/linux/kfifo.h:296: * kfifo_avail - returns the number of unused elements in the fifo
include/linux/kfifo.h-297- * @fifo: address of the fifo to be used
include/linux/kfifo.h-298- */
include/linux/kfifo.h:299:#define kfifo_avail(fifo) \
include/linux/kfifo.h-300-__kfifo_uint_must_check_helper( \
--
sound/soc/intel/avs/debugfs.c=18=static unsigned int __kfifo_fromio(struct kfifo *fifo, const void __iomem *src, unsigned int len)
--
sound/soc/intel/avs/debugfs.c-22-
sound/soc/intel/avs/debugfs.c:23: len = min(len, kfifo_avail(fifo));
sound/soc/intel/avs/debugfs.c-24- off = __fifo->in & __fifo->mask;
--
sound/usb/line6/driver.c=652=static void line6_hwdep_push_message(struct usb_line6 *line6)
--
sound/usb/line6/driver.c-656-
sound/usb/line6/driver.c:657: if (kfifo_avail(&line6->messages.fifo) >= line6->message_length) {
sound/usb/line6/driver.c-658- /* No race condition here, there's only one writer */
]
|
| 34/2 |
2026/05/26 02:30 |
llm |
expert |
0m
Model:
Tokens:
input: 56782
output: 41
thoughts: 21
Thoughts: Here's my attempt at summarizing the thought process, tailored for an expert audience:
**Diving into KFIFO Implementation**
Okay, so I need to understand this `kfifo` implementation better. Time to get my hands dirty. Let's start by pinpointing a specific area within `include/linux/kfifo.h`. I'm thinking around line 299 might be a good starting point. That likely marks the beginning of a crucial structure or function related to the core logic. I'm expecting to find either a data structure declaration or a key function implementation that handles core read or write operations, or perhaps the buffer management itself. Going in blind is not always the best, but the include suggests this is where the implementation lives, so that's where I will start, focusing on the details around line 299. Let's see what we've got.
|
| 35/2 |
2026/05/26 02:30 |
tool |
codesearch-definition-source |
0m
Error:
Args: map[ContextFile:include/linux/kfifo.h IncludeLines:true Name:kfifo_avail]
Results: map[SourceCode: SourceFile:]
|
| 36/2 |
2026/05/26 02:30 |
llm |
expert |
0m
Model:
Tokens:
input: 57051
output: 23
thoughts: 18
Thoughts: Here's my take on the `include/linux/kfifo.h` header file.
**Diving into the Kernel FIFO**
Alright, let's skip the abstractions for now and go straight to the source. I'm going to take a look at `include/linux/kfifo.h`. I've got a pretty good understanding of data structures, especially circular buffers, but I always find it useful to see how the kernel engineers implement these things. I'm expecting to see a highly optimized implementation, probably leveraging the compiler and processor's capabilities. I'm curious about how they handle the common concerns with FIFOs like concurrency, memory allocation (especially if it's dynamic), and overflow/underflow conditions. I'm looking for elegance, cleverness, and, of course, rock-solid reliability – what I'm hoping to get out of this is fresh inspiration for my own designs. Let's see what's in there.
|
| 37/2 |
2026/05/26 02:31 |
tool |
read-file |
0m
Args: map[File:include/linux/kfifo.h]
Results: map[Contents:/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* A generic kernel FIFO implementation
*
* Copyright (C) 2013 Stefani Seibold <stefani@seibold.net>
*/
#ifndef _LINUX_KFIFO_H
#define _LINUX_KFIFO_H
/*
* How to porting drivers to the new generic FIFO API:
*
* - Modify the declaration of the "struct kfifo *" object into a
* in-place "struct kfifo" object
* - Init the in-place object with kfifo_alloc() or kfifo_init()
* Note: The address of the in-place "struct kfifo" object must be
* passed as the first argument to this functions
* - Replace the use of __kfifo_put into kfifo_in and __kfifo_get
* into kfifo_out
* - Replace the use of kfifo_put into kfifo_in_spinlocked and kfifo_get
* into kfifo_out_spinlocked
* Note: the spinlock pointer formerly passed to kfifo_init/kfifo_alloc
* must be passed now to the kfifo_in_spinlocked and kfifo_out_spinlocked
* as the last parameter
* - The formerly __kfifo_* functions are renamed into kfifo_*
*/
/*
* Note about locking: There is no locking required until only one reader
* and one writer is using the fifo and no kfifo_reset() will be called.
* kfifo_reset_out() can be safely used, until it will be only called
* in the reader thread.
* For multiple writer and one reader there is only a need to lock the writer.
* And vice versa for only one writer and multiple reader there is only a need
* to lock the reader.
*/
#include <linux/array_size.h>
#include <linux/spinlock.h>
#include <linux/stddef.h>
#include <linux/types.h>
#include <asm/barrier.h>
#include <asm/errno.h>
struct scatterlist;
struct __kfifo {
unsigned int in;
unsigned int out;
unsigned int mask;
unsigned int esize;
void *data;
};
#define __STRUCT_KFIFO_COMMON(datatype, recsize, ptrtype) \
union { \
struct __kfifo kfifo; \
datatype *type; \
const datatype *const_type; \
char (*rectype)[recsize]; \
ptrtype *ptr; \
ptrtype const *ptr_const; \
}
#define __STRUCT_KFIFO(type, size, recsize, ptrtype) \
{ \
__STRUCT_KFIFO_COMMON(type, recsize, ptrtype); \
type buf[((size < 2) || (size & (size - 1))) ? -1 : size]; \
}
#define STRUCT_KFIFO(type, size) \
struct __STRUCT_KFIFO(type, size, 0, type)
#define __STRUCT_KFIFO_PTR(type, recsize, ptrtype) \
{ \
__STRUCT_KFIFO_COMMON(type, recsize, ptrtype); \
type buf[0]; \
}
#define STRUCT_KFIFO_PTR(type) \
struct __STRUCT_KFIFO_PTR(type, 0, type)
/*
* define compatibility "struct kfifo" for dynamic allocated fifos
*/
struct kfifo __STRUCT_KFIFO_PTR(unsigned char, 0, void);
#define STRUCT_KFIFO_REC_1(size) \
struct __STRUCT_KFIFO(unsigned char, size, 1, void)
#define STRUCT_KFIFO_REC_2(size) \
struct __STRUCT_KFIFO(unsigned char, size, 2, void)
/*
* define kfifo_rec types
*/
struct kfifo_rec_ptr_1 __STRUCT_KFIFO_PTR(unsigned char, 1, void);
struct kfifo_rec_ptr_2 __STRUCT_KFIFO_PTR(unsigned char, 2, void);
/*
* helper macro to distinguish between real in place fifo where the fifo
* array is a part of the structure and the fifo type where the array is
* outside of the fifo structure.
*/
#define __is_kfifo_ptr(fifo) \
(sizeof(*fifo) == sizeof(STRUCT_KFIFO_PTR(typeof(*(fifo)->type))))
/**
* DECLARE_KFIFO_PTR - macro to declare a fifo pointer object
* @fifo: name of the declared fifo
* @type: type of the fifo elements
*/
#define DECLARE_KFIFO_PTR(fifo, type) STRUCT_KFIFO_PTR(type) fifo
/**
* DECLARE_KFIFO - macro to declare a fifo object
* @fifo: name of the declared fifo
* @type: type of the fifo elements
* @size: the number of elements in the fifo, this must be a power of 2
*/
#define DECLARE_KFIFO(fifo, type, size) STRUCT_KFIFO(type, size) fifo
/**
* INIT_KFIFO - Initialize a fifo declared by DECLARE_KFIFO
* @fifo: name of the declared fifo datatype
*/
#define INIT_KFIFO(fifo) \
(void)({ \
typeof(&(fifo)) __tmp = &(fifo); \
struct __kfifo *__kfifo = &__tmp->kfifo; \
__kfifo->in = 0; \
__kfifo->out = 0; \
__kfifo->mask = __is_kfifo_ptr(__tmp) ? 0 : ARRAY_SIZE(__tmp->buf) - 1;\
__kfifo->esize = sizeof(*__tmp->buf); \
__kfifo->data = __is_kfifo_ptr(__tmp) ? NULL : __tmp->buf; \
})
/**
* DEFINE_KFIFO - macro to define and initialize a fifo
* @fifo: name of the declared fifo datatype
* @type: type of the fifo elements
* @size: the number of elements in the fifo, this must be a power of 2
*
* Note: the macro can be used for global and local fifo data type variables.
*/
#define DEFINE_KFIFO(fifo, type, size) \
DECLARE_KFIFO(fifo, type, size) = \
(typeof(fifo)) { \
{ \
{ \
.in = 0, \
.out = 0, \
.mask = __is_kfifo_ptr(&(fifo)) ? \
0 : \
ARRAY_SIZE((fifo).buf) - 1, \
.esize = sizeof(*(fifo).buf), \
.data = __is_kfifo_ptr(&(fifo)) ? \
NULL : \
(fifo).buf, \
} \
} \
}
static inline unsigned int __must_check
__kfifo_uint_must_check_helper(unsigned int val)
{
return val;
}
static inline int __must_check
__kfifo_int_must_check_helper(int val)
{
return val;
}
/**
* kfifo_initialized - Check if the fifo is initialized
* @fifo: address of the fifo to check
*
* Return %true if fifo is initialized, otherwise %false.
* Assumes the fifo was 0 before.
*/
#define kfifo_initialized(fifo) ((fifo)->kfifo.mask)
/**
* kfifo_esize - returns the size of the element managed by the fifo
* @fifo: address of the fifo to be used
*/
#define kfifo_esize(fifo) ((fifo)->kfifo.esize)
/**
* kfifo_recsize - returns the size of the record length field
* @fifo: address of the fifo to be used
*/
#define kfifo_recsize(fifo) (sizeof(*(fifo)->rectype))
/**
* kfifo_size - returns the size of the fifo in elements
* @fifo: address of the fifo to be used
*/
#define kfifo_size(fifo) ((fifo)->kfifo.mask + 1)
/**
* kfifo_reset - removes the entire fifo content
* @fifo: address of the fifo to be used
*
* Note: usage of kfifo_reset() is dangerous. It should be only called when the
* fifo is exclusived locked or when it is secured that no other thread is
* accessing the fifo.
*/
#define kfifo_reset(fifo) \
(void)({ \
typeof((fifo) + 1) __tmp = (fifo); \
__tmp->kfifo.in = __tmp->kfifo.out = 0; \
})
/**
* kfifo_reset_out - skip fifo content
* @fifo: address of the fifo to be used
*
* Note: The usage of kfifo_reset_out() is safe until it will be only called
* from the reader thread and there is only one concurrent reader. Otherwise
* it is dangerous and must be handled in the same way as kfifo_reset().
*/
#define kfifo_reset_out(fifo) \
(void)({ \
typeof((fifo) + 1) __tmp = (fifo); \
__tmp->kfifo.out = __tmp->kfifo.in; \
})
/**
* kfifo_len - returns the number of used elements in the fifo
* @fifo: address of the fifo to be used
*/
#define kfifo_len(fifo) \
({ \
typeof((fifo) + 1) __tmpl = (fifo); \
__tmpl->kfifo.in - __tmpl->kfifo.out; \
})
/**
* kfifo_is_empty - returns true if the fifo is empty
* @fifo: address of the fifo to be used
*/
#define kfifo_is_empty(fifo) \
({ \
typeof((fifo) + 1) __tmpq = (fifo); \
__tmpq->kfifo.in == __tmpq->kfifo.out; \
})
/**
* kfifo_is_empty_spinlocked - returns true if the fifo is empty using
* a spinlock for locking
* @fifo: address of the fifo to be used
* @lock: spinlock to be used for locking
*/
#define kfifo_is_empty_spinlocked(fifo, lock) \
({ \
unsigned long __flags; \
bool __ret; \
spin_lock_irqsave(lock, __flags); \
__ret = kfifo_is_empty(fifo); \
spin_unlock_irqrestore(lock, __flags); \
__ret; \
})
/**
* kfifo_is_empty_spinlocked_noirqsave - returns true if the fifo is empty
* using a spinlock for locking, doesn't disable interrupts
* @fifo: address of the fifo to be used
* @lock: spinlock to be used for locking
*/
#define kfifo_is_empty_spinlocked_noirqsave(fifo, lock) \
({ \
bool __ret; \
spin_lock(lock); \
__ret = kfifo_is_empty(fifo); \
spin_unlock(lock); \
__ret; \
})
/**
* kfifo_is_full - returns true if the fifo is full
* @fifo: address of the fifo to be used
*/
#define kfifo_is_full(fifo) \
({ \
typeof((fifo) + 1) __tmpq = (fifo); \
kfifo_len(__tmpq) > __tmpq->kfifo.mask; \
})
/**
* kfifo_avail - returns the number of unused elements in the fifo
* @fifo: address of the fifo to be used
*/
#define kfifo_avail(fifo) \
__kfifo_uint_must_check_helper( \
({ \
typeof((fifo) + 1) __tmpq = (fifo); \
const size_t __recsize = sizeof(*__tmpq->rectype); \
unsigned int __avail = kfifo_size(__tmpq) - kfifo_len(__tmpq); \
(__recsize) ? ((__avail <= __recsize) ? 0 : \
__kfifo_max_r(__avail - __recsize, __recsize)) : \
__avail; \
}) \
)
/**
* kfifo_skip_count - skip output data
* @fifo: address of the fifo to be used
* @count: count of data to skip
*/
#define kfifo_skip_count(fifo, count) do { \
typeof((fifo) + 1) __tmp = (fifo); \
const size_t __recsize = sizeof(*__tmp->rectype); \
struct __kfifo *__kfifo = &__tmp->kfifo; \
if (__recsize) \
__kfifo_skip_r(__kfifo, __recsize); \
else \
__kfifo->out += (count); \
} while(0)
/**
* kfifo_skip - skip output data
* @fifo: address of the fifo to be used
*/
#define kfifo_skip(fifo) kfifo_skip_count(fifo, 1)
/**
* kfifo_peek_len - gets the size of the next fifo record
* @fifo: address of the fifo to be used
*
* This function returns the size of the next fifo record in number of bytes.
*/
#define kfifo_peek_len(fifo) \
__kfifo_uint_must_check_helper( \
({ \
typeof((fifo) + 1) __tmp = (fifo); \
const size_t __recsize = sizeof(*__tmp->rectype); \
struct __kfifo *__kfifo = &__tmp->kfifo; \
(!__recsize) ? kfifo_len(__tmp) * sizeof(*__tmp->type) : \
__kfifo_len_r(__kfifo, __recsize); \
}) \
)
/**
* kfifo_alloc - dynamically allocates a new fifo buffer
* @fifo: pointer to the fifo
* @size: the number of elements in the fifo, this must be a power of 2
* @gfp_mask: get_free_pages mask, passed to kmalloc()
*
* This macro dynamically allocates a new fifo buffer.
*
* The number of elements will be rounded-up to a power of 2.
* The fifo will be release with kfifo_free().
* Return 0 if no error, otherwise an error code.
*/
#define kfifo_alloc(fifo, size, gfp_mask) \
__kfifo_int_must_check_helper( \
({ \
typeof((fifo) + 1) __tmp = (fifo); \
struct __kfifo *__kfifo = &__tmp->kfifo; \
__is_kfifo_ptr(__tmp) ? \
__kfifo_alloc(__kfifo, size, sizeof(*__tmp->type), gfp_mask) : \
-EINVAL; \
}) \
)
/**
* kfifo_free - frees the fifo
* @fifo: the fifo to be freed
*/
#define kfifo_free(fifo) \
({ \
typeof((fifo) + 1) __tmp = (fifo); \
struct __kfifo *__kfifo = &__tmp->kfifo; \
if (__is_kfifo_ptr(__tmp)) \
__kfifo_free(__kfifo); \
})
/**
* kfifo_init - initialize a fifo using a preallocated buffer
* @fifo: the fifo to assign the buffer
* @buffer: the preallocated buffer to be used
* @size: the size of the internal buffer, this have to be a power of 2
*
* This macro initializes a fifo using a preallocated buffer.
*
* The number of elements will be rounded-up to a power of 2.
* Return 0 if no error, otherwise an error code.
*/
#define kfifo_init(fifo, buffer, size) \
({ \
typeof((fifo) + 1) __tmp = (fifo); \
struct __kfifo *__kfifo = &__tmp->kfifo; \
__is_kfifo_ptr(__tmp) ? \
__kfifo_init(__kfifo, buffer, size, sizeof(*__tmp->type)) : \
-EINVAL; \
})
/**
* kfifo_put - put data into the fifo
* @fifo: address of the fifo to be used
* @val: the data to be added
*
* This macro copies the given value into the fifo.
* It returns 0 if the fifo was full. Otherwise it returns the number
* processed elements.
*
* Note that with only one concurrent reader and one concurrent
* writer, you don't need extra locking to use these macro.
*/
#define kfifo_put(fifo, val) \
({ \
typeof((fifo) + 1) __tmp = (fifo); \
typeof(*__tmp->const_type) __val = (val); \
unsigned int __ret; \
size_t __recsize = sizeof(*__tmp->rectype); \
struct __kfifo *__kfifo = &__tmp->kfifo; \
if (__recsize) \
__ret = __kfifo_in_r(__kfifo, &__val, sizeof(__val), \
__recsize); \
else { \
__ret = !kfifo_is_full(__tmp); \
if (__ret) { \
(__is_kfifo_ptr(__tmp) ? \
((typeof(__tmp->type))__kfifo->data) : \
(__tmp->buf) \
)[__kfifo->in & __tmp->kfifo.mask] = \
*(typeof(__tmp->type))&__val; \
smp_wmb(); \
__kfifo->in++; \
} \
} \
__ret; \
})
/**
* kfifo_get - get data from the fifo
* @fifo: address of the fifo to be used
* @val: address where to store the data
*
* This macro reads the data from the fifo.
* It returns 0 if the fifo was empty. Otherwise it returns the number
* processed elements.
*
* Note that with only one concurrent reader and one concurrent
* writer, you don't need extra locking to use these macro.
*/
#define kfifo_get(fifo, val) \
__kfifo_uint_must_check_helper( \
({ \
typeof((fifo) + 1) __tmp = (fifo); \
typeof(__tmp->ptr) __val = (val); \
unsigned int __ret; \
const size_t __recsize = sizeof(*__tmp->rectype); \
struct __kfifo *__kfifo = &__tmp->kfifo; \
if (__recsize) \
__ret = __kfifo_out_r(__kfifo, __val, sizeof(*__val), \
__recsize); \
else { \
__ret = !kfifo_is_empty(__tmp); \
if (__ret) { \
*(typeof(__tmp->type))__val = \
(__is_kfifo_ptr(__tmp) ? \
((typeof(__tmp->type))__kfifo->data) : \
(__tmp->buf) \
)[__kfifo->out & __tmp->kfifo.mask]; \
smp_wmb(); \
__kfifo->out++; \
} \
} \
__ret; \
}) \
)
/**
* kfifo_peek - get data from the fifo without removing
* @fifo: address of the fifo to be used
* @val: address where to store the data
*
* This reads the data from the fifo without removing it from the fifo.
* It returns 0 if the fifo was empty. Otherwise it returns the number
* processed elements.
*
* Note that with only one concurrent reader and one concurrent
* writer, you don't need extra locking to use these macro.
*/
#define kfifo_peek(fifo, val) \
__kfifo_uint_must_check_helper( \
({ \
typeof((fifo) + 1) __tmp = (fifo); \
typeof(__tmp->ptr) __val = (val); \
unsigned int __ret; \
const size_t __recsize = sizeof(*__tmp->rectype); \
struct __kfifo *__kfifo = &__tmp->kfifo; \
if (__recsize) \
__ret = __kfifo_out_peek_r(__kfifo, __val, sizeof(*__val), \
__recsize); \
else { \
__ret = !kfifo_is_empty(__tmp); \
if (__ret) { \
*(typeof(__tmp->type))__val = \
(__is_kfifo_ptr(__tmp) ? \
((typeof(__tmp->type))__kfifo->data) : \
(__tmp->buf) \
)[__kfifo->out & __tmp->kfifo.mask]; \
smp_wmb(); \
} \
} \
__ret; \
}) \
)
/**
* kfifo_in - put data into the fifo
* @fifo: address of the fifo to be used
* @buf: the data to be added
* @n: number of elements to be added
*
* This macro copies the given buffer into the fifo and returns the
* number of copied elements.
*
* Note that with only one concurrent reader and one concurrent
* writer, you don't need extra locking to use these macro.
*/
#define kfifo_in(fifo, buf, n) \
({ \
typeof((fifo) + 1) __tmp = (fifo); \
typeof(__tmp->ptr_const) __buf = (buf); \
unsigned long __n = (n); \
const size_t __recsize = sizeof(*__tmp->rectype); \
struct __kfifo *__kfifo = &__tmp->kfifo; \
(__recsize) ?\
__kfifo_in_r(__kfifo, __buf, __n, __recsize) : \
__kfifo_in(__kfifo, __buf, __n); \
})
/**
* kfifo_in_spinlocked - put data into the fifo using a spinlock for locking
* @fifo: address of the fifo to be used
* @buf: the data to be added
* @n: number of elements to be added
* @lock: pointer to the spinlock to use for locking
*
* This macro copies the given values buffer into the fifo and returns the
* number of copied elements.
*/
#define kfifo_in_spinlocked(fifo, buf, n, lock) \
({ \
unsigned long __flags; \
unsigned int __ret; \
spin_lock_irqsave(lock, __flags); \
__ret = kfifo_in(fifo, buf, n); \
spin_unlock_irqrestore(lock, __flags); \
__ret; \
})
/**
* kfifo_in_spinlocked_noirqsave - put data into fifo using a spinlock for
* locking, don't disable interrupts
* @fifo: address of the fifo to be used
* @buf: the data to be added
* @n: number of elements to be added
* @lock: pointer to the spinlock to use for locking
*
* This is a variant of kfifo_in_spinlocked() but uses spin_lock/unlock()
* for locking and doesn't disable interrupts.
*/
#define kfifo_in_spinlocked_noirqsave(fifo, buf, n, lock) \
({ \
unsigned int __ret; \
spin_lock(lock); \
__ret = kfifo_in(fifo, buf, n); \
spin_unlock(lock); \
__ret; \
})
/* alias for kfifo_in_spinlocked, will be removed in a future release */
#define kfifo_in_locked(fifo, buf, n, lock) \
kfifo_in_spinlocked(fifo, buf, n, lock)
/**
* kfifo_out - get data from the fifo
* @fifo: address of the fifo to be used
* @buf: pointer to the storage buffer
* @n: max. number of elements to get
*
* This macro gets some data from the fifo and returns the numbers of elements
* copied.
*
* Note that with only one concurrent reader and one concurrent
* writer, you don't need extra locking to use these macro.
*/
#define kfifo_out(fifo, buf, n) \
__kfifo_uint_must_check_helper( \
({ \
typeof((fifo) + 1) __tmp = (fifo); \
typeof(__tmp->ptr) __buf = (buf); \
unsigned long __n = (n); \
const size_t __recsize = sizeof(*__tmp->rectype); \
struct __kfifo *__kfifo = &__tmp->kfifo; \
(__recsize) ?\
__kfifo_out_r(__kfifo, __buf, __n, __recsize) : \
__kfifo_out(__kfifo, __buf, __n); \
}) \
)
/**
* kfifo_out_spinlocked - get data from the fifo using a spinlock for locking
* @fifo: address of the fifo to be used
* @buf: pointer to the storage buffer
* @n: max. number of elements to get
* @lock: pointer to the spinlock to use for locking
*
* This macro gets the data from the fifo and returns the numbers of elements
* copied.
*/
#define kfifo_out_spinlocked(fifo, buf, n, lock) \
__kfifo_uint_must_check_helper( \
({ \
unsigned long __flags; \
unsigned int __ret; \
spin_lock_irqsave(lock, __flags); \
__ret = kfifo_out(fifo, buf, n); \
spin_unlock_irqrestore(lock, __flags); \
__ret; \
}) \
)
/**
* kfifo_out_spinlocked_noirqsave - get data from the fifo using a spinlock
* for locking, don't disable interrupts
* @fifo: address of the fifo to be used
* @buf: pointer to the storage buffer
* @n: max. number of elements to get
* @lock: pointer to the spinlock to use for locking
*
* This is a variant of kfifo_out_spinlocked() which uses spin_lock/unlock()
* for locking and doesn't disable interrupts.
*/
#define kfifo_out_spinlocked_noirqsave(fifo, buf, n, lock) \
__kfifo_uint_must_check_helper( \
({ \
unsigned int __ret; \
spin_lock(lock); \
__ret = kfifo_out(fifo, buf, n); \
spin_unlock(lock); \
__ret; \
}) \
)
/* alias for kfifo_out_spinlocked, will be removed in a future release */
#define kfifo_out_locked(fifo, buf, n, lock) \
kfifo_out_spinlocked(fifo, buf, n, lock)
/**
* kfifo_from_user - puts some data from user space into the fifo
* @fifo: address of the fifo to be used
* @from: pointer to the data to be added
* @len: the length of the data to be added
* @copied: pointer to output variable to store the number of copied bytes
*
* This macro copies at most @len bytes from the @from into the
* fifo, depending of the available space and returns -EFAULT/0.
*
* Note that with only one concurrent reader and one concurrent
* writer, you don't need extra locking to use these macro.
*/
#define kfifo_from_user(fifo, from, len, copied) \
__kfifo_uint_must_check_helper( \
({ \
typeof((fifo) + 1) __tmp = (fifo); \
const void __user *__from = (from); \
unsigned int __len = (len); \
unsigned int *__copied = (copied); \
const size_t __recsize = sizeof(*__tmp->rectype); \
struct __kfifo *__kfifo = &__tmp->kfifo; \
(__recsize) ? \
__kfifo_from_user_r(__kfifo, __from, __len, __copied, __recsize) : \
__kfifo_from_user(__kfifo, __from, __len, __copied); \
}) \
)
/**
* kfifo_to_user - copies data from the fifo into user space
* @fifo: address of the fifo to be used
* @to: where the data must be copied
* @len: the size of the destination buffer
* @copied: pointer to output variable to store the number of copied bytes
*
* This macro copies at most @len bytes from the fifo into the
* @to buffer and returns -EFAULT/0.
*
* Note that with only one concurrent reader and one concurrent
* writer, you don't need extra locking to use these macro.
*/
#define kfifo_to_user(fifo, to, len, copied) \
__kfifo_int_must_check_helper( \
({ \
typeof((fifo) + 1) __tmp = (fifo); \
void __user *__to = (to); \
unsigned int __len = (len); \
unsigned int *__copied = (copied); \
const size_t __recsize = sizeof(*__tmp->rectype); \
struct __kfifo *__kfifo = &__tmp->kfifo; \
(__recsize) ? \
__kfifo_to_user_r(__kfifo, __to, __len, __copied, __recsize) : \
__kfifo_to_user(__kfifo, __to, __len, __copied); \
}) \
)
/**
* kfifo_dma_in_prepare_mapped - setup a scatterlist for DMA input
* @fifo: address of the fifo to be used
* @sgl: pointer to the scatterlist array
* @nents: number of entries in the scatterlist array
* @len: number of elements to transfer
* @dma: mapped dma address to fill into @sgl
*
* This macro fills a scatterlist for DMA input.
* It returns the number entries in the scatterlist array.
*
* Note that with only one concurrent reader and one concurrent
* writer, you don't need extra locking to use these macros.
*/
#define kfifo_dma_in_prepare_mapped(fifo, sgl, nents, len, dma) \
({ \
typeof((fifo) + 1) __tmp = (fifo); \
struct scatterlist *__sgl = (sgl); \
int __nents = (nents); \
unsigned int __len = (len); \
const size_t __recsize = sizeof(*__tmp->rectype); \
struct __kfifo *__kfifo = &__tmp->kfifo; \
(__recsize) ? \
__kfifo_dma_in_prepare_r(__kfifo, __sgl, __nents, __len, __recsize, \
dma) : \
__kfifo_dma_in_prepare(__kfifo, __sgl, __nents, __len, dma); \
})
#define kfifo_dma_in_prepare(fifo, sgl, nents, len) \
kfifo_dma_in_prepare_mapped(fifo, sgl, nents, len, DMA_MAPPING_ERROR)
/**
* kfifo_dma_in_finish - finish a DMA IN operation
* @fifo: address of the fifo to be used
* @len: number of bytes to received
*
* This macro finishes a DMA IN operation. The in counter will be updated by
* the len parameter. No error checking will be done.
*
* Note that with only one concurrent reader and one concurrent
* writer, you don't need extra locking to use these macros.
*/
#define kfifo_dma_in_finish(fifo, len) \
(void)({ \
typeof((fifo) + 1) __tmp = (fifo); \
unsigned int __len = (len); \
const size_t __recsize = sizeof(*__tmp->rectype); \
struct __kfifo *__kfifo = &__tmp->kfifo; \
if (__recsize) \
__kfifo_dma_in_finish_r(__kfifo, __len, __recsize); \
else \
__kfifo->in += __len / sizeof(*__tmp->type); \
})
/**
* kfifo_dma_out_prepare_mapped - setup a scatterlist for DMA output
* @fifo: address of the fifo to be used
* @sgl: pointer to the scatterlist array
* @nents: number of entries in the scatterlist array
* @len: number of elements to transfer
* @dma: mapped dma address to fill into @sgl
*
* This macro fills a scatterlist for DMA output which at most @len bytes
* to transfer.
* It returns the number entries in the scatterlist array.
* A zero means there is no space available and the scatterlist is not filled.
*
* Note that with only one concurrent reader and one concurrent
* writer, you don't need extra locking to use these macros.
*/
#define kfifo_dma_out_prepare_mapped(fifo, sgl, nents, len, dma) \
({ \
typeof((fifo) + 1) __tmp = (fifo); \
struct scatterlist *__sgl = (sgl); \
int __nents = (nents); \
unsigned int __len = (len); \
const size_t __recsize = sizeof(*__tmp->rectype); \
struct __kfifo *__kfifo = &__tmp->kfifo; \
(__recsize) ? \
__kfifo_dma_out_prepare_r(__kfifo, __sgl, __nents, __len, __recsize, \
dma) : \
__kfifo_dma_out_prepare(__kfifo, __sgl, __nents, __len, dma); \
})
#define kfifo_dma_out_prepare(fifo, sgl, nents, len) \
kfifo_dma_out_prepare_mapped(fifo, sgl, nents, len, DMA_MAPPING_ERROR)
/**
* kfifo_dma_out_finish - finish a DMA OUT operation
* @fifo: address of the fifo to be used
* @len: number of bytes transferred
*
* This macro finishes a DMA OUT operation. The out counter will be updated by
* the len parameter. No error checking will be done.
*
* Note that with only one concurrent reader and one concurrent
* writer, you don't need extra locking to use these macros.
*/
#define kfifo_dma_out_finish(fifo, len) do { \
typeof((fifo) + 1) ___tmp = (fifo); \
kfifo_skip_count(___tmp, (len) / sizeof(*___tmp->type)); \
} while (0)
/**
* kfifo_out_peek - gets some data from the fifo
* @fifo: address of the fifo to be used
* @buf: pointer to the storage buffer
* @n: max. number of elements to get
*
* This macro gets the data from the fifo and returns the numbers of elements
* copied. The data is not removed from the fifo.
*
* Note that with only one concurrent reader and one concurrent
* writer, you don't need extra locking to use these macro.
*/
#define kfifo_out_peek(fifo, buf, n) \
__kfifo_uint_must_check_helper( \
({ \
typeof((fifo) + 1) __tmp = (fifo); \
typeof(__tmp->ptr) __buf = (buf); \
unsigned long __n = (n); \
const size_t __recsize = sizeof(*__tmp->rectype); \
struct __kfifo *__kfifo = &__tmp->kfifo; \
(__recsize) ? \
__kfifo_out_peek_r(__kfifo, __buf, __n, __recsize) : \
__kfifo_out_peek(__kfifo, __buf, __n); \
}) \
)
/**
* kfifo_out_linear - gets a tail of/offset to available data
* @fifo: address of the fifo to be used
* @tail: pointer to an unsigned int to store the value of tail
* @n: max. number of elements to point at
*
* This macro obtains the offset (tail) to the available data in the fifo
* buffer and returns the
* numbers of elements available. It returns the available count till the end
* of data or till the end of the buffer. So that it can be used for linear
* data processing (like memcpy() of (@fifo->data + @tail) with count
* returned).
*
* Note that with only one concurrent reader and one concurrent
* writer, you don't need extra locking to use these macro.
*/
#define kfifo_out_linear(fifo, tail, n) \
__kfifo_uint_must_check_helper( \
({ \
typeof((fifo) + 1) __tmp = (fifo); \
unsigned int *__tail = (tail); \
unsigned long __n = (n); \
const size_t __recsize = sizeof(*__tmp->rectype); \
struct __kfifo *__kfifo = &__tmp->kfifo; \
(__recsize) ? \
__kfifo_out_linear_r(__kfifo, __tail, __n, __recsize) : \
__kfifo_out_linear(__kfifo, __tail, __n); \
}) \
)
/**
* kfifo_out_linear_ptr - gets a pointer to the available data
* @fifo: address of the fifo to be used
* @ptr: pointer to data to store the pointer to tail
* @n: max. number of elements to point at
*
* Similarly to kfifo_out_linear(), this macro obtains the pointer to the
* available data in the fifo buffer and returns the numbers of elements
* available. It returns the available count till the end of available data or
* till the end of the buffer. So that it can be used for linear data
* processing (like memcpy() of @ptr with count returned).
*
* Note that with only one concurrent reader and one concurrent
* writer, you don't need extra locking to use these macro.
*/
#define kfifo_out_linear_ptr(fifo, ptr, n) \
__kfifo_uint_must_check_helper( \
({ \
typeof((fifo) + 1) ___tmp = (fifo); \
unsigned int ___tail; \
unsigned int ___n = kfifo_out_linear(___tmp, &___tail, (n)); \
*(ptr) = ___tmp->kfifo.data + ___tail * kfifo_esize(___tmp); \
___n; \
}) \
)
extern int __kfifo_alloc(struct __kfifo *fifo, unsigned int size,
size_t esize, gfp_t gfp_mask);
extern void __kfifo_free(struct __kfifo *fifo);
extern int __kfifo_init(struct __kfifo *fifo, void *buffer,
unsigned int size, size_t esize);
extern unsigned int __kfifo_in(struct __kfifo *fifo,
const void *buf, unsigned int len);
extern unsigned int __kfifo_out(struct __kfifo *fifo,
void *buf, unsigned int len);
extern int __kfifo_from_user(struct __kfifo *fifo,
const void __user *from, unsigned long len, unsigned int *copied);
extern int __kfifo_to_user(struct __kfifo *fifo,
void __user *to, unsigned long len, unsigned int *copied);
extern unsigned int __kfifo_dma_in_prepare(struct __kfifo *fifo,
struct scatterlist *sgl, int nents, unsigned int len, dma_addr_t dma);
extern unsigned int __kfifo_dma_out_prepare(struct __kfifo *fifo,
struct scatterlist *sgl, int nents, unsigned int len, dma_addr_t dma);
extern unsigned int __kfifo_out_peek(struct __kfifo *fifo,
void *buf, unsigned int len);
extern unsigned int __kfifo_out_linear(struct __kfifo *fifo,
unsigned int *tail, unsigned int n);
extern unsigned int __kfifo_in_r(struct __kfifo *fifo,
const void *buf, unsigned int len, size_t recsize);
extern unsigned int __kfifo_out_r(struct __kfifo *fifo,
void *buf, unsigned int len, size_t recsize);
extern int __kfifo_from_user_r(struct __kfifo *fifo,
const void __user *from, unsigned long len, unsigned int *copied,
size_t recsize);
extern int __kfifo_to_user_r(struct __kfifo *fifo, void __user *to,
unsigned long len, unsigned int *copied, size_t recsize);
extern unsigned int __kfifo_dma_in_prepare_r(struct __kfifo *fifo,
struct scatterlist *sgl, int nents, unsigned int len, size_t recsize,
dma_addr_t dma);
extern void __kfifo_dma_in_finish_r(struct __kfifo *fifo,
unsigned int len, size_t recsize);
extern unsigned int __kfifo_dma_out_prepare_r(struct __kfifo *fifo,
struct scatterlist *sgl, int nents, unsigned int len, size_t recsize,
dma_addr_t dma);
extern unsigned int __kfifo_len_r(struct __kfifo *fifo, size_t recsize);
extern void __kfifo_skip_r(struct __kfifo *fifo, size_t recsize);
extern unsigned int __kfifo_out_peek_r(struct __kfifo *fifo,
void *buf, unsigned int len, size_t recsize);
extern unsigned int __kfifo_out_linear_r(struct __kfifo *fifo,
unsigned int *tail, unsigned int n, size_t recsize);
extern unsigned int __kfifo_max_r(unsigned int len, size_t recsize);
#endif
]
|
| 38/2 |
2026/05/26 02:31 |
llm |
expert |
0m
Model:
Tokens:
input: 67508
output: 43
thoughts: 1337
Thoughts: **Analyzing the CAIF Serial Driver's Infinite Loop**
Okay, let's break this down. I'm looking at this `kfifo_avail` macro and how it's used in the context of the CAIF serial driver. My first thought is to understand how the available space in the transmit FIFO (`xmit_fifo`) is calculated. The macro's definition is a bit convoluted, but essentially, it boils down to `kfifo_size(fifo) - kfifo_len(fifo)`.
Now, if `xmit_fifo` is zero-initialized, which seems to be the case before `tty_port_alloc_xmit_buf` is called (or skipped, which is the problem), the size is 1 and the length is 0, giving us an initial availability of 1.
The critical function seems to be `uart_write_room`. It calls `kfifo_avail` and returns the result. If `xmit_buf` is NULL, which it likely is in this particular scenario, `uart_write_room` ends up returning 1 because the FIFO is basically empty. However, `uart_write` will return 0 if `xmit_buf` is NULL.
So, the issue is that `uart_write_room` returns a misleading value, specifically 1, but `uart_write` will actually return 0 if `xmit_buf` is NULL.
I'm now tracing the execution within `handle_tx` in `drivers/net/caif/caif_serial.c`. The code checks if the `tty_write_room` function returns a non-zero value, it then sets the `len` to 1, as that is the minimum we would expect from a `skb->len`. Then it calls `tty->ops->write`, which ends up calling `uart_write`. Since `uart_write` returns 0 (due to the null `xmit_buf`), the problem is here.
This gives `tty_wr` to equal zero, but the code proceeds as if data *was* written. `skb_pull` does nothing because zero bytes were written. The loop then repeats, resulting in an infinite loop. This is because the `skb` is never fully consumed.
The critical piece seems to be the lack of a proper buffer allocation. The provided reproducer uses `openat` on `/dev/ttyS3` and then sets the line discipline to `N_CAIF`, bypassing the typical `tty_port_alloc_xmit_buf` call. So this calls the `uart_open` function in the serial core code. I need to examine what happens in the `uart_open` function next. This is most likely where the issue is.
|
| 39/2 |
2026/05/26 02:31 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/tty/serial/serial_core.c IncludeLines:true Name:uart_open]
Results: map[SourceCode:1959: /*
1960: * Calls to uart_open are serialised by the tty_lock in
1961: * drivers/tty/tty_io.c:tty_open()
1962: * Note that if this fails, then uart_close() _will_ be called.
1963: *
1964: * In time, we want to scrap the "opening nonpresent ports"
1965: * behaviour and implement an alternative way for setserial
1966: * to set base addresses/ports/types. This will allow us to
1967: * get rid of a certain amount of extra tests.
1968: */
1969: static int uart_open(struct tty_struct *tty, struct file *filp)
1970: {
1971: struct uart_state *state = tty->driver_data;
1972: int retval;
1973:
1974: retval = tty_port_open(&state->port, tty, filp);
1975: if (retval > 0)
1976: retval = 0;
1977:
1978: return retval;
1979: }
SourceFile:drivers/tty/serial/serial_core.c]
|
| 40/2 |
2026/05/26 02:31 |
llm |
expert |
0m
Model:
Tokens:
input: 69840
output: 43
thoughts: 44
Thoughts: Here's my thought process, as requested:
**Investigating tty_port_open and its Transmit Buffer Allocation**
Okay, so `tty_port_open` is calling `tty_port_alloc_xmit_buf`... that's interesting. I need to understand how the transmit buffer is allocated within the tty port initialization sequence. I'm going to jump into the `drivers/tty/tty_port.c` file and specifically examine the `tty_port_open` function. I need to see exactly how this allocation is triggered. I'm looking for the context; what conditions prompt that call? What kind of checks or initialization steps happen before that call? I want to see if there's any allocation failures and how they are handled. I need to understand the relationship between the `tty_port` structure and the allocated buffer, and how the buffer's size is determined and configured. Knowing this, I can start forming a mental model of tty driver resource management.
|
| 41/2 |
2026/05/26 02:31 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/tty/tty_port.c IncludeLines:true Name:tty_port_open]
Results: map[SourceCode: 746: /**
747: * tty_port_open - generic tty->ops->open handler
748: * @port: tty_port of the device
749: * @tty: tty to be opened
750: * @filp: passed file pointer
751: *
752: * It is a generic helper to be used in driver's @tty->ops->open. It activates
753: * the devices using @port->ops->activate if not active already. And waits for
754: * the device to be ready using tty_port_block_til_ready() (e.g. raises
755: * DTR/CTS and waits for carrier).
756: *
757: * Note that @port->ops->shutdown is not called when @port->ops->activate
758: * returns an error (on the contrary, @tty->ops->close is).
759: *
760: * Locking: Caller holds tty lock.
761: *
762: * Note: may drop and reacquire tty lock (in tty_port_block_til_ready()) so
763: * @tty and @port may have changed state (eg., may be hung up now).
764: */
765: int tty_port_open(struct tty_port *port, struct tty_struct *tty,
766: struct file *filp)
767: {
768: spin_lock_irq(&port->lock);
769: ++port->count;
770: spin_unlock_irq(&port->lock);
771: tty_port_tty_set(port, tty);
772:
773: /*
774: * Do the device-specific open only if the hardware isn't
775: * already initialized. Serialize open and shutdown using the
776: * port mutex.
777: */
778:
779: mutex_lock(&port->mutex);
780:
781: if (!tty_port_initialized(port)) {
782: clear_bit(TTY_IO_ERROR, &tty->flags);
783: if (port->ops->activate) {
784: int retval = port->ops->activate(port, tty);
785:
786: if (retval) {
787: mutex_unlock(&port->mutex);
788: return retval;
789: }
790: }
791: tty_port_set_initialized(port, true);
792: }
793: mutex_unlock(&port->mutex);
794: return tty_port_block_til_ready(port, tty, filp);
795: }
SourceFile:drivers/tty/tty_port.c]
|
| 42/2 |
2026/05/26 02:31 |
llm |
expert |
0m
Model:
Tokens:
input: 70953
output: 45
thoughts: 54
Thoughts: Okay, here's my thought process as I'd articulate it, considering I'm deep in this field:
**Decoding the `port->ops->activate` Call**
Alright, I'm looking at this call to `port->ops->activate`. Immediately, my brain is searching for the context. This is likely a device driver operation, and the `port` variable suggests it's related to some kind of port abstraction. Given the context, I'm betting this is about serial communications, specifically a `uart_port`. My first instinct is to zero in on what `port->ops->activate` *means* in the context of a UART. It's a key function pointer within that struct, so it’s critical for initialisation or turning on the device, possibly reconfiguring.
Where would I find the answer? My experience tells me that's in `drivers/tty/serial/serial_core.c`. I'm going to look for a function named, perhaps, `uart_port_activate` or something similar, likely in the same file. That's the most likely place where this port activation is implemented for the generic UART driver. I need to understand exactly what gets done when that activate function is called.
|
| 43/2 |
2026/05/26 02:31 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/tty/serial/serial_core.c IncludeLines:true Name:uart_port_activate]
Results: map[SourceCode:1981: static int uart_port_activate(struct tty_port *port, struct tty_struct *tty)
1982: {
1983: struct uart_state *state = container_of(port, struct uart_state, port);
1984: struct uart_port *uport;
1985: int ret;
1986:
1987: uport = uart_port_check(state);
1988: if (!uport || uport->flags & UPF_DEAD)
1989: return -ENXIO;
1990:
1991: /*
1992: * Start up the serial port.
1993: */
1994: ret = uart_startup(tty, state, false);
1995: if (ret > 0)
1996: tty_port_set_active(port, true);
1997:
1998: return ret;
1999: }
SourceFile:drivers/tty/serial/serial_core.c]
|
| 44/2 |
2026/05/26 02:31 |
llm |
expert |
0m
Model:
Tokens:
input: 71612
output: 43
thoughts: 9
Thoughts: Okay, here's my interpretation of that thought process, tailored for an expert audience, and written in the first person:
**Initial Assessment of the `uart_startup` Function**
Alright, time to get started. My immediate thought is, let's take a look at the `uart_startup` function. Given the context of embedded systems and serial communication, I'm already anticipating it's core purpose is setting up the UART hardware – configuring the baud rate, parity, data bits, stop bits, flow control, interrupt enables, and likely any necessary clock enable steps. I'll need to check how it initializes the peripheral registers and where it's called in the overall system initialization sequence. I want to see if it handles potential race conditions or critical sections well. My experience suggests that improper initialization here can lead to frustrating intermittent communication errors. Furthermore, it's worth examining the associated clock source selection and how the system deals with clock dividers, as this is a frequent source of UART performance issues, particularly on processors with multiple clock domains.
|
| 45/2 |
2026/05/26 02:31 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/tty/serial/serial_core.c IncludeLines:true Name:uart_startup]
Results: map[SourceCode: 357: static int uart_startup(struct tty_struct *tty, struct uart_state *state,
358: bool init_hw)
359: {
360: struct tty_port *port = &state->port;
361: struct uart_port *uport;
362: int retval;
363:
364: if (tty_port_initialized(port))
365: goto out_base_port_startup;
366:
367: retval = uart_port_startup(tty, state, init_hw);
368: if (retval) {
369: set_bit(TTY_IO_ERROR, &tty->flags);
370: return retval;
371: }
372:
373: out_base_port_startup:
374: uport = uart_port_check(state);
375: if (!uport)
376: return -EIO;
377:
378: serial_base_port_startup(uport);
379:
380: return 0;
381: }
SourceFile:drivers/tty/serial/serial_core.c]
|
| 46/2 |
2026/05/26 02:31 |
llm |
expert |
0m
Model:
Tokens:
input: 72244
output: 45
thoughts: 11
Thoughts: Okay, here's my attempt at summarizing that thought process, keeping in mind I'm speaking to a fellow expert:
**Investigating `uart_port_startup`**
Right, let's dive in. I need to refresh my memory on the startup sequence, particularly for the UART port. My immediate thought is to check the `uart_port_startup` function. Where does it fit into the broader picture? What are the key initialization steps it performs? I need to quickly ascertain if there are any potential bottlenecks or areas prone to issues within this function. I'm thinking about potential register configurations, interrupt enabling, baud rate setting, and perhaps any hardware-specific dependencies it might have. Understanding this function's exact role is vital for troubleshooting, and I need to solidify my understanding of it.
|
| 47/2 |
2026/05/26 02:31 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/tty/serial/serial_core.c IncludeLines:true Name:uart_port_startup]
Results: map[SourceCode: 301: /*
302: * Startup the port. This will be called once per open. All calls
303: * will be serialised by the per-port mutex.
304: */
305: static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
306: bool init_hw)
307: {
308: struct uart_port *uport = uart_port_check(state);
309: int retval;
310:
311: if (uport->type == PORT_UNKNOWN)
312: return 1;
313:
314: /*
315: * Make sure the device is in D0 state.
316: */
317: uart_change_pm(state, UART_PM_STATE_ON);
318:
319: retval = uart_alloc_xmit_buf(&state->port);
320: if (retval)
321: return retval;
322:
323: retval = uport->ops->startup(uport);
324: if (retval == 0) {
325: if (uart_console(uport) && uport->cons->cflag) {
326: tty->termios.c_cflag = uport->cons->cflag;
327: tty->termios.c_ispeed = uport->cons->ispeed;
328: tty->termios.c_ospeed = uport->cons->ospeed;
329: uport->cons->cflag = 0;
330: uport->cons->ispeed = 0;
331: uport->cons->ospeed = 0;
332: }
333: /*
334: * Initialise the hardware port settings.
335: */
336: uart_change_line_settings(tty, state, NULL);
337:
338: /*
339: * Setup the RTS and DTR signals once the
340: * port is open and ready to respond.
341: */
342: if (init_hw && C_BAUD(tty))
343: uart_port_dtr_rts(uport, true);
344: }
345:
346: /*
347: * This is to allow setserial on this port. People may want to set
348: * port/irq/type and then reconfigure the port properly if it failed
349: * now.
350: */
351: if (retval && capable(CAP_SYS_ADMIN))
352: return 1;
353:
354: return retval;
355: }
SourceFile:drivers/tty/serial/serial_core.c]
|
| 48/2 |
2026/05/26 02:31 |
llm |
expert |
0m
Model:
Tokens:
input: 73291
output: 48
thoughts: 40
Thoughts: Okay, here's my take on those thoughts, framed from a technical expert's perspective:
**Deep Dive into UART Initialization**
Alright, so `uart_port_startup`... that's where the UART peripheral comes alive, right? The key action there seems to be this call to `uart_alloc_xmit_buf(&state->port)`. That's where we're going to allocate the transmit buffer for this UART port. Now, before I go any further, I want to take a look at the code for `uart_alloc_xmit_buf`. I need to understand exactly how the buffer is being allocated, what memory region it's pulling from, if there's any allocation strategy in play (e.g., static, dynamic, DMA-friendly), and whether there are any potential race conditions that need to be considered if other threads are initializing UART ports simultaneously. We need to be able to understand the full picture here. I also need to verify that we are handling errors appropriately if the memory allocation fails.
|
| 49/2 |
2026/05/26 02:31 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/tty/serial/serial_core.c IncludeLines:true Name:uart_alloc_xmit_buf]
Results: map[SourceCode: 246: static int uart_alloc_xmit_buf(struct tty_port *port)
247: {
248: struct uart_state *state = container_of(port, struct uart_state, port);
249: struct uart_port *uport;
250: unsigned long flags;
251: unsigned long page;
252:
253: /*
254: * Initialise and allocate the transmit and temporary
255: * buffer.
256: */
257: page = get_zeroed_page(GFP_KERNEL);
258: if (!page)
259: return -ENOMEM;
260:
261: uport = uart_port_lock(state, flags);
262: if (!state->port.xmit_buf) {
263: state->port.xmit_buf = (unsigned char *)page;
264: kfifo_init(&state->port.xmit_fifo, state->port.xmit_buf,
265: PAGE_SIZE);
266: uart_port_unlock(uport, flags);
267: } else {
268: uart_port_unlock(uport, flags);
269: /*
270: * Do not free() the page under the port lock, see
271: * uart_free_xmit_buf().
272: */
273: free_page(page);
274: }
275:
276: return 0;
277: }
SourceFile:drivers/tty/serial/serial_core.c]
|
| 50/2 |
2026/05/26 02:31 |
llm |
expert |
0m
Model:
Tokens:
input: 74077
output: 43
thoughts: 122
Thoughts: **Debugging a Null Pointer Dereference in UART Transmission**
Okay, so I'm looking at this UART code, and something's not adding up. I see that `uart_alloc_xmit_buf` is supposed to allocate the `xmit_buf` and initialize the `xmit_fifo`. Pretty standard, makes sense. Now, based on the logic, if `uart_alloc_xmit_buf` gets called, `xmit_buf` *shouldn't* be NULL. But then, I'm getting a return value of 0 from `uart_write`, and that's because `!state->port.xmit_buf` is true, indicating `xmit_buf` is indeed NULL at that point! This doesn't compute.
How on earth is `xmit_buf` NULL when it should have been allocated? The only likely explanation is that something is freeing the buffer. I'm thinking maybe `uart_close` is the culprit. Let me jump into `drivers/tty/serial/serial_core.c` and take a closer look at what that function does. I need to understand when and how `xmit_buf` might be deallocated to track down this potential race condition or logic error.
|
| 51/2 |
2026/05/26 02:31 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/tty/serial/serial_core.c IncludeLines:true Name:uart_close]
Results: map[SourceCode:1735: /*
1736: * Calls to uart_close() are serialised via the tty_lock in
1737: * drivers/tty/tty_io.c:tty_release()
1738: * drivers/tty/tty_io.c:do_tty_hangup()
1739: */
1740: static void uart_close(struct tty_struct *tty, struct file *filp)
1741: {
1742: struct uart_state *state = tty->driver_data;
1743:
1744: if (!state) {
1745: struct uart_driver *drv = tty->driver->driver_state;
1746: struct tty_port *port;
1747:
1748: state = drv->state + tty->index;
1749: port = &state->port;
1750: spin_lock_irq(&port->lock);
1751: --port->count;
1752: spin_unlock_irq(&port->lock);
1753: return;
1754: }
1755:
1756: pr_debug("uart_close(%d) called\n", tty->index);
1757:
1758: tty_port_close(tty->port, tty, filp);
1759: }
SourceFile:drivers/tty/serial/serial_core.c]
|
| 52/2 |
2026/05/26 02:31 |
llm |
expert |
0m
Model:
Tokens:
input: 74921
output: 45
thoughts: 31
Thoughts: Here's my thought process, as requested:
**Investigating a UART Port Shutdown**
Okay, so `tty_port_close` calls the port's `ops->shutdown` function. That's the key. I need to understand what's happening during a shutdown, particularly for UART ports. My immediate instinct is to look at the standard implementations, which likely involve `uart_port_shutdown` or a function with a similar name within the UART driver framework. I'll need to examine that function, or whatever is the relevant equivalent in the specific driver I'm looking at, to understand the shutdown sequence: what resources are being released, what state is being cleared, and what, if any, hardware-level actions are being performed. The goal is to identify how this process impacts the port's availability and how potential issues could arise during its closing sequence.
|
| 53/2 |
2026/05/26 02:31 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/tty/serial/serial_core.c IncludeLines:true Name:uart_port_shutdown]
Results: map[SourceCode:1889: /* uport == NULL if uart_port has already been removed */
1890: static void uart_port_shutdown(struct tty_port *port)
1891: {
1892: struct uart_state *state = container_of(port, struct uart_state, port);
1893: struct uart_port *uport = uart_port_check(state);
1894:
1895: /*
1896: * clear delta_msr_wait queue to avoid mem leaks: we may free
1897: * the irq here so the queue might never be woken up. Note
1898: * that we won't end up waiting on delta_msr_wait again since
1899: * any outstanding file descriptors should be pointing at
1900: * hung_up_tty_fops now.
1901: */
1902: wake_up_interruptible(&port->delta_msr_wait);
1903:
1904: if (uport) {
1905: /* Free the IRQ and disable the port. */
1906: uport->ops->shutdown(uport);
1907:
1908: /* Ensure that the IRQ handler isn't running on another CPU. */
1909: synchronize_irq(uport->irq);
1910: }
1911: }
SourceFile:drivers/tty/serial/serial_core.c]
|
| 54/2 |
2026/05/26 02:31 |
llm |
expert |
0m
Model:
Tokens:
input: 75587
output: 49
thoughts: 12
Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience:
**Memory Management Deep Dive - The Curious Case of `xmit_buf`**
Alright, so I'm looking at this code, and my primary concern just popped up like a red flag: Where in the heck is `xmit_buf` being freed? I'm scanning through the logic, tracing the function calls, and I'm not seeing the explicit `free()` or equivalent memory deallocation routine. This immediately raises a huge question, especially considering this is likely dealing with data that might be variable in size or lifespan. We all know what happens if that buffer isn't released correctly - memory leaks, potential system instability, and a general lack of robustness. I need to figure out where the corresponding `free()` call is, or confirm if the memory is managed in a way that avoids an explicit free, such as in the stack. I need to determine if this is handled further up the call stack, if a smart pointer is involved, or if I'm missing something subtle in the resource management scheme. This has to be addressed before I can be comfortable with this part of the code.
|
| 55/2 |
2026/05/26 02:31 |
tool |
codesearch-find-references |
0m
Args: map[ContextFile:drivers/tty/serial/serial_core.c IncludeSnippetLines:0 Name:uart_free_xmit_buf]
Results: map[References:[map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:uart_shutdown SourceFile:drivers/tty/serial/serial_core.c SourceLine:431] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:uart_tty_port_shutdown SourceFile:drivers/tty/serial/serial_core.c SourceLine:1787]] TruncatedOutput:false]
|
| 56/2 |
2026/05/26 02:31 |
llm |
expert |
0m
Model:
Tokens:
input: 76020
output: 43
thoughts: 9
Thoughts: Okay, here's my interpretation of that thought process, assuming I'm deep in the weeds of embedded systems or hardware design:
**Checking `uart_shutdown`**
Alright, time to get to it. The system's acting up, and my first instinct, given my experience, is to zero in on the UART shutdown routine, `uart_shutdown`. It's a common point of failure, especially when dealing with interrupt-driven communication or power-down sequences. My mind's already running through the potential issues: are there race conditions? Is the interrupt handling clean? Does it properly flush the transmit buffer? Is there a subtle DMA interaction causing a lockup? I need to verify its behavior under different conditions. I'm thinking, "Let's dig into that code, verify that it's doing what I think it should." Gotta be methodical. It's time to troubleshoot.
|
| 57/2 |
2026/05/26 02:31 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/tty/serial/serial_core.c IncludeLines:true Name:uart_shutdown]
Results: map[SourceCode: 383: /*
384: * This routine will shutdown a serial port; interrupts are disabled, and
385: * DTR is dropped if the hangup on close termio flag is on. Calls to
386: * uart_shutdown are serialised by the per-port semaphore.
387: *
388: * uport == NULL if uart_port has already been removed
389: */
390: static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
391: {
392: struct uart_port *uport = uart_port_check(state);
393: struct tty_port *port = &state->port;
394:
395: /*
396: * Set the TTY IO error marker
397: */
398: if (tty)
399: set_bit(TTY_IO_ERROR, &tty->flags);
400:
401: if (uport)
402: serial_base_port_shutdown(uport);
403:
404: if (tty_port_initialized(port)) {
405: tty_port_set_initialized(port, false);
406:
407: /*
408: * Turn off DTR and RTS early.
409: */
410: if (uport) {
411: if (uart_console(uport) && tty) {
412: uport->cons->cflag = tty->termios.c_cflag;
413: uport->cons->ispeed = tty->termios.c_ispeed;
414: uport->cons->ospeed = tty->termios.c_ospeed;
415: }
416:
417: if (!tty || C_HUPCL(tty))
418: uart_port_dtr_rts(uport, false);
419: }
420:
421: uart_port_shutdown(port);
422: }
423:
424: /*
425: * It's possible for shutdown to be called after suspend if we get
426: * a DCD drop (hangup) at just the right time. Clear suspended bit so
427: * we don't try to resume a port that has been shutdown.
428: */
429: tty_port_set_suspended(port, false);
430:
431: uart_free_xmit_buf(port);
432: }
SourceFile:drivers/tty/serial/serial_core.c]
|
| 58/2 |
2026/05/26 02:31 |
llm |
expert |
0m
Model:
Tokens:
input: 77029
output: 48
thoughts: 36
Thoughts: Okay, here's my interpretation of that thought process, from an expert's perspective:
**Diving into UART Shutdown and Transmission Buffers**
Right, `uart_shutdown` is the call that's causing this. Okay, so it calls `uart_free_xmit_buf(port)`. That's the key. That's where we need to focus our attention. The `port` is the context, obviously. So, now, let's drill down and see exactly what `uart_free_xmit_buf` is doing. This has to be where the transmission buffer is being released, and the potential problem lies within that deallocation process. We need to understand how the memory is freed. What locks are held? What race conditions could be present? What happens if the driver is in the middle of a transmit when this is called? We need to verify that buffer management is handled correctly here. Let's see...
|
| 59/2 |
2026/05/26 02:32 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/tty/serial/serial_core.c IncludeLines:true Name:uart_free_xmit_buf]
Results: map[SourceCode: 279: static void uart_free_xmit_buf(struct tty_port *port)
280: {
281: struct uart_state *state = container_of(port, struct uart_state, port);
282: struct uart_port *uport;
283: unsigned long flags;
284: char *xmit_buf;
285:
286: /*
287: * Do not free() the transmit buffer page under the port lock since
288: * this can create various circular locking scenarios. For instance,
289: * console driver may need to allocate/free a debug object, which
290: * can end up in printk() recursion.
291: */
292: uport = uart_port_lock(state, flags);
293: xmit_buf = port->xmit_buf;
294: port->xmit_buf = NULL;
295: INIT_KFIFO(port->xmit_fifo);
296: uart_port_unlock(uport, flags);
297:
298: free_page((unsigned long)xmit_buf);
299: }
SourceFile:drivers/tty/serial/serial_core.c]
|
| 60/2 |
2026/05/26 02:32 |
llm |
expert |
0m
Model:
Tokens:
input: 77674
output: 48
thoughts: 592
Thoughts: **Analyzing UART Transmission Buffer Management and Potential Race Conditions**
Okay, so `uart_free_xmit_buf` is setting `port->xmit_buf` to NULL and, crucially, calling `INIT_KFIFO(port->xmit_fifo)`. I need to dig into `INIT_KFIFO`. Ah, it sets the `mask` to 0! That means `kfifo_avail` will return 1, which could lead to some interesting states.
Now, recall that `uart_shutdown` frees the `xmit_buf` and sets it to NULL. But the TTY is still "open" in some sense, right? No, no, `uart_shutdown` is called from `uart_close` or `uart_hangup`. If the TTY is closed, then how could `handle_tx` possibly be called?
Hold on... `handle_tx` is called by the `aoe_tx0` thread. This thread transmits packets using `dev_queue_xmit` to the CAIF serial device. That device is attached to the TTY using `ioctl(TIOCSETD, N_CAIF)`. If the TTY is closed, the line discipline is closed. But, is it possible for the `aoe_tx0` thread to *still* be transmitting packets?
Wait, in `caif_serial.c`, there's `ldisc_receive` and also a direct call to `tty->ops->write`. If the TTY is closed, `tty->ops->write` *might* still be called if the line discipline isn't properly detached or there's a race condition. This is where I need to focus.
Thinking about it, `uart_close` calls `tty_port_close`, which in turn calls `tty_port_shutdown`. However, `uart_close` itself is called when the file descriptor is closed. The line discipline, if it's `N_CAIF`, registers a network device, `caif_serial`. When the TTY is closed, `tty_ldisc_release` is called, and that triggers `ldisc->ops->close`. This is the critical sequence. I need to understand `caif_serial.c` and specifically `caif_tty_close`. I need to see what it does with the queue and potential data still being sent. I need to understand how the CAIF serial device cleans up and avoids this possible race. This is where the vulnerability might lie.
|
| 61/2 |
2026/05/26 02:32 |
tool |
codesearch-definition-source |
0m
Error:
Args: map[ContextFile:drivers/net/caif/caif_serial.c IncludeLines:true Name:caif_tty_close]
Results: map[SourceCode: SourceFile:]
|
| 62/2 |
2026/05/26 02:32 |
llm |
expert |
0m
Model:
Tokens:
input: 78869
output: 16
thoughts: 21
Thoughts: Here's my thought process, as requested:
**Navigating the Caif Serial Code for Resource Management**
Okay, so I'm thinking, where should I start looking to understand this serial port behavior? My gut tells me to check the `caif_serial.c` file first. That's usually the place to find the low-level serial port driver implementation, and it's where I'd expect to see how they're handling things like closing the port or, more specifically, dealing with line disciplines (`ldisc`). The `close` function is the obvious candidate for resource cleanup – I want to see what happens when the port is shut down. But, I also need to be aware of how the line discipline is managed because that controls how characters get passed through the port, and it's a potential area for leaks or unexpected behavior. Let me see what I can find in that file, and then I'll formulate my next move.
|
| 63/2 |
2026/05/26 02:32 |
tool |
grepper |
0m
Args:
Results: map[Output:
Full output is too long, showing 500 out of 2839 lines.
Use more precise expression if possible.
[Documentation/ABI/testing/sysfs-platform-kim=18=Description:
--
Documentation/ABI/testing/sysfs-platform-kim-23- command. The entry is read and made use by the user-space
Documentation/ABI/testing/sysfs-platform-kim:24: daemon when the ldisc install is requested.
Documentation/ABI/testing/sysfs-platform-kim-25-
--
Documentation/ABI/testing/sysfs-platform-kim=40=Description:
--
Documentation/ABI/testing/sysfs-platform-kim-47- by the sysfs_notify. The value would be '1' when UART needs
Documentation/ABI/testing/sysfs-platform-kim:48: to be opened/ldisc installed, and would be '0' when UART
Documentation/ABI/testing/sysfs-platform-kim-49- is no more required and needs to be closed.
--
Documentation/driver-api/tty/index.rst=21=Every character received by the kernel (both from devices and users) is passed
Documentation/driver-api/tty/index.rst:22:through a preselected :doc:`tty_ldisc` (in
Documentation/driver-api/tty/index.rst:23:short ldisc; in C, struct tty_ldisc_ops). Its task is to transform characters
Documentation/driver-api/tty/index.rst:24:as defined by a particular ldisc or by user too. The default one is n_tty,
Documentation/driver-api/tty/index.rst-25-implementing echoes, signal handling, jobs control, special characters
--
Documentation/driver-api/tty/index.rst=29=In-detail description of the named TTY structures is in separate documents:
--
Documentation/driver-api/tty/index.rst-36- tty_struct
Documentation/driver-api/tty/index.rst:37: tty_ldisc
Documentation/driver-api/tty/index.rst-38- tty_buffer
--
Documentation/driver-api/tty/n_gsm.rst=18=Config Initiator
--
Documentation/driver-api/tty/n_gsm.rst-46-
Documentation/driver-api/tty/n_gsm.rst:47: int ldisc = N_GSM0710;
Documentation/driver-api/tty/n_gsm.rst-48- struct gsm_config c;
--
Documentation/driver-api/tty/n_gsm.rst-68- /* use n_gsm line discipline */
Documentation/driver-api/tty/n_gsm.rst:69: ioctl(fd, TIOCSETD, &ldisc);
Documentation/driver-api/tty/n_gsm.rst-70-
--
Documentation/driver-api/tty/n_gsm.rst=119=Config Requester
--
Documentation/driver-api/tty/n_gsm.rst-143-
Documentation/driver-api/tty/n_gsm.rst:144: int ldisc = N_GSM0710;
Documentation/driver-api/tty/n_gsm.rst-145- struct gsm_config c;
--
Documentation/driver-api/tty/n_gsm.rst-158- /* use n_gsm line discipline */
Documentation/driver-api/tty/n_gsm.rst:159: ioctl(fd, TIOCSETD, &ldisc);
Documentation/driver-api/tty/n_gsm.rst-160-
--
Documentation/driver-api/tty/n_tty.rst=4=N_TTY
--
Documentation/driver-api/tty/n_tty.rst-8-
Documentation/driver-api/tty/n_tty.rst:9:The default (and fallback) :doc:`TTY line discipline <tty_ldisc>`. It tries to
Documentation/driver-api/tty/n_tty.rst-10-handle characters as per POSIX.
--
Documentation/driver-api/tty/tty_buffer.rst=11=then flip the buffer, so that the data are passed to :doc:`line discipline
Documentation/driver-api/tty/tty_buffer.rst:12:<tty_ldisc>` for further processing.
Documentation/driver-api/tty/tty_buffer.rst-13-
Documentation/driver-api/tty/tty_buffer.rst=14=Flip Buffer Management
--
Documentation/driver-api/tty/tty_buffer.rst-18- :identifiers: tty_prepare_flip_string
Documentation/driver-api/tty/tty_buffer.rst:19: tty_flip_buffer_push tty_ldisc_receive_buf
Documentation/driver-api/tty/tty_buffer.rst-20-
--
Documentation/driver-api/tty/tty_ldisc.rst=15=Registration
--
Documentation/driver-api/tty/tty_ldisc.rst-17-
Documentation/driver-api/tty/tty_ldisc.rst:18:Line disciplines are registered with tty_register_ldisc() passing the ldisc
Documentation/driver-api/tty/tty_ldisc.rst-19-structure. At the point of registration the discipline must be ready to use and
Documentation/driver-api/tty/tty_ldisc.rst=20=it is possible it will get used before the call returns success. If the call
Documentation/driver-api/tty/tty_ldisc.rst:21:returns an error then it won’t get called. Do not re-use ldisc numbers as they
Documentation/driver-api/tty/tty_ldisc.rst:22:are part of the userspace ABI and writing over an existing ldisc will cause
Documentation/driver-api/tty/tty_ldisc.rst-23-demons to eat your computer. You must not re-register over the top of the line
Documentation/driver-api/tty/tty_ldisc.rst=24=discipline even with the same data or your computer again will be eaten by
Documentation/driver-api/tty/tty_ldisc.rst:25:demons. In order to remove a line discipline call tty_unregister_ldisc().
Documentation/driver-api/tty/tty_ldisc.rst-26-
Documentation/driver-api/tty/tty_ldisc.rst=27=Heed this warning: the reference count field of the registered copies of the
Documentation/driver-api/tty/tty_ldisc.rst:28:tty_ldisc structure in the ldisc table counts the number of lines using this
Documentation/driver-api/tty/tty_ldisc.rst:29:discipline. The reference count of the tty_ldisc structure within a tty counts
Documentation/driver-api/tty/tty_ldisc.rst:30:the number of active users of the ldisc at this instant. In effect it counts
Documentation/driver-api/tty/tty_ldisc.rst:31:the number of threads of execution within an ldisc method (plus those about to
Documentation/driver-api/tty/tty_ldisc.rst-32-enter and exit although this detail matters not).
Documentation/driver-api/tty/tty_ldisc.rst-33-
Documentation/driver-api/tty/tty_ldisc.rst:34:.. kernel-doc:: drivers/tty/tty_ldisc.c
Documentation/driver-api/tty/tty_ldisc.rst:35: :identifiers: tty_register_ldisc tty_unregister_ldisc
Documentation/driver-api/tty/tty_ldisc.rst-36-
Documentation/driver-api/tty/tty_ldisc.rst=37=Other Functions
--
Documentation/driver-api/tty/tty_ldisc.rst-39-
Documentation/driver-api/tty/tty_ldisc.rst:40:.. kernel-doc:: drivers/tty/tty_ldisc.c
Documentation/driver-api/tty/tty_ldisc.rst:41: :identifiers: tty_set_ldisc tty_ldisc_flush
Documentation/driver-api/tty/tty_ldisc.rst-42-
Documentation/driver-api/tty/tty_ldisc.rst=43=Line Discipline Operations Reference
--
Documentation/driver-api/tty/tty_ldisc.rst-45-
Documentation/driver-api/tty/tty_ldisc.rst:46:.. kernel-doc:: include/linux/tty_ldisc.h
Documentation/driver-api/tty/tty_ldisc.rst:47: :identifiers: tty_ldisc_ops
Documentation/driver-api/tty/tty_ldisc.rst-48-
--
Documentation/driver-api/tty/tty_ldisc.rst=66=but not yet enforced.
Documentation/driver-api/tty/tty_ldisc.rst-67-
Documentation/driver-api/tty/tty_ldisc.rst:68:.. kernel-doc:: drivers/tty/tty_ldisc.c
Documentation/driver-api/tty/tty_ldisc.rst:69: :identifiers: tty_ldisc_ref_wait tty_ldisc_ref tty_ldisc_deref
Documentation/driver-api/tty/tty_ldisc.rst-70-
--
Documentation/driver-api/tty/tty_ldisc.rst=73=need to take a reference when they push bits up through the driver.
Documentation/driver-api/tty/tty_ldisc.rst-74-
Documentation/driver-api/tty/tty_ldisc.rst:75:A caution: The :c:member:`tty_ldisc_ops.open()`,
Documentation/driver-api/tty/tty_ldisc.rst:76::c:member:`tty_ldisc_ops.close()` and :c:member:`tty_driver.set_ldisc()`
Documentation/driver-api/tty/tty_ldisc.rst:77:functions are called with the ldisc unavailable. Thus tty_ldisc_ref() will fail
Documentation/driver-api/tty/tty_ldisc.rst-78-in this situation if used within these functions. Ldisc and driver code
--
Documentation/driver-api/tty/tty_ldisc.rst=81=Internal Functions
--
Documentation/driver-api/tty/tty_ldisc.rst-83-
Documentation/driver-api/tty/tty_ldisc.rst:84:.. kernel-doc:: drivers/tty/tty_ldisc.c
Documentation/driver-api/tty/tty_ldisc.rst-85- :internal:
--
Documentation/filesystems/proc.rst=1520=this directory, as shown in Table 1-11.
--
Documentation/filesystems/proc.rst-1528- drivers list of drivers and their usage
Documentation/filesystems/proc.rst:1529: ldiscs registered line disciplines
Documentation/filesystems/proc.rst-1530- driver/serial usage statistic and status of single tty lines
--
Documentation/input/joydev/joystick.rst=84=your needs::
Documentation/input/joydev/joystick.rst-85-
Documentation/input/joydev/joystick.rst:86: alias tty-ldisc-2 serport
Documentation/input/joydev/joystick.rst-87- alias char-major-13 input
--
Documentation/networking/caif/caif.rst=35=the TTY device.
Documentation/networking/caif/caif.rst-36-
Documentation/networking/caif/caif.rst:37:To achieve this we need to install the N_CAIF ldisc from user space.
Documentation/networking/caif/caif.rst-38-The benefit is that we can hook up to any TTY.
--
Documentation/networking/caif/caif.rst=120=Error Scenarios
--
Documentation/networking/caif/caif.rst-123-- last_tx_msg contains channel setup message and last_rx_msg is empty ->
Documentation/networking/caif/caif.rst:124: The host seems to be able to send over the UART, at least the CAIF ldisc get
Documentation/networking/caif/caif.rst-125- notified that sending is completed.
--
Documentation/networking/device_drivers/can/can327.rst=78=sheet. This needs to be done before attaching the line discipline.
Documentation/networking/device_drivers/can/can327.rst-79-
Documentation/networking/device_drivers/can/can327.rst:80:Once the ldisc is attached, the CAN interface starts out unconfigured.
Documentation/networking/device_drivers/can/can327.rst-81-Set the speed before starting it::
--
Documentation/staging/magic-number.rst=20=the structure, like so::
Documentation/staging/magic-number.rst-21-
Documentation/staging/magic-number.rst:22: struct tty_ldisc {
Documentation/staging/magic-number.rst-23- int magic;
--
Documentation/trace/ftrace.rst=3752=After running it for a few minutes, the output looks like:
--
Documentation/trace/ftrace.rst-3770- 9) 1808 128 flush_work+0xfe/0x119
Documentation/trace/ftrace.rst:3771: 10) 1680 16 tty_flush_to_ldisc+0x1e/0x20
Documentation/trace/ftrace.rst-3772- 11) 1664 48 input_available_p+0x1d/0x5c
--
Documentation/translations/it_IT/staging/magic-number.rst=25=dati, come di seguito::
Documentation/translations/it_IT/staging/magic-number.rst-26-
Documentation/translations/it_IT/staging/magic-number.rst:27: struct tty_ldisc {
Documentation/translations/it_IT/staging/magic-number.rst-28- int magic;
--
Documentation/translations/sp_SP/process/magic-number.rst=26=estructura, así::
Documentation/translations/sp_SP/process/magic-number.rst-27-
Documentation/translations/sp_SP/process/magic-number.rst:28: struct tty_ldisc {
Documentation/translations/sp_SP/process/magic-number.rst-29- int magic;
--
Documentation/translations/zh_CN/process/magic-number.rst=22=tty源码经常通过特定驱动使用这种方法用来反复地排列特定方面的结构体。
--
Documentation/translations/zh_CN/process/magic-number.rst-25-
Documentation/translations/zh_CN/process/magic-number.rst:26: struct tty_ldisc {
Documentation/translations/zh_CN/process/magic-number.rst-27- int magic;
--
Documentation/translations/zh_TW/process/magic-number.rst=17=Linux 魔術數
--
Documentation/translations/zh_TW/process/magic-number.rst-25-
Documentation/translations/zh_TW/process/magic-number.rst:26: struct tty_ldisc {
Documentation/translations/zh_TW/process/magic-number.rst-27- int magic;
--
drivers/accessibility/speakup/main.c=2327=static void __exit speakup_exit(void)
--
drivers/accessibility/speakup/main.c-2341- mutex_unlock(&spk_mutex);
drivers/accessibility/speakup/main.c:2342: spk_ttyio_unregister_ldisc();
drivers/accessibility/speakup/main.c-2343-
--
drivers/accessibility/speakup/main.c=2363=static int __init speakup_init(void)
--
drivers/accessibility/speakup/main.c-2404-
drivers/accessibility/speakup/main.c:2405: spk_ttyio_register_ldisc();
drivers/accessibility/speakup/main.c-2406- synth_init(synth_name);
--
drivers/accessibility/speakup/spk_priv.h=38=void spk_ttyio_release(struct spk_synth *synth);
drivers/accessibility/speakup/spk_priv.h:39:void spk_ttyio_register_ldisc(void);
drivers/accessibility/speakup/spk_priv.h:40:void spk_ttyio_unregister_ldisc(void);
drivers/accessibility/speakup/spk_priv.h-41-
--
drivers/accessibility/speakup/spk_ttyio.c-10-
drivers/accessibility/speakup/spk_ttyio.c:11:struct spk_ldisc_data {
drivers/accessibility/speakup/spk_ttyio.c-12- char buf;
--
drivers/accessibility/speakup/spk_ttyio.c-18-/*
drivers/accessibility/speakup/spk_ttyio.c:19: * This allows to catch within spk_ttyio_ldisc_open whether it is getting set
drivers/accessibility/speakup/spk_ttyio.c-20- * on for a speakup-driven device.
--
drivers/accessibility/speakup/spk_ttyio.c=37=static int get_dev_to_use(struct spk_synth *synth, dev_t *dev_no)
--
drivers/accessibility/speakup/spk_ttyio.c-46-
drivers/accessibility/speakup/spk_ttyio.c:47:static int spk_ttyio_ldisc_open(struct tty_struct *tty)
drivers/accessibility/speakup/spk_ttyio.c-48-{
drivers/accessibility/speakup/spk_ttyio.c:49: struct spk_ldisc_data *ldisc_data;
drivers/accessibility/speakup/spk_ttyio.c-50-
--
drivers/accessibility/speakup/spk_ttyio.c-57-
drivers/accessibility/speakup/spk_ttyio.c:58: ldisc_data = kmalloc(sizeof(*ldisc_data), GFP_KERNEL);
drivers/accessibility/speakup/spk_ttyio.c:59: if (!ldisc_data)
drivers/accessibility/speakup/spk_ttyio.c-60- return -ENOMEM;
drivers/accessibility/speakup/spk_ttyio.c-61-
drivers/accessibility/speakup/spk_ttyio.c:62: init_completion(&ldisc_data->completion);
drivers/accessibility/speakup/spk_ttyio.c:63: ldisc_data->buf_free = true;
drivers/accessibility/speakup/spk_ttyio.c:64: tty->disc_data = ldisc_data;
drivers/accessibility/speakup/spk_ttyio.c-65-
--
drivers/accessibility/speakup/spk_ttyio.c-68-
drivers/accessibility/speakup/spk_ttyio.c:69:static void spk_ttyio_ldisc_close(struct tty_struct *tty)
drivers/accessibility/speakup/spk_ttyio.c-70-{
--
drivers/accessibility/speakup/spk_ttyio.c=74=static size_t spk_ttyio_receive_buf2(struct tty_struct *tty, const u8 *cp,
--
drivers/accessibility/speakup/spk_ttyio.c-76-{
drivers/accessibility/speakup/spk_ttyio.c:77: struct spk_ldisc_data *ldisc_data = tty->disc_data;
drivers/accessibility/speakup/spk_ttyio.c:78: struct spk_synth *synth = ldisc_data->synth;
drivers/accessibility/speakup/spk_ttyio.c-79-
--
drivers/accessibility/speakup/spk_ttyio.c-88-
drivers/accessibility/speakup/spk_ttyio.c:89: if (!ldisc_data->buf_free)
drivers/accessibility/speakup/spk_ttyio.c-90- /* ttyio_in will tty_flip_buffer_push */
--
drivers/accessibility/speakup/spk_ttyio.c-97-
drivers/accessibility/speakup/spk_ttyio.c:98: ldisc_data->buf = cp[0];
drivers/accessibility/speakup/spk_ttyio.c:99: ldisc_data->buf_free = false;
drivers/accessibility/speakup/spk_ttyio.c:100: complete(&ldisc_data->completion);
drivers/accessibility/speakup/spk_ttyio.c-101-
--
drivers/accessibility/speakup/spk_ttyio.c-104-
drivers/accessibility/speakup/spk_ttyio.c:105:static struct tty_ldisc_ops spk_ttyio_ldisc_ops = {
drivers/accessibility/speakup/spk_ttyio.c-106- .owner = THIS_MODULE,
drivers/accessibility/speakup/spk_ttyio.c-107- .num = N_SPEAKUP,
drivers/accessibility/speakup/spk_ttyio.c:108: .name = "speakup_ldisc",
drivers/accessibility/speakup/spk_ttyio.c:109: .open = spk_ttyio_ldisc_open,
drivers/accessibility/speakup/spk_ttyio.c:110: .close = spk_ttyio_ldisc_close,
drivers/accessibility/speakup/spk_ttyio.c-111- .receive_buf2 = spk_ttyio_receive_buf2,
--
drivers/accessibility/speakup/spk_ttyio.c=135=static inline void get_termios(struct tty_struct *tty,
--
drivers/accessibility/speakup/spk_ttyio.c-142-
drivers/accessibility/speakup/spk_ttyio.c:143:static int spk_ttyio_initialise_ldisc(struct spk_synth *synth)
drivers/accessibility/speakup/spk_ttyio.c-144-{
--
drivers/accessibility/speakup/spk_ttyio.c-187- speakup_tty = tty;
drivers/accessibility/speakup/spk_ttyio.c:188: ret = tty_set_ldisc(tty, N_SPEAKUP);
drivers/accessibility/speakup/spk_ttyio.c-189- speakup_tty = NULL;
--
drivers/accessibility/speakup/spk_ttyio.c-193- /* Success */
drivers/accessibility/speakup/spk_ttyio.c:194: struct spk_ldisc_data *ldisc_data = tty->disc_data;
drivers/accessibility/speakup/spk_ttyio.c-195-
drivers/accessibility/speakup/spk_ttyio.c:196: ldisc_data->synth = synth;
drivers/accessibility/speakup/spk_ttyio.c-197- synth->dev = tty;
--
drivers/accessibility/speakup/spk_ttyio.c-212-
drivers/accessibility/speakup/spk_ttyio.c:213:void spk_ttyio_register_ldisc(void)
drivers/accessibility/speakup/spk_ttyio.c-214-{
drivers/accessibility/speakup/spk_ttyio.c:215: if (tty_register_ldisc(&spk_ttyio_ldisc_ops))
drivers/accessibility/speakup/spk_ttyio.c-216- pr_warn("speakup: Error registering line discipline. Most synths won't work.\n");
--
drivers/accessibility/speakup/spk_ttyio.c-218-
drivers/accessibility/speakup/spk_ttyio.c:219:void spk_ttyio_unregister_ldisc(void)
drivers/accessibility/speakup/spk_ttyio.c-220-{
drivers/accessibility/speakup/spk_ttyio.c:221: tty_unregister_ldisc(&spk_ttyio_ldisc_ops);
drivers/accessibility/speakup/spk_ttyio.c-222-}
--
drivers/accessibility/speakup/spk_ttyio.c=291=static unsigned char ttyio_in(struct spk_synth *in_synth, int timeout)
--
drivers/accessibility/speakup/spk_ttyio.c-293- struct tty_struct *tty = in_synth->dev;
drivers/accessibility/speakup/spk_ttyio.c:294: struct spk_ldisc_data *ldisc_data = tty->disc_data;
drivers/accessibility/speakup/spk_ttyio.c-295- char rv;
--
drivers/accessibility/speakup/spk_ttyio.c-297- if (!timeout) {
drivers/accessibility/speakup/spk_ttyio.c:298: if (!try_wait_for_completion(&ldisc_data->completion))
drivers/accessibility/speakup/spk_ttyio.c-299- return 0xff;
drivers/accessibility/speakup/spk_ttyio.c:300: } else if (wait_for_completion_timeout(&ldisc_data->completion,
drivers/accessibility/speakup/spk_ttyio.c-301- usecs_to_jiffies(timeout)) == 0) {
--
drivers/accessibility/speakup/spk_ttyio.c-306-
drivers/accessibility/speakup/spk_ttyio.c:307: rv = ldisc_data->buf;
drivers/accessibility/speakup/spk_ttyio.c-308- /* Make sure we have read buf before we set buf_free to let
--
drivers/accessibility/speakup/spk_ttyio.c-311- mb();
drivers/accessibility/speakup/spk_ttyio.c:312: ldisc_data->buf_free = true;
drivers/accessibility/speakup/spk_ttyio.c-313- /* Let TTY push more characters */
--
drivers/accessibility/speakup/spk_ttyio.c=339=int spk_ttyio_synth_probe(struct spk_synth *synth)
drivers/accessibility/speakup/spk_ttyio.c-340-{
drivers/accessibility/speakup/spk_ttyio.c:341: int rv = spk_ttyio_initialise_ldisc(synth);
drivers/accessibility/speakup/spk_ttyio.c-342-
--
drivers/accessibility/speakup/spk_ttyio.c=352=void spk_ttyio_release(struct spk_synth *in_synth)
--
drivers/accessibility/speakup/spk_ttyio.c-363-
drivers/accessibility/speakup/spk_ttyio.c:364: tty_ldisc_flush(tty);
drivers/accessibility/speakup/spk_ttyio.c-365- tty_unlock(tty);
--
drivers/bluetooth/Makefile=40=btmrvl-$(CONFIG_DEBUG_FS) += btmrvl_debugfs.o
drivers/bluetooth/Makefile-41-
drivers/bluetooth/Makefile:42:hci_uart-y := hci_ldisc.o
drivers/bluetooth/Makefile-43-hci_uart-$(CONFIG_BT_HCIUART_SERDEV) += hci_serdev.o
--
drivers/bluetooth/hci_bcm.c=441=static int bcm_open(struct hci_uart *hu)
--
drivers/bluetooth/hci_bcm.c-497-
drivers/bluetooth/hci_bcm.c:498: /* If oper_speed is set, ldisc/serdev will set the baudrate
drivers/bluetooth/hci_bcm.c-499- * before calling setup()
--
drivers/bluetooth/hci_ldisc.c=227=static int hci_uart_flush(struct hci_dev *hdev)
--
drivers/bluetooth/hci_ldisc.c-238- /* Flush any pending characters in the driver and discipline. */
drivers/bluetooth/hci_ldisc.c:239: tty_ldisc_flush(tty);
drivers/bluetooth/hci_ldisc.c-240- tty_driver_flush_buffer(tty);
--
drivers/bluetooth/hci_ldisc.c=822=static ssize_t hci_uart_tty_write(struct tty_struct *tty, struct file *file,
--
drivers/bluetooth/hci_ldisc.c-827-
drivers/bluetooth/hci_ldisc.c:828:static struct tty_ldisc_ops hci_uart_ldisc = {
drivers/bluetooth/hci_ldisc.c-829- .owner = THIS_MODULE,
--
drivers/bluetooth/hci_ldisc.c=842=static int __init hci_uart_init(void)
--
drivers/bluetooth/hci_ldisc.c-848- /* Register the tty discipline */
drivers/bluetooth/hci_ldisc.c:849: err = tty_register_ldisc(&hci_uart_ldisc);
drivers/bluetooth/hci_ldisc.c-850- if (err) {
--
drivers/bluetooth/hci_ldisc.c=891=static void __exit hci_uart_exit(void)
--
drivers/bluetooth/hci_ldisc.c-925-#endif
drivers/bluetooth/hci_ldisc.c:926: tty_unregister_ldisc(&hci_uart_ldisc);
drivers/bluetooth/hci_ldisc.c-927-}
--
drivers/bluetooth/hci_serdev.c-6- *
drivers/bluetooth/hci_serdev.c:7: * Based on hci_ldisc.c:
drivers/bluetooth/hci_serdev.c-8- *
--
drivers/input/serio/serport.c=61=static void serport_serio_close(struct serio *serio)
--
drivers/input/serio/serport.c-69-/*
drivers/input/serio/serport.c:70: * serport_ldisc_open() is the routine that is called upon setting our line
drivers/input/serio/serport.c-71- * discipline on a tty. It prepares the serio struct.
--
drivers/input/serio/serport.c-73-
drivers/input/serio/serport.c:74:static int serport_ldisc_open(struct tty_struct *tty)
drivers/input/serio/serport.c-75-{
--
drivers/input/serio/serport.c-96-/*
drivers/input/serio/serport.c:97: * serport_ldisc_close() is the opposite of serport_ldisc_open()
drivers/input/serio/serport.c-98- */
drivers/input/serio/serport.c-99-
drivers/input/serio/serport.c:100:static void serport_ldisc_close(struct tty_struct *tty)
drivers/input/serio/serport.c-101-{
--
drivers/input/serio/serport.c-107-/*
drivers/input/serio/serport.c:108: * serport_ldisc_receive() is called by the low level tty driver when characters
drivers/input/serio/serport.c-109- * are ready for us. We forward the characters and flags, one by one to the
--
drivers/input/serio/serport.c-112-
drivers/input/serio/serport.c:113:static void serport_ldisc_receive(struct tty_struct *tty, const u8 *cp,
drivers/input/serio/serport.c-114- const u8 *fp, size_t count)
--
drivers/input/serio/serport.c-146-/*
drivers/input/serio/serport.c:147: * serport_ldisc_read() just waits indefinitely if everything goes well.
drivers/input/serio/serport.c-148- * However, when the serio driver closes the serio port, it finishes,
--
drivers/input/serio/serport.c-151-
drivers/input/serio/serport.c:152:static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file,
drivers/input/serio/serport.c-153- u8 *kbuf, size_t nr, void **cookie,
--
drivers/input/serio/serport.c=189=static void serport_set_type(struct tty_struct *tty, unsigned long type)
--
drivers/input/serio/serport.c-198-/*
drivers/input/serio/serport.c:199: * serport_ldisc_ioctl() allows to set the port protocol, and device ID
drivers/input/serio/serport.c-200- */
drivers/input/serio/serport.c-201-
drivers/input/serio/serport.c:202:static int serport_ldisc_ioctl(struct tty_struct *tty, unsigned int cmd,
drivers/input/serio/serport.c-203- unsigned long arg)
--
drivers/input/serio/serport.c-219-#define COMPAT_SPIOCSTYPE _IOW('q', 0x01, compat_ulong_t)
drivers/input/serio/serport.c:220:static int serport_ldisc_compat_ioctl(struct tty_struct *tty,
drivers/input/serio/serport.c-221- unsigned int cmd, unsigned long arg)
--
drivers/input/serio/serport.c-237-
drivers/input/serio/serport.c:238:static void serport_ldisc_hangup(struct tty_struct *tty)
drivers/input/serio/serport.c-239-{
--
drivers/input/serio/serport.c-247-
drivers/input/serio/serport.c:248:static void serport_ldisc_write_wakeup(struct tty_struct * tty)
drivers/input/serio/serport.c-249-{
--
drivers/input/serio/serport.c-261-
drivers/input/serio/serport.c:262:static struct tty_ldisc_ops serport_ldisc = {
drivers/input/serio/serport.c-263- .owner = THIS_MODULE,
--
drivers/input/serio/serport.c-265- .name = "input",
drivers/input/serio/serport.c:266: .open = serport_ldisc_open,
drivers/input/serio/serport.c:267: .close = serport_ldisc_close,
drivers/input/serio/serport.c:268: .read = serport_ldisc_read,
drivers/input/serio/serport.c:269: .ioctl = serport_ldisc_ioctl,
drivers/input/serio/serport.c-270-#ifdef CONFIG_COMPAT
drivers/input/serio/serport.c:271: .compat_ioctl = serport_ldisc_compat_ioctl,
drivers/input/serio/serport.c-272-#endif
drivers/input/serio/serport.c:273: .receive_buf = serport_ldisc_receive,
drivers/input/serio/serport.c:274: .hangup = serport_ldisc_hangup,
drivers/input/serio/serport.c:275: .write_wakeup = serport_ldisc_write_wakeup
drivers/input/serio/serport.c-276-};
--
drivers/input/serio/serport.c=282=static int __init serport_init(void)
--
drivers/input/serio/serport.c-284- int retval;
drivers/input/serio/serport.c:285: retval = tty_register_ldisc(&serport_ldisc);
drivers/input/serio/serport.c-286- if (retval)
--
drivers/input/serio/serport.c=292=static void __exit serport_exit(void)
drivers/input/serio/serport.c-293-{
drivers/input/serio/serport.c:294: tty_unregister_ldisc(&serport_ldisc);
drivers/input/serio/serport.c-295-}
--
drivers/isdn/capi/capi.c=407=static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb)
--
drivers/isdn/capi/capi.c-412- u16 errcode, datahandle;
drivers/isdn/capi/capi.c:413: struct tty_ldisc *ld;
drivers/isdn/capi/capi.c-414- int ret = -1;
--
drivers/isdn/capi/capi.c-421-
drivers/isdn/capi/capi.c:422: ld = tty_ldisc_ref(tty);
drivers/isdn/capi/capi.c-423- if (!ld) {
--
drivers/isdn/capi/capi.c-430- if (ld->ops->receive_buf == NULL) {
drivers/isdn/capi/capi.c:431: pr_debug("capi: ldisc has no receive_buf function\n");
drivers/isdn/capi/capi.c-432- /* fatal error, do not requeue */
--
drivers/isdn/capi/capi.c-436- pr_debug("capi: recv tty throttled\n");
drivers/isdn/capi/capi.c:437: goto deref_ldisc;
drivers/isdn/capi/capi.c-438- }
--
drivers/isdn/capi/capi.c-441- pr_debug("capi: no room in tty\n");
drivers/isdn/capi/capi.c:442: goto deref_ldisc;
drivers/isdn/capi/capi.c-443- }
--
drivers/isdn/capi/capi.c-447- printk(KERN_ERR "capi: gen_data_b3_resp failed\n");
drivers/isdn/capi/capi.c:448: goto deref_ldisc;
drivers/isdn/capi/capi.c-449- }
--
drivers/isdn/capi/capi.c-456- skb_pull(skb, CAPIMSG_LEN(skb->data));
drivers/isdn/capi/capi.c:457: pr_debug("capi: DATA_B3_RESP %u len=%d => ldisc\n",
drivers/isdn/capi/capi.c-458- datahandle, skb->len);
--
drivers/isdn/capi/capi.c-465- if (errcode == CAPI_SENDQUEUEFULL)
drivers/isdn/capi/capi.c:466: goto deref_ldisc;
drivers/isdn/capi/capi.c-467- }
--
drivers/isdn/capi/capi.c-472-
drivers/isdn/capi/capi.c:473:deref_ldisc:
drivers/isdn/capi/capi.c:474: tty_ldisc_deref(ld);
drivers/isdn/capi/capi.c-475-
--
drivers/net/caif/Kconfig=14=config CAIF_TTY
--
drivers/net/caif/Kconfig-18- help
drivers/net/caif/Kconfig:19: The CAIF TTY transport driver is a Line Discipline (ldisc)
drivers/net/caif/Kconfig:20: identified as N_CAIF. When this ldisc is opened from user space
drivers/net/caif/Kconfig-21- it will redirect the TTY's traffic into the CAIF stack.
--
drivers/net/caif/caif_serial.c=84=static void caifdev_setup(struct net_device *dev);
drivers/net/caif/caif_serial.c:85:static void ldisc_tx_wakeup(struct tty_struct *tty);
drivers/net/caif/caif_serial.c-86-#ifdef CONFIG_DEBUG_FS
--
drivers/net/caif/caif_serial.c=142=static inline void debugfs_rx(struct ser_device *ser, const u8 *data, int size)
--
drivers/net/caif/caif_serial.c-146-
drivers/net/caif/caif_serial.c:147:static void ldisc_receive(struct tty_struct *tty, const u8 *data,
drivers/net/caif/caif_serial.c-148- const u8 *flags, size_t count)
--
drivers/net/caif/caif_serial.c=194=static int handle_tx(struct ser_device *ser)
--
drivers/net/caif/caif_serial.c-225- tty_wr = len;
drivers/net/caif/caif_serial.c:226: ldisc_receive(tty, skb->data, NULL, len);
drivers/net/caif/caif_serial.c-227- }
--
drivers/net/caif/caif_serial.c=254=static netdev_tx_t caif_xmit(struct sk_buff *skb, struct net_device *dev)
--
drivers/net/caif/caif_serial.c-271-
drivers/net/caif/caif_serial.c:272:static void ldisc_tx_wakeup(struct tty_struct *tty)
drivers/net/caif/caif_serial.c-273-{
--
drivers/net/caif/caif_serial.c=303=static DECLARE_WORK(ser_release_work, ser_release);
drivers/net/caif/caif_serial.c-304-
drivers/net/caif/caif_serial.c:305:static int ldisc_open(struct tty_struct *tty)
drivers/net/caif/caif_serial.c-306-{
--
drivers/net/caif/caif_serial.c-353-
]
]
|
| 64/2 |
2026/05/26 02:32 |
llm |
expert |
0m
Model:
Tokens:
input: 89880
output: 46
thoughts: 33
Thoughts: Okay, let's dive into this. Here's how I'd approach that examination, as if it were my thought process:
**Diving into the CAIF Serial Driver's Lifecycle**
Alright, time to get my hands dirty. I need to understand the lifecycle of the serial interface within the CAIF framework, specifically how it's initialized and shut down. To do that, I'm going to head straight into the heart of the matter: `drivers/net/caif/caif_serial.c`. This file is clearly where the core serial-specific CAIF implementation resides. My primary focus right now has to be on the `ldisc_open` and `ldisc_close` functions. These are likely the crucial entry points and exit points for the line discipline associated with the serial port and CAIF, and they’re what define when the serial port is brought up and down within this driver. I'll need to scrutinize how these functions interact with the underlying serial port hardware and the CAIF core. I'll be looking for how resources are allocated, how the serial port is configured (baud rate, parity, etc.), and how data is passed between the serial interface and the CAIF layers. The `ldisc_close` function will be just as important to me, so I can ensure all resources are properly released, and the serial interface is cleanly brought down, avoiding any potential leaks or dangling pointers. This investigation feels like a solid starting point for getting a grip on the serial component.
|
| 65/2 |
2026/05/26 02:32 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/net/caif/caif_serial.c IncludeLines:true Name:ldisc_close]
Results: map[SourceCode: 354: static void ldisc_close(struct tty_struct *tty)
355: {
356: struct ser_device *ser = tty->disc_data;
357:
358: tty_kref_put(ser->tty);
359:
360: spin_lock(&ser_lock);
361: list_move(&ser->node, &ser_release_list);
362: spin_unlock(&ser_lock);
363: schedule_work(&ser_release_work);
364: }
SourceFile:drivers/net/caif/caif_serial.c]
|
| 66/2 |
2026/05/26 02:32 |
llm |
expert |
0m
Model:
Tokens:
input: 90472
output: 45
thoughts: 28
Thoughts: Here's my take on the thought process, as if it were my own:
**Investigating a Potential Serialisation Bottleneck**
Hold on a second! I'm pretty sure `ldisc_close` is responsible for scheduling `ser_release_work`. Right, that's ringing a bell. Okay, let's just make absolutely sure, and double-check exactly how `ser_release_work` functions. Gotta understand what happens in that release step. This could be where things are gumming up, or maybe it’s a completely normal execution point, but best be sure, and clear, what this step entails.
|
| 67/2 |
2026/05/26 02:32 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/net/caif/caif_serial.c IncludeLines:true Name:ser_release]
Results: map[SourceCode: 283: static void ser_release(struct work_struct *work)
284: {
285: struct list_head list;
286: struct ser_device *ser, *tmp;
287:
288: spin_lock(&ser_lock);
289: list_replace_init(&ser_release_list, &list);
290: spin_unlock(&ser_lock);
291:
292: if (!list_empty(&list)) {
293: rtnl_lock();
294: list_for_each_entry_safe(ser, tmp, &list, node) {
295: dev_close(ser->dev);
296: unregister_netdevice(ser->dev);
297: debugfs_deinit(ser);
298: }
299: rtnl_unlock();
300: }
301: }
SourceFile:drivers/net/caif/caif_serial.c]
|
| 68/2 |
2026/05/26 02:32 |
llm |
expert |
0m
Model:
Tokens:
input: 90976
output: 47
thoughts: 151
Thoughts: **My Line Discipline Unregistration Conundrum**
Okay, so I'm tracing this `ldisc_close` function, and it seems like the plan is to schedule a work item to unregister the netdevice. But here's the kicker: `ldisc_close` returns *immediately*. This means `tty_ldisc_release` completes, which then calls `uart_close`. And *that* leads us to `uart_shutdown`, which is where things get interesting. That function frees up the `xmit_buf` and empties the `xmit_fifo` (mask = 0).
The problem is, the netdevice *remains* registered and active until `ser_release_work` finally gets a chance to run. That's a significant window of vulnerability! My concern now is about a race condition. If, during this brief period, either `aoe_tx0` or any other thread tries to send a packet to the CAIF netdevice, `caif_xmit` will be invoked. I have a feeling this is where things could go horribly wrong. I really need to understand what's happening inside `caif_xmit` now.
|
| 69/2 |
2026/05/26 02:32 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/net/caif/caif_serial.c IncludeLines:true Name:caif_xmit]
Results: map[SourceCode: 254: static netdev_tx_t caif_xmit(struct sk_buff *skb, struct net_device *dev)
255: {
256: struct ser_device *ser;
257:
258: ser = netdev_priv(dev);
259:
260: /* Send flow off once, on high water mark */
261: if (ser->head.qlen > SEND_QUEUE_HIGH &&
262: !test_and_set_bit(CAIF_FLOW_OFF_SENT, &ser->state) &&
263: ser->common.flowctrl != NULL)
264:
265: ser->common.flowctrl(ser->dev, OFF);
266:
267: skb_queue_tail(&ser->head, skb);
268: return handle_tx(ser);
269: }
SourceFile:drivers/net/caif/caif_serial.c]
|
| 70/2 |
2026/05/26 02:32 |
llm |
expert |
0m
Model:
Tokens:
input: 91715
output: 46
thoughts: 1046
Thoughts: **Analysis of Potential RCU Stall in CAIF Serial Driver**
Okay, so here's what's happening. `caif_xmit` calls `handle_tx(ser)`, right? And `handle_tx` then calls `tty_write_room(tty)`. Here's where it gets interesting. If `uart_shutdown` has already run, meaning the `xmit_buf` is freed and the `xmit_fifo` is re-initialized with a mask of zero, `tty_write_room` is going to return 1. Then `handle_tx` calls `tty->ops->write(tty, skb->data, 1)`. Because `xmit_buf` is now `NULL`, `uart_write` immediately returns 0. The `skb_pull(skb, 0)` call doesn't do anything to change the length. And boom, the loop in `handle_tx` continues infinitely!
Now, *handle_tx* doesn't explicitly disable interrupts, but given that it might be called from `dev_queue_xmit`, which *does* disable preemption via `rcu_read_lock_bh` or a similar mechanism, this creates an RCU stall situation!
Let me verify the exact sequence, this is important:
1. A thread (Thread A) opens `/dev/ttyS3`.
2. Then, it sets the line discipline with `ioctl(TIOCSETD, N_CAIF)`. This calls `ldisc_open`, which sets up and registers the `caif_serial` netdevice.
3. Thread A closes the serial port `/dev/ttyS3`.
4. `tty_release` runs, which eventually hits `ldisc_close` in `caif_serial.c`.
5. `ldisc_close` schedules `ser_release_work` and then returns.
6. `tty_release` continues, calls `tty->ops->close` which then runs `uart_close`, then `uart_shutdown`, which then runs `uart_free_xmit_buf`.
7. `uart_free_xmit_buf` sets `xmit_buf = NULL` and initializes `xmit_fifo` which resets the mask to zero (important!).
8. Before the workqueue runs (before `ser_release_work`), Thread B (could be, say, `aoe_tx0`) tries to transmit a packet via the `caif_serial` netdevice.
9. This transmission triggers `caif_xmit`, which calls `handle_tx`.
10. Now, the loop in `handle_tx` starts:
* `tty_write_room` returns 1 (because the mask is zero).
* `tty->ops->write` (`uart_write`) returns 0 (because `xmit_buf` is NULL).
* `skb_pull(skb, 0)` does nothing.
* And the loop starts again… and again… forever!
That's the bug, 100%.
Alright, security impact now. This is a real infinite loop, leading to an RCU stall. If `panic_on_rcu_stall` is set, we get a panic. Otherwise, it's just a system hang. So, Denial of Service (DoS), for sure. But is it privilege escalation? No. The `skb_pull` call with 0 length doesn't cause any memory corruption, and `uart_write` safely returns 0 with a null buffer. This particular code flow can't be exploited for any privilege escalation.
Now, how accessible is this from an unprivileged process? To trigger it, an unprivileged user needs to:
1. Open a serial port like `/dev/ttyS3`.
2. Call `ioctl(TIOCSETD, N_CAIF)`.
3. Close the serial port.
4. Send a packet to the CAIF netdevice *before* that workqueue runs, which means before the buffer is actually freed.
Wait, can an *unprivileged* user even open `/dev/ttyS3`? Typically, `/dev/ttyS*` is owned by `root:dialout` with permissions `0660`. A standard, unprivileged user without `dialout` membership wouldn't have access. However, what about pseudo-terminals, `/dev/ptmx`? Can we set `N_CAIF` on a PTY? Yes, `ioctl(TIOCSETD)` works on any TTY, including PTYs. So, the question now is, is a capability
|
| 71/2 |
2026/05/26 02:32 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/net/caif/caif_serial.c IncludeLines:true Name:ldisc_open]
Results: map[SourceCode: 305: static int ldisc_open(struct tty_struct *tty)
306: {
307: struct ser_device *ser;
308: struct net_device *dev;
309: char name[64];
310: int result;
311:
312: /* No write no play */
313: if (tty->ops->write == NULL)
314: return -EOPNOTSUPP;
315: if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_TTY_CONFIG))
316: return -EPERM;
317:
318: /* release devices to avoid name collision */
319: ser_release(NULL);
320:
321: result = snprintf(name, sizeof(name), "cf%s", tty->name);
322: if (result >= IFNAMSIZ)
323: return -EINVAL;
324: dev = alloc_netdev(sizeof(*ser), name, NET_NAME_UNKNOWN,
325: caifdev_setup);
326: if (!dev)
327: return -ENOMEM;
328:
329: ser = netdev_priv(dev);
330: ser->tty = tty_kref_get(tty);
331: ser->dev = dev;
332: debugfs_init(ser, tty);
333: tty->receive_room = 4096;
334: tty->disc_data = ser;
335: set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
336: rtnl_lock();
337: result = register_netdevice(dev);
338: if (result) {
339: tty_kref_put(tty);
340: rtnl_unlock();
341: free_netdev(dev);
342: return -ENODEV;
343: }
344:
345: spin_lock(&ser_lock);
346: list_add(&ser->node, &ser_list);
347: spin_unlock(&ser_lock);
348: rtnl_unlock();
349: netif_stop_queue(dev);
350: update_tty_status(ser);
351: return 0;
352: }
SourceFile:drivers/net/caif/caif_serial.c]
|
| 72/2 |
2026/05/26 02:32 |
llm |
expert |
0m
Model:
Tokens:
input: 94560
output: 35
thoughts: 164
Thoughts: **Analyzing the Capability Checks in `ldisc_open`**
Okay, so I'm looking at the `ldisc_open` function, specifically this security check:
```c
if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_TTY_CONFIG))
return -EPERM;
```
Right, it's checking for either `CAP_SYS_ADMIN` or `CAP_SYS_TTY_CONFIG`. Standard stuff for resource management. But then it hits me... wait a second! That `capable()` function... doesn't that check against the *initial* user namespace? Not necessarily the current one?
I need to confirm this. I seem to recall `capable()` referencing `init_user_ns`. If it was using `ns_capable()`, *then* it would be checking the current user namespace which would be accessible from a user namespace! But, if it's using the "global" `capable()`, we're dealing with a check against the *initial* user namespace only. Therefore, it's *not* accessible from the current user namespace. It's a fundamental difference.
I need to double-check that. Let's make absolutely sure that `capable()` is indeed looking at `init_user_ns`. I want to be 100% certain. This has significant implications for how we're securing the system. It would be a critical oversight if it was using the incorrect namespace.
|
| 73/2 |
2026/05/26 02:33 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:kernel/capability.c IncludeLines:true Name:capable]
Results: map[SourceCode: 404: /**
405: * capable - Determine if the current task has a superior capability in effect
406: * @cap: The capability to be tested for
407: *
408: * Return true if the current task has the given superior capability currently
409: * available for use, false if not.
410: *
411: * This sets PF_SUPERPRIV on the task if the capability is available on the
412: * assumption that it's about to be used.
413: */
414: bool capable(int cap)
415: {
416: return ns_capable(&init_user_ns, cap);
417: }
SourceFile:kernel/capability.c]
|
| 74/2 |
2026/05/26 02:33 |
llm |
expert |
0m
Model:
Tokens:
input: 95298
output: 39
thoughts: 857
Thoughts: **Analyzing the Potential Impact of a TTY Driver Bug**
Okay, so I'm thinking through this potential vulnerability. Initially, I saw that `capable()` checks `init_user_ns`, so an unprivileged user shouldn't be able to trigger this, even with a user namespace. But then I remember Syzbot. I need to be sure. The reproducer! Right, it's running as root. Let's look at the C code... Ah, no `unshare()` call, no user namespace setup. So Syzkaller is running the reproducer as root, confirming my suspicion.
So, this means this bug is only exploitable by someone with `CAP_SYS_ADMIN` or `CAP_SYS_TTY_CONFIG` in the initial user namespace. Essentially, root-level access. The security impact is therefore minimal.
But hang on, let's not jump to conclusions. Is there *another* way to trigger that `handle_tx` infinite loop? What if the TTY *isn't* closed, but `tty_write_room` gives me 1, while `uart_write` returns 0 for a different reason? `uart_write` returns 0 if `!state->port.xmit_buf` or if `kfifo_in` returns 0. `kfifo_in` returns 0 if the FIFO is full, but `tty_write_room` returns `kfifo_avail`. If the FIFO is full, then `kfifo_avail` will be 0. So when the FIFO is full `handle_tx` breaks out of the loop:
```c
room = tty_write_room(tty);
if (!room)
break;
```
So that's fine. The only way `uart_write` can return 0 *while* `tty_write_room` says there's room is if `state->port.xmit_buf` is NULL. And when is *that* the case? Well, it's NULL before `uart_startup` or after `uart_shutdown`. Can `handle_tx` get called before `uart_startup`? Hmm, `uart_startup` happens during `uart_port_activate`, which gets called during `tty_port_open`. And `tty_port_open` is called during `uart_open`. So, `xmit_buf` gets allocated when the TTY is opened. And freed when it's closed, naturally. The CAIF ldisc is attached via `ioctl(TIOCSETD)`, which requires the TTY to be open, so `xmit_buf` will be allocated when that happens. But what about when it's closed?
Right, `xmit_buf` is NULL only after the TTY is closed. And as we saw before, `ldisc_close` defers netdevice unregistration, creating a use-after-close window. So even though the TTY is closed, the netdevice might still be active, *and* `xmit_buf` will be NULL.
Okay, let's broaden the scope. Are there other TTY drivers that have this potentially similar issue? What about a PTY? I should check `pty_write` and `pty_write_room`.
|
| 75/2 |
2026/05/26 02:33 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/tty/pty.c IncludeLines:true Name:pty_write]
Results: map[SourceCode: 111: static ssize_t pty_write(struct tty_struct *tty, const u8 *buf, size_t c)
112: {
113: struct tty_struct *to = tty->link;
114:
115: if (tty->flow.stopped || !c)
116: return 0;
117:
118: return tty_insert_flip_string_and_push_buffer(to->port, buf, c);
119: }
SourceFile:drivers/tty/pty.c]
|
| 76/2 |
2026/05/26 02:33 |
llm |
expert |
0m
Model:
Tokens:
input: 97074
output: 41
thoughts: 47
Thoughts: **Analyzing the Data Flow of `pty_write`**
Okay, so `pty_write` is calling `tty_insert_flip_string_and_push_buffer`. That's the core action, getting data into the TTY system. But I need to understand its behavior fully. The conditional return is the key. If the TTY's flow control is stopped (`tty->flow.stopped`), it immediately returns 0. That makes perfect sense; no point in trying to write if the receiver isn't ready.
Now the question is: how is the buffer in `tty_insert_flip_string_and_push_buffer` actually handled? I need to understand the function better, including the return of `pty_write_room`, and how it interacts with flow control. What is `pty_write_room`'s role in this whole process? Does it provide a size or space limit for the write? Or, does it return the amount written? I need to dig deeper into the code of `pty_write_room` function to have a clearer understanding. This conditional return is a typical check for a non-blocking device. I need to figure out what happens, exactly, to the data. Is it discarded? Is it buffered somewhere? Understanding the interactions between these two functions will give me the full picture.
|
| 77/2 |
2026/05/26 02:33 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/tty/pty.c IncludeLines:true Name:pty_write_room]
Results: map[SourceCode: 129: static unsigned int pty_write_room(struct tty_struct *tty)
130: {
131: if (tty->flow.stopped)
132: return 0;
133: return tty_buffer_space_avail(tty->link->port);
134: }
SourceFile:drivers/tty/pty.c]
|
| 78/2 |
2026/05/26 02:33 |
llm |
expert |
0m
Model:
Tokens:
input: 97562
output: 51
thoughts: 130
Thoughts: **Analyzing the Consistency of Write Functions**
Okay, so if the terminal's flow control is stopped (`tty->flow.stopped`), then `pty_write_room` will indeed return 0. This makes sense; it's the expected behavior. This means the return values of `pty_write` and `pty_write_room` are consistent with each other. A positive value from `pty_write_room` implies a positive return from `pty_write`, unless the write length `c` is somehow zero, but the `handle_tx` function assures `len` will always be > 0. Wait a minute... something feels a bit off. I need to be sure. I'm recalling something about potential memory allocation failures in `tty_insert_flip_string_and_push_buffer`. I need to verify if that function can return 0, even when other checks are passing, because that would break my whole premise. Let me dive into that function and make absolutely sure.
|
| 79/2 |
2026/05/26 02:33 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/tty/tty_buffer.c IncludeLines:true Name:tty_insert_flip_string_and_push_buffer]
Results: map[SourceCode: 538: /**
539: * tty_insert_flip_string_and_push_buffer - add characters to the tty buffer and
540: * push
541: * @port: tty port
542: * @chars: characters
543: * @size: size
544: *
545: * The function combines tty_insert_flip_string() and tty_flip_buffer_push()
546: * with the exception of properly holding the @port->lock.
547: *
548: * To be used only internally (by pty currently).
549: *
550: * Returns: the number added.
551: */
552: int tty_insert_flip_string_and_push_buffer(struct tty_port *port,
553: const u8 *chars, size_t size)
554: {
555: struct tty_bufhead *buf = &port->buf;
556: unsigned long flags;
557:
558: spin_lock_irqsave(&port->lock, flags);
559: size = tty_insert_flip_string(port, chars, size);
560: if (size)
561: tty_flip_buffer_commit(buf->tail);
562: spin_unlock_irqrestore(&port->lock, flags);
563:
564: queue_work(system_unbound_wq, &buf->work);
565:
566: return size;
567: }
SourceFile:drivers/tty/tty_buffer.c]
|
| 80/2 |
2026/05/26 02:33 |
llm |
expert |
0m
Model:
Tokens:
input: 98435
output: 45
thoughts: 84
Thoughts: **Analyzing Potential Error Paths in Serial Communication**
Okay, so I'm digging into this code, specifically around serial communication and potential write errors. My immediate concern is this `tty_insert_flip_string` function. I know it can return a zero value if it has memory allocation issues – a classic problem, really. If that function craps out and returns zero, then the calling function, `pty_write`, is also going to return zero, signaling failure. Seems straightforward so far.
But here's where it gets interesting. `pty_write_room` returns the result of `tty_buffer_space_avail(tty->link->port)`. That's not the return value of `pty_write`, though it is part of how `pty_write` does its work. So, even if `tty_insert_flip_string` returns zero, `pty_write_room` might still give us a positive number. That looks like a potentially misleading status. I want to understand what's *really* going on. I need to trace this control flow. So, I need to look closely at what `tty_buffer_space_avail` actually reports. Is it a reliable indicator of success/failure in this particular scenario, or am I missing something? That's the next critical piece of this puzzle I need to solve.
|
| 81/2 |
2026/05/26 02:33 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/tty/tty_buffer.c IncludeLines:true Name:tty_buffer_space_avail]
Results: map[SourceCode: 83: /**
84: * tty_buffer_space_avail - return unused buffer space
85: * @port: tty port owning the flip buffer
86: *
87: * Returns: the # of bytes which can be written by the driver without reaching
88: * the buffer limit.
89: *
90: * Note: this does not guarantee that memory is available to write the returned
91: * # of bytes (use tty_prepare_flip_string() to pre-allocate if memory
92: * guarantee is required).
93: */
94: unsigned int tty_buffer_space_avail(struct tty_port *port)
95: {
96: int space = port->buf.mem_limit - atomic_read(&port->buf.mem_used);
97:
98: return max(space, 0);
99: }
SourceFile:drivers/tty/tty_buffer.c]
|
| 82/2 |
2026/05/26 02:33 |
llm |
expert |
1m
Model:
Tokens:
input: 99127
output: 19
thoughts: 371
Thoughts: **Analyzing a Potential Infinite Loop in TTY Handling**
Okay, so I'm digging into this `tty_buffer_space_avail` function, and it's hitting me that this isn't the *actual* allocated space, it's the theoretical limit, right? Which means we need to look deeper into memory allocation failures. Specifically, if `tty_insert_flip_string` craps out and can't allocate memory, it returns zero. That's the key. And when that happens, `pty_write` also returns zero. Hmm.
But here’s the problem: `pty_write_room` could *still* be returning a value greater than zero, even if the write fails! If that’s the case, then in `caif_serial.c`’s `handle_tx`, we’re staring down the barrel of an infinite loop!
Let me make sure I've got this right… `tty_insert_flip_string` fails, returns zero. `handle_tx` loops, calls `pty_write_room`, which says there's room, then calls `pty_write`… which fails *again* because memory allocation is still broken. *Infinite loop*. This could happen on a PTY, and if that's the case…
Okay, wait, can an unprivileged user even *get* `N_CAIF` set on a PTY? We already looked at `ldisc_open` for `N_CAIF`. We have a check that would only allow `CAP_SYS_ADMIN` or `CAP_SYS_TTY_CONFIG`.
```c
if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_TTY_CONFIG))
return -EPERM;
```
Right, so even on a PTY, setting `N_CAIF` needs a privileged capability in the initial user namespace. That means an unprivileged user CANNOT set `N_CAIF` on *any* TTY, including PTYs. Crisis averted!
But, I should still check if there are other line disciplines that have a similar `handle_tx` design and check for this kind of infinite loop. Time to check `drivers/net/slip/slip.c` or `drivers/net/ppp/ppp_async.c`. Gotta be thorough.
|
| 83/2 |
2026/05/26 02:34 |
tool |
grepper |
0m
Args: map[Expression:tty_write_room]
Results: map[Output:arch/m68k/emu/nfcon.c=80=static int nfcon_tty_put_char(struct tty_struct *tty, u8 ch)
--
arch/m68k/emu/nfcon.c-87-
arch/m68k/emu/nfcon.c:88:static unsigned int nfcon_tty_write_room(struct tty_struct *tty)
arch/m68k/emu/nfcon.c-89-{
--
arch/m68k/emu/nfcon.c=93=static const struct tty_operations nfcon_tty_ops = {
--
arch/m68k/emu/nfcon.c-97- .put_char = nfcon_tty_put_char,
arch/m68k/emu/nfcon.c:98: .write_room = nfcon_tty_write_room,
arch/m68k/emu/nfcon.c-99-};
--
drivers/accessibility/speakup/spk_ttyio.c=372=const char *spk_ttyio_synth_immediate(struct spk_synth *in_synth, const char *buff)
--
drivers/accessibility/speakup/spk_ttyio.c-379- ch = in_synth->procspeech;
drivers/accessibility/speakup/spk_ttyio.c:380: if (tty_write_room(tty) < 1 ||
drivers/accessibility/speakup/spk_ttyio.c-381- !in_synth->io_ops->synth_out(in_synth, ch))
--
drivers/isdn/capi/capi.c=1157=static void capinc_tty_flush_chars(struct tty_struct *tty)
--
drivers/isdn/capi/capi.c-1176-
drivers/isdn/capi/capi.c:1177:static unsigned int capinc_tty_write_room(struct tty_struct *tty)
drivers/isdn/capi/capi.c-1178-{
--
drivers/isdn/capi/capi.c-1183- room *= CAPI_MAX_BLKSIZE;
drivers/isdn/capi/capi.c:1184: pr_debug("capinc_tty_write_room = %u\n", room);
drivers/isdn/capi/capi.c-1185- return room;
--
drivers/isdn/capi/capi.c=1240=static const struct tty_operations capinc_ops = {
--
drivers/isdn/capi/capi.c-1245- .flush_chars = capinc_tty_flush_chars,
drivers/isdn/capi/capi.c:1246: .write_room = capinc_tty_write_room,
drivers/isdn/capi/capi.c-1247- .chars_in_buffer = capinc_tty_chars_in_buffer,
--
drivers/misc/bcm-vk/bcm_vk_tty.c=189=static ssize_t bcm_vk_tty_write(struct tty_struct *tty, const u8 *buffer,
--
drivers/misc/bcm-vk/bcm_vk_tty.c-215-
drivers/misc/bcm-vk/bcm_vk_tty.c:216:static unsigned int bcm_vk_tty_write_room(struct tty_struct *tty)
drivers/misc/bcm-vk/bcm_vk_tty.c-217-{
--
drivers/misc/bcm-vk/bcm_vk_tty.c=223=static const struct tty_operations serial_ops = {
--
drivers/misc/bcm-vk/bcm_vk_tty.c-226- .write = bcm_vk_tty_write,
drivers/misc/bcm-vk/bcm_vk_tty.c:227: .write_room = bcm_vk_tty_write_room,
drivers/misc/bcm-vk/bcm_vk_tty.c-228-};
--
drivers/net/caif/caif_serial.c=194=static int handle_tx(struct ser_device *ser)
--
drivers/net/caif/caif_serial.c-211- len = skb->len;
drivers/net/caif/caif_serial.c:212: room = tty_write_room(tty);
drivers/net/caif/caif_serial.c-213- if (!room)
--
drivers/s390/char/sclp_tty.c=89=static unsigned int
drivers/s390/char/sclp_tty.c:90:sclp_tty_write_room (struct tty_struct *tty)
drivers/s390/char/sclp_tty.c-91-{
--
drivers/s390/char/sclp_tty.c=482=static const struct tty_operations sclp_ops = {
--
drivers/s390/char/sclp_tty.c-487- .flush_chars = sclp_tty_flush_chars,
drivers/s390/char/sclp_tty.c:488: .write_room = sclp_tty_write_room,
drivers/s390/char/sclp_tty.c-489- .chars_in_buffer = sclp_tty_chars_in_buffer,
--
drivers/staging/greybus/uart.c=430=static ssize_t gb_tty_write(struct tty_struct *tty, const u8 *buf, size_t count)
--
drivers/staging/greybus/uart.c-441-
drivers/staging/greybus/uart.c:442:static unsigned int gb_tty_write_room(struct tty_struct *tty)
drivers/staging/greybus/uart.c-443-{
--
drivers/staging/greybus/uart.c=776=static const struct tty_operations gb_ops = {
--
drivers/staging/greybus/uart.c-782- .write = gb_tty_write,
drivers/staging/greybus/uart.c:783: .write_room = gb_tty_write_room,
drivers/staging/greybus/uart.c-784- .ioctl = gb_tty_ioctl,
--
drivers/tty/ehv_bytechan.c=451=static irqreturn_t ehv_bc_tty_tx_isr(int irq, void *data)
--
drivers/tty/ehv_bytechan.c-466- * We don't need to worry about whether there is enough room in the buffer for
drivers/tty/ehv_bytechan.c:467: * all the data. The purpose of ehv_bc_tty_write_room() is to tell the tty
drivers/tty/ehv_bytechan.c-468- * layer how much data it can safely send to us. We guarantee that
drivers/tty/ehv_bytechan.c:469: * ehv_bc_tty_write_room() will never lie, so the tty layer will never send us
drivers/tty/ehv_bytechan.c-470- * too much data.
--
drivers/tty/ehv_bytechan.c=526=static void ehv_bc_tty_close(struct tty_struct *ttys, struct file *filp)
--
drivers/tty/ehv_bytechan.c-540- */
drivers/tty/ehv_bytechan.c:541:static unsigned int ehv_bc_tty_write_room(struct tty_struct *ttys)
drivers/tty/ehv_bytechan.c-542-{
--
drivers/tty/ehv_bytechan.c=605=static const struct tty_operations ehv_bc_ops = {
--
drivers/tty/ehv_bytechan.c-608- .write = ehv_bc_tty_write,
drivers/tty/ehv_bytechan.c:609: .write_room = ehv_bc_tty_write_room,
drivers/tty/ehv_bytechan.c-610- .throttle = ehv_bc_tty_throttle,
--
drivers/tty/goldfish.c=181=static ssize_t goldfish_tty_write(struct tty_struct *tty, const u8 *buf,
--
drivers/tty/goldfish.c-187-
drivers/tty/goldfish.c:188:static unsigned int goldfish_tty_write_room(struct tty_struct *tty)
drivers/tty/goldfish.c-189-{
--
drivers/tty/goldfish.c=227=static const struct tty_operations goldfish_tty_ops = {
--
drivers/tty/goldfish.c-231- .write = goldfish_tty_write,
drivers/tty/goldfish.c:232: .write_room = goldfish_tty_write_room,
drivers/tty/goldfish.c-233- .chars_in_buffer = goldfish_tty_chars_in_buffer,
--
drivers/tty/mips_ejtag_fdc.c=799=static ssize_t mips_ejtag_fdc_tty_write(struct tty_struct *tty, const u8 *buf,
--
drivers/tty/mips_ejtag_fdc.c-842-
drivers/tty/mips_ejtag_fdc.c:843:static unsigned int mips_ejtag_fdc_tty_write_room(struct tty_struct *tty)
drivers/tty/mips_ejtag_fdc.c-844-{
--
drivers/tty/mips_ejtag_fdc.c=870=static const struct tty_operations mips_ejtag_fdc_tty_ops = {
--
drivers/tty/mips_ejtag_fdc.c-875- .write = mips_ejtag_fdc_tty_write,
drivers/tty/mips_ejtag_fdc.c:876: .write_room = mips_ejtag_fdc_tty_write_room,
drivers/tty/mips_ejtag_fdc.c-877- .chars_in_buffer = mips_ejtag_fdc_tty_chars_in_buffer,
--
drivers/tty/n_gsm.c=3514=static int gsmld_output(struct gsm_mux *gsm, u8 *data, int len)
drivers/tty/n_gsm.c-3515-{
drivers/tty/n_gsm.c:3516: if (tty_write_room(gsm->tty) < len) {
drivers/tty/n_gsm.c-3517- set_bit(TTY_DO_WRITE_WAKEUP, &gsm->tty->flags);
--
drivers/tty/n_gsm.c=3770=static ssize_t gsmld_write(struct tty_struct *tty, struct file *file,
--
drivers/tty/n_gsm.c-3782- spin_lock_irqsave(&gsm->tx_lock, flags);
drivers/tty/n_gsm.c:3783: space = tty_write_room(tty);
drivers/tty/n_gsm.c-3784- if (space >= nr)
--
drivers/tty/n_gsm.c=3807=static __poll_t gsmld_poll(struct tty_struct *tty, struct file *file,
--
drivers/tty/n_gsm.c-3821- mask |= EPOLLHUP;
drivers/tty/n_gsm.c:3822: if (!tty_is_writelocked(tty) && tty_write_room(tty) > 0)
drivers/tty/n_gsm.c-3823- mask |= EPOLLOUT | EPOLLWRNORM;
--
drivers/tty/n_gsm.c=4378=static ssize_t gsmtty_write(struct tty_struct *tty, const u8 *buf, size_t len)
--
drivers/tty/n_gsm.c-4390-
drivers/tty/n_gsm.c:4391:static unsigned int gsmtty_write_room(struct tty_struct *tty)
drivers/tty/n_gsm.c-4392-{
--
drivers/tty/n_gsm.c=4578=static const struct tty_operations gsmtty_ops = {
--
drivers/tty/n_gsm.c-4582- .write = gsmtty_write,
drivers/tty/n_gsm.c:4583: .write_room = gsmtty_write_room,
drivers/tty/n_gsm.c-4584- .chars_in_buffer = gsmtty_chars_in_buffer,
--
drivers/tty/n_tty.c=480=static int process_output(u8 c, struct tty_struct *tty)
--
drivers/tty/n_tty.c-485-
drivers/tty/n_tty.c:486: if (do_output_char(c, tty, tty_write_room(tty)) < 0)
drivers/tty/n_tty.c-487- return -1;
--
drivers/tty/n_tty.c=510=static ssize_t process_output_block(struct tty_struct *tty,
--
drivers/tty/n_tty.c-518-
drivers/tty/n_tty.c:519: space = tty_write_room(tty);
drivers/tty/n_tty.c-520- if (space == 0)
--
drivers/tty/n_tty.c=680=static size_t __process_echoes(struct tty_struct *tty)
--
drivers/tty/n_tty.c-686-
drivers/tty/n_tty.c:687: old_space = space = tty_write_room(tty);
drivers/tty/n_tty.c-688-
--
drivers/tty/n_tty.c=2445=static __poll_t n_tty_poll(struct tty_struct *tty, struct file *file,
--
drivers/tty/n_tty.c-2466- tty_chars_in_buffer(tty) < WAKEUP_CHARS &&
drivers/tty/n_tty.c:2467: tty_write_room(tty) > 0)
drivers/tty/n_tty.c-2468- mask |= EPOLLOUT | EPOLLWRNORM;
--
drivers/tty/nozomi.c=1583=static ssize_t ntty_write(struct tty_struct *tty, const u8 *buffer,
--
drivers/tty/nozomi.c-1622- */
drivers/tty/nozomi.c:1623:static unsigned int ntty_write_room(struct tty_struct *tty)
drivers/tty/nozomi.c-1624-{
--
drivers/tty/nozomi.c=1779=static const struct tty_operations tty_ops = {
--
drivers/tty/nozomi.c-1784- .write = ntty_write,
drivers/tty/nozomi.c:1785: .write_room = ntty_write_room,
drivers/tty/nozomi.c-1786- .unthrottle = ntty_unthrottle,
--
drivers/tty/rpmsg_tty.c=76=static ssize_t rpmsg_tty_write(struct tty_struct *tty, const u8 *buf,
--
drivers/tty/rpmsg_tty.c-104-
drivers/tty/rpmsg_tty.c:105:static unsigned int rpmsg_tty_write_room(struct tty_struct *tty)
drivers/tty/rpmsg_tty.c-106-{
--
drivers/tty/rpmsg_tty.c=122=static const struct tty_operations rpmsg_tty_ops = {
--
drivers/tty/rpmsg_tty.c-126- .write = rpmsg_tty_write,
drivers/tty/rpmsg_tty.c:127: .write_room = rpmsg_tty_write_room,
drivers/tty/rpmsg_tty.c-128- .hangup = rpmsg_tty_hangup,
--
drivers/tty/tty_ioctl.c=54=EXPORT_SYMBOL(tty_chars_in_buffer);
--
drivers/tty/tty_ioctl.c-56-/**
drivers/tty/tty_ioctl.c:57: * tty_write_room - write queue space
drivers/tty/tty_ioctl.c-58- * @tty: terminal
--
drivers/tty/tty_ioctl.c-65- */
drivers/tty/tty_ioctl.c:66:unsigned int tty_write_room(struct tty_struct *tty)
drivers/tty/tty_ioctl.c-67-{
--
drivers/tty/tty_ioctl.c-71-}
drivers/tty/tty_ioctl.c:72:EXPORT_SYMBOL(tty_write_room);
drivers/tty/tty_ioctl.c-73-
--
drivers/usb/class/cdc-acm.c=814=static ssize_t acm_tty_write(struct tty_struct *tty, const u8 *buf,
--
drivers/usb/class/cdc-acm.c-867-
drivers/usb/class/cdc-acm.c:868:static unsigned int acm_tty_write_room(struct tty_struct *tty)
drivers/usb/class/cdc-acm.c-869-{
--
drivers/usb/class/cdc-acm.c=2057=static const struct tty_operations acm_ops = {
--
drivers/usb/class/cdc-acm.c-2063- .write = acm_tty_write,
drivers/usb/class/cdc-acm.c:2064: .write_room = acm_tty_write_room,
drivers/usb/class/cdc-acm.c-2065- .flush_buffer = acm_tty_flush_buffer,
--
drivers/usb/host/xhci-dbgtty.c=326=static void dbc_tty_flush_chars(struct tty_struct *tty)
--
drivers/usb/host/xhci-dbgtty.c-335-
drivers/usb/host/xhci-dbgtty.c:336:static unsigned int dbc_tty_write_room(struct tty_struct *tty)
drivers/usb/host/xhci-dbgtty.c-337-{
--
drivers/usb/host/xhci-dbgtty.c=376=static const struct tty_operations dbc_tty_ops = {
--
drivers/usb/host/xhci-dbgtty.c-382- .flush_chars = dbc_tty_flush_chars,
drivers/usb/host/xhci-dbgtty.c:383: .write_room = dbc_tty_write_room,
drivers/usb/host/xhci-dbgtty.c-384- .chars_in_buffer = dbc_tty_chars_in_buffer,
--
include/linux/tty.h=409=unsigned int tty_chars_in_buffer(struct tty_struct *tty);
include/linux/tty.h:410:unsigned int tty_write_room(struct tty_struct *tty);
include/linux/tty.h-411-void tty_driver_flush_buffer(struct tty_struct *tty);
--
include/linux/tty_driver.h=93=enum tty_driver_subtype {
--
include/linux/tty_driver.h-202- * Required if @write method is provided else not needed. Do not call this
include/linux/tty_driver.h:203: * function directly, call tty_write_room()
include/linux/tty_driver.h-204- *
--
net/bluetooth/rfcomm/tty.c=779=static ssize_t rfcomm_tty_write(struct tty_struct *tty, const u8 *buf,
--
net/bluetooth/rfcomm/tty.c-808-
net/bluetooth/rfcomm/tty.c:809:static unsigned int rfcomm_tty_write_room(struct tty_struct *tty)
net/bluetooth/rfcomm/tty.c-810-{
--
net/bluetooth/rfcomm/tty.c=1104=static const struct tty_operations rfcomm_ops = {
--
net/bluetooth/rfcomm/tty.c-1107- .write = rfcomm_tty_write,
net/bluetooth/rfcomm/tty.c:1108: .write_room = rfcomm_tty_write_room,
net/bluetooth/rfcomm/tty.c-1109- .chars_in_buffer = rfcomm_tty_chars_in_buffer,
]
|
| 84/2 |
2026/05/26 02:34 |
llm |
expert |
0m
Model:
Tokens:
input: 105355
output: 42
thoughts: 83
Thoughts: **Analyzing Serial Line Disciplines**
Okay, so I'm digging into how these serial line disciplines are implemented, specifically focusing on data transmission. My initial concern is with `handle_tx`, which is currently defined within `drivers/net/caif/caif_serial.c`. That's where the transmission handling logic for that particular CAIF serial interface resides. I need to understand if this pattern is unique to CAIF or if it's more widespread.
My next step is to investigate if other line disciplines follow a similar approach. Specifically, I'm thinking about the standard Serial Line Internet Protocol (SLIP) implementation. If I recall correctly, `drivers/net/slip/slip.c` might be a good example to check. Does SLIP also have its own transmission handler, or does it do something different?
Let me jump to `drivers/net/slip/slip.c` and take a look at the `sl_xmit` function. I suspect it might be using the `tty->ops->write(tty, ...)` function directly to interact with the underlying serial port. That would represent a significant design contrast if CAIF uses its own `handle_tx` implementation. Understanding this distinction is crucial for getting a complete picture of the range of solutions and their implications for future serial line driver work.
|
| 85/2 |
2026/05/26 02:35 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/net/slip/slip.c IncludeLines:true Name:sl_xmit]
Results: map[SourceCode: 497: /* Encapsulate an IP datagram and kick it into a TTY queue. */
498: static netdev_tx_t
499: sl_xmit(struct sk_buff *skb, struct net_device *dev)
500: {
501: struct slip *sl = netdev_priv(dev);
502:
503: spin_lock(&sl->lock);
504: if (!netif_running(dev)) {
505: spin_unlock(&sl->lock);
506: printk(KERN_WARNING "%s: xmit call when iface is down\n", dev->name);
507: dev_kfree_skb(skb);
508: return NETDEV_TX_OK;
509: }
510: if (sl->tty == NULL) {
511: spin_unlock(&sl->lock);
512: dev_kfree_skb(skb);
513: return NETDEV_TX_OK;
514: }
515:
516: sl_lock(sl);
517: dev->stats.tx_bytes += skb->len;
518: sl_encaps(sl, skb->data, skb->len);
519: spin_unlock(&sl->lock);
520:
521: dev_kfree_skb(skb);
522: return NETDEV_TX_OK;
523: }
SourceFile:drivers/net/slip/slip.c]
|
| 86/2 |
2026/05/26 02:35 |
llm |
expert |
0m
Model:
Tokens:
input: 106206
output: 42
thoughts: 27
Thoughts: Okay, here's my attempt at summarizing that thought process, assuming I'm a seasoned kernel developer:
**Delving into the Serial Line Encapsulation**
Right, `sl_encaps`... that function call looks a bit familiar. Let me mentally trace this. It's calling `sl->tty->ops->write`. Okay, so `sl_encaps` is likely interacting with the serial port driver's `write` operation. Makes sense, that's where the data transmission happens, I'd expect. Now I need to quickly confirm what's happening in `sl_encaps` and understand the flow of data. I'll need to double-check the context, especially around how `sl` is populated and how the `tty` structure is associated with the serial line interface. What's it doing with `sl->tty`? Is it just passing data through, or is there any packetization or other processing going on before the write operation? Best to have a look and refresh myself on the details.
|
| 87/2 |
2026/05/26 02:35 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/net/slip/slip.c IncludeLines:true Name:sl_encaps]
Results: map[SourceCode: 375: /* Encapsulate one IP datagram and stuff into a TTY queue. */
376: static void sl_encaps(struct slip *sl, unsigned char *icp, int len)
377: {
378: unsigned char *p;
379: int actual, count;
380:
381: if (len > sl->mtu) { /* Sigh, shouldn't occur BUT ... */
382: printk(KERN_WARNING "%s: truncating oversized transmit packet!\n", sl->dev->name);
383: sl->dev->stats.tx_dropped++;
384: sl_unlock(sl);
385: return;
386: }
387:
388: p = icp;
389: #ifdef SL_INCLUDE_CSLIP
390: if (sl->mode & SL_MODE_CSLIP)
391: len = slhc_compress(sl->slcomp, p, len, sl->cbuff, &p, 1);
392: #endif
393: #ifdef CONFIG_SLIP_MODE_SLIP6
394: if (sl->mode & SL_MODE_SLIP6)
395: count = slip_esc6(p, sl->xbuff, len);
396: else
397: #endif
398: count = slip_esc(p, sl->xbuff, len);
399:
400: /* Order of next two lines is *very* important.
401: * When we are sending a little amount of data,
402: * the transfer may be completed inside the ops->write()
403: * routine, because it's running with interrupts enabled.
404: * In this case we *never* got WRITE_WAKEUP event,
405: * if we did not request it before write operation.
406: * 14 Oct 1994 Dmitry Gorodchanin.
407: */
408: set_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags);
409: actual = sl->tty->ops->write(sl->tty, sl->xbuff, count);
410: #ifdef SL_CHECK_TRANSMIT
411: netif_trans_update(sl->dev);
412: #endif
413: sl->xleft = count - actual;
414: sl->xhead = sl->xbuff + actual;
415: #ifdef CONFIG_SLIP_SMART
416: /* VSV */
417: clear_bit(SLF_OUTWAIT, &sl->flags); /* reset outfill flag */
418: #endif
419: }
SourceFile:drivers/net/slip/slip.c]
|
| 88/2 |
2026/05/26 02:35 |
llm |
expert |
0m
Model:
Tokens:
input: 107285
output: 45
thoughts: 99
Thoughts: **My Analysis of the `sl_encaps` Function**
Okay, so `sl_encaps` is fairly straightforward. It seems that `sl_encaps` is designed to send data to the serial line. It calls `sl->tty->ops->write(sl->tty, sl->xbuff, count)`. Now, if that write operation returns zero, indicating a failure to write anything (a completely filled buffer, perhaps), the variable `actual` is set to zero as well. Crucially, I see that `sl->xleft` is assigned the initial `count` value, the number of bytes that were *intended* to be written. The important thing here, the bit that confirms my understanding, is that this doesn't loop. This isn't a tight loop waiting for the entire buffer to empty. Instead, it relies on a `WRITE_WAKEUP` signal to handle the remaining data. That implies it's non-blocking, which makes the `slip` (Serial Line Internet Protocol) code seem much safer, preventing potential deadlock situations.
Now I need to turn my attention to `drivers/net/ppp/ppp_async.c`. This analysis seems to suggest some patterns that might relate to the asynchronous nature of PPP and needs further investigation.
|
| 89/2 |
2026/05/26 02:35 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/net/ppp/ppp_async.c IncludeLines:true Name:ppp_async_push]
Results: map[SourceCode: 638: /*
639: * Push as much data as possible out to the tty.
640: */
641: static int
642: ppp_async_push(struct asyncppp *ap)
643: {
644: int avail, sent, done = 0;
645: struct tty_struct *tty = ap->tty;
646: int tty_stuffed = 0;
647:
648: /*
649: * We can get called recursively here if the tty write
650: * function calls our wakeup function. This can happen
651: * for example on a pty with both the master and slave
652: * set to PPP line discipline.
653: * We use the XMIT_BUSY bit to detect this and get out,
654: * leaving the XMIT_WAKEUP bit set to tell the other
655: * instance that it may now be able to write more now.
656: */
657: if (test_and_set_bit(XMIT_BUSY, &ap->xmit_flags))
658: return 0;
659: spin_lock_bh(&ap->xmit_lock);
660: for (;;) {
661: if (test_and_clear_bit(XMIT_WAKEUP, &ap->xmit_flags))
662: tty_stuffed = 0;
663: if (!tty_stuffed && ap->optr < ap->olim) {
664: avail = ap->olim - ap->optr;
665: set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
666: sent = tty->ops->write(tty, ap->optr, avail);
667: if (sent < 0)
668: goto flush; /* error, e.g. loss of CD */
669: ap->optr += sent;
670: if (sent < avail)
671: tty_stuffed = 1;
672: continue;
673: }
674: if (ap->optr >= ap->olim && ap->tpkt) {
675: if (ppp_async_encode(ap)) {
676: /* finished processing ap->tpkt */
677: clear_bit(XMIT_FULL, &ap->xmit_flags);
678: done = 1;
679: }
680: continue;
681: }
682: /*
683: * We haven't made any progress this time around.
684: * Clear XMIT_BUSY to let other callers in, but
685: * after doing so we have to check if anyone set
686: * XMIT_WAKEUP since we last checked it. If they
687: * did, we should try again to set XMIT_BUSY and go
688: * around again in case XMIT_BUSY was still set when
689: * the other caller tried.
690: */
691: clear_bit(XMIT_BUSY, &ap->xmit_flags);
692: /* any more work to do? if not, exit the loop */
693: if (!(test_bit(XMIT_WAKEUP, &ap->xmit_flags) ||
694: (!tty_stuffed && ap->tpkt)))
695: break;
696: /* more work to do, see if we can do it now */
697: if (test_and_set_bit(XMIT_BUSY, &ap->xmit_flags))
698: break;
699: }
700: spin_unlock_bh(&ap->xmit_lock);
701: return done;
702:
703: flush:
704: clear_bit(XMIT_BUSY, &ap->xmit_flags);
705: if (ap->tpkt) {
706: kfree_skb(ap->tpkt);
707: ap->tpkt = NULL;
708: clear_bit(XMIT_FULL, &ap->xmit_flags);
709: done = 1;
710: }
711: ap->optr = ap->olim;
712: spin_unlock_bh(&ap->xmit_lock);
713: return done;
714: }
SourceFile:drivers/net/ppp/ppp_async.c]
|
| 90/2 |
2026/05/26 02:35 |
llm |
expert |
0m
Model:
Tokens:
input: 108985
output: 66
thoughts: 1135
Thoughts: **Analysis of the CAIF Serial Driver Infinite Loop Vulnerability**
Okay, let's break this down. My initial thought was about how `ppp_async_push` interacts with the `tty` write operation. Specifically, if `tty->ops->write` returns 0, the code sets `tty_stuffed` and continues. However, I noticed that `ppp_async` safely exits the loop under these conditions because of the `XMIT_BUSY` check and breaking the loop. So, that's not the problem.
Then, I focused on the `caif_serial.c` code. It became clear that there's a serious flaw in how `handle_tx` handles a zero return from `tty->ops->write`. The loop condition doesn't update `skb->data`, it doesn't move data out of the socket buffer, meaning if the tty write returns 0, the loop will repeat infinitely. Because `tty_write_room` returns >0, the loop has no break condition. This is a classic infinite loop bug, and it is in fact a denial-of-service vulnerability.
The security impact is limited, however. I'm seeing that the bug involves a `tty` write. It's a local DoS, not a remote exploit. To trigger this, a process needs either `CAP_SYS_ADMIN` or `CAP_SYS_TTY_CONFIG` in the *initial* user namespace to set up the `N_CAIF` line discipline. This means unprivileged processes, even those with all capabilities *within* a user namespace, can't trigger it.
I then started thinking about a more complex scenario. Could an unprivileged process exploit this if a privileged process sets up the CAIF line discipline, and then the privileged process shuts it down? In that brief window, a race condition is possible: if an unprivileged process sends a packet to the CAIF netdevice *before* the privileged process finishes shutting down and freeing the resources, the bug *could* trigger. This is a very narrow window, requiring very specific timing and coordination between privileged and unprivileged processes. It's still just a local DoS, but the race condition makes it more concerning.
After rechecking the capabilities requirements, I'm confident in the security assessment. It boils down to:
* **Exploitable:** False (no memory corruption or privilege escalation).
* **Denial of Service:** True (infinite loop leading to RCU stall).
* **Unprivileged:** False (requires capabilities).
* **User Namespace:** False (initial user namespace requirements).
* **Other Triggers:** False (no remote, network, filesystem, VM guest/host, or peripheral triggers).
Therefore, the issue is a local DoS vulnerability, unlikely to be exploited due to requiring capabilities in the initial namespace, and even the race condition is unlikely in most real-world scenarios.
|
| 91/2 |
2026/05/26 02:35 |
tool |
set-results |
0m
Args: map[DenialOfService:true Exploitable:false FilesystemTrigger:false NetworkTrigger:false PeripheralTrigger:false RemoteTrigger:false Unprivileged:false UserNamespace:false VMGuestTrigger:false VMHostTrigger:false]
Results: map[DenialOfService:true Exploitable:false FilesystemTrigger:false NetworkTrigger:false PeripheralTrigger:false RemoteTrigger:false Unprivileged:false UserNamespace:false VMGuestTrigger:false VMHostTrigger:false]
|
| 92/2 |
2026/05/26 02:35 |
llm |
expert |
1m
Model:
Tokens:
input: 110875
output: 815
thoughts: 527
Thoughts: **Finalizing the Analysis: Root Cause and Security Impact**
Alright, the analysis is complete. Now it's time to craft the final response, clearly outlining the root cause of this issue and, of course, the resulting security impact.
The core of the problem lies within an infinite loop buried deep within `drivers/net/caif/caif_serial.c`, specifically in the `handle_tx` function. The sequence of events that triggers this is quite intricate. When the CAIF line discipline (`N_CAIF`) is closed, `ldisc_close` sets up a workqueue, `ser_release_work`, to unregister the CAIF network device. However, this function returns immediately. Simultaneously, the TTY layer continues its close procedures, cascading down to `uart_close`, then `uart_shutdown`, and finally, `uart_free_xmit_buf`.
Here's where things get interesting. `uart_free_xmit_buf` does two critical things: it frees the TTY's transmit buffer (`port->xmit_buf = NULL`) and re-initializes the transmit FIFO (`INIT_KFIFO(port->xmit_fifo)`). This re-initialization sets the FIFO's mask to zero. If a packet is transmitted via the CAIF network device *before* the workqueue can unregister it, `caif_xmit` kicks off `handle_tx`. Inside `handle_tx`, `tty_write_room(tty)` returns 1 (because the zero-initialized FIFO acts as though it has some room available!). However, the TTY operation `tty->ops->write` (which is `uart_write` in this case) returns 0 because the transmit buffer (`state->port.xmit_buf`) is, at this point, NULL. Since `tty_wr` is zero, `skb_pull(skb, 0)` doesn't actually remove anything from the buffer, and the loop just repeats forever, because `skb->len` doesn't change. This infinite loop, with preemption disabled (courtesy of `dev_queue_xmit`), inevitably causes an RCU stall, resulting in a system hang.
Now, let's address the security implications. Thankfully, this is *not* directly exploitable for privilege escalation or memory corruption. It's a classic denial-of-service vulnerability. This infinite loop definitely causes a system crash or freeze due to the RCU stall and CPU lock-up. As for accessibility, it requires setting the `N_CAIF` line discipline. This demands `CAP_SYS_ADMIN` or `CAP_SYS_TTY_CONFIG` in the *initial* user namespace, checked by the `capable()` function in `ldisc_open`. This means unprivileged users, even inside user namespaces, are locked out of triggering this particular condition. It's also worth noting that triggering this bug is limited to local execution of specific `ioctl` commands on a TTY device.
|
| 93/1 |
2026/05/26 02:36 |
action |
format-explanation |
0m
Results: map[Explanation:**Root Cause Analysis**
The bug is an infinite loop in the `handle_tx` function in
`drivers/net/caif/caif_serial.c`, which leads to an RCU stall and CPU hang.
When the CAIF line discipline (`N_CAIF`) is detached from a TTY (e.g., when the
TTY is closed), `ldisc_close` is called. This function schedules a workqueue
(`ser_release_work`) to unregister the CAIF network device but returns
immediately.
Meanwhile, the TTY layer continues the close process, eventually calling
`uart_close` -> `uart_shutdown` -> `uart_free_xmit_buf`. The
`uart_free_xmit_buf` function frees the TTY's transmit buffer (`port->xmit_buf =
NULL`) and re-initializes the transmit FIFO (`INIT_KFIFO(port->xmit_fifo)`),
which resets the FIFO's mask to 0.
If a packet is transmitted via the CAIF network device (e.g., by a kernel thread
like `aoe_tx0` or another process) during this small race window before the
workqueue actually unregisters the netdevice, `caif_xmit` is called, which in
turn calls `handle_tx`.
In `handle_tx`, the code loops over the packets to send:
1. `tty_write_room(tty)` is called. Because the FIFO was zero-initialized,
`kfifo_avail` calculates the available space as 1.
2. Since `room > 0`, `handle_tx` attempts to write the data by calling
`tty->ops->write` (which maps to `uart_write`).
3. `uart_write` checks if the transmit buffer exists (`if
(!state->port.xmit_buf)`). Since it was freed and set to `NULL`, it safely
returns `0` (0 bytes written).
4. `handle_tx` receives `tty_wr = 0`. It calls `skb_pull(skb, 0)`, which does
nothing. The `skb->len` remains unchanged.
5. The loop repeats infinitely because the packet is never consumed,
`tty_write_room` keeps returning 1, and `uart_write` keeps returning 0.
This infinite loop runs with preemption disabled (as it's called from the
network transmit path), causing an RCU stall and effectively hanging the CPU.
**Security Impact Assessment**
* **Exploitable:** No. The bug is a pure logical infinite loop. It does not
involve memory corruption, out-of-bounds accesses, or use-after-free
vulnerabilities that could be leveraged for privilege escalation or arbitrary
code execution.
* **Denial Of Service:** Yes. Triggering the bug hangs the CPU in an infinite
loop, leading to an RCU stall and a complete system freeze or panic.
* **Accessible From Unprivileged Processes:** No. Attaching the `N_CAIF` line
discipline to a TTY requires the caller to have `CAP_SYS_ADMIN` or
`CAP_SYS_TTY_CONFIG` capabilities. This is explicitly checked in `ldisc_open` in
`caif_serial.c`.
* **Accessible From User Namespaces:** No. The capability check in `ldisc_open`
uses `capable(CAP_SYS_ADMIN)`, which checks the capabilities against the
**initial** user namespace (`init_user_ns`), not the current user namespace.
Therefore, an unprivileged user cannot bypass this restriction by creating a new
user namespace.
* **Other Triggers:** The bug cannot be triggered remotely, via network packets,
malicious filesystems, or plugged peripherals. It strictly requires local
execution of specific `ioctl` commands on a TTY device by a highly privileged
user.]
|