Skip to content

Commit eacf5b3

Browse files
hfreudehcahca
authored andcommitted
s390/ap: introduce mutex to lock the AP bus scan
Rework the invocations around ap_scan_bus(): - Protect ap_scan_bus() with a mutex to make sure only one scan at a time is running. - The workqueue invocation which is triggered by either the module init or via AP bus scan timer expiration uses this mutex and if there is already a scan running, the work is simple aborted (as the job is done by another task). - The ap_bus_force_rescan() which is invoked by higher level layers mostly on failures which indicate a bus scan may help is reworked to call ap_scan_bus() direct instead of enqueuing work into a system workqueue and waiting for that to finish. Of course the mutex is respected and in case of another task already running a bus scan the shortcut of waiting for this scan to finish and reusing the scan result is taken. Signed-off-by: Harald Freudenberger <[email protected]> Reviewed-by: Holger Dengler <[email protected]> Signed-off-by: Heiko Carstens <[email protected]>
1 parent b5caf05 commit eacf5b3

File tree

2 files changed

+58
-11
lines changed

2 files changed

+58
-11
lines changed

drivers/s390/crypto/ap_bus.c

Lines changed: 57 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ debug_info_t *ap_dbf_info;
101101
/*
102102
* AP bus rescan related things.
103103
*/
104+
static bool ap_scan_bus(void);
105+
static bool ap_scan_bus_result; /* result of last ap_scan_bus() */
106+
static DEFINE_MUTEX(ap_scan_bus_mutex); /* mutex ap_scan_bus() invocations */
104107
static atomic64_t ap_scan_bus_count; /* counter ap_scan_bus() invocations */
105108
static int ap_scan_bus_time = AP_CONFIG_TIME;
106109
static struct timer_list ap_scan_bus_timer;
@@ -1011,16 +1014,47 @@ void ap_driver_unregister(struct ap_driver *ap_drv)
10111014
}
10121015
EXPORT_SYMBOL(ap_driver_unregister);
10131016

1014-
void ap_bus_force_rescan(void)
1017+
/*
1018+
* Enforce a synchronous AP bus rescan.
1019+
* Returns true if the bus scan finds a change in the AP configuration
1020+
* and AP devices have been added or deleted when this function returns.
1021+
*/
1022+
bool ap_bus_force_rescan(void)
10151023
{
1024+
unsigned long scan_counter = atomic64_read(&ap_scan_bus_count);
1025+
bool rc = false;
1026+
1027+
pr_debug(">%s scan counter=%lu\n", __func__, scan_counter);
1028+
10161029
/* Only trigger AP bus scans after the initial scan is done */
1017-
if (atomic64_read(&ap_scan_bus_count) <= 0)
1018-
return;
1030+
if (scan_counter <= 0)
1031+
goto out;
10191032

1020-
/* processing a asynchronous bus rescan */
1021-
del_timer(&ap_scan_bus_timer);
1022-
queue_work(system_long_wq, &ap_scan_bus_work);
1023-
flush_work(&ap_scan_bus_work);
1033+
/* Try to acquire the AP scan bus mutex */
1034+
if (mutex_trylock(&ap_scan_bus_mutex)) {
1035+
/* mutex acquired, run the AP bus scan */
1036+
ap_scan_bus_result = ap_scan_bus();
1037+
rc = ap_scan_bus_result;
1038+
mutex_unlock(&ap_scan_bus_mutex);
1039+
goto out;
1040+
}
1041+
1042+
/*
1043+
* Mutex acquire failed. So there is currently another task
1044+
* already running the AP bus scan. Then let's simple wait
1045+
* for the lock which means the other task has finished and
1046+
* stored the result in ap_scan_bus_result.
1047+
*/
1048+
if (mutex_lock_interruptible(&ap_scan_bus_mutex)) {
1049+
/* some error occurred, ignore and go out */
1050+
goto out;
1051+
}
1052+
rc = ap_scan_bus_result;
1053+
mutex_unlock(&ap_scan_bus_mutex);
1054+
1055+
out:
1056+
pr_debug("%s rc=%d\n", __func__, rc);
1057+
return rc;
10241058
}
10251059
EXPORT_SYMBOL(ap_bus_force_rescan);
10261060

@@ -2179,8 +2213,10 @@ static bool ap_config_has_new_doms(void)
21792213

21802214
/**
21812215
* ap_scan_bus(): Scan the AP bus for new devices
2216+
* Always run under mutex ap_scan_bus_mutex protection
2217+
* which needs to get locked/unlocked by the caller!
21822218
* Returns true if any config change has been detected
2183-
* otherwise false.
2219+
* during the scan, otherwise false.
21842220
*/
21852221
static bool ap_scan_bus(void)
21862222
{
@@ -2259,8 +2295,19 @@ static void ap_scan_bus_timer_callback(struct timer_list *unused)
22592295
*/
22602296
static void ap_scan_bus_wq_callback(struct work_struct *unused)
22612297
{
2262-
/* now finally do the AP bus scan */
2263-
ap_scan_bus();
2298+
/*
2299+
* Try to invoke an ap_scan_bus(). If the mutex acquisition
2300+
* fails there is currently another task already running the
2301+
* AP scan bus and there is no need to wait and re-trigger the
2302+
* scan again. Please note at the end of the scan bus function
2303+
* the AP scan bus timer is re-armed which triggers then the
2304+
* ap_scan_bus_timer_callback which enqueues a work into the
2305+
* system_long_wq which invokes this function here again.
2306+
*/
2307+
if (mutex_trylock(&ap_scan_bus_mutex)) {
2308+
ap_scan_bus_result = ap_scan_bus();
2309+
mutex_unlock(&ap_scan_bus_mutex);
2310+
}
22642311
}
22652312

22662313
static int __init ap_debug_init(void)

drivers/s390/crypto/ap_bus.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ int ap_sb_available(void);
266266
bool ap_is_se_guest(void);
267267
void ap_wait(enum ap_sm_wait wait);
268268
void ap_request_timeout(struct timer_list *t);
269-
void ap_bus_force_rescan(void);
269+
bool ap_bus_force_rescan(void);
270270

271271
int ap_test_config_usage_domain(unsigned int domain);
272272
int ap_test_config_ctrl_domain(unsigned int domain);

0 commit comments

Comments
 (0)