Skip to content

Commit 7b923a9

Browse files
committed
coresight: configfs: Fix unload of configurations on module exit
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2055405 commit 199380d Author: Mike Leach <mike.leach@linaro.org> Date: Tue Jun 28 18:30:03 2022 +0100 coresight: configfs: Fix unload of configurations on module exit Any loaded configurations must be correctly unloaded on coresight module exit, or issues can arise with nested locking in the configfs directory code if built with CONFIG_LOCKDEP. Prior to this patch, the preloaded configuration configfs directory entries were being unloaded by the recursive code in configfs_unregister_subsystem(). However, when built with CONFIG_LOCKDEP, this caused a nested lock warning, which was not mitigated by the LOCKDEP dependent code in fs/configfs/dir.c designed to prevent this, due to the different directory levels for the root of the directory being removed. As the preloaded (and all other) configurations are registered after configfs_register_subsystem(), we now explicitly unload them before the call to configfs_unregister_subsystem(). The new routine cscfg_unload_cfgs_on_exit() iterates through the load owner list to unload any remaining configurations that were not unloaded by the user before the module exits. This covers both the CSCFG_OWNER_PRELOAD and CSCFG_OWNER_MODULE owner types, and will be extended to cover future load owner types for CoreSight configurations. Fixes: eb2ec49 ("coresight: syscfg: Update load API for config loadable modules") Reported-by: Suzuki Poulose <suzuki.poulose@arm.com> Signed-off-by: Mike Leach <mike.leach@linaro.org> Reviewed-and-tested-by: Suzuki K Poulose <suzuki.poulose@arm.com> Link: https://lore.kernel.org/r/20220628173004.30002-2-mike.leach@linaro.org Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org> Signed-off-by: Jeremy Linton <jlinton@redhat.com>
1 parent 27979e2 commit 7b923a9

File tree

1 file changed

+93
-11
lines changed

1 file changed

+93
-11
lines changed

drivers/hwtracing/coresight/coresight-syscfg.c

Lines changed: 93 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,27 @@ static void cscfg_remove_owned_csdev_features(struct coresight_device *csdev, vo
414414
}
415415
}
416416

417+
/*
418+
* Unregister all configuration and features from configfs owned by load_owner.
419+
* Although this is called without the list mutex being held, it is in the
420+
* context of an unload operation which are strictly serialised,
421+
* so the lists cannot change during this call.
422+
*/
423+
static void cscfg_fs_unregister_cfgs_feats(void *load_owner)
424+
{
425+
struct cscfg_config_desc *config_desc;
426+
struct cscfg_feature_desc *feat_desc;
427+
428+
list_for_each_entry(config_desc, &cscfg_mgr->config_desc_list, item) {
429+
if (config_desc->load_owner == load_owner)
430+
cscfg_configfs_del_config(config_desc);
431+
}
432+
list_for_each_entry(feat_desc, &cscfg_mgr->feat_desc_list, item) {
433+
if (feat_desc->load_owner == load_owner)
434+
cscfg_configfs_del_feature(feat_desc);
435+
}
436+
}
437+
417438
/*
418439
* removal is relatively easy - just remove from all lists, anything that
419440
* matches the owner. Memory for the descriptors will be managed by the owner,
@@ -1022,8 +1043,10 @@ struct device *cscfg_device(void)
10221043
/* Must have a release function or the kernel will complain on module unload */
10231044
static void cscfg_dev_release(struct device *dev)
10241045
{
1046+
mutex_lock(&cscfg_mutex);
10251047
kfree(cscfg_mgr);
10261048
cscfg_mgr = NULL;
1049+
mutex_unlock(&cscfg_mutex);
10271050
}
10281051

10291052
/* a device is needed to "own" some kernel elements such as sysfs entries. */
@@ -1042,6 +1065,13 @@ static int cscfg_create_device(void)
10421065
if (!cscfg_mgr)
10431066
goto create_dev_exit_unlock;
10441067

1068+
/* initialise the cscfg_mgr structure */
1069+
INIT_LIST_HEAD(&cscfg_mgr->csdev_desc_list);
1070+
INIT_LIST_HEAD(&cscfg_mgr->feat_desc_list);
1071+
INIT_LIST_HEAD(&cscfg_mgr->config_desc_list);
1072+
INIT_LIST_HEAD(&cscfg_mgr->load_order_list);
1073+
atomic_set(&cscfg_mgr->sys_active_cnt, 0);
1074+
10451075
/* setup the device */
10461076
dev = cscfg_device();
10471077
dev->release = cscfg_dev_release;
@@ -1056,38 +1086,90 @@ static int cscfg_create_device(void)
10561086
return err;
10571087
}
10581088

1059-
static void cscfg_clear_device(void)
1089+
/*
1090+
* Loading and unloading is generally on user discretion.
1091+
* If exiting due to coresight module unload, we need to unload any configurations that remain,
1092+
* before we unregister the configfs intrastructure.
1093+
*
1094+
* Do this by walking the load_owner list and taking appropriate action, depending on the load
1095+
* owner type.
1096+
*/
1097+
static void cscfg_unload_cfgs_on_exit(void)
10601098
{
1061-
struct cscfg_config_desc *cfg_desc;
1099+
struct cscfg_load_owner_info *owner_info = NULL;
10621100

1101+
/*
1102+
* grab the mutex - even though we are exiting, some configfs files
1103+
* may still be live till we dump them, so ensure list data is
1104+
* protected from a race condition.
1105+
*/
10631106
mutex_lock(&cscfg_mutex);
1064-
list_for_each_entry(cfg_desc, &cscfg_mgr->config_desc_list, item) {
1065-
etm_perf_del_symlink_cscfg(cfg_desc);
1107+
while (!list_empty(&cscfg_mgr->load_order_list)) {
1108+
1109+
/* remove in reverse order of loading */
1110+
owner_info = list_last_entry(&cscfg_mgr->load_order_list,
1111+
struct cscfg_load_owner_info, item);
1112+
1113+
/* action according to type */
1114+
switch (owner_info->type) {
1115+
case CSCFG_OWNER_PRELOAD:
1116+
/*
1117+
* preloaded descriptors are statically allocated in
1118+
* this module - just need to unload dynamic items from
1119+
* csdev lists, and remove from configfs directories.
1120+
*/
1121+
pr_info("cscfg: unloading preloaded configurations\n");
1122+
break;
1123+
1124+
case CSCFG_OWNER_MODULE:
1125+
/*
1126+
* this is an error - the loadable module must have been unloaded prior
1127+
* to the coresight module unload. Therefore that module has not
1128+
* correctly unloaded configs in its own exit code.
1129+
* Nothing to do other than emit an error string as the static descriptor
1130+
* references we need to unload will have disappeared with the module.
1131+
*/
1132+
pr_err("cscfg: ERROR: prior module failed to unload configuration\n");
1133+
goto list_remove;
1134+
}
1135+
1136+
/* remove from configfs - outside the scope of the list mutex */
1137+
mutex_unlock(&cscfg_mutex);
1138+
cscfg_fs_unregister_cfgs_feats(owner_info);
1139+
mutex_lock(&cscfg_mutex);
1140+
1141+
/* Next unload from csdev lists. */
1142+
cscfg_unload_owned_cfgs_feats(owner_info);
1143+
1144+
list_remove:
1145+
/* remove from load order list */
1146+
list_del(&owner_info->item);
10661147
}
1148+
mutex_unlock(&cscfg_mutex);
1149+
}
1150+
1151+
static void cscfg_clear_device(void)
1152+
{
1153+
cscfg_unload_cfgs_on_exit();
10671154
cscfg_configfs_release(cscfg_mgr);
10681155
device_unregister(cscfg_device());
1069-
mutex_unlock(&cscfg_mutex);
10701156
}
10711157

10721158
/* Initialise system config management API device */
10731159
int __init cscfg_init(void)
10741160
{
10751161
int err = 0;
10761162

1163+
/* create the device and init cscfg_mgr */
10771164
err = cscfg_create_device();
10781165
if (err)
10791166
return err;
10801167

1168+
/* initialise configfs subsystem */
10811169
err = cscfg_configfs_init(cscfg_mgr);
10821170
if (err)
10831171
goto exit_err;
10841172

1085-
INIT_LIST_HEAD(&cscfg_mgr->csdev_desc_list);
1086-
INIT_LIST_HEAD(&cscfg_mgr->feat_desc_list);
1087-
INIT_LIST_HEAD(&cscfg_mgr->config_desc_list);
1088-
INIT_LIST_HEAD(&cscfg_mgr->load_order_list);
1089-
atomic_set(&cscfg_mgr->sys_active_cnt, 0);
1090-
10911173
/* preload built-in configurations */
10921174
err = cscfg_preload(THIS_MODULE);
10931175
if (err)

0 commit comments

Comments
 (0)