diff --git a/boards/sim/sim/sim/configs/citest/defconfig b/boards/sim/sim/sim/configs/citest/defconfig index c67f4eae55..c6f88a869e 100644 --- a/boards/sim/sim/sim/configs/citest/defconfig +++ b/boards/sim/sim/sim/configs/citest/defconfig @@ -49,6 +49,7 @@ CONFIG_FRAME_POINTER=y CONFIG_FSUTILS_PASSWD=y CONFIG_FSUTILS_PASSWD_READONLY=y CONFIG_FS_AIO=y +CONFIG_FS_BACKTRACE=8 CONFIG_FS_BINFS=y CONFIG_FS_FAT=y CONFIG_FS_HOSTFS=y diff --git a/fs/inode/fs_files.c b/fs/inode/fs_files.c index 40cb5f9911..5017a72a8e 100644 --- a/fs/inode/fs_files.c +++ b/fs/inode/fs_files.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -460,6 +461,8 @@ found: inode_addref(inode); } + FS_ADD_BACKTRACE(filep); + #ifdef CONFIG_FDCHECK return fdcheck_protect(i * CONFIG_NFILE_DESCRIPTORS_PER_BLOCK + j); #else @@ -487,6 +490,27 @@ int file_allocate(FAR struct inode *inode, int oflags, off_t pos, pos, priv, minfd, addref); } +FAR char *file_dump_backtrace(FAR struct file *filep, FAR char *buffer, + size_t len) +{ +#if CONFIG_FS_BACKTRACE > 0 + FAR const char *format = "%0*p "; + int k; + + buffer[0] = '\0'; + for (k = 0; k < CONFIG_FS_BACKTRACE && filep->f_backtrace[k]; k++) + { + snprintf(buffer + k * FS_BACKTRACE_WIDTH, + len - k * FS_BACKTRACE_WIDTH, + format, FS_BACKTRACE_WIDTH - 1, + filep->f_backtrace[k]); + } +#else + buffer[0] = '\0'; +#endif + return buffer; +} + /**************************************************************************** * Name: files_duplist * diff --git a/fs/inode/inode.h b/fs/inode/inode.h index 3518676765..a3bfe991cb 100644 --- a/fs/inode/inode.h +++ b/fs/inode/inode.h @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -65,6 +66,23 @@ } \ while (0) +#if CONFIG_FS_BACKTRACE > 0 +# define FS_ADD_BACKTRACE(filep) \ + do \ + { \ + int n = sched_backtrace(_SCHED_GETTID(), filep->f_backtrace, \ + CONFIG_FS_BACKTRACE, \ + CONFIG_FS_BACKTRACE_SKIP); \ + if (n < CONFIG_FS_BACKTRACE) \ + { \ + (filep->f_backtrace)[n] = NULL; \ + } \ + } \ + while (0) +#else +# define FS_ADD_BACKTRACE(filep) +#endif + /**************************************************************************** * Public Types ****************************************************************************/ diff --git a/fs/procfs/fs_procfsproc.c b/fs/procfs/fs_procfsproc.c index 4f5911e130..0a7811f578 100644 --- a/fs/procfs/fs_procfsproc.c +++ b/fs/procfs/fs_procfsproc.c @@ -1244,8 +1244,6 @@ static ssize_t proc_groupfd(FAR struct proc_file_s *procfile, size_t buflen, off_t offset) { FAR struct task_group_s *group = tcb->group; - FAR struct file *filep; - char path[PATH_MAX]; size_t remaining; size_t linesize; size_t copysize; @@ -1253,6 +1251,10 @@ static ssize_t proc_groupfd(FAR struct proc_file_s *procfile, int count; int i; + FAR struct file *filep; + char path[PATH_MAX]; + char backtrace[FS_BACKTRACE_BUFFER_LEN]; + DEBUGASSERT(group != NULL); count = files_countlist(&group->tg_filelist); @@ -1265,8 +1267,14 @@ static ssize_t proc_groupfd(FAR struct proc_file_s *procfile, totalsize = 0; linesize = procfs_snprintf(procfile->line, STATUS_LINELEN, - "\n%-3s %-7s %-4s %-9s %s\n", - "FD", "OFLAGS", "TYPE", "POS", "PATH"); + "\n%-3s %-7s %-4s %-9s %-14s %s\n", + "FD", "OFLAGS", "TYPE", "POS", "PATH", +#if CONFIG_FS_BACKTRACE > 0 + "BACKTRACE" +#else + "" +#endif + ); copysize = procfs_memcpy(procfile->line, linesize, buffer, remaining, &offset); @@ -1298,12 +1306,22 @@ static ssize_t proc_groupfd(FAR struct proc_file_s *procfile, } linesize = procfs_snprintf(procfile->line, STATUS_LINELEN, - "%-3d %-7d %-4x %-9ld %s\n", + "%-3d %-7d %-4x %-9ld %-14s %s\n", i, filep->f_oflags, INODE_GET_TYPE(filep->f_inode), - (long)filep->f_pos, path); + (long)filep->f_pos, path, + file_dump_backtrace(filep, + backtrace, + sizeof(backtrace) + ) + ); copysize = procfs_memcpy(procfile->line, linesize, buffer, remaining, &offset); + if (linesize + 1 == STATUS_LINELEN) + { + procfile->line[STATUS_LINELEN - 2] = '\n'; + linesize = STATUS_LINELEN; + } totalsize += copysize; buffer += copysize; diff --git a/fs/vfs/Kconfig b/fs/vfs/Kconfig index 7760e29d01..aab361518f 100644 --- a/fs/vfs/Kconfig +++ b/fs/vfs/Kconfig @@ -64,3 +64,16 @@ config SIGNAL_FD_NPOLLWAITERS Maximum number of threads that can be waiting on poll() endif # SIGNAL_FD + +config FS_BACKTRACE + int "VFS backtrace" + default 0 + ---help--- + Add backtrace to vfs file open. + +config FS_BACKTRACE_SKIP + int "Backtrace to skip" + default 2 + depends on FS_BACKTRACE > 0 + ---help--- + Skip depth of backtrace. diff --git a/fs/vfs/fs_dup2.c b/fs/vfs/fs_dup2.c index f5917456e7..e9e4114e2e 100644 --- a/fs/vfs/fs_dup2.c +++ b/fs/vfs/fs_dup2.c @@ -174,6 +174,7 @@ int file_dup3(FAR struct file *filep1, FAR struct file *filep2, int flags) filep2->f_tag_fdcheck = filep1->f_tag_fdcheck; #endif + FS_ADD_BACKTRACE(filep2); return OK; } diff --git a/include/nuttx/fs/fs.h b/include/nuttx/fs/fs.h index 067686dc60..83cc0802f2 100644 --- a/include/nuttx/fs/fs.h +++ b/include/nuttx/fs/fs.h @@ -164,6 +164,9 @@ #define CH_STAT_ATIME (1 << 3) #define CH_STAT_MTIME (1 << 4) +#define FS_BACKTRACE_WIDTH (sizeof(uintptr_t) * 2 + 3) /* 3: ' 0x' prefix */ +#define FS_BACKTRACE_BUFFER_LEN (CONFIG_FS_BACKTRACE * FS_BACKTRACE_WIDTH + 1) + /**************************************************************************** * Public Type Definitions ****************************************************************************/ @@ -475,6 +478,10 @@ struct file #ifdef CONFIG_FDCHECK uint8_t f_tag_fdcheck; /* File owner fdcheck tag, init to 0 */ #endif + +#if CONFIG_FS_BACKTRACE > 0 + FAR void *f_backtrace[CONFIG_FS_BACKTRACE]; /* Backtrace to while file opens */ +#endif }; /* This defines a two layer array of files indexed by the file descriptor. @@ -946,6 +953,20 @@ int file_allocate_from_tcb(FAR struct tcb_s *tcb, FAR struct inode *inode, int file_allocate(FAR struct inode *inode, int oflags, off_t pos, FAR void *priv, int minfd, bool addref); +/**************************************************************************** + * Name: file_dump_backtrace + * + * Description: + * Dump the backtrace of the file open to given buffer. + * + * Returned Value: + * Returns the backtrace string, it could be empty. + * + ****************************************************************************/ + +FAR char *file_dump_backtrace(FAR struct file *filep, FAR char *buffer, + size_t len); + /**************************************************************************** * Name: file_dup *