Skip to content

Commit 9511bce

Browse files
liu-song-6Ingo Molnar
authored andcommitted
perf/core: Fix bad use of igrab()
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 <[email protected]> Reported-by: Miklos Szeredi <[email protected]> Signed-off-by: Song Liu <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Cc: <[email protected]> Cc: Alexander Shishkin <[email protected]> Cc: Arnaldo Carvalho de Melo <[email protected]> Cc: Jiri Olsa <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Stephane Eranian <[email protected]> Cc: Thomas Gleixner <[email protected]> Cc: Vince Weaver <[email protected]> Fixes: 375637b ("perf/core: Introduce address range filtering") Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Ingo Molnar <[email protected]>
1 parent a1150c2 commit 9511bce

File tree

3 files changed

+12
-15
lines changed

3 files changed

+12
-15
lines changed

arch/x86/events/intel/pt.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1194,7 +1194,7 @@ static int pt_event_addr_filters_validate(struct list_head *filters)
11941194
filter->action == PERF_ADDR_FILTER_ACTION_START)
11951195
return -EOPNOTSUPP;
11961196

1197-
if (!filter->inode) {
1197+
if (!filter->path.dentry) {
11981198
if (!valid_kernel_ip(filter->offset))
11991199
return -EINVAL;
12001200

@@ -1221,7 +1221,7 @@ static void pt_event_addr_filters_sync(struct perf_event *event)
12211221
return;
12221222

12231223
list_for_each_entry(filter, &head->list, entry) {
1224-
if (filter->inode && !offs[range]) {
1224+
if (filter->path.dentry && !offs[range]) {
12251225
msr_a = msr_b = 0;
12261226
} else {
12271227
/* apply the offset */

include/linux/perf_event.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,7 @@ enum perf_addr_filter_action_t {
467467
*/
468468
struct perf_addr_filter {
469469
struct list_head entry;
470-
struct inode *inode;
470+
struct path path;
471471
unsigned long offset;
472472
unsigned long size;
473473
enum perf_addr_filter_action_t action;

kernel/events/core.c

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6668,7 +6668,7 @@ static void perf_event_addr_filters_exec(struct perf_event *event, void *data)
66686668

66696669
raw_spin_lock_irqsave(&ifh->lock, flags);
66706670
list_for_each_entry(filter, &ifh->list, entry) {
6671-
if (filter->inode) {
6671+
if (filter->path.dentry) {
66726672
event->addr_filters_offs[count] = 0;
66736673
restart++;
66746674
}
@@ -7333,7 +7333,7 @@ static bool perf_addr_filter_match(struct perf_addr_filter *filter,
73337333
struct file *file, unsigned long offset,
73347334
unsigned long size)
73357335
{
7336-
if (filter->inode != file_inode(file))
7336+
if (d_inode(filter->path.dentry) != file_inode(file))
73377337
return false;
73387338

73397339
if (filter->offset > offset + size)
@@ -8686,8 +8686,7 @@ static void free_filters_list(struct list_head *filters)
86868686
struct perf_addr_filter *filter, *iter;
86878687

86888688
list_for_each_entry_safe(filter, iter, filters, entry) {
8689-
if (filter->inode)
8690-
iput(filter->inode);
8689+
path_put(&filter->path);
86918690
list_del(&filter->entry);
86928691
kfree(filter);
86938692
}
@@ -8784,7 +8783,7 @@ static void perf_event_addr_filters_apply(struct perf_event *event)
87848783
* Adjust base offset if the filter is associated to a binary
87858784
* that needs to be mapped:
87868785
*/
8787-
if (filter->inode)
8786+
if (filter->path.dentry)
87888787
event->addr_filters_offs[count] =
87898788
perf_addr_filter_apply(filter, mm);
87908789

@@ -8858,7 +8857,6 @@ perf_event_parse_addr_filter(struct perf_event *event, char *fstr,
88588857
{
88598858
struct perf_addr_filter *filter = NULL;
88608859
char *start, *orig, *filename = NULL;
8861-
struct path path;
88628860
substring_t args[MAX_OPT_ARGS];
88638861
int state = IF_STATE_ACTION, token;
88648862
unsigned int kernel = 0;
@@ -8971,19 +8969,18 @@ perf_event_parse_addr_filter(struct perf_event *event, char *fstr,
89718969
goto fail_free_name;
89728970

89738971
/* look up the path and grab its inode */
8974-
ret = kern_path(filename, LOOKUP_FOLLOW, &path);
8972+
ret = kern_path(filename, LOOKUP_FOLLOW,
8973+
&filter->path);
89758974
if (ret)
89768975
goto fail_free_name;
89778976

8978-
filter->inode = igrab(d_inode(path.dentry));
8979-
path_put(&path);
89808977
kfree(filename);
89818978
filename = NULL;
89828979

89838980
ret = -EINVAL;
8984-
if (!filter->inode ||
8985-
!S_ISREG(filter->inode->i_mode))
8986-
/* free_filters_list() will iput() */
8981+
if (!filter->path.dentry ||
8982+
!S_ISREG(d_inode(filter->path.dentry)
8983+
->i_mode))
89878984
goto fail;
89888985

89898986
event->addr_filters.nr_file_filters++;

0 commit comments

Comments
 (0)