Skip to content

Commit 15756da

Browse files
net/iob: Add CONFIG_IOB_OWNER_TRACKING to record IOB owner for debugging
This adds a Kconfig option to optionally track the allocating context of each IOB (task PID or ISR). The extra metadata makes it much easier to diagnose IOB leaks, starvation, and ownership/lifetime bugs across task/ISR boundaries without changing the IOB API seen by callers. Signed-off-by: Peter van der Perk <peter.vanderperk@nxp.com>
1 parent 51bcec5 commit 15756da

7 files changed

Lines changed: 347 additions & 0 deletions

File tree

fs/procfs/fs_procfsiobinfo.c

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#include <nuttx/mm/iob.h>
4444
#include <nuttx/fs/fs.h>
4545
#include <nuttx/fs/procfs.h>
46+
#include <nuttx/spinlock.h>
4647

4748
#include "fs_heap.h"
4849

@@ -111,6 +112,11 @@ const struct procfs_operations g_iobinfo_operations =
111112
iobinfo_stat /* stat */
112113
};
113114

115+
#ifdef CONFIG_IOB_OWNER_TRACKING
116+
extern volatile spinlock_t g_iob_lock;
117+
extern FAR struct iob_s *g_iob_committed;
118+
#endif
119+
114120
/****************************************************************************
115121
* Private Functions
116122
****************************************************************************/
@@ -223,6 +229,44 @@ static ssize_t iobinfo_read(FAR struct file *filep, FAR char *buffer,
223229
&offset);
224230
totalsize += copysize;
225231

232+
#ifdef CONFIG_IOB_OWNER_TRACKING
233+
buffer += copysize;
234+
buflen -= copysize;
235+
236+
irqstate_t flags = spin_lock_irqsave(&g_iob_lock);
237+
238+
for (unsigned int i = 0; i < CONFIG_IOB_NBUFFERS; i++)
239+
{
240+
FAR struct iob_s *iob = iob_get_iob_by_index(i);
241+
242+
/* Print: PID (or -1 for ISR) and flags in hex */
243+
244+
if (iob->io_owner_flags != 0)
245+
{
246+
linesize = procfs_snprintf(iobfile->line, IOBINFO_LINELEN,
247+
"%02d %p -> %p pid=%d flags=0x%02x\n", i,
248+
iob, iob->io_flink,
249+
(int)iob->io_owner_pid,
250+
(unsigned)iob->io_owner_flags);
251+
}
252+
else
253+
{
254+
linesize = procfs_snprintf(iobfile->line, IOBINFO_LINELEN,
255+
"%02d %p -> %p Free\n", i,
256+
iob, iob->io_flink);
257+
}
258+
259+
copysize = procfs_memcpy(iobfile->line, linesize,
260+
buffer, buflen, &offset);
261+
totalsize += copysize;
262+
263+
buffer += copysize;
264+
buflen -= copysize;
265+
}
266+
267+
spin_unlock_irqrestore(&g_iob_lock, flags);
268+
#endif
269+
226270
/* Update the file offset */
227271

228272
filep->f_pos += totalsize;

include/nuttx/mm/iob.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,12 @@ struct iob_s
126126
#endif
127127
unsigned int io_pktlen; /* Total length of the packet */
128128

129+
#ifdef CONFIG_IOB_OWNER_TRACKING
130+
int16_t io_owner_pid;
131+
uint8_t io_owner_cpu; /* CPU index (SMP), 0 on UP */
132+
uint8_t io_owner_flags; /* bit0: ISR; bit1: committed; future use */
133+
#endif
134+
129135
#ifdef CONFIG_IOB_ALLOC
130136
iob_free_cb_t io_free; /* Custom free callback */
131137
FAR uint8_t *io_data;
@@ -183,6 +189,10 @@ struct iob_stats_s
183189

184190
void iob_initialize(void);
185191

