Skip to content

Commit 2082f4e

Browse files
committed
coresight: syscfg: Update load and unload operations
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2055405 commit 8add26f Author: Mike Leach <mike.leach@linaro.org> Date: Tue Jun 28 18:30:04 2022 +0100 coresight: syscfg: Update load and unload operations The configfs system is a source of access to the config information in the configuration and feature lists. This can result in additional LOCKDEP issues as a result of the mutex ordering between the config list mutex (cscfg_mutex) and the configfs system mutexes. As such we need to adjust how load/unload operations work to ensure correct operation. 1) Previously the cscfg_mutex was held throughout the load/unload operation. This is now only held during configuration list manipulations, resulting in a multi-stage load/unload process. 2) All operations that manipulate the configfs representation of the configurations and features are now separated out and run without the cscfg_mutex being held. This avoids circular lock_dep issue with the built-in configfs mutexes and semaphores 3) As the load and unload is now multi-stage, some parts under the cscfg_mutex and others not: i) A flag indicating a load / unload operation in progress is used to serialise load / unload operations. ii) activating any configuration not possible when unload is in progress. iii) Configurations have an "available" flag set only after the last load stage for the configuration is complete. Activation of the configuration not possible till flag is set. 4) Following load/unload rules remain: i) Unload prevented while any configuration is active remains. ii) Unload in strict reverse order of load. iii) Existing configurations can be activated while a new load operation is underway. (by definition there can be no dependencies between an existing configuration and a new loading one due to ii) above.) 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-3-mike.leach@linaro.org Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org> Signed-off-by: Jeremy Linton <jlinton@redhat.com>
1 parent 7b923a9 commit 2082f4e

File tree

3 files changed

+165
-41
lines changed

3 files changed

+165
-41
lines changed

drivers/hwtracing/coresight/coresight-config.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ struct cscfg_feature_desc {
134134
* @active_cnt: ref count for activate on this configuration.
135135
* @load_owner: handle to load owner for dynamic load and unload of configs.
136136
* @fs_group: reference to configfs group for dynamic unload.
137+
* @available: config can be activated - multi-stage load sets true on completion.
137138
*/
138139
struct cscfg_config_desc {
139140
const char *name;
@@ -148,6 +149,7 @@ struct cscfg_config_desc {
148149
atomic_t active_cnt;
149150
void *load_owner;
150151
struct config_group *fs_group;
152+
bool available;
151153
};
152154

153155
/**

drivers/hwtracing/coresight/coresight-syscfg.c

Lines changed: 150 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,8 @@ static void cscfg_unload_owned_cfgs_feats(void *load_owner)
447447
struct cscfg_feature_desc *feat_desc, *feat_tmp;
448448
struct cscfg_registered_csdev *csdev_item;
449449

450+
lockdep_assert_held(&cscfg_mutex);
451+
450452
/* remove from each csdev instance feature and config lists */
451453
list_for_each_entry(csdev_item, &cscfg_mgr->csdev_desc_list, item) {
452454
/*
@@ -460,7 +462,6 @@ static void cscfg_unload_owned_cfgs_feats(void *load_owner)
460462
/* remove from the config descriptor lists */
461463
list_for_each_entry_safe(config_desc, cfg_tmp, &cscfg_mgr->config_desc_list, item) {
462464
if (config_desc->load_owner == load_owner) {
463-
cscfg_configfs_del_config(config_desc);
464465
etm_perf_del_symlink_cscfg(config_desc);
465466
list_del(&config_desc->item);
466467
}
@@ -469,12 +470,90 @@ static void cscfg_unload_owned_cfgs_feats(void *load_owner)
469470
/* remove from the feature descriptor lists */
470471
list_for_each_entry_safe(feat_desc, feat_tmp, &cscfg_mgr->feat_desc_list, item) {
471472
if (feat_desc->load_owner == load_owner) {
472-
cscfg_configfs_del_feature(feat_desc);
473473
list_del(&feat_desc->item);
474474
}
475475
}
476476
}
477477

478+
/*
479+
* load the features and configs to the lists - called with list mutex held
480+
*/
481+
static int cscfg_load_owned_cfgs_feats(struct cscfg_config_desc **config_descs,
482+
struct cscfg_feature_desc **feat_descs,
483+
struct cscfg_load_owner_info *owner_info)
484+
{
485+
int i, err;
486+
487+
lockdep_assert_held(&cscfg_mutex);
488+
489+
/* load features first */
490+
if (feat_descs) {
491+
for (i = 0; feat_descs[i]; i++) {
492+
err = cscfg_load_feat(feat_descs[i]);
493+
if (err) {
494+
pr_err("coresight-syscfg: Failed to load feature %s\n",
495+
feat_descs[i]->name);
496+
return err;
497+
}
498+
feat_descs[i]->load_owner = owner_info;
499+
}
500+
}
501+
502+
/* next any configurations to check feature dependencies */
503+
if (config_descs) {
504+
for (i = 0; config_descs[i]; i++) {
505+
err = cscfg_load_config(config_descs[i]);
506+
if (err) {
507+
pr_err("coresight-syscfg: Failed to load configuration %s\n",
508+
config_descs[i]->name);
509+
return err;
510+
}
511+
config_descs[i]->load_owner = owner_info;
512+
config_descs[i]->available = false;
513+
}
514+
}
515+
return 0;
516+
}
517+
518+
/* set configurations as available to activate at the end of the load process */
519+
static void cscfg_set_configs_available(struct cscfg_config_desc **config_descs)
520+
{
521+
int i;
522+
523+
lockdep_assert_held(&cscfg_mutex);
524+
525+
if (config_descs) {
526+
for (i = 0; config_descs[i]; i++)
527+
config_descs[i]->available = true;
528+
}
529+
}
530+
531+
/*
532+
* Create and register each of the configurations and features with configfs.
533+
* Called without mutex being held.
534+
*/
535+
static int cscfg_fs_register_cfgs_feats(struct cscfg_config_desc **config_descs,
536+
struct cscfg_feature_desc **feat_descs)
537+
{
538+
int i, err;
539+
540+
if (feat_descs) {
541+
for (i = 0; feat_descs[i]; i++) {
542+
err = cscfg_configfs_add_feature(feat_descs[i]);
543+
if (err)
544+
return err;
545+
}
546+
}
547+
if (config_descs) {
548+
for (i = 0; config_descs[i]; i++) {
549+
err = cscfg_configfs_add_config(config_descs[i]);
550+
if (err)
551+
return err;
552+
}
553+
}
554+
return 0;
555+
}
556+
478557
/**
479558
* cscfg_load_config_sets - API function to load feature and config sets.
480559
*
@@ -497,57 +576,63 @@ int cscfg_load_config_sets(struct cscfg_config_desc **config_descs,
497576
struct cscfg_feature_desc **feat_descs,
498577
struct cscfg_load_owner_info *owner_info)
499578
{
500-
int err = 0, i = 0;
579+
int err = 0;
501580

502581
mutex_lock(&cscfg_mutex);
503-
504-
/* load features first */
505-
if (feat_descs) {
506-
while (feat_descs[i]) {
507-
err = cscfg_load_feat(feat_descs[i]);
508-
if (!err)
509-
err = cscfg_configfs_add_feature(feat_descs[i]);
510-
if (err) {
511-
pr_err("coresight-syscfg: Failed to load feature %s\n",
512-
feat_descs[i]->name);
513-
cscfg_unload_owned_cfgs_feats(owner_info);
514-
goto exit_unlock;
515-
}
516-
feat_descs[i]->load_owner = owner_info;
517-
i++;
518-
}
582+
if (cscfg_mgr->load_state != CSCFG_NONE) {
583+
mutex_unlock(&cscfg_mutex);
584+
return -EBUSY;
519585
}
586+
cscfg_mgr->load_state = CSCFG_LOAD;
520587

521-
/* next any configurations to check feature dependencies */
522-
i = 0;
523-
if (config_descs) {
524-
while (config_descs[i]) {
525-
err = cscfg_load_config(config_descs[i]);
526-
if (!err)
527-
err = cscfg_configfs_add_config(config_descs[i]);
528-
if (err) {
529-
pr_err("coresight-syscfg: Failed to load configuration %s\n",
530-
config_descs[i]->name);
531-
cscfg_unload_owned_cfgs_feats(owner_info);
532-
goto exit_unlock;
533-
}
534-
config_descs[i]->load_owner = owner_info;
535-
i++;
536-
}
537-
}
588+
/* first load and add to the lists */
589+
err = cscfg_load_owned_cfgs_feats(config_descs, feat_descs, owner_info);
590+
if (err)
591+
goto err_clean_load;
538592

539593
/* add the load owner to the load order list */
540594
list_add_tail(&owner_info->item, &cscfg_mgr->load_order_list);
541595
if (!list_is_singular(&cscfg_mgr->load_order_list)) {
542596
/* lock previous item in load order list */
543597
err = cscfg_owner_get(list_prev_entry(owner_info, item));
544-
if (err) {
545-
cscfg_unload_owned_cfgs_feats(owner_info);
546-
list_del(&owner_info->item);
547-
}
598+
if (err)
599+
goto err_clean_owner_list;
548600
}
549601

602+
/*
603+
* make visible to configfs - configfs manipulation must occur outside
604+
* the list mutex lock to avoid circular lockdep issues with configfs
605+
* built in mutexes and semaphores. This is safe as it is not possible
606+
* to start a new load/unload operation till the current one is done.
607+
*/
608+
mutex_unlock(&cscfg_mutex);
609+
610+
/* create the configfs elements */
611+
err = cscfg_fs_register_cfgs_feats(config_descs, feat_descs);
612+
mutex_lock(&cscfg_mutex);
613+
614+
if (err)
615+
goto err_clean_cfs;
616+
617+
/* mark any new configs as available for activation */
618+
cscfg_set_configs_available(config_descs);
619+
goto exit_unlock;
620+
621+
err_clean_cfs:
622+
/* cleanup after error registering with configfs */
623+
cscfg_fs_unregister_cfgs_feats(owner_info);
624+
625+
if (!list_is_singular(&cscfg_mgr->load_order_list))
626+
cscfg_owner_put(list_prev_entry(owner_info, item));
627+
628+
err_clean_owner_list:
629+
list_del(&owner_info->item);
630+
631+
err_clean_load:
632+
cscfg_unload_owned_cfgs_feats(owner_info);
633+
550634
exit_unlock:
635+
cscfg_mgr->load_state = CSCFG_NONE;
551636
mutex_unlock(&cscfg_mutex);
552637
return err;
553638
}
@@ -564,6 +649,9 @@ EXPORT_SYMBOL_GPL(cscfg_load_config_sets);
564649
* 1) no configurations are active.
565650
* 2) the set being unloaded was the last to be loaded to maintain dependencies.
566651
*
652+
* Once the unload operation commences, we disallow any configuration being
653+
* made active until it is complete.
654+
*
567655
* @owner_info: Information on owner for set being unloaded.
568656
*/
569657
int cscfg_unload_config_sets(struct cscfg_load_owner_info *owner_info)
@@ -572,6 +660,13 @@ int cscfg_unload_config_sets(struct cscfg_load_owner_info *owner_info)
572660
struct cscfg_load_owner_info *load_list_item = NULL;
573661

574662
mutex_lock(&cscfg_mutex);
663+
if (cscfg_mgr->load_state != CSCFG_NONE) {
664+
mutex_unlock(&cscfg_mutex);
665+
return -EBUSY;
666+
}
667+
668+
/* unload op in progress also prevents activation of any config */
669+
cscfg_mgr->load_state = CSCFG_UNLOAD;
575670

576671
/* cannot unload if anything is active */
577672
if (atomic_read(&cscfg_mgr->sys_active_cnt)) {
@@ -592,7 +687,12 @@ int cscfg_unload_config_sets(struct cscfg_load_owner_info *owner_info)
592687
goto exit_unlock;
593688
}
594689

595-
/* unload all belonging to load_owner */
690+
/* remove from configfs - again outside the scope of the list mutex */
691+
mutex_unlock(&cscfg_mutex);
692+
cscfg_fs_unregister_cfgs_feats(owner_info);
693+
mutex_lock(&cscfg_mutex);
694+
695+
/* unload everything from lists belonging to load_owner */
596696
cscfg_unload_owned_cfgs_feats(owner_info);
597697

598698
/* remove from load order list */
@@ -603,6 +703,7 @@ int cscfg_unload_config_sets(struct cscfg_load_owner_info *owner_info)
603703
list_del(&owner_info->item);
604704

605705
exit_unlock:
706+
cscfg_mgr->load_state = CSCFG_NONE;
606707
mutex_unlock(&cscfg_mutex);
607708
return err;
608709
}
@@ -780,8 +881,15 @@ static int _cscfg_activate_config(unsigned long cfg_hash)
780881
struct cscfg_config_desc *config_desc;
781882
int err = -EINVAL;
782883

884+
if (cscfg_mgr->load_state == CSCFG_UNLOAD)
885+
return -EBUSY;
886+
783887
list_for_each_entry(config_desc, &cscfg_mgr->config_desc_list, item) {
784888
if ((unsigned long)config_desc->event_ea->var == cfg_hash) {
889+
/* if we happen upon a partly loaded config, can't use it */
890+
if (config_desc->available == false)
891+
return -EBUSY;
892+
785893
/* must ensure that config cannot be unloaded in use */
786894
err = cscfg_owner_get(config_desc->load_owner);
787895
if (err)
@@ -1071,6 +1179,7 @@ static int cscfg_create_device(void)
10711179
INIT_LIST_HEAD(&cscfg_mgr->config_desc_list);
10721180
INIT_LIST_HEAD(&cscfg_mgr->load_order_list);
10731181
atomic_set(&cscfg_mgr->sys_active_cnt, 0);
1182+
cscfg_mgr->load_state = CSCFG_NONE;
10741183

10751184
/* setup the device */
10761185
dev = cscfg_device();

drivers/hwtracing/coresight/coresight-syscfg.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,17 @@
1212

1313
#include "coresight-config.h"
1414

15+
/*
16+
* Load operation types.
17+
* When loading or unloading, another load operation cannot be run.
18+
* When unloading configurations cannot be activated.
19+
*/
20+
enum cscfg_load_ops {
21+
CSCFG_NONE,
22+
CSCFG_LOAD,
23+
CSCFG_UNLOAD
24+
};
25+
1526
/**
1627
* System configuration manager device.
1728
*
@@ -30,6 +41,7 @@
3041
* @cfgfs_subsys: configfs subsystem used to manage configurations.
3142
* @sysfs_active_config:Active config hash used if CoreSight controlled from sysfs.
3243
* @sysfs_active_preset:Active preset index used if CoreSight controlled from sysfs.
44+
* @load_state: A multi-stage load/unload operation is in progress.
3345
*/
3446
struct cscfg_manager {
3547
struct device dev;
@@ -41,6 +53,7 @@ struct cscfg_manager {
4153
struct configfs_subsystem cfgfs_subsys;
4254
u32 sysfs_active_config;
4355
int sysfs_active_preset;
56+
enum cscfg_load_ops load_state;
4457
};
4558

4659
/* get reference to dev in cscfg_manager */

0 commit comments

Comments
 (0)