]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
fs: WQ_PERCPU added to alloc_workqueue users
authorMarco Crivellari <marco.crivellari@suse.com>
Tue, 16 Sep 2025 08:29:06 +0000 (10:29 +0200)
committerChristian Brauner <brauner@kernel.org>
Fri, 19 Sep 2025 14:15:07 +0000 (16:15 +0200)
Currently if a user enqueue a work item using schedule_delayed_work() the
used wq is "system_wq" (per-cpu wq) while queue_delayed_work() use
WORK_CPU_UNBOUND (used when a cpu is not specified). The same applies to
schedule_work() that is using system_wq and queue_work(), that makes use
again of WORK_CPU_UNBOUND.
This lack of consistentcy cannot be addressed without refactoring the API.

alloc_workqueue() treats all queues as per-CPU by default, while unbound
workqueues must opt-in via WQ_UNBOUND.

This default is suboptimal: most workloads benefit from unbound queues,
allowing the scheduler to place worker threads where they’re needed and
reducing noise when CPUs are isolated.

This patch adds a new WQ_PERCPU flag to all the fs subsystem users to
explicitly request the use of the per-CPU behavior. Both flags coexist
for one release cycle to allow callers to transition their calls.

Once migration is complete, WQ_UNBOUND can be removed and unbound will
become the implicit default.

With the introduction of the WQ_PERCPU flag (equivalent to !WQ_UNBOUND),
any alloc_workqueue() caller that doesn’t explicitly specify WQ_UNBOUND
must now use WQ_PERCPU.

All existing users have been updated accordingly.

Suggested-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Marco Crivellari <marco.crivellari@suse.com>
Link: https://lore.kernel.org/20250916082906.77439-4-marco.crivellari@suse.com
Signed-off-by: Christian Brauner <brauner@kernel.org>
19 files changed:
fs/afs/main.c
fs/bcachefs/super.c
fs/btrfs/disk-io.c
fs/ceph/super.c
fs/dlm/lowcomms.c
fs/dlm/main.c
fs/fs-writeback.c
fs/gfs2/main.c
fs/gfs2/ops_fstype.c
fs/ocfs2/dlm/dlmdomain.c
fs/ocfs2/dlmfs/dlmfs.c
fs/smb/client/cifsfs.c
fs/smb/server/ksmbd_work.c
fs/smb/server/transport_rdma.c
fs/super.c
fs/verity/verify.c
fs/xfs/xfs_log.c
fs/xfs/xfs_mru_cache.c
fs/xfs/xfs_super.c

index 02475d415d885e39f84b906c75b03906b34bbe96..e6bb8237db989a9a89b97e576bf9a362c4116afb 100644 (file)
@@ -169,13 +169,13 @@ static int __init afs_init(void)
 
        printk(KERN_INFO "kAFS: Red Hat AFS client v0.1 registering.\n");
 
-       afs_wq = alloc_workqueue("afs", 0, 0);
+       afs_wq = alloc_workqueue("afs", WQ_PERCPU, 0);
        if (!afs_wq)
                goto error_afs_wq;
        afs_async_calls = alloc_workqueue("kafsd", WQ_MEM_RECLAIM | WQ_UNBOUND, 0);
        if (!afs_async_calls)
                goto error_async;
-       afs_lock_manager = alloc_workqueue("kafs_lockd", WQ_MEM_RECLAIM, 0);
+       afs_lock_manager = alloc_workqueue("kafs_lockd", WQ_MEM_RECLAIM | WQ_PERCPU, 0);
        if (!afs_lock_manager)
                goto error_lockmgr;
 
index c46b1053a02c9024624c7395160f34afc43e4d55..f2417d298b844fb5bab23c3bdad61b25c4a56213 100644 (file)
@@ -801,13 +801,13 @@ int bch2_fs_init_rw(struct bch_fs *c)
        if (!(c->btree_update_wq = alloc_workqueue("bcachefs",
                                WQ_HIGHPRI|WQ_FREEZABLE|WQ_MEM_RECLAIM|WQ_UNBOUND, 512)) ||
            !(c->btree_write_complete_wq = alloc_workqueue("bcachefs_btree_write_complete",
-                               WQ_HIGHPRI|WQ_FREEZABLE|WQ_MEM_RECLAIM, 1)) ||
+                               WQ_HIGHPRI|WQ_FREEZABLE|WQ_MEM_RECLAIM|WQ_PERCPU, 1)) ||
            !(c->copygc_wq = alloc_workqueue("bcachefs_copygc",
-                               WQ_HIGHPRI|WQ_FREEZABLE|WQ_MEM_RECLAIM|WQ_CPU_INTENSIVE, 1)) ||
+                               WQ_HIGHPRI|WQ_FREEZABLE|WQ_MEM_RECLAIM|WQ_CPU_INTENSIVE|WQ_PERCPU, 1)) ||
            !(c->btree_write_submit_wq = alloc_workqueue("bcachefs_btree_write_sumit",
-                               WQ_HIGHPRI|WQ_FREEZABLE|WQ_MEM_RECLAIM, 1)) ||
+                               WQ_HIGHPRI|WQ_FREEZABLE|WQ_MEM_RECLAIM|WQ_PERCPU, 1)) ||
            !(c->write_ref_wq = alloc_workqueue("bcachefs_write_ref",
-                               WQ_FREEZABLE, 0)))
+                               WQ_FREEZABLE|WQ_PERCPU, 0)))
                return bch_err_throw(c, ENOMEM_fs_other_alloc);
 
        int ret = bch2_fs_btree_interior_update_init(c) ?:
@@ -975,7 +975,7 @@ static struct bch_fs *bch2_fs_alloc(struct bch_sb *sb, struct bch_opts *opts,
                sizeof(struct sort_iter_set);
 
        if (!(c->btree_read_complete_wq = alloc_workqueue("bcachefs_btree_read_complete",
-                               WQ_HIGHPRI|WQ_FREEZABLE|WQ_MEM_RECLAIM, 512)) ||
+                               WQ_HIGHPRI|WQ_FREEZABLE|WQ_MEM_RECLAIM|WQ_PERCPU, 512)) ||
            enumerated_ref_init(&c->writes, BCH_WRITE_REF_NR,
                                bch2_writes_disabled) ||
            mempool_init_kmalloc_pool(&c->fill_iter, 1, iter_size) ||
index 70fc4e7cc5a0e6cd8885df91c3959455322eb6d0..aa4393eba9977932082136c1179136b2dedea7ca 100644 (file)
@@ -1958,7 +1958,7 @@ static int btrfs_init_workqueues(struct btrfs_fs_info *fs_info)
 {
        u32 max_active = fs_info->thread_pool_size;
        unsigned int flags = WQ_MEM_RECLAIM | WQ_FREEZABLE | WQ_UNBOUND;
-       unsigned int ordered_flags = WQ_MEM_RECLAIM | WQ_FREEZABLE;
+       unsigned int ordered_flags = WQ_MEM_RECLAIM | WQ_FREEZABLE | WQ_PERCPU;
 
        fs_info->workers =
                btrfs_alloc_workqueue(fs_info, "worker", flags, max_active, 16);
index c3eb651862c555254fb3b4818db4c3f7355bfbb4..2dc64515f259d904e7602a42cca7669413ed9b02 100644 (file)
@@ -862,7 +862,7 @@ static struct ceph_fs_client *create_fs_client(struct ceph_mount_options *fsopt,
        fsc->inode_wq = alloc_workqueue("ceph-inode", WQ_UNBOUND, 0);
        if (!fsc->inode_wq)
                goto fail_client;
-       fsc->cap_wq = alloc_workqueue("ceph-cap", 0, 1);
+       fsc->cap_wq = alloc_workqueue("ceph-cap", WQ_PERCPU, 1);
        if (!fsc->cap_wq)
                goto fail_inode_wq;
 
index e4373bce1bc2390882dd5a85243c305e939d20bd..9a0b6c2b6b01e4f3d6bdc6ceaffd4f52ac817513 100644 (file)
@@ -1703,7 +1703,7 @@ static int work_start(void)
                return -ENOMEM;
        }
 
-       process_workqueue = alloc_workqueue("dlm_process", WQ_HIGHPRI | WQ_BH, 0);
+       process_workqueue = alloc_workqueue("dlm_process", WQ_HIGHPRI | WQ_BH | WQ_PERCPU, 0);
        if (!process_workqueue) {
                log_print("can't start dlm_process");
                destroy_workqueue(io_workqueue);
index 4887c8a05318dd21b8fb87f500f1885f80e8f0a4..a44d16da7187c82880355006601d6f30045bbfc8 100644 (file)
@@ -52,7 +52,7 @@ static int __init init_dlm(void)
        if (error)
                goto out_user;
 
-       dlm_wq = alloc_workqueue("dlm_wq", 0, 0);
+       dlm_wq = alloc_workqueue("dlm_wq", WQ_PERCPU, 0);
        if (!dlm_wq) {
                error = -ENOMEM;
                goto out_plock;
index cf51a265bf2712ddcfaa5aa1767e3da832e95126..4b1a53a3266bb37e1a267477c83625168c292c11 100644 (file)
@@ -1180,7 +1180,7 @@ void cgroup_writeback_umount(struct super_block *sb)
 
 static int __init cgroup_writeback_init(void)
 {
-       isw_wq = alloc_workqueue("inode_switch_wbs", 0, 0);
+       isw_wq = alloc_workqueue("inode_switch_wbs", WQ_PERCPU, 0);
        if (!isw_wq)
                return -ENOMEM;
        return 0;
index 0727f60ad02883d629c87b8986364e2dd9e5d6e4..9d65719353faad93c25cbf5303fbed034bf264ab 100644 (file)
@@ -151,7 +151,8 @@ static int __init init_gfs2_fs(void)
 
        error = -ENOMEM;
        gfs2_recovery_wq = alloc_workqueue("gfs2_recovery",
-                                         WQ_MEM_RECLAIM | WQ_FREEZABLE, 0);
+                                         WQ_MEM_RECLAIM | WQ_FREEZABLE | WQ_PERCPU,
+                                         0);
        if (!gfs2_recovery_wq)
                goto fail_wq1;
 
@@ -160,7 +161,7 @@ static int __init init_gfs2_fs(void)
        if (!gfs2_control_wq)
                goto fail_wq2;
 
-       gfs2_freeze_wq = alloc_workqueue("gfs2_freeze", 0, 0);
+       gfs2_freeze_wq = alloc_workqueue("gfs2_freeze", WQ_PERCPU, 0);
 
        if (!gfs2_freeze_wq)
                goto fail_wq3;
index efe99b73255137dc7b326316813246348bdf6044..05f936cc5db78f50fac811bc56f177adcc3070be 100644 (file)
@@ -1193,13 +1193,15 @@ static int gfs2_fill_super(struct super_block *sb, struct fs_context *fc)
 
        error = -ENOMEM;
        sdp->sd_glock_wq = alloc_workqueue("gfs2-glock/%s",
-                       WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_FREEZABLE, 0,
+                       WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_FREEZABLE | WQ_PERCPU,
+                       0,
                        sdp->sd_fsname);
        if (!sdp->sd_glock_wq)
                goto fail_iput;
 
        sdp->sd_delete_wq = alloc_workqueue("gfs2-delete/%s",
-                       WQ_MEM_RECLAIM | WQ_FREEZABLE, 0, sdp->sd_fsname);
+                       WQ_MEM_RECLAIM | WQ_FREEZABLE | WQ_PERCPU, 0,
+                       sdp->sd_fsname);
        if (!sdp->sd_delete_wq)
                goto fail_glock_wq;
 
index 2018501b2249373fc8ecb7070b82164dc9c036e1..2347a50f079b7b9502b24df003155eb3120a198b 100644 (file)
@@ -1876,7 +1876,8 @@ static int dlm_join_domain(struct dlm_ctxt *dlm)
        dlm_debug_init(dlm);
 
        snprintf(wq_name, O2NM_MAX_NAME_LEN, "dlm_wq-%s", dlm->name);
-       dlm->dlm_worker = alloc_workqueue(wq_name, WQ_MEM_RECLAIM, 0);
+       dlm->dlm_worker = alloc_workqueue(wq_name, WQ_MEM_RECLAIM | WQ_PERCPU,
+                                         0);
        if (!dlm->dlm_worker) {
                status = -ENOMEM;
                mlog_errno(status);
index 5130ec44e5e158913f09f8d6bf1a01edd4e9df8c..0b730535b2c88033037918a4f1ee4e97ed4eb186 100644 (file)
@@ -595,7 +595,8 @@ static int __init init_dlmfs_fs(void)
        }
        cleanup_inode = 1;
 
-       user_dlm_worker = alloc_workqueue("user_dlm", WQ_MEM_RECLAIM, 0);
+       user_dlm_worker = alloc_workqueue("user_dlm",
+                                         WQ_MEM_RECLAIM | WQ_PERCPU, 0);
        if (!user_dlm_worker) {
                status = -ENOMEM;
                goto bail;
index 3bd85ab2deb1924412fb726778a48804f0cc5812..7882b03468633217c508d6a25027bba509c54210 100644 (file)
@@ -1881,7 +1881,9 @@ init_cifs(void)
                cifs_dbg(VFS, "dir_cache_timeout set to max of 65000 seconds\n");
        }
 
-       cifsiod_wq = alloc_workqueue("cifsiod", WQ_FREEZABLE|WQ_MEM_RECLAIM, 0);
+       cifsiod_wq = alloc_workqueue("cifsiod",
+                                    WQ_FREEZABLE | WQ_MEM_RECLAIM | WQ_PERCPU,
+                                    0);
        if (!cifsiod_wq) {
                rc = -ENOMEM;
                goto out_clean_proc;
@@ -1909,28 +1911,32 @@ init_cifs(void)
        }
 
        cifsoplockd_wq = alloc_workqueue("cifsoplockd",
-                                        WQ_FREEZABLE|WQ_MEM_RECLAIM, 0);
+                                        WQ_FREEZABLE | WQ_MEM_RECLAIM | WQ_PERCPU,
+                                        0);
        if (!cifsoplockd_wq) {
                rc = -ENOMEM;
                goto out_destroy_fileinfo_put_wq;
        }
 
        deferredclose_wq = alloc_workqueue("deferredclose",
-                                          WQ_FREEZABLE|WQ_MEM_RECLAIM, 0);
+                                          WQ_FREEZABLE | WQ_MEM_RECLAIM | WQ_PERCPU,
+                                          0);
        if (!deferredclose_wq) {
                rc = -ENOMEM;
                goto out_destroy_cifsoplockd_wq;
        }
 
        serverclose_wq = alloc_workqueue("serverclose",
-                                          WQ_FREEZABLE|WQ_MEM_RECLAIM, 0);
+                                          WQ_FREEZABLE | WQ_MEM_RECLAIM | WQ_PERCPU,
+                                          0);
        if (!serverclose_wq) {
                rc = -ENOMEM;
                goto out_destroy_deferredclose_wq;
        }
 
        cfid_put_wq = alloc_workqueue("cfid_put_wq",
-                                     WQ_FREEZABLE|WQ_MEM_RECLAIM, 0);
+                                     WQ_FREEZABLE | WQ_MEM_RECLAIM | WQ_PERCPU,
+                                     0);
        if (!cfid_put_wq) {
                rc = -ENOMEM;
                goto out_destroy_serverclose_wq;
index 72b00ca6e455172bca35b616a777dac805dc4099..4a71f46d7020be745ed9abe95b595028b43c23cd 100644 (file)
@@ -78,7 +78,7 @@ int ksmbd_work_pool_init(void)
 
 int ksmbd_workqueue_init(void)
 {
-       ksmbd_wq = alloc_workqueue("ksmbd-io", 0, 0);
+       ksmbd_wq = alloc_workqueue("ksmbd-io", WQ_PERCPU, 0);
        if (!ksmbd_wq)
                return -ENOMEM;
        return 0;
index 8d366db5f60547af18b035842bfd3c0aff59f8e4..9394b358e795557fae1684f24e5e0c0d95762f05 100644 (file)
@@ -2177,7 +2177,8 @@ int ksmbd_rdma_init(void)
         * for lack of credits
         */
        smb_direct_wq = alloc_workqueue("ksmbd-smb_direct-wq",
-                                       WQ_HIGHPRI | WQ_MEM_RECLAIM, 0);
+                                       WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_PERCPU,
+                                       0);
        if (!smb_direct_wq)
                return -ENOMEM;
 
index 7f876f32343ad47fc082b72b2c521bcaaa2f6873..5cb3f41e42cad0835e4221406cd7683abd6104ed 100644 (file)
@@ -2314,7 +2314,8 @@ int sb_init_dio_done_wq(struct super_block *sb)
 {
        struct workqueue_struct *old;
        struct workqueue_struct *wq = alloc_workqueue("dio/%s",
-                                                     WQ_MEM_RECLAIM, 0,
+                                                     WQ_MEM_RECLAIM | WQ_PERCPU,
+                                                     0,
                                                      sb->s_id);
        if (!wq)
                return -ENOMEM;
index a1f00c3fd3b2765eca730bf10ff5ef6db9c411e0..628c23710f9fb916c56ffbb73ee6b2a3bd67102a 100644 (file)
@@ -355,7 +355,7 @@ void __init fsverity_init_workqueue(void)
         * latency on ARM64.
         */
        fsverity_read_workqueue = alloc_workqueue("fsverity_read_queue",
-                                                 WQ_HIGHPRI,
+                                                 WQ_HIGHPRI | WQ_PERCPU,
                                                  num_online_cpus());
        if (!fsverity_read_workqueue)
                panic("failed to allocate fsverity_read_queue");
index c8a57e21a1d3e070daa48f22ba0ad3f33137ebe0..0da19472d6030966bd74e5eced3a2a3215d544d8 100644 (file)
@@ -1489,8 +1489,7 @@ xlog_alloc_log(
        log->l_iclog->ic_prev = prev_iclog;     /* re-write 1st prev ptr */
 
        log->l_ioend_workqueue = alloc_workqueue("xfs-log/%s",
-                       XFS_WQFLAGS(WQ_FREEZABLE | WQ_MEM_RECLAIM |
-                                   WQ_HIGHPRI),
+                       XFS_WQFLAGS(WQ_FREEZABLE | WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_PERCPU),
                        0, mp->m_super->s_id);
        if (!log->l_ioend_workqueue)
                goto out_free_iclog;
index 866c71d9fbaed4800f90e6547cf2e2c9c1f41742..73b7e72944e47fc99998215f5cfd7a3df06d7c63 100644 (file)
@@ -293,7 +293,8 @@ int
 xfs_mru_cache_init(void)
 {
        xfs_mru_reap_wq = alloc_workqueue("xfs_mru_cache",
-                       XFS_WQFLAGS(WQ_MEM_RECLAIM | WQ_FREEZABLE), 1);
+                       XFS_WQFLAGS(WQ_MEM_RECLAIM | WQ_FREEZABLE | WQ_PERCPU),
+                       1);
        if (!xfs_mru_reap_wq)
                return -ENOMEM;
        return 0;
index bb0a82635a770d48a8562b994fe13eb28b922069..43e9aab7161031145227bc227cc43e57d87d4c9f 100644 (file)
@@ -578,19 +578,19 @@ xfs_init_mount_workqueues(
        struct xfs_mount        *mp)
 {
        mp->m_buf_workqueue = alloc_workqueue("xfs-buf/%s",
-                       XFS_WQFLAGS(WQ_FREEZABLE | WQ_MEM_RECLAIM),
+                       XFS_WQFLAGS(WQ_FREEZABLE | WQ_MEM_RECLAIM | WQ_PERCPU),
                        1, mp->m_super->s_id);
        if (!mp->m_buf_workqueue)
                goto out;
 
        mp->m_unwritten_workqueue = alloc_workqueue("xfs-conv/%s",
-                       XFS_WQFLAGS(WQ_FREEZABLE | WQ_MEM_RECLAIM),
+                       XFS_WQFLAGS(WQ_FREEZABLE | WQ_MEM_RECLAIM | WQ_PERCPU),
                        0, mp->m_super->s_id);
        if (!mp->m_unwritten_workqueue)
                goto out_destroy_buf;
 
        mp->m_reclaim_workqueue = alloc_workqueue("xfs-reclaim/%s",
-                       XFS_WQFLAGS(WQ_FREEZABLE | WQ_MEM_RECLAIM),
+                       XFS_WQFLAGS(WQ_FREEZABLE | WQ_MEM_RECLAIM | WQ_PERCPU),
                        0, mp->m_super->s_id);
        if (!mp->m_reclaim_workqueue)
                goto out_destroy_unwritten;
@@ -602,13 +602,14 @@ xfs_init_mount_workqueues(
                goto out_destroy_reclaim;
 
        mp->m_inodegc_wq = alloc_workqueue("xfs-inodegc/%s",
-                       XFS_WQFLAGS(WQ_FREEZABLE | WQ_MEM_RECLAIM),
+                       XFS_WQFLAGS(WQ_FREEZABLE | WQ_MEM_RECLAIM | WQ_PERCPU),
                        1, mp->m_super->s_id);
        if (!mp->m_inodegc_wq)
                goto out_destroy_blockgc;
 
        mp->m_sync_workqueue = alloc_workqueue("xfs-sync/%s",
-                       XFS_WQFLAGS(WQ_FREEZABLE), 0, mp->m_super->s_id);
+                       XFS_WQFLAGS(WQ_FREEZABLE | WQ_PERCPU), 0,
+                       mp->m_super->s_id);
        if (!mp->m_sync_workqueue)
                goto out_destroy_inodegc;
 
@@ -2596,8 +2597,8 @@ xfs_init_workqueues(void)
         * AGs in all the filesystems mounted. Hence use the default large
         * max_active value for this workqueue.
         */
-       xfs_alloc_wq = alloc_workqueue("xfsalloc",
-                       XFS_WQFLAGS(WQ_MEM_RECLAIM | WQ_FREEZABLE), 0);
+       xfs_alloc_wq = alloc_workqueue("xfsalloc", XFS_WQFLAGS(WQ_MEM_RECLAIM | WQ_FREEZABLE | WQ_PERCPU),
+                       0);
        if (!xfs_alloc_wq)
                return -ENOMEM;