xref: /OK3568_Linux_fs/kernel/Documentation/filesystems/caching/operations.rst (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun.. SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun
3*4882a593Smuzhiyun================================
4*4882a593SmuzhiyunAsynchronous Operations Handling
5*4882a593Smuzhiyun================================
6*4882a593Smuzhiyun
7*4882a593SmuzhiyunBy: David Howells <dhowells@redhat.com>
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun.. Contents:
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun (*) Overview.
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun (*) Operation record initialisation.
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun (*) Parameters.
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun (*) Procedure.
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun (*) Asynchronous callback.
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun
22*4882a593SmuzhiyunOverview
23*4882a593Smuzhiyun========
24*4882a593Smuzhiyun
25*4882a593SmuzhiyunFS-Cache has an asynchronous operations handling facility that it uses for its
26*4882a593Smuzhiyundata storage and retrieval routines.  Its operations are represented by
27*4882a593Smuzhiyunfscache_operation structs, though these are usually embedded into some other
28*4882a593Smuzhiyunstructure.
29*4882a593Smuzhiyun
30*4882a593SmuzhiyunThis facility is available to and expected to be used by the cache backends,
31*4882a593Smuzhiyunand FS-Cache will create operations and pass them off to the appropriate cache
32*4882a593Smuzhiyunbackend for completion.
33*4882a593Smuzhiyun
34*4882a593SmuzhiyunTo make use of this facility, <linux/fscache-cache.h> should be #included.
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun
37*4882a593SmuzhiyunOperation Record Initialisation
38*4882a593Smuzhiyun===============================
39*4882a593Smuzhiyun
40*4882a593SmuzhiyunAn operation is recorded in an fscache_operation struct::
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun	struct fscache_operation {
43*4882a593Smuzhiyun		union {
44*4882a593Smuzhiyun			struct work_struct fast_work;
45*4882a593Smuzhiyun			struct slow_work slow_work;
46*4882a593Smuzhiyun		};
47*4882a593Smuzhiyun		unsigned long		flags;
48*4882a593Smuzhiyun		fscache_operation_processor_t processor;
49*4882a593Smuzhiyun		...
50*4882a593Smuzhiyun	};
51*4882a593Smuzhiyun
52*4882a593SmuzhiyunSomeone wanting to issue an operation should allocate something with this
53*4882a593Smuzhiyunstruct embedded in it.  They should initialise it by calling::
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun	void fscache_operation_init(struct fscache_operation *op,
56*4882a593Smuzhiyun				    fscache_operation_release_t release);
57*4882a593Smuzhiyun
58*4882a593Smuzhiyunwith the operation to be initialised and the release function to use.
59*4882a593Smuzhiyun
60*4882a593SmuzhiyunThe op->flags parameter should be set to indicate the CPU time provision and
61*4882a593Smuzhiyunthe exclusivity (see the Parameters section).
62*4882a593Smuzhiyun
63*4882a593SmuzhiyunThe op->fast_work, op->slow_work and op->processor flags should be set as
64*4882a593Smuzhiyunappropriate for the CPU time provision (see the Parameters section).
65*4882a593Smuzhiyun
66*4882a593SmuzhiyunFSCACHE_OP_WAITING may be set in op->flags prior to each submission of the
67*4882a593Smuzhiyunoperation and waited for afterwards.
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun
70*4882a593SmuzhiyunParameters
71*4882a593Smuzhiyun==========
72*4882a593Smuzhiyun
73*4882a593SmuzhiyunThere are a number of parameters that can be set in the operation record's flag
74*4882a593Smuzhiyunparameter.  There are three options for the provision of CPU time in these
75*4882a593Smuzhiyunoperations:
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun (1) The operation may be done synchronously (FSCACHE_OP_MYTHREAD).  A thread
78*4882a593Smuzhiyun     may decide it wants to handle an operation itself without deferring it to
79*4882a593Smuzhiyun     another thread.
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun     This is, for example, used in read operations for calling readpages() on
82*4882a593Smuzhiyun     the backing filesystem in CacheFiles.  Although readpages() does an
83*4882a593Smuzhiyun     asynchronous data fetch, the determination of whether pages exist is done
84*4882a593Smuzhiyun     synchronously - and the netfs does not proceed until this has been
85*4882a593Smuzhiyun     determined.
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun     If this option is to be used, FSCACHE_OP_WAITING must be set in op->flags
88*4882a593Smuzhiyun     before submitting the operation, and the operating thread must wait for it
89*4882a593Smuzhiyun     to be cleared before proceeding::
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun		wait_on_bit(&op->flags, FSCACHE_OP_WAITING,
92*4882a593Smuzhiyun			    TASK_UNINTERRUPTIBLE);
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun (2) The operation may be fast asynchronous (FSCACHE_OP_FAST), in which case it
96*4882a593Smuzhiyun     will be given to keventd to process.  Such an operation is not permitted
97*4882a593Smuzhiyun     to sleep on I/O.
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun     This is, for example, used by CacheFiles to copy data from a backing fs
100*4882a593Smuzhiyun     page to a netfs page after the backing fs has read the page in.
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun     If this option is used, op->fast_work and op->processor must be
103*4882a593Smuzhiyun     initialised before submitting the operation::
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun		INIT_WORK(&op->fast_work, do_some_work);
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun (3) The operation may be slow asynchronous (FSCACHE_OP_SLOW), in which case it
109*4882a593Smuzhiyun     will be given to the slow work facility to process.  Such an operation is
110*4882a593Smuzhiyun     permitted to sleep on I/O.
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun     This is, for example, used by FS-Cache to handle background writes of
113*4882a593Smuzhiyun     pages that have just been fetched from a remote server.
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun     If this option is used, op->slow_work and op->processor must be
116*4882a593Smuzhiyun     initialised before submitting the operation::
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun		fscache_operation_init_slow(op, processor)
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun
121*4882a593SmuzhiyunFurthermore, operations may be one of two types:
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun (1) Exclusive (FSCACHE_OP_EXCLUSIVE).  Operations of this type may not run in
124*4882a593Smuzhiyun     conjunction with any other operation on the object being operated upon.
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun     An example of this is the attribute change operation, in which the file
127*4882a593Smuzhiyun     being written to may need truncation.
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun (2) Shareable.  Operations of this type may be running simultaneously.  It's
130*4882a593Smuzhiyun     up to the operation implementation to prevent interference between other
131*4882a593Smuzhiyun     operations running at the same time.
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun
134*4882a593SmuzhiyunProcedure
135*4882a593Smuzhiyun=========
136*4882a593Smuzhiyun
137*4882a593SmuzhiyunOperations are used through the following procedure:
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun (1) The submitting thread must allocate the operation and initialise it
140*4882a593Smuzhiyun     itself.  Normally this would be part of a more specific structure with the
141*4882a593Smuzhiyun     generic op embedded within.
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun (2) The submitting thread must then submit the operation for processing using
144*4882a593Smuzhiyun     one of the following two functions::
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun	int fscache_submit_op(struct fscache_object *object,
147*4882a593Smuzhiyun			      struct fscache_operation *op);
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun	int fscache_submit_exclusive_op(struct fscache_object *object,
150*4882a593Smuzhiyun					struct fscache_operation *op);
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun     The first function should be used to submit non-exclusive ops and the
153*4882a593Smuzhiyun     second to submit exclusive ones.  The caller must still set the
154*4882a593Smuzhiyun     FSCACHE_OP_EXCLUSIVE flag.
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun     If successful, both functions will assign the operation to the specified
157*4882a593Smuzhiyun     object and return 0.  -ENOBUFS will be returned if the object specified is
158*4882a593Smuzhiyun     permanently unavailable.
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun     The operation manager will defer operations on an object that is still
161*4882a593Smuzhiyun     undergoing lookup or creation.  The operation will also be deferred if an
162*4882a593Smuzhiyun     operation of conflicting exclusivity is in progress on the object.
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun     If the operation is asynchronous, the manager will retain a reference to
165*4882a593Smuzhiyun     it, so the caller should put their reference to it by passing it to::
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun	void fscache_put_operation(struct fscache_operation *op);
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun (3) If the submitting thread wants to do the work itself, and has marked the
170*4882a593Smuzhiyun     operation with FSCACHE_OP_MYTHREAD, then it should monitor
171*4882a593Smuzhiyun     FSCACHE_OP_WAITING as described above and check the state of the object if
172*4882a593Smuzhiyun     necessary (the object might have died while the thread was waiting).
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun     When it has finished doing its processing, it should call
175*4882a593Smuzhiyun     fscache_op_complete() and fscache_put_operation() on it.
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun (4) The operation holds an effective lock upon the object, preventing other
178*4882a593Smuzhiyun     exclusive ops conflicting until it is released.  The operation can be
179*4882a593Smuzhiyun     enqueued for further immediate asynchronous processing by adjusting the
180*4882a593Smuzhiyun     CPU time provisioning option if necessary, eg::
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun	op->flags &= ~FSCACHE_OP_TYPE;
183*4882a593Smuzhiyun	op->flags |= ~FSCACHE_OP_FAST;
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun     and calling::
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun	void fscache_enqueue_operation(struct fscache_operation *op)
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun     This can be used to allow other things to have use of the worker thread
190*4882a593Smuzhiyun     pools.
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun
193*4882a593SmuzhiyunAsynchronous Callback
194*4882a593Smuzhiyun=====================
195*4882a593Smuzhiyun
196*4882a593SmuzhiyunWhen used in asynchronous mode, the worker thread pool will invoke the
197*4882a593Smuzhiyunprocessor method with a pointer to the operation.  This should then get at the
198*4882a593Smuzhiyuncontainer struct by using container_of()::
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun	static void fscache_write_op(struct fscache_operation *_op)
201*4882a593Smuzhiyun	{
202*4882a593Smuzhiyun		struct fscache_storage *op =
203*4882a593Smuzhiyun			container_of(_op, struct fscache_storage, op);
204*4882a593Smuzhiyun	...
205*4882a593Smuzhiyun	}
206*4882a593Smuzhiyun
207*4882a593SmuzhiyunThe caller holds a reference on the operation, and will invoke
208*4882a593Smuzhiyunfscache_put_operation() when the processor function returns.  The processor
209*4882a593Smuzhiyunfunction is at liberty to call fscache_enqueue_operation() or to take extra
210*4882a593Smuzhiyunreferences.
211