Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-or-later
2 : : /* FS-Cache worker operation management routines
3 : : *
4 : : * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved.
5 : : * Written by David Howells (dhowells@redhat.com)
6 : : *
7 : : * See Documentation/filesystems/caching/operations.txt
8 : : */
9 : :
10 : : #define FSCACHE_DEBUG_LEVEL OPERATION
11 : : #include <linux/module.h>
12 : : #include <linux/seq_file.h>
13 : : #include <linux/slab.h>
14 : : #include "internal.h"
15 : :
16 : : atomic_t fscache_op_debug_id;
17 : : EXPORT_SYMBOL(fscache_op_debug_id);
18 : :
19 : 0 : static void fscache_operation_dummy_cancel(struct fscache_operation *op)
20 : : {
21 : 0 : }
22 : :
23 : : /**
24 : : * fscache_operation_init - Do basic initialisation of an operation
25 : : * @op: The operation to initialise
26 : : * @release: The release function to assign
27 : : *
28 : : * Do basic initialisation of an operation. The caller must still set flags,
29 : : * object and processor if needed.
30 : : */
31 : 0 : void fscache_operation_init(struct fscache_cookie *cookie,
32 : : struct fscache_operation *op,
33 : : fscache_operation_processor_t processor,
34 : : fscache_operation_cancel_t cancel,
35 : : fscache_operation_release_t release)
36 : : {
37 : 0 : INIT_WORK(&op->work, fscache_op_work_func);
38 : : atomic_set(&op->usage, 1);
39 : 0 : op->state = FSCACHE_OP_ST_INITIALISED;
40 : 0 : op->debug_id = atomic_inc_return(&fscache_op_debug_id);
41 : 0 : op->processor = processor;
42 [ # # ]: 0 : op->cancel = cancel ?: fscache_operation_dummy_cancel;
43 : 0 : op->release = release;
44 : 0 : INIT_LIST_HEAD(&op->pend_link);
45 : : fscache_stat(&fscache_n_op_initialised);
46 : 0 : trace_fscache_op(cookie, op, fscache_op_init);
47 : 0 : }
48 : : EXPORT_SYMBOL(fscache_operation_init);
49 : :
50 : : /**
51 : : * fscache_enqueue_operation - Enqueue an operation for processing
52 : : * @op: The operation to enqueue
53 : : *
54 : : * Enqueue an operation for processing by the FS-Cache thread pool.
55 : : *
56 : : * This will get its own ref on the object.
57 : : */
58 : 0 : void fscache_enqueue_operation(struct fscache_operation *op)
59 : : {
60 : 0 : struct fscache_cookie *cookie = op->object->cookie;
61 : :
62 : : _enter("{OBJ%x OP%x,%u}",
63 : : op->object->debug_id, op->debug_id, atomic_read(&op->usage));
64 : :
65 [ # # ]: 0 : ASSERT(list_empty(&op->pend_link));
66 [ # # ]: 0 : ASSERT(op->processor != NULL);
67 [ # # ]: 0 : ASSERT(fscache_object_is_available(op->object));
68 [ # # ]: 0 : ASSERTCMP(atomic_read(&op->usage), >, 0);
69 [ # # ]: 0 : ASSERTIFCMP(op->state != FSCACHE_OP_ST_IN_PROGRESS,
70 : : op->state, ==, FSCACHE_OP_ST_CANCELLED);
71 : :
72 : : fscache_stat(&fscache_n_op_enqueue);
73 [ # # # ]: 0 : switch (op->flags & FSCACHE_OP_TYPE) {
74 : : case FSCACHE_OP_ASYNC:
75 : 0 : trace_fscache_op(cookie, op, fscache_op_enqueue_async);
76 : : _debug("queue async");
77 : 0 : atomic_inc(&op->usage);
78 [ # # ]: 0 : if (!queue_work(fscache_op_wq, &op->work))
79 : 0 : fscache_put_operation(op);
80 : : break;
81 : : case FSCACHE_OP_MYTHREAD:
82 : 0 : trace_fscache_op(cookie, op, fscache_op_enqueue_mythread);
83 : : _debug("queue for caller's attention");
84 : 0 : break;
85 : : default:
86 : 0 : pr_err("Unexpected op type %lx", op->flags);
87 : 0 : BUG();
88 : : break;
89 : : }
90 : 0 : }
91 : : EXPORT_SYMBOL(fscache_enqueue_operation);
92 : :
93 : : /*
94 : : * start an op running
95 : : */
96 : 0 : static void fscache_run_op(struct fscache_object *object,
97 : : struct fscache_operation *op)
98 : : {
99 [ # # ]: 0 : ASSERTCMP(op->state, ==, FSCACHE_OP_ST_PENDING);
100 : :
101 : 0 : op->state = FSCACHE_OP_ST_IN_PROGRESS;
102 : 0 : object->n_in_progress++;
103 [ # # ]: 0 : if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags))
104 : 0 : wake_up_bit(&op->flags, FSCACHE_OP_WAITING);
105 [ # # ]: 0 : if (op->processor)
106 : 0 : fscache_enqueue_operation(op);
107 : : else
108 : 0 : trace_fscache_op(object->cookie, op, fscache_op_run);
109 : : fscache_stat(&fscache_n_op_run);
110 : 0 : }
111 : :
112 : : /*
113 : : * report an unexpected submission
114 : : */
115 : 0 : static void fscache_report_unexpected_submission(struct fscache_object *object,
116 : : struct fscache_operation *op,
117 : : const struct fscache_state *ostate)
118 : : {
119 : : static bool once_only;
120 : : struct fscache_operation *p;
121 : : unsigned n;
122 : :
123 [ # # ]: 0 : if (once_only)
124 : 0 : return;
125 : 0 : once_only = true;
126 : :
127 : 0 : kdebug("unexpected submission OP%x [OBJ%x %s]",
128 : : op->debug_id, object->debug_id, object->state->name);
129 : 0 : kdebug("objstate=%s [%s]", object->state->name, ostate->name);
130 : 0 : kdebug("objflags=%lx", object->flags);
131 : 0 : kdebug("objevent=%lx [%lx]", object->events, object->event_mask);
132 : 0 : kdebug("ops=%u inp=%u exc=%u",
133 : : object->n_ops, object->n_in_progress, object->n_exclusive);
134 : :
135 [ # # ]: 0 : if (!list_empty(&object->pending_ops)) {
136 : : n = 0;
137 [ # # ]: 0 : list_for_each_entry(p, &object->pending_ops, pend_link) {
138 [ # # ]: 0 : ASSERTCMP(p->object, ==, object);
139 : 0 : kdebug("%p %p", op->processor, op->release);
140 : 0 : n++;
141 : : }
142 : :
143 : 0 : kdebug("n=%u", n);
144 : : }
145 : :
146 : 0 : dump_stack();
147 : : }
148 : :
149 : : /*
150 : : * submit an exclusive operation for an object
151 : : * - other ops are excluded from running simultaneously with this one
152 : : * - this gets any extra refs it needs on an op
153 : : */
154 : 0 : int fscache_submit_exclusive_op(struct fscache_object *object,
155 : : struct fscache_operation *op)
156 : : {
157 : : const struct fscache_state *ostate;
158 : : unsigned long flags;
159 : : int ret;
160 : :
161 : : _enter("{OBJ%x OP%x},", object->debug_id, op->debug_id);
162 : :
163 : 0 : trace_fscache_op(object->cookie, op, fscache_op_submit_ex);
164 : :
165 [ # # ]: 0 : ASSERTCMP(op->state, ==, FSCACHE_OP_ST_INITIALISED);
166 [ # # ]: 0 : ASSERTCMP(atomic_read(&op->usage), >, 0);
167 : :
168 : : spin_lock(&object->lock);
169 [ # # ]: 0 : ASSERTCMP(object->n_ops, >=, object->n_in_progress);
170 [ # # ]: 0 : ASSERTCMP(object->n_ops, >=, object->n_exclusive);
171 [ # # ]: 0 : ASSERT(list_empty(&op->pend_link));
172 : :
173 : 0 : ostate = object->state;
174 : 0 : smp_rmb();
175 : :
176 : 0 : op->state = FSCACHE_OP_ST_PENDING;
177 : : flags = READ_ONCE(object->flags);
178 [ # # ]: 0 : if (unlikely(!(flags & BIT(FSCACHE_OBJECT_IS_LIVE)))) {
179 : : fscache_stat(&fscache_n_op_rejected);
180 : 0 : op->cancel(op);
181 : 0 : op->state = FSCACHE_OP_ST_CANCELLED;
182 : : ret = -ENOBUFS;
183 [ # # ]: 0 : } else if (unlikely(fscache_cache_is_broken(object))) {
184 : 0 : op->cancel(op);
185 : 0 : op->state = FSCACHE_OP_ST_CANCELLED;
186 : : ret = -EIO;
187 [ # # ]: 0 : } else if (flags & BIT(FSCACHE_OBJECT_IS_AVAILABLE)) {
188 : 0 : op->object = object;
189 : 0 : object->n_ops++;
190 : 0 : object->n_exclusive++; /* reads and writes must wait */
191 : :
192 [ # # ]: 0 : if (object->n_in_progress > 0) {
193 : 0 : atomic_inc(&op->usage);
194 : 0 : list_add_tail(&op->pend_link, &object->pending_ops);
195 : : fscache_stat(&fscache_n_op_pend);
196 [ # # ]: 0 : } else if (!list_empty(&object->pending_ops)) {
197 : 0 : atomic_inc(&op->usage);
198 : : list_add_tail(&op->pend_link, &object->pending_ops);
199 : : fscache_stat(&fscache_n_op_pend);
200 : 0 : fscache_start_operations(object);
201 : : } else {
202 [ # # ]: 0 : ASSERTCMP(object->n_in_progress, ==, 0);
203 : 0 : fscache_run_op(object, op);
204 : : }
205 : :
206 : : /* need to issue a new write op after this */
207 : 0 : clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags);
208 : : ret = 0;
209 [ # # ]: 0 : } else if (flags & BIT(FSCACHE_OBJECT_IS_LOOKED_UP)) {
210 : 0 : op->object = object;
211 : 0 : object->n_ops++;
212 : 0 : object->n_exclusive++; /* reads and writes must wait */
213 : 0 : atomic_inc(&op->usage);
214 : 0 : list_add_tail(&op->pend_link, &object->pending_ops);
215 : : fscache_stat(&fscache_n_op_pend);
216 : : ret = 0;
217 [ # # ]: 0 : } else if (flags & BIT(FSCACHE_OBJECT_KILLED_BY_CACHE)) {
218 : 0 : op->cancel(op);
219 : 0 : op->state = FSCACHE_OP_ST_CANCELLED;
220 : : ret = -ENOBUFS;
221 : : } else {
222 : 0 : fscache_report_unexpected_submission(object, op, ostate);
223 : 0 : op->cancel(op);
224 : 0 : op->state = FSCACHE_OP_ST_CANCELLED;
225 : : ret = -ENOBUFS;
226 : : }
227 : :
228 : : spin_unlock(&object->lock);
229 : 0 : return ret;
230 : : }
231 : :
232 : : /*
233 : : * submit an operation for an object
234 : : * - objects may be submitted only in the following states:
235 : : * - during object creation (write ops may be submitted)
236 : : * - whilst the object is active
237 : : * - after an I/O error incurred in one of the two above states (op rejected)
238 : : * - this gets any extra refs it needs on an op
239 : : */
240 : 0 : int fscache_submit_op(struct fscache_object *object,
241 : : struct fscache_operation *op)
242 : : {
243 : : const struct fscache_state *ostate;
244 : : unsigned long flags;
245 : : int ret;
246 : :
247 : : _enter("{OBJ%x OP%x},{%u}",
248 : : object->debug_id, op->debug_id, atomic_read(&op->usage));
249 : :
250 : 0 : trace_fscache_op(object->cookie, op, fscache_op_submit);
251 : :
252 [ # # ]: 0 : ASSERTCMP(op->state, ==, FSCACHE_OP_ST_INITIALISED);
253 [ # # ]: 0 : ASSERTCMP(atomic_read(&op->usage), >, 0);
254 : :
255 : : spin_lock(&object->lock);
256 [ # # ]: 0 : ASSERTCMP(object->n_ops, >=, object->n_in_progress);
257 [ # # ]: 0 : ASSERTCMP(object->n_ops, >=, object->n_exclusive);
258 [ # # ]: 0 : ASSERT(list_empty(&op->pend_link));
259 : :
260 : 0 : ostate = object->state;
261 : 0 : smp_rmb();
262 : :
263 : 0 : op->state = FSCACHE_OP_ST_PENDING;
264 : : flags = READ_ONCE(object->flags);
265 [ # # ]: 0 : if (unlikely(!(flags & BIT(FSCACHE_OBJECT_IS_LIVE)))) {
266 : : fscache_stat(&fscache_n_op_rejected);
267 : 0 : op->cancel(op);
268 : 0 : op->state = FSCACHE_OP_ST_CANCELLED;
269 : : ret = -ENOBUFS;
270 [ # # ]: 0 : } else if (unlikely(fscache_cache_is_broken(object))) {
271 : 0 : op->cancel(op);
272 : 0 : op->state = FSCACHE_OP_ST_CANCELLED;
273 : : ret = -EIO;
274 [ # # ]: 0 : } else if (flags & BIT(FSCACHE_OBJECT_IS_AVAILABLE)) {
275 : 0 : op->object = object;
276 : 0 : object->n_ops++;
277 : :
278 [ # # ]: 0 : if (object->n_exclusive > 0) {
279 : 0 : atomic_inc(&op->usage);
280 : 0 : list_add_tail(&op->pend_link, &object->pending_ops);
281 : : fscache_stat(&fscache_n_op_pend);
282 [ # # ]: 0 : } else if (!list_empty(&object->pending_ops)) {
283 : 0 : atomic_inc(&op->usage);
284 : : list_add_tail(&op->pend_link, &object->pending_ops);
285 : : fscache_stat(&fscache_n_op_pend);
286 : 0 : fscache_start_operations(object);
287 : : } else {
288 [ # # ]: 0 : ASSERTCMP(object->n_exclusive, ==, 0);
289 : 0 : fscache_run_op(object, op);
290 : : }
291 : : ret = 0;
292 [ # # ]: 0 : } else if (flags & BIT(FSCACHE_OBJECT_IS_LOOKED_UP)) {
293 : 0 : op->object = object;
294 : 0 : object->n_ops++;
295 : 0 : atomic_inc(&op->usage);
296 : 0 : list_add_tail(&op->pend_link, &object->pending_ops);
297 : : fscache_stat(&fscache_n_op_pend);
298 : : ret = 0;
299 [ # # ]: 0 : } else if (flags & BIT(FSCACHE_OBJECT_KILLED_BY_CACHE)) {
300 : 0 : op->cancel(op);
301 : 0 : op->state = FSCACHE_OP_ST_CANCELLED;
302 : : ret = -ENOBUFS;
303 : : } else {
304 : 0 : fscache_report_unexpected_submission(object, op, ostate);
305 [ # # ]: 0 : ASSERT(!fscache_object_is_active(object));
306 : 0 : op->cancel(op);
307 : 0 : op->state = FSCACHE_OP_ST_CANCELLED;
308 : : ret = -ENOBUFS;
309 : : }
310 : :
311 : : spin_unlock(&object->lock);
312 : 0 : return ret;
313 : : }
314 : :
315 : : /*
316 : : * queue an object for withdrawal on error, aborting all following asynchronous
317 : : * operations
318 : : */
319 : 0 : void fscache_abort_object(struct fscache_object *object)
320 : : {
321 : : _enter("{OBJ%x}", object->debug_id);
322 : :
323 : 0 : fscache_raise_event(object, FSCACHE_OBJECT_EV_ERROR);
324 : 0 : }
325 : :
326 : : /*
327 : : * Jump start the operation processing on an object. The caller must hold
328 : : * object->lock.
329 : : */
330 : 0 : void fscache_start_operations(struct fscache_object *object)
331 : : {
332 : : struct fscache_operation *op;
333 : : bool stop = false;
334 : :
335 [ # # # # ]: 0 : while (!list_empty(&object->pending_ops) && !stop) {
336 : 0 : op = list_entry(object->pending_ops.next,
337 : : struct fscache_operation, pend_link);
338 : :
339 [ # # ]: 0 : if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags)) {
340 [ # # ]: 0 : if (object->n_in_progress > 0)
341 : : break;
342 : : stop = true;
343 : : }
344 : 0 : list_del_init(&op->pend_link);
345 : 0 : fscache_run_op(object, op);
346 : :
347 : : /* the pending queue was holding a ref on the object */
348 : 0 : fscache_put_operation(op);
349 : : }
350 : :
351 [ # # ]: 0 : ASSERTCMP(object->n_in_progress, <=, object->n_ops);
352 : :
353 : : _debug("woke %d ops on OBJ%x",
354 : : object->n_in_progress, object->debug_id);
355 : 0 : }
356 : :
357 : : /*
358 : : * cancel an operation that's pending on an object
359 : : */
360 : 0 : int fscache_cancel_op(struct fscache_operation *op,
361 : : bool cancel_in_progress_op)
362 : : {
363 : 0 : struct fscache_object *object = op->object;
364 : : bool put = false;
365 : : int ret;
366 : :
367 : : _enter("OBJ%x OP%x}", op->object->debug_id, op->debug_id);
368 : :
369 : 0 : trace_fscache_op(object->cookie, op, fscache_op_cancel);
370 : :
371 [ # # ]: 0 : ASSERTCMP(op->state, >=, FSCACHE_OP_ST_PENDING);
372 [ # # ]: 0 : ASSERTCMP(op->state, !=, FSCACHE_OP_ST_CANCELLED);
373 [ # # ]: 0 : ASSERTCMP(atomic_read(&op->usage), >, 0);
374 : :
375 : : spin_lock(&object->lock);
376 : :
377 : : ret = -EBUSY;
378 [ # # ]: 0 : if (op->state == FSCACHE_OP_ST_PENDING) {
379 [ # # ]: 0 : ASSERT(!list_empty(&op->pend_link));
380 : : list_del_init(&op->pend_link);
381 : : put = true;
382 : :
383 : : fscache_stat(&fscache_n_op_cancelled);
384 : 0 : op->cancel(op);
385 : 0 : op->state = FSCACHE_OP_ST_CANCELLED;
386 [ # # ]: 0 : if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags))
387 : 0 : object->n_exclusive--;
388 [ # # ]: 0 : if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags))
389 : 0 : wake_up_bit(&op->flags, FSCACHE_OP_WAITING);
390 : : ret = 0;
391 [ # # # # ]: 0 : } else if (op->state == FSCACHE_OP_ST_IN_PROGRESS && cancel_in_progress_op) {
392 [ # # ]: 0 : ASSERTCMP(object->n_in_progress, >, 0);
393 [ # # ]: 0 : if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags))
394 : 0 : object->n_exclusive--;
395 : 0 : object->n_in_progress--;
396 [ # # ]: 0 : if (object->n_in_progress == 0)
397 : 0 : fscache_start_operations(object);
398 : :
399 : : fscache_stat(&fscache_n_op_cancelled);
400 : 0 : op->cancel(op);
401 : 0 : op->state = FSCACHE_OP_ST_CANCELLED;
402 [ # # ]: 0 : if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags))
403 : 0 : object->n_exclusive--;
404 [ # # ]: 0 : if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags))
405 : 0 : wake_up_bit(&op->flags, FSCACHE_OP_WAITING);
406 : : ret = 0;
407 : : }
408 : :
409 [ # # ]: 0 : if (put)
410 : 0 : fscache_put_operation(op);
411 : : spin_unlock(&object->lock);
412 : : _leave(" = %d", ret);
413 : 0 : return ret;
414 : : }
415 : :
416 : : /*
417 : : * Cancel all pending operations on an object
418 : : */
419 : 0 : void fscache_cancel_all_ops(struct fscache_object *object)
420 : : {
421 : : struct fscache_operation *op;
422 : :
423 : : _enter("OBJ%x", object->debug_id);
424 : :
425 : : spin_lock(&object->lock);
426 : :
427 [ # # ]: 0 : while (!list_empty(&object->pending_ops)) {
428 : 0 : op = list_entry(object->pending_ops.next,
429 : : struct fscache_operation, pend_link);
430 : : fscache_stat(&fscache_n_op_cancelled);
431 : 0 : list_del_init(&op->pend_link);
432 : :
433 : 0 : trace_fscache_op(object->cookie, op, fscache_op_cancel_all);
434 : :
435 [ # # ]: 0 : ASSERTCMP(op->state, ==, FSCACHE_OP_ST_PENDING);
436 : 0 : op->cancel(op);
437 : 0 : op->state = FSCACHE_OP_ST_CANCELLED;
438 : :
439 [ # # ]: 0 : if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags))
440 : 0 : object->n_exclusive--;
441 [ # # ]: 0 : if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags))
442 : 0 : wake_up_bit(&op->flags, FSCACHE_OP_WAITING);
443 : 0 : fscache_put_operation(op);
444 : 0 : cond_resched_lock(&object->lock);
445 : : }
446 : :
447 : : spin_unlock(&object->lock);
448 : : _leave("");
449 : 0 : }
450 : :
451 : : /*
452 : : * Record the completion or cancellation of an in-progress operation.
453 : : */
454 : 0 : void fscache_op_complete(struct fscache_operation *op, bool cancelled)
455 : : {
456 : 0 : struct fscache_object *object = op->object;
457 : :
458 : : _enter("OBJ%x", object->debug_id);
459 : :
460 [ # # ]: 0 : ASSERTCMP(op->state, ==, FSCACHE_OP_ST_IN_PROGRESS);
461 [ # # ]: 0 : ASSERTCMP(object->n_in_progress, >, 0);
462 [ # # # # ]: 0 : ASSERTIFCMP(test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags),
463 : : object->n_exclusive, >, 0);
464 [ # # # # ]: 0 : ASSERTIFCMP(test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags),
465 : : object->n_in_progress, ==, 1);
466 : :
467 : : spin_lock(&object->lock);
468 : :
469 [ # # ]: 0 : if (!cancelled) {
470 : 0 : trace_fscache_op(object->cookie, op, fscache_op_completed);
471 : 0 : op->state = FSCACHE_OP_ST_COMPLETE;
472 : : } else {
473 : 0 : op->cancel(op);
474 : 0 : trace_fscache_op(object->cookie, op, fscache_op_cancelled);
475 : 0 : op->state = FSCACHE_OP_ST_CANCELLED;
476 : : }
477 : :
478 [ # # ]: 0 : if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags))
479 : 0 : object->n_exclusive--;
480 : 0 : object->n_in_progress--;
481 [ # # ]: 0 : if (object->n_in_progress == 0)
482 : 0 : fscache_start_operations(object);
483 : :
484 : : spin_unlock(&object->lock);
485 : : _leave("");
486 : 0 : }
487 : : EXPORT_SYMBOL(fscache_op_complete);
488 : :
489 : : /*
490 : : * release an operation
491 : : * - queues pending ops if this is the last in-progress op
492 : : */
493 : 0 : void fscache_put_operation(struct fscache_operation *op)
494 : : {
495 : : struct fscache_object *object;
496 : : struct fscache_cache *cache;
497 : :
498 : : _enter("{OBJ%x OP%x,%d}",
499 : : op->object ? op->object->debug_id : 0,
500 : : op->debug_id, atomic_read(&op->usage));
501 : :
502 [ # # ]: 0 : ASSERTCMP(atomic_read(&op->usage), >, 0);
503 : :
504 [ # # ]: 0 : if (!atomic_dec_and_test(&op->usage))
505 : : return;
506 : :
507 [ # # ]: 0 : trace_fscache_op(op->object ? op->object->cookie : NULL, op, fscache_op_put);
508 : :
509 : : _debug("PUT OP");
510 [ # # # # ]: 0 : ASSERTIFCMP(op->state != FSCACHE_OP_ST_INITIALISED &&
511 : : op->state != FSCACHE_OP_ST_COMPLETE,
512 : : op->state, ==, FSCACHE_OP_ST_CANCELLED);
513 : :
514 : : fscache_stat(&fscache_n_op_release);
515 : :
516 [ # # ]: 0 : if (op->release) {
517 : 0 : op->release(op);
518 : 0 : op->release = NULL;
519 : : }
520 : 0 : op->state = FSCACHE_OP_ST_DEAD;
521 : :
522 : 0 : object = op->object;
523 [ # # ]: 0 : if (likely(object)) {
524 [ # # ]: 0 : if (test_bit(FSCACHE_OP_DEC_READ_CNT, &op->flags))
525 : 0 : atomic_dec(&object->n_reads);
526 [ # # ]: 0 : if (test_bit(FSCACHE_OP_UNUSE_COOKIE, &op->flags))
527 : 0 : fscache_unuse_cookie(object);
528 : :
529 : : /* now... we may get called with the object spinlock held, so we
530 : : * complete the cleanup here only if we can immediately acquire the
531 : : * lock, and defer it otherwise */
532 [ # # ]: 0 : if (!spin_trylock(&object->lock)) {
533 : : _debug("defer put");
534 : : fscache_stat(&fscache_n_op_deferred_release);
535 : :
536 : 0 : cache = object->cache;
537 : : spin_lock(&cache->op_gc_list_lock);
538 : 0 : list_add_tail(&op->pend_link, &cache->op_gc_list);
539 : : spin_unlock(&cache->op_gc_list_lock);
540 : 0 : schedule_work(&cache->op_gc);
541 : : _leave(" [defer]");
542 : 0 : return;
543 : : }
544 : :
545 [ # # ]: 0 : ASSERTCMP(object->n_ops, >, 0);
546 : 0 : object->n_ops--;
547 [ # # ]: 0 : if (object->n_ops == 0)
548 : 0 : fscache_raise_event(object, FSCACHE_OBJECT_EV_CLEARED);
549 : :
550 : : spin_unlock(&object->lock);
551 : : }
552 : :
553 : 0 : kfree(op);
554 : : _leave(" [done]");
555 : : }
556 : : EXPORT_SYMBOL(fscache_put_operation);
557 : :
558 : : /*
559 : : * garbage collect operations that have had their release deferred
560 : : */
561 : 0 : void fscache_operation_gc(struct work_struct *work)
562 : : {
563 : : struct fscache_operation *op;
564 : : struct fscache_object *object;
565 : : struct fscache_cache *cache =
566 : : container_of(work, struct fscache_cache, op_gc);
567 : : int count = 0;
568 : :
569 : : _enter("");
570 : :
571 : : do {
572 : : spin_lock(&cache->op_gc_list_lock);
573 [ # # ]: 0 : if (list_empty(&cache->op_gc_list)) {
574 : : spin_unlock(&cache->op_gc_list_lock);
575 : : break;
576 : : }
577 : :
578 : 0 : op = list_entry(cache->op_gc_list.next,
579 : : struct fscache_operation, pend_link);
580 : : list_del(&op->pend_link);
581 : : spin_unlock(&cache->op_gc_list_lock);
582 : :
583 : 0 : object = op->object;
584 : 0 : trace_fscache_op(object->cookie, op, fscache_op_gc);
585 : :
586 : : spin_lock(&object->lock);
587 : :
588 : : _debug("GC DEFERRED REL OBJ%x OP%x",
589 : : object->debug_id, op->debug_id);
590 : : fscache_stat(&fscache_n_op_gc);
591 : :
592 [ # # ]: 0 : ASSERTCMP(atomic_read(&op->usage), ==, 0);
593 [ # # ]: 0 : ASSERTCMP(op->state, ==, FSCACHE_OP_ST_DEAD);
594 : :
595 [ # # ]: 0 : ASSERTCMP(object->n_ops, >, 0);
596 : 0 : object->n_ops--;
597 [ # # ]: 0 : if (object->n_ops == 0)
598 : 0 : fscache_raise_event(object, FSCACHE_OBJECT_EV_CLEARED);
599 : :
600 : : spin_unlock(&object->lock);
601 : 0 : kfree(op);
602 : :
603 [ # # ]: 0 : } while (count++ < 20);
604 : :
605 [ # # ]: 0 : if (!list_empty(&cache->op_gc_list))
606 : 0 : schedule_work(&cache->op_gc);
607 : :
608 : : _leave("");
609 : 0 : }
610 : :
611 : : /*
612 : : * execute an operation using fs_op_wq to provide processing context -
613 : : * the caller holds a ref to this object, so we don't need to hold one
614 : : */
615 : 0 : void fscache_op_work_func(struct work_struct *work)
616 : : {
617 : : struct fscache_operation *op =
618 : : container_of(work, struct fscache_operation, work);
619 : : unsigned long start;
620 : :
621 : : _enter("{OBJ%x OP%x,%d}",
622 : : op->object->debug_id, op->debug_id, atomic_read(&op->usage));
623 : :
624 : 0 : trace_fscache_op(op->object->cookie, op, fscache_op_work);
625 : :
626 [ # # ]: 0 : ASSERT(op->processor != NULL);
627 : 0 : start = jiffies;
628 : 0 : op->processor(op);
629 : 0 : fscache_hist(fscache_ops_histogram, start);
630 : 0 : fscache_put_operation(op);
631 : :
632 : : _leave("");
633 : 0 : }
|