From patchwork Wed May 10 20:12:03 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Johannes Berg X-Patchwork-Id: 92285 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b0ea:0:b0:3b6:4342:cba0 with SMTP id b10csp3893063vqo; Wed, 10 May 2023 13:15:11 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ5PyNNbABv+UXqFaYwVMGQlwJTym1ej6rkKTlL+tWb+sHMC2uDNOWYLZbnWYlIbeMUjvEfv X-Received: by 2002:a17:90a:9305:b0:250:40f5:6838 with SMTP id p5-20020a17090a930500b0025040f56838mr17124848pjo.30.1683749710872; Wed, 10 May 2023 13:15:10 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1683749710; cv=none; d=google.com; s=arc-20160816; b=Njo+UgHuj8xm/4TWxNTEE3ZcviFR23fCO5BU+2daWFlWWuej7fjrtThxLv1AcW9+jj VAoPVAPoU17KYX/yqjTzk+UQwJxahlUJvFrqTGuPLoozzaU1/vBbteriW+4S+XAXWKAw qm3zc6/ZqNh7fbKN63ep/H5IojajJWam1hBHwNi6zlhZm+JBGF/aHHbuthPRMOfc6qDy zTUhyqecnfqpZeAxEqHmym9ME8UqIPubQ5ohz3pFQTxg96tWUkQlLQFCcNPEsvwENvd4 eC74Dp8JMspLsPNyFeRSTAJb/wtSAuTedEMzMlKRE9/e2GYjryKuc96froWSVy3JUHu4 HAjA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=1eItkrSnBXDxwAy/pbcSMdyZKnv054ktdoQQCOFc/k0=; b=bzGXNO0hNOVfVA48vJrQ3wtJA234zK1lAvJNpkijkxwnoRGqdcEKjbu6NN++GT8QTs nJQwYBVey3gBblueUHQ2VRn8lGJjJfkE+m5u0t+N2ZMpMKdtG87RC1SM4mY3wri4MUEz V49tg7CVv00CUt9aYeUHPSUbB31q185hEHsbFmqJXRkKoL+9V+tHHLQxnLUTHz2RsVD6 dBtbv8+XCKUUGdFt9cYkcIV8HAPx6g7OEi6RhRZPsIurDRIRCbKG7HpcpulkVHd10d0K AVpn8pYPLAzUDx9rBId1L0Knm5TZXAlTpao5hCkn7Utxnj0S3YzcQa9+i1rWqPw3LS9R EaHw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@sipsolutions.net header.s=mail header.b=PrntjE60; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=REJECT dis=NONE) header.from=sipsolutions.net Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id pc11-20020a17090b3b8b00b002507cbb009bsi9578449pjb.112.2023.05.10.13.14.57; Wed, 10 May 2023 13:15:10 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@sipsolutions.net header.s=mail header.b=PrntjE60; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=REJECT dis=NONE) header.from=sipsolutions.net Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236313AbjEJUMY (ORCPT + 99 others); Wed, 10 May 2023 16:12:24 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44332 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236175AbjEJUMP (ORCPT ); Wed, 10 May 2023 16:12:15 -0400 Received: from sipsolutions.net (s3.sipsolutions.net [IPv6:2a01:4f8:191:4433::2]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1C9FE10C3; Wed, 10 May 2023 13:12:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sipsolutions.net; s=mail; h=Content-Transfer-Encoding:MIME-Version: References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From:Content-Type:Sender :Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From:Resent-To: Resent-Cc:Resent-Message-ID; bh=1eItkrSnBXDxwAy/pbcSMdyZKnv054ktdoQQCOFc/k0=; t=1683749533; x=1684959133; b=PrntjE60vMfUngjv6eSjAfhwfFxtup2Qrxk37uYUhspoLiD FiTXzmEDo96wSQgbNAKH6OR/Km/AbVMWNulQxnxEWlgq6vQr9Jm3+lfagjV/8HCZbrjKcwgDb/SoA 64EF5GkB53jfNwu6jS09AjEOf2ZhRk/Klowr55QeS2imJDxvnyIsb74LqVc0w2oyg5RFywpNpzKYJ Z0BNCX7fUh9TAJ1a4yObnsFilBKuEl0u45tJhbtbufhf8u40PzbxXuEJrFFFtzkfAcmQ/vPSEe5uY GFO1Hzfhf+97Ritgpw57nZr/Gcz70RPX9dzQ36W90uHRiFOvvhV/bD3/bZaGACNg==; Received: by sipsolutions.net with esmtpsa (TLS1.3:ECDHE_X25519__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim 4.96) (envelope-from ) id 1pwqAS-005aH5-2u; Wed, 10 May 2023 22:12:09 +0200 From: Johannes Berg To: linux-kernel@vger.kernel.org Cc: linux-wireless@vger.kernel.org, Tejun Heo , Lai Jiangshan , Johannes Berg Subject: [RFC PATCH v2 1/3] workqueue: support pausing ordered workqueues Date: Wed, 10 May 2023 22:12:03 +0200 Message-Id: <20230510220918.1dc654070530.Ia49f779e11c2814294ea7f8bb29f825fb840be51@changeid> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20230510201205.308542-1-johannes@sipsolutions.net> References: <20230510201205.308542-1-johannes@sipsolutions.net> MIME-Version: 1.0 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_PASS,SPF_PASS, T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1765539537076628161?= X-GMAIL-MSGID: =?utf-8?q?1765539537076628161?= From: Johannes Berg Add some infrastructure to support pausing ordered workqueues, so that no work items are executing nor can execute while the workqueue is paused. This can be used to simplify locking between work structs and other processes (e.g. userspace calls) when the workqueue is paused while other code is running, where we can then more easily avoid issues in code paths needing to cancel works. Signed-off-by: Johannes Berg --- v2: - fix bug with new_max_active no being used - don't unify pause/resume - looked at unifying pause/freeze, but the conditions are very different so I didn't find a plausible way --- include/linux/workqueue.h | 4 +++ kernel/workqueue.c | 54 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index ac551b8ee7d9..7a76d27d325f 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -340,6 +340,7 @@ enum { __WQ_ORDERED = 1 << 17, /* internal: workqueue is ordered */ __WQ_LEGACY = 1 << 18, /* internal: create*_workqueue() */ __WQ_ORDERED_EXPLICIT = 1 << 19, /* internal: alloc_ordered_workqueue() */ + __WQ_PAUSED = 1 << 20, /* internal: workqueue_pause() */ WQ_MAX_ACTIVE = 512, /* I like 512, better ideas? */ WQ_MAX_UNBOUND_PER_CPU = 4, /* 4 * #cpus for unbound wq */ @@ -475,6 +476,9 @@ extern void show_all_workqueues(void); extern void show_one_workqueue(struct workqueue_struct *wq); extern void wq_worker_comm(char *buf, size_t size, struct task_struct *task); +void workqueue_pause(struct workqueue_struct *wq); +void workqueue_resume(struct workqueue_struct *wq); + /** * queue_work - queue work on a workqueue * @wq: workqueue to use diff --git a/kernel/workqueue.c b/kernel/workqueue.c index b8b541caed48..12e8b003568f 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -3863,12 +3863,18 @@ static void pwq_adjust_max_active(struct pool_workqueue *pwq) struct workqueue_struct *wq = pwq->wq; bool freezable = wq->flags & WQ_FREEZABLE; unsigned long flags; + int new_max_active; - /* for @wq->saved_max_active */ + /* for @wq->saved_max_active and @wq->flags */ lockdep_assert_held(&wq->mutex); + if (wq->flags & __WQ_PAUSED) + new_max_active = 0; + else + new_max_active = wq->saved_max_active; + /* fast exit for non-freezable wqs */ - if (!freezable && pwq->max_active == wq->saved_max_active) + if (!freezable && pwq->max_active == new_max_active) return; /* this function can be called during early boot w/ irq disabled */ @@ -3882,7 +3888,7 @@ static void pwq_adjust_max_active(struct pool_workqueue *pwq) if (!freezable || !workqueue_freezing) { bool kick = false; - pwq->max_active = wq->saved_max_active; + pwq->max_active = new_max_active; while (!list_empty(&pwq->inactive_works) && pwq->nr_active < pwq->max_active) { @@ -4642,6 +4648,48 @@ void workqueue_set_max_active(struct workqueue_struct *wq, int max_active) } EXPORT_SYMBOL_GPL(workqueue_set_max_active); +/** + * workqueue_pause - pause a workqueue + * @wq: workqueue to pause + * + * Pause (and flush) the given workqueue so it's not executing any + * work structs and won't until workqueue_resume() is called. + */ +void workqueue_pause(struct workqueue_struct *wq) +{ + struct pool_workqueue *pwq; + + mutex_lock(&wq->mutex); + wq->flags |= __WQ_PAUSED; + + for_each_pwq(pwq, wq) + pwq_adjust_max_active(pwq); + mutex_unlock(&wq->mutex); + + flush_workqueue(wq); +} +EXPORT_SYMBOL_GPL(workqueue_pause); + +/** + * workqueue_resume - resume a paused workqueue + * @wq: workqueue to resume + * + * Resume the given workqueue that was paused previously to + * make it run work structs again. + */ +void workqueue_resume(struct workqueue_struct *wq) +{ + struct pool_workqueue *pwq; + + mutex_lock(&wq->mutex); + wq->flags &= ~__WQ_PAUSED; + + for_each_pwq(pwq, wq) + pwq_adjust_max_active(pwq); + mutex_unlock(&wq->mutex); +} +EXPORT_SYMBOL_GPL(workqueue_resume); + /** * current_work - retrieve %current task's work struct *