192+
#ifdef CONFIG_IOB_OWNER_TRACKING
193+
struct iob_s *iob_get_iob_by_index(unsigned int index);
194+
#endif
195+
186196
/****************************************************************************
187197
* Name: iob_timedalloc
188198
*

mm/iob/Kconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,5 +122,14 @@ config IOB_DEBUG
122122
NOTE that this selection is not available if IOBs are being used
123123
to syslog buffering logic (CONFIG_SYSLOG_BUFFER=y)!
124124

125+
config IOB_OWNER_TRACKING
126+
bool "Track task/ISR owner of each IOB (for debugging)"
127+
default n
128+
help
129+
When enabled, each IOB carries small metadata indicating the
130+
allocating context (task PID or ISR). This helps debug leaks,
131+
starvation and ownership bugs without changing the IOB API.
132+
Disabled by default to avoid extra RAM on small targets.
133+
125134
endif # MM_IOB
126135
endmenu # Common I/O buffer support

mm/iob/iob_alloc.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,34 @@
3838
#include <nuttx/nuttx.h>
3939
#include <nuttx/mm/iob.h>
4040

41+
#ifdef CONFIG_IOB_OWNER_TRACKING
42+
#include <nuttx/irq.h> /* up_interrupt_context() */
43+
#include <nuttx/sched.h> /* getpid(), this_cpu() if available */
44+
#endif
45+
4146
#include "iob.h"
4247

4348
/****************************************************************************
4449
* Private Functions
4550
****************************************************************************/
4651

52+
/* Small helper to stamp owner information */
53+
#ifdef CONFIG_IOB_OWNER_TRACKING
54+
static inline void iob_set_owner(FAR struct iob_s *iob, bool is_committed)
55+
{
56+
bool isr = up_interrupt_context();
57+
int pid = isr ? -1 : getpid(); /* Kernel-space getpid is OK */
58+
#ifdef CONFIG_SMP
59+
iob->io_owner_cpu = (uint8_t)this_cpu(); /* otherwise 0 on UP */
60+
#else
61+
iob->io_owner_cpu = 0;
62+
#endif
63+
iob->io_owner_pid = (int16_t)pid;
64+
iob->io_owner_flags = 0x1 |
65+
(isr ? 0x02 : 0x00) | (is_committed ? 0x04 : 0x00);
66+
}
67+
#endif
68+
4769
static clock_t iob_allocwait_gettimeout(clock_t start, unsigned int timeout)
4870
{
4971
sclock_t tick;
@@ -96,6 +118,9 @@ static FAR struct iob_s *iob_alloc_committed(void)
96118
iob->io_len = 0; /* Length of the data in the entry */
97119
iob->io_offset = 0; /* Offset to the beginning of data */
98120
iob->io_pktlen = 0; /* Total length of the packet */
121+
#ifdef CONFIG_IOB_OWNER_TRACKING
122+
iob_set_owner(iob, true);
123+
#endif
99124
}
100125

101126
spin_unlock_irqrestore(&g_iob_lock, flags);
@@ -135,6 +160,11 @@ static FAR struct iob_s *iob_tryalloc_internal(bool throttled)
135160
iob->io_len = 0; /* Length of the data in the entry */
136161
iob->io_offset = 0; /* Offset to the beginning of data */
137162
iob->io_pktlen = 0; /* Total length of the packet */
163+
164+
#ifdef CONFIG_IOB_OWNER_TRACKING
165+
iob_set_owner(iob, false);
166+
#endif
167+
138168
return iob;
139169
}
140170
}

mm/iob/iob_free.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,13 @@ FAR struct iob_s *iob_free(FAR struct iob_s *iob)
133133
kmm_free(iob);
134134
}
135135

136+
#ifdef CONFIG_IOB_OWNER_TRACKING
137+
/* Clear owner metadata when returning to free list */
138+
139+
iob->io_owner_pid = 0;
140+
iob->io_owner_cpu = 0;
141+
iob->io_owner_flags = 0;
142+
#endif
136143
return next;
137144
}
138145
#endif
@@ -196,6 +203,14 @@ FAR struct iob_s *iob_free(FAR struct iob_s *iob)
196203
}
197204
#endif
198205

206+
#ifdef CONFIG_IOB_OWNER_TRACKING
207+
/* Clear owner metadata when returning to free list */
208+
209+
iob->io_owner_pid = 0;
210+
iob->io_owner_cpu = 0;
211+
iob->io_owner_flags = 0;
212+
#endif
213+
199214
/* And return the I/O buffer after the one that was freed */
200215

201216
return next;

0 commit comments

Comments
 (0)