diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2019-08-15 11:10:38 +0200 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2019-08-15 11:10:38 +0200 |
commit | 4511708b9a044f2bc83c7c7f7f8a2c45ec488219 (patch) | |
tree | e892580504b082e9852f5925ba66d1e22910f5e8 /drivers/base/core.c | |
parent | 7f06d0aa530cc61cb5e048d4eb34921dee12058a (diff) | |
parent | 1cd8fa288eb83c1fe0dfa492b09d228a8d802fbf (diff) |
Merge tag 'perf-core-for-mingo-5.4-20190814' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo:
Intel PT:
Adrian Hunter:
- Add PEBS via Intel PT support, the kernel bits went via PeterZ.
perf record:
Alexander Shishkin:
- Add an option to take an AUX snapshot on exit.
Tan Xiaojun:
- Support aarch64 random socket_id assignment, just like was fixed for S/390.
tools:
Andy Shevchenko:
- Keep list of tools in alphabetical order on 'make -C tools help'.
perf session:
Arnaldo Carvalho de Melo:
- Avoid infinite loop when seeing invalid header.size, reported by
Vince Weaver using a perf.data fuzzer.
Documentation:
Vince Weaver:
- Clarify HEADER_SAMPLE_TOPOLOGY format in the perf.data spec.
perf config:
Arnaldo Carvalho de Melo:
- Honour $PERF_CONFIG env var to specify alternate .perfconfig.
perf test:
Arnaldo Carvalho de Melo:
- Disable ~/.perfconfig to get default output in 'perf trace' tests.
perf top:
Arnaldo Carvalho de Melo:
- Set display thread COMM to help with debugging.
- Collapse and resort evsels in a group, so that we have output
similar to 'perf report' when using event groups, i.e.
perf top -e '{cycles,instructions}'
Will have two columns, and the instructions one will work.
core:
Igor Lubashev:
- Detect if libcap development files are available so that we
can use capabilities to match the checks made by the kernel instead
of using plain (geteuid() == 0).
Intel:
Haiyan Song:
- Add Icelake V1.00 event file.
perf trace:
Leo Yan:
- Fix segmentation fault when access syscall info on arm64.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'drivers/base/core.c')
-rw-r--r-- | drivers/base/core.c | 53 |
1 files changed, 52 insertions, 1 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c index 636058bbf48a..1669d41fcddc 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -1823,12 +1823,63 @@ static inline struct kobject *get_glue_dir(struct device *dev) */ static void cleanup_glue_dir(struct device *dev, struct kobject *glue_dir) { + unsigned int ref; + /* see if we live in a "glue" directory */ if (!live_in_glue_dir(glue_dir, dev)) return; mutex_lock(&gdp_mutex); - if (!kobject_has_children(glue_dir)) + /** + * There is a race condition between removing glue directory + * and adding a new device under the glue directory. + * + * CPU1: CPU2: + * + * device_add() + * get_device_parent() + * class_dir_create_and_add() + * kobject_add_internal() + * create_dir() // create glue_dir + * + * device_add() + * get_device_parent() + * kobject_get() // get glue_dir + * + * device_del() + * cleanup_glue_dir() + * kobject_del(glue_dir) + * + * kobject_add() + * kobject_add_internal() + * create_dir() // in glue_dir + * sysfs_create_dir_ns() + * kernfs_create_dir_ns(sd) + * + * sysfs_remove_dir() // glue_dir->sd=NULL + * sysfs_put() // free glue_dir->sd + * + * // sd is freed + * kernfs_new_node(sd) + * kernfs_get(glue_dir) + * kernfs_add_one() + * kernfs_put() + * + * Before CPU1 remove last child device under glue dir, if CPU2 add + * a new device under glue dir, the glue_dir kobject reference count + * will be increase to 2 in kobject_get(k). And CPU2 has been called + * kernfs_create_dir_ns(). Meanwhile, CPU1 call sysfs_remove_dir() + * and sysfs_put(). This result in glue_dir->sd is freed. + * + * Then the CPU2 will see a stale "empty" but still potentially used + * glue dir around in kernfs_new_node(). + * + * In order to avoid this happening, we also should make sure that + * kernfs_node for glue_dir is released in CPU1 only when refcount + * for glue_dir kobj is 1. + */ + ref = kref_read(&glue_dir->kref); + if (!kobject_has_children(glue_dir) && !--ref) kobject_del(glue_dir); kobject_put(glue_dir); mutex_unlock(&gdp_mutex); |