diff mbox series

[RFC,11/16] padata: Cap helpers started to online CPUs

Message ID 20220106004656.126790-12-daniel.m.jordan@oracle.com (mailing list archive)
State New, archived
Headers show
Series padata, vfio, sched: Multithreaded VFIO page pinning | expand

Commit Message

Daniel Jordan Jan. 6, 2022, 12:46 a.m. UTC
padata can start num_possible_cpus() helpers, but this is too many
considering that every job's main thread participates and there may
be fewer online than possible CPUs.

Limit overall concurrency, including main thread(s), to
num_online_cpus() with the padata_works_inuse counter to prevent
CPU-intensive threads flooding the system in case of concurrent jobs.

Signed-off-by: Daniel Jordan <daniel.m.jordan@oracle.com>
---
 kernel/padata.c | 24 ++++++++++++++++++------
 1 file changed, 18 insertions(+), 6 deletions(-)
diff mbox series

Patch

diff --git a/kernel/padata.c b/kernel/padata.c
index 0f4002ed1518..e27988d3e9ed 100644
--- a/kernel/padata.c
+++ b/kernel/padata.c
@@ -50,6 +50,7 @@  struct padata_work {
 
 static DEFINE_SPINLOCK(padata_works_lock);
 static struct padata_work *padata_works;
+static unsigned int padata_works_inuse;
 static LIST_HEAD(padata_free_works);
 
 struct padata_mt_job_state {
@@ -98,11 +99,16 @@  static struct padata_work *padata_work_alloc(void)
 
 	lockdep_assert_held(&padata_works_lock);
 
-	if (list_empty(&padata_free_works))
-		return NULL;	/* No more work items allowed to be queued. */
+	/* Are more work items allowed to be queued? */
+	if (padata_works_inuse >= num_online_cpus())
+		return NULL;
+
+	if (WARN_ON_ONCE(list_empty(&padata_free_works)))
+		return NULL;
 
 	pw = list_first_entry(&padata_free_works, struct padata_work, pw_list);
 	list_del(&pw->pw_list);
+	++padata_works_inuse;
 	return pw;
 }
 
@@ -111,7 +117,11 @@  static int padata_work_alloc_mt(int nworks, struct list_head *head)
 	int i;
 
 	spin_lock(&padata_works_lock);
-	/* Start at 1 because the current task participates in the job. */
+	/*
+	 * Increment inuse and start iterating at 1 to account for the main
+	 * thread participating in the job with its stack-allocated work.
+	 */
+	++padata_works_inuse;
 	for (i = 1; i < nworks; ++i) {
 		struct padata_work *pw = padata_work_alloc();
 
@@ -128,20 +138,22 @@  static void padata_work_free(struct padata_work *pw)
 {
 	lockdep_assert_held(&padata_works_lock);
 	list_add(&pw->pw_list, &padata_free_works);
+	WARN_ON_ONCE(!padata_works_inuse);
+	--padata_works_inuse;
 }
 
 static void padata_works_free(struct list_head *works)
 {
 	struct padata_work *cur, *next;
 
-	if (list_empty(works))
-		return;
-
 	spin_lock(&padata_works_lock);
 	list_for_each_entry_safe(cur, next, works, pw_list) {
 		list_del(&cur->pw_list);
 		padata_work_free(cur);
 	}
+	/* To account for the main thread finishing its part of the job. */
+	WARN_ON_ONCE(!padata_works_inuse);
+	--padata_works_inuse;
 	spin_unlock(&padata_works_lock);
 }