xref: /OK3568_Linux_fs/kernel/fs/xfs/xfs_pwork.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (C) 2019 Oracle.  All Rights Reserved.
4*4882a593Smuzhiyun  * Author: Darrick J. Wong <darrick.wong@oracle.com>
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun #include "xfs.h"
7*4882a593Smuzhiyun #include "xfs_fs.h"
8*4882a593Smuzhiyun #include "xfs_shared.h"
9*4882a593Smuzhiyun #include "xfs_format.h"
10*4882a593Smuzhiyun #include "xfs_log_format.h"
11*4882a593Smuzhiyun #include "xfs_trans_resv.h"
12*4882a593Smuzhiyun #include "xfs_mount.h"
13*4882a593Smuzhiyun #include "xfs_trace.h"
14*4882a593Smuzhiyun #include "xfs_sysctl.h"
15*4882a593Smuzhiyun #include "xfs_pwork.h"
16*4882a593Smuzhiyun #include <linux/nmi.h>
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun /*
19*4882a593Smuzhiyun  * Parallel Work Queue
20*4882a593Smuzhiyun  * ===================
21*4882a593Smuzhiyun  *
22*4882a593Smuzhiyun  * Abstract away the details of running a large and "obviously" parallelizable
23*4882a593Smuzhiyun  * task across multiple CPUs.  Callers initialize the pwork control object with
24*4882a593Smuzhiyun  * a desired level of parallelization and a work function.  Next, they embed
25*4882a593Smuzhiyun  * struct xfs_pwork in whatever structure they use to pass work context to a
26*4882a593Smuzhiyun  * worker thread and queue that pwork.  The work function will be passed the
27*4882a593Smuzhiyun  * pwork item when it is run (from process context) and any returned error will
28*4882a593Smuzhiyun  * be recorded in xfs_pwork_ctl.error.  Work functions should check for errors
29*4882a593Smuzhiyun  * and abort if necessary; the non-zeroness of xfs_pwork_ctl.error does not
30*4882a593Smuzhiyun  * stop workqueue item processing.
31*4882a593Smuzhiyun  *
32*4882a593Smuzhiyun  * This is the rough equivalent of the xfsprogs workqueue code, though we can't
33*4882a593Smuzhiyun  * reuse that name here.
34*4882a593Smuzhiyun  */
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun /* Invoke our caller's function. */
37*4882a593Smuzhiyun static void
xfs_pwork_work(struct work_struct * work)38*4882a593Smuzhiyun xfs_pwork_work(
39*4882a593Smuzhiyun 	struct work_struct	*work)
40*4882a593Smuzhiyun {
41*4882a593Smuzhiyun 	struct xfs_pwork	*pwork;
42*4882a593Smuzhiyun 	struct xfs_pwork_ctl	*pctl;
43*4882a593Smuzhiyun 	int			error;
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun 	pwork = container_of(work, struct xfs_pwork, work);
46*4882a593Smuzhiyun 	pctl = pwork->pctl;
47*4882a593Smuzhiyun 	error = pctl->work_fn(pctl->mp, pwork);
48*4882a593Smuzhiyun 	if (error && !pctl->error)
49*4882a593Smuzhiyun 		pctl->error = error;
50*4882a593Smuzhiyun 	if (atomic_dec_and_test(&pctl->nr_work))
51*4882a593Smuzhiyun 		wake_up(&pctl->poll_wait);
52*4882a593Smuzhiyun }
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun /*
55*4882a593Smuzhiyun  * Set up control data for parallel work.  @work_fn is the function that will
56*4882a593Smuzhiyun  * be called.  @tag will be written into the kernel threads.  @nr_threads is
57*4882a593Smuzhiyun  * the level of parallelism desired, or 0 for no limit.
58*4882a593Smuzhiyun  */
59*4882a593Smuzhiyun int
xfs_pwork_init(struct xfs_mount * mp,struct xfs_pwork_ctl * pctl,xfs_pwork_work_fn work_fn,const char * tag,unsigned int nr_threads)60*4882a593Smuzhiyun xfs_pwork_init(
61*4882a593Smuzhiyun 	struct xfs_mount	*mp,
62*4882a593Smuzhiyun 	struct xfs_pwork_ctl	*pctl,
63*4882a593Smuzhiyun 	xfs_pwork_work_fn	work_fn,
64*4882a593Smuzhiyun 	const char		*tag,
65*4882a593Smuzhiyun 	unsigned int		nr_threads)
66*4882a593Smuzhiyun {
67*4882a593Smuzhiyun #ifdef DEBUG
68*4882a593Smuzhiyun 	if (xfs_globals.pwork_threads >= 0)
69*4882a593Smuzhiyun 		nr_threads = xfs_globals.pwork_threads;
70*4882a593Smuzhiyun #endif
71*4882a593Smuzhiyun 	trace_xfs_pwork_init(mp, nr_threads, current->pid);
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun 	pctl->wq = alloc_workqueue("%s-%d", WQ_FREEZABLE, nr_threads, tag,
74*4882a593Smuzhiyun 			current->pid);
75*4882a593Smuzhiyun 	if (!pctl->wq)
76*4882a593Smuzhiyun 		return -ENOMEM;
77*4882a593Smuzhiyun 	pctl->work_fn = work_fn;
78*4882a593Smuzhiyun 	pctl->error = 0;
79*4882a593Smuzhiyun 	pctl->mp = mp;
80*4882a593Smuzhiyun 	atomic_set(&pctl->nr_work, 0);
81*4882a593Smuzhiyun 	init_waitqueue_head(&pctl->poll_wait);
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun 	return 0;
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun /* Queue some parallel work. */
87*4882a593Smuzhiyun void
xfs_pwork_queue(struct xfs_pwork_ctl * pctl,struct xfs_pwork * pwork)88*4882a593Smuzhiyun xfs_pwork_queue(
89*4882a593Smuzhiyun 	struct xfs_pwork_ctl	*pctl,
90*4882a593Smuzhiyun 	struct xfs_pwork	*pwork)
91*4882a593Smuzhiyun {
92*4882a593Smuzhiyun 	INIT_WORK(&pwork->work, xfs_pwork_work);
93*4882a593Smuzhiyun 	pwork->pctl = pctl;
94*4882a593Smuzhiyun 	atomic_inc(&pctl->nr_work);
95*4882a593Smuzhiyun 	queue_work(pctl->wq, &pwork->work);
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun /* Wait for the work to finish and tear down the control structure. */
99*4882a593Smuzhiyun int
xfs_pwork_destroy(struct xfs_pwork_ctl * pctl)100*4882a593Smuzhiyun xfs_pwork_destroy(
101*4882a593Smuzhiyun 	struct xfs_pwork_ctl	*pctl)
102*4882a593Smuzhiyun {
103*4882a593Smuzhiyun 	destroy_workqueue(pctl->wq);
104*4882a593Smuzhiyun 	pctl->wq = NULL;
105*4882a593Smuzhiyun 	return pctl->error;
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun /*
109*4882a593Smuzhiyun  * Wait for the work to finish by polling completion status and touch the soft
110*4882a593Smuzhiyun  * lockup watchdog.  This is for callers such as mount which hold locks.
111*4882a593Smuzhiyun  */
112*4882a593Smuzhiyun void
xfs_pwork_poll(struct xfs_pwork_ctl * pctl)113*4882a593Smuzhiyun xfs_pwork_poll(
114*4882a593Smuzhiyun 	struct xfs_pwork_ctl	*pctl)
115*4882a593Smuzhiyun {
116*4882a593Smuzhiyun 	while (wait_event_timeout(pctl->poll_wait,
117*4882a593Smuzhiyun 				atomic_read(&pctl->nr_work) == 0, HZ) == 0)
118*4882a593Smuzhiyun 		touch_softlockup_watchdog();
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun /*
122*4882a593Smuzhiyun  * Return the amount of parallelism that the data device can handle, or 0 for
123*4882a593Smuzhiyun  * no limit.
124*4882a593Smuzhiyun  */
125*4882a593Smuzhiyun unsigned int
xfs_pwork_guess_datadev_parallelism(struct xfs_mount * mp)126*4882a593Smuzhiyun xfs_pwork_guess_datadev_parallelism(
127*4882a593Smuzhiyun 	struct xfs_mount	*mp)
128*4882a593Smuzhiyun {
129*4882a593Smuzhiyun 	struct xfs_buftarg	*btp = mp->m_ddev_targp;
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	/*
132*4882a593Smuzhiyun 	 * For now we'll go with the most conservative setting possible,
133*4882a593Smuzhiyun 	 * which is two threads for an SSD and 1 thread everywhere else.
134*4882a593Smuzhiyun 	 */
135*4882a593Smuzhiyun 	return blk_queue_nonrot(btp->bt_bdev->bd_disk->queue) ? 2 : 1;
136*4882a593Smuzhiyun }
137