This is a note to let you know that I've just added the patch titled perf/core: Fix bad use of igrab() to the 4.9-stable tree which can be found at: http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary The filename of the patch is: perf-core-fix-bad-use-of-igrab.patch and it can be found in the queue-4.9 subdirectory. If you, or anyone else, feels it should not be added to the stable tree, please let <stable@xxxxxxxxxxxxxxx> know about it. >From foo@baz Tue Nov 17 12:22:26 PM CET 2020 From: Song Liu <songliubraving@xxxxxx> Date: Tue, 17 Apr 2018 23:29:07 -0700 Subject: perf/core: Fix bad use of igrab() From: Song Liu <songliubraving@xxxxxx> commit 9511bce9fe8e5e6c0f923c09243a713eba560141 upstream As Miklos reported and suggested: "This pattern repeats two times in trace_uprobe.c and in kernel/events/core.c as well: ret = kern_path(filename, LOOKUP_FOLLOW, &path); if (ret) goto fail_address_parse; inode = igrab(d_inode(path.dentry)); path_put(&path); And it's wrong. You can only hold a reference to the inode if you have an active ref to the superblock as well (which is normally through path.mnt) or holding s_umount. This way unmounting the containing filesystem while the tracepoint is active will give you the "VFS: Busy inodes after unmount..." message and a crash when the inode is finally put. Solution: store path instead of inode." This patch fixes the issue in kernel/event/core.c. Reviewed-and-tested-by: Alexander Shishkin <alexander.shishkin@xxxxxxxxxxxxxxx> Reported-by: Miklos Szeredi <miklos@xxxxxxxxxx> Signed-off-by: Song Liu <songliubraving@xxxxxx> Signed-off-by: Peter Zijlstra (Intel) <peterz@xxxxxxxxxxxxx> Cc: <kernel-team@xxxxxx> Cc: Alexander Shishkin <alexander.shishkin@xxxxxxxxxxxxxxx> Cc: Arnaldo Carvalho de Melo <acme@xxxxxxxxxx> Cc: Jiri Olsa <jolsa@xxxxxxxxxx> Cc: Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx> Cc: Peter Zijlstra <peterz@xxxxxxxxxxxxx> Cc: Stephane Eranian <eranian@xxxxxxxxxx> Cc: Thomas Gleixner <tglx@xxxxxxxxxxxxx> Cc: Vince Weaver <vincent.weaver@xxxxxxxxx> Fixes: 375637bc5249 ("perf/core: Introduce address range filtering") Link: http://lkml.kernel.org/r/20180418062907.3210386-2-songliubraving@xxxxxx Signed-off-by: Ingo Molnar <mingo@xxxxxxxxxx> [sudip: Backported to 4.9: use file_inode()] Signed-off-by: Sudip Mukherjee <sudipm.mukherjee@xxxxxxxxx> Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> --- arch/x86/events/intel/pt.c | 4 ++-- include/linux/perf_event.h | 2 +- kernel/events/core.c | 21 +++++++++------------ 3 files changed, 12 insertions(+), 15 deletions(-) --- a/arch/x86/events/intel/pt.c +++ b/arch/x86/events/intel/pt.c @@ -1117,7 +1117,7 @@ static int pt_event_addr_filters_validat if (!filter->range || !filter->size) return -EOPNOTSUPP; - if (!filter->inode) { + if (!filter->path.dentry) { if (!valid_kernel_ip(filter->offset)) return -EINVAL; @@ -1144,7 +1144,7 @@ static void pt_event_addr_filters_sync(s return; list_for_each_entry(filter, &head->list, entry) { - if (filter->inode && !offs[range]) { + if (filter->path.dentry && !offs[range]) { msr_a = msr_b = 0; } else { /* apply the offset */ --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -475,7 +475,7 @@ struct pmu { */ struct perf_addr_filter { struct list_head entry; - struct inode *inode; + struct path path; unsigned long offset; unsigned long size; unsigned int range : 1, --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -6271,7 +6271,7 @@ static void perf_event_addr_filters_exec raw_spin_lock_irqsave(&ifh->lock, flags); list_for_each_entry(filter, &ifh->list, entry) { - if (filter->inode) { + if (filter->path.dentry) { event->addr_filters_offs[count] = 0; restart++; } @@ -6814,7 +6814,7 @@ static bool perf_addr_filter_match(struc struct file *file, unsigned long offset, unsigned long size) { - if (filter->inode != file->f_inode) + if (d_inode(filter->path.dentry) != file_inode(file)) return false; if (filter->offset > offset + size) @@ -8028,8 +8028,7 @@ static void free_filters_list(struct lis struct perf_addr_filter *filter, *iter; list_for_each_entry_safe(filter, iter, filters, entry) { - if (filter->inode) - iput(filter->inode); + path_put(&filter->path); list_del(&filter->entry); kfree(filter); } @@ -8123,7 +8122,7 @@ static void perf_event_addr_filters_appl * Adjust base offset if the filter is associated to a binary * that needs to be mapped: */ - if (filter->inode) + if (filter->path.dentry) event->addr_filters_offs[count] = perf_addr_filter_apply(filter, mm); @@ -8196,7 +8195,6 @@ perf_event_parse_addr_filter(struct perf { struct perf_addr_filter *filter = NULL; char *start, *orig, *filename = NULL; - struct path path; substring_t args[MAX_OPT_ARGS]; int state = IF_STATE_ACTION, token; unsigned int kernel = 0; @@ -8287,19 +8285,18 @@ perf_event_parse_addr_filter(struct perf goto fail; /* look up the path and grab its inode */ - ret = kern_path(filename, LOOKUP_FOLLOW, &path); + ret = kern_path(filename, LOOKUP_FOLLOW, + &filter->path); if (ret) goto fail_free_name; - filter->inode = igrab(d_inode(path.dentry)); - path_put(&path); kfree(filename); filename = NULL; ret = -EINVAL; - if (!filter->inode || - !S_ISREG(filter->inode->i_mode)) - /* free_filters_list() will iput() */ + if (!filter->path.dentry || + !S_ISREG(d_inode(filter->path.dentry) + ->i_mode)) goto fail; } Patches currently in stable-queue which might be from songliubraving@xxxxxx are queue-4.9/perf-core-fix-bad-use-of-igrab.patch queue-4.9/perf-core-fix-crash-when-using-hw-tracing-kernel-filters.patch