blob: 80b549141ea6a5de2afb8552ac3ac23c8da54ae5 [file] [log] [blame]
David Howells36c95592009-04-03 16:42:38 +01001/* FS-Cache object state machine handler
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 * See Documentation/filesystems/caching/object.txt for a description of the
12 * object state machine and the in-kernel representations.
13 */
14
15#define FSCACHE_DEBUG_LEVEL COOKIE
16#include <linux/module.h>
David Howellsef778e72012-12-20 21:52:36 +000017#include <linux/slab.h>
David Howells36c95592009-04-03 16:42:38 +010018#include "internal.h"
19
David Howells440f0af2009-11-19 18:11:01 +000020const char *fscache_object_states[FSCACHE_OBJECT__NSTATES] = {
David Howells36c95592009-04-03 16:42:38 +010021 [FSCACHE_OBJECT_INIT] = "OBJECT_INIT",
22 [FSCACHE_OBJECT_LOOKING_UP] = "OBJECT_LOOKING_UP",
23 [FSCACHE_OBJECT_CREATING] = "OBJECT_CREATING",
24 [FSCACHE_OBJECT_AVAILABLE] = "OBJECT_AVAILABLE",
25 [FSCACHE_OBJECT_ACTIVE] = "OBJECT_ACTIVE",
David Howellsef778e72012-12-20 21:52:36 +000026 [FSCACHE_OBJECT_INVALIDATING] = "OBJECT_INVALIDATING",
David Howells36c95592009-04-03 16:42:38 +010027 [FSCACHE_OBJECT_UPDATING] = "OBJECT_UPDATING",
28 [FSCACHE_OBJECT_DYING] = "OBJECT_DYING",
29 [FSCACHE_OBJECT_LC_DYING] = "OBJECT_LC_DYING",
30 [FSCACHE_OBJECT_ABORT_INIT] = "OBJECT_ABORT_INIT",
31 [FSCACHE_OBJECT_RELEASING] = "OBJECT_RELEASING",
32 [FSCACHE_OBJECT_RECYCLING] = "OBJECT_RECYCLING",
33 [FSCACHE_OBJECT_WITHDRAWING] = "OBJECT_WITHDRAWING",
34 [FSCACHE_OBJECT_DEAD] = "OBJECT_DEAD",
35};
36EXPORT_SYMBOL(fscache_object_states);
37
David Howells4fbf4292009-11-19 18:11:04 +000038const char fscache_object_states_short[FSCACHE_OBJECT__NSTATES][5] = {
David Howells440f0af2009-11-19 18:11:01 +000039 [FSCACHE_OBJECT_INIT] = "INIT",
40 [FSCACHE_OBJECT_LOOKING_UP] = "LOOK",
41 [FSCACHE_OBJECT_CREATING] = "CRTN",
42 [FSCACHE_OBJECT_AVAILABLE] = "AVBL",
43 [FSCACHE_OBJECT_ACTIVE] = "ACTV",
David Howellsef778e72012-12-20 21:52:36 +000044 [FSCACHE_OBJECT_INVALIDATING] = "INVL",
David Howells440f0af2009-11-19 18:11:01 +000045 [FSCACHE_OBJECT_UPDATING] = "UPDT",
46 [FSCACHE_OBJECT_DYING] = "DYNG",
47 [FSCACHE_OBJECT_LC_DYING] = "LCDY",
48 [FSCACHE_OBJECT_ABORT_INIT] = "ABTI",
49 [FSCACHE_OBJECT_RELEASING] = "RELS",
50 [FSCACHE_OBJECT_RECYCLING] = "RCYC",
51 [FSCACHE_OBJECT_WITHDRAWING] = "WTHD",
52 [FSCACHE_OBJECT_DEAD] = "DEAD",
53};
54
Tejun Heo8b8edef2010-07-20 22:09:01 +020055static int fscache_get_object(struct fscache_object *);
56static void fscache_put_object(struct fscache_object *);
David Howells36c95592009-04-03 16:42:38 +010057static void fscache_initialise_object(struct fscache_object *);
58static void fscache_lookup_object(struct fscache_object *);
59static void fscache_object_available(struct fscache_object *);
David Howellsef778e72012-12-20 21:52:36 +000060static void fscache_invalidate_object(struct fscache_object *);
David Howells36c95592009-04-03 16:42:38 +010061static void fscache_release_object(struct fscache_object *);
62static void fscache_withdraw_object(struct fscache_object *);
63static void fscache_enqueue_dependents(struct fscache_object *);
64static void fscache_dequeue_object(struct fscache_object *);
65
David Howells36c95592009-04-03 16:42:38 +010066/*
67 * we need to notify the parent when an op completes that we had outstanding
68 * upon it
69 */
70static inline void fscache_done_parent_op(struct fscache_object *object)
71{
72 struct fscache_object *parent = object->parent;
73
74 _enter("OBJ%x {OBJ%x,%x}",
75 object->debug_id, parent->debug_id, parent->n_ops);
76
77 spin_lock_nested(&parent->lock, 1);
78 parent->n_ops--;
79 parent->n_obj_ops--;
80 if (parent->n_ops == 0)
81 fscache_raise_event(parent, FSCACHE_OBJECT_EV_CLEARED);
82 spin_unlock(&parent->lock);
83}
84
85/*
David Howellsef778e72012-12-20 21:52:36 +000086 * Notify netfs of invalidation completion.
87 */
88static inline void fscache_invalidation_complete(struct fscache_cookie *cookie)
89{
90 if (test_and_clear_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags))
91 wake_up_bit(&cookie->flags, FSCACHE_COOKIE_INVALIDATING);
92}
93
94/*
David Howells36c95592009-04-03 16:42:38 +010095 * process events that have been sent to an object's state machine
96 * - initiates parent lookup
97 * - does object lookup
98 * - does object creation
99 * - does object recycling and retirement
100 * - does object withdrawal
101 */
102static void fscache_object_state_machine(struct fscache_object *object)
103{
104 enum fscache_object_state new_state;
David Howellsd461d262009-11-19 18:11:41 +0000105 struct fscache_cookie *cookie;
David Howells36c95592009-04-03 16:42:38 +0100106
107 ASSERT(object != NULL);
108
109 _enter("{OBJ%x,%s,%lx}",
110 object->debug_id, fscache_object_states[object->state],
111 object->events);
112
113 switch (object->state) {
114 /* wait for the parent object to become ready */
115 case FSCACHE_OBJECT_INIT:
116 object->event_mask =
117 ULONG_MAX & ~(1 << FSCACHE_OBJECT_EV_CLEARED);
118 fscache_initialise_object(object);
119 goto done;
120
121 /* look up the object metadata on disk */
122 case FSCACHE_OBJECT_LOOKING_UP:
123 fscache_lookup_object(object);
124 goto lookup_transit;
125
126 /* create the object metadata on disk */
127 case FSCACHE_OBJECT_CREATING:
128 fscache_lookup_object(object);
129 goto lookup_transit;
130
131 /* handle an object becoming available; start pending
132 * operations and queue dependent operations for processing */
133 case FSCACHE_OBJECT_AVAILABLE:
134 fscache_object_available(object);
135 goto active_transit;
136
137 /* normal running state */
138 case FSCACHE_OBJECT_ACTIVE:
139 goto active_transit;
140
David Howellsef778e72012-12-20 21:52:36 +0000141 /* Invalidate an object on disk */
142 case FSCACHE_OBJECT_INVALIDATING:
143 clear_bit(FSCACHE_OBJECT_EV_INVALIDATE, &object->events);
144 fscache_stat(&fscache_n_invalidates_run);
145 fscache_stat(&fscache_n_cop_invalidate_object);
146 fscache_invalidate_object(object);
147 fscache_stat_d(&fscache_n_cop_invalidate_object);
148 fscache_raise_event(object, FSCACHE_OBJECT_EV_UPDATE);
149 goto active_transit;
150
David Howells36c95592009-04-03 16:42:38 +0100151 /* update the object metadata on disk */
152 case FSCACHE_OBJECT_UPDATING:
153 clear_bit(FSCACHE_OBJECT_EV_UPDATE, &object->events);
154 fscache_stat(&fscache_n_updates_run);
David Howells52bd75f2009-11-19 18:11:08 +0000155 fscache_stat(&fscache_n_cop_update_object);
David Howells36c95592009-04-03 16:42:38 +0100156 object->cache->ops->update_object(object);
David Howells52bd75f2009-11-19 18:11:08 +0000157 fscache_stat_d(&fscache_n_cop_update_object);
David Howells36c95592009-04-03 16:42:38 +0100158 goto active_transit;
159
160 /* handle an object dying during lookup or creation */
161 case FSCACHE_OBJECT_LC_DYING:
162 object->event_mask &= ~(1 << FSCACHE_OBJECT_EV_UPDATE);
David Howells52bd75f2009-11-19 18:11:08 +0000163 fscache_stat(&fscache_n_cop_lookup_complete);
David Howells36c95592009-04-03 16:42:38 +0100164 object->cache->ops->lookup_complete(object);
David Howells52bd75f2009-11-19 18:11:08 +0000165 fscache_stat_d(&fscache_n_cop_lookup_complete);
David Howells36c95592009-04-03 16:42:38 +0100166
167 spin_lock(&object->lock);
168 object->state = FSCACHE_OBJECT_DYING;
David Howellsd461d262009-11-19 18:11:41 +0000169 cookie = object->cookie;
170 if (cookie) {
171 if (test_and_clear_bit(FSCACHE_COOKIE_LOOKING_UP,
172 &cookie->flags))
173 wake_up_bit(&cookie->flags,
174 FSCACHE_COOKIE_LOOKING_UP);
175 if (test_and_clear_bit(FSCACHE_COOKIE_CREATING,
176 &cookie->flags))
177 wake_up_bit(&cookie->flags,
178 FSCACHE_COOKIE_CREATING);
179 }
David Howells36c95592009-04-03 16:42:38 +0100180 spin_unlock(&object->lock);
181
182 fscache_done_parent_op(object);
183
184 /* wait for completion of all active operations on this object
185 * and the death of all child objects of this object */
186 case FSCACHE_OBJECT_DYING:
187 dying:
188 clear_bit(FSCACHE_OBJECT_EV_CLEARED, &object->events);
189 spin_lock(&object->lock);
190 _debug("dying OBJ%x {%d,%d}",
191 object->debug_id, object->n_ops, object->n_children);
192 if (object->n_ops == 0 && object->n_children == 0) {
193 object->event_mask &=
194 ~(1 << FSCACHE_OBJECT_EV_CLEARED);
195 object->event_mask |=
196 (1 << FSCACHE_OBJECT_EV_WITHDRAW) |
197 (1 << FSCACHE_OBJECT_EV_RETIRE) |
198 (1 << FSCACHE_OBJECT_EV_RELEASE) |
199 (1 << FSCACHE_OBJECT_EV_ERROR);
200 } else {
201 object->event_mask &=
202 ~((1 << FSCACHE_OBJECT_EV_WITHDRAW) |
203 (1 << FSCACHE_OBJECT_EV_RETIRE) |
204 (1 << FSCACHE_OBJECT_EV_RELEASE) |
205 (1 << FSCACHE_OBJECT_EV_ERROR));
206 object->event_mask |=
207 1 << FSCACHE_OBJECT_EV_CLEARED;
208 }
209 spin_unlock(&object->lock);
210 fscache_enqueue_dependents(object);
David Howells60d543c2009-11-19 18:11:45 +0000211 fscache_start_operations(object);
David Howells36c95592009-04-03 16:42:38 +0100212 goto terminal_transit;
213
214 /* handle an abort during initialisation */
215 case FSCACHE_OBJECT_ABORT_INIT:
216 _debug("handle abort init %lx", object->events);
217 object->event_mask &= ~(1 << FSCACHE_OBJECT_EV_UPDATE);
218
219 spin_lock(&object->lock);
220 fscache_dequeue_object(object);
221
222 object->state = FSCACHE_OBJECT_DYING;
223 if (test_and_clear_bit(FSCACHE_COOKIE_CREATING,
224 &object->cookie->flags))
225 wake_up_bit(&object->cookie->flags,
226 FSCACHE_COOKIE_CREATING);
227 spin_unlock(&object->lock);
228 goto dying;
229
230 /* handle the netfs releasing an object and possibly marking it
231 * obsolete too */
232 case FSCACHE_OBJECT_RELEASING:
233 case FSCACHE_OBJECT_RECYCLING:
234 object->event_mask &=
235 ~((1 << FSCACHE_OBJECT_EV_WITHDRAW) |
236 (1 << FSCACHE_OBJECT_EV_RETIRE) |
237 (1 << FSCACHE_OBJECT_EV_RELEASE) |
238 (1 << FSCACHE_OBJECT_EV_ERROR));
239 fscache_release_object(object);
240 spin_lock(&object->lock);
241 object->state = FSCACHE_OBJECT_DEAD;
242 spin_unlock(&object->lock);
243 fscache_stat(&fscache_n_object_dead);
244 goto terminal_transit;
245
246 /* handle the parent cache of this object being withdrawn from
247 * active service */
248 case FSCACHE_OBJECT_WITHDRAWING:
249 object->event_mask &=
250 ~((1 << FSCACHE_OBJECT_EV_WITHDRAW) |
251 (1 << FSCACHE_OBJECT_EV_RETIRE) |
252 (1 << FSCACHE_OBJECT_EV_RELEASE) |
253 (1 << FSCACHE_OBJECT_EV_ERROR));
254 fscache_withdraw_object(object);
255 spin_lock(&object->lock);
256 object->state = FSCACHE_OBJECT_DEAD;
257 spin_unlock(&object->lock);
258 fscache_stat(&fscache_n_object_dead);
259 goto terminal_transit;
260
261 /* complain about the object being woken up once it is
262 * deceased */
263 case FSCACHE_OBJECT_DEAD:
264 printk(KERN_ERR "FS-Cache:"
265 " Unexpected event in dead state %lx\n",
266 object->events & object->event_mask);
267 BUG();
268
269 default:
270 printk(KERN_ERR "FS-Cache: Unknown object state %u\n",
271 object->state);
272 BUG();
273 }
274
275 /* determine the transition from a lookup state */
276lookup_transit:
277 switch (fls(object->events & object->event_mask) - 1) {
278 case FSCACHE_OBJECT_EV_WITHDRAW:
279 case FSCACHE_OBJECT_EV_RETIRE:
280 case FSCACHE_OBJECT_EV_RELEASE:
281 case FSCACHE_OBJECT_EV_ERROR:
282 new_state = FSCACHE_OBJECT_LC_DYING;
283 goto change_state;
284 case FSCACHE_OBJECT_EV_REQUEUE:
285 goto done;
286 case -1:
287 goto done; /* sleep until event */
288 default:
289 goto unsupported_event;
290 }
291
292 /* determine the transition from an active state */
293active_transit:
294 switch (fls(object->events & object->event_mask) - 1) {
295 case FSCACHE_OBJECT_EV_WITHDRAW:
296 case FSCACHE_OBJECT_EV_RETIRE:
297 case FSCACHE_OBJECT_EV_RELEASE:
298 case FSCACHE_OBJECT_EV_ERROR:
299 new_state = FSCACHE_OBJECT_DYING;
300 goto change_state;
David Howellsef778e72012-12-20 21:52:36 +0000301 case FSCACHE_OBJECT_EV_INVALIDATE:
302 new_state = FSCACHE_OBJECT_INVALIDATING;
303 goto change_state;
David Howells36c95592009-04-03 16:42:38 +0100304 case FSCACHE_OBJECT_EV_UPDATE:
305 new_state = FSCACHE_OBJECT_UPDATING;
306 goto change_state;
307 case -1:
308 new_state = FSCACHE_OBJECT_ACTIVE;
309 goto change_state; /* sleep until event */
310 default:
311 goto unsupported_event;
312 }
313
314 /* determine the transition from a terminal state */
315terminal_transit:
316 switch (fls(object->events & object->event_mask) - 1) {
317 case FSCACHE_OBJECT_EV_WITHDRAW:
318 new_state = FSCACHE_OBJECT_WITHDRAWING;
319 goto change_state;
320 case FSCACHE_OBJECT_EV_RETIRE:
321 new_state = FSCACHE_OBJECT_RECYCLING;
322 goto change_state;
323 case FSCACHE_OBJECT_EV_RELEASE:
324 new_state = FSCACHE_OBJECT_RELEASING;
325 goto change_state;
326 case FSCACHE_OBJECT_EV_ERROR:
327 new_state = FSCACHE_OBJECT_WITHDRAWING;
328 goto change_state;
329 case FSCACHE_OBJECT_EV_CLEARED:
330 new_state = FSCACHE_OBJECT_DYING;
331 goto change_state;
332 case -1:
333 goto done; /* sleep until event */
334 default:
335 goto unsupported_event;
336 }
337
338change_state:
339 spin_lock(&object->lock);
340 object->state = new_state;
341 spin_unlock(&object->lock);
342
343done:
344 _leave(" [->%s]", fscache_object_states[object->state]);
345 return;
346
347unsupported_event:
348 printk(KERN_ERR "FS-Cache:"
349 " Unsupported event %lx [mask %lx] in state %s\n",
350 object->events, object->event_mask,
351 fscache_object_states[object->state]);
352 BUG();
353}
354
355/*
356 * execute an object
357 */
Tejun Heo8b8edef2010-07-20 22:09:01 +0200358void fscache_object_work_func(struct work_struct *work)
David Howells36c95592009-04-03 16:42:38 +0100359{
360 struct fscache_object *object =
361 container_of(work, struct fscache_object, work);
362 unsigned long start;
363
364 _enter("{OBJ%x}", object->debug_id);
365
David Howells36c95592009-04-03 16:42:38 +0100366 start = jiffies;
367 fscache_object_state_machine(object);
368 fscache_hist(fscache_objs_histogram, start);
369 if (object->events & object->event_mask)
370 fscache_enqueue_object(object);
David Howells868411b2009-11-19 18:11:48 +0000371 clear_bit(FSCACHE_OBJECT_EV_REQUEUE, &object->events);
Tejun Heo8b8edef2010-07-20 22:09:01 +0200372 fscache_put_object(object);
David Howells36c95592009-04-03 16:42:38 +0100373}
Tejun Heo8b8edef2010-07-20 22:09:01 +0200374EXPORT_SYMBOL(fscache_object_work_func);
David Howells440f0af2009-11-19 18:11:01 +0000375
376/*
David Howells36c95592009-04-03 16:42:38 +0100377 * initialise an object
378 * - check the specified object's parent to see if we can make use of it
379 * immediately to do a creation
380 * - we may need to start the process of creating a parent and we need to wait
381 * for the parent's lookup and creation to complete if it's not there yet
382 * - an object's cookie is pinned until we clear FSCACHE_COOKIE_CREATING on the
383 * leaf-most cookies of the object and all its children
384 */
385static void fscache_initialise_object(struct fscache_object *object)
386{
387 struct fscache_object *parent;
388
389 _enter("");
390 ASSERT(object->cookie != NULL);
391 ASSERT(object->cookie->parent != NULL);
David Howells36c95592009-04-03 16:42:38 +0100392
393 if (object->events & ((1 << FSCACHE_OBJECT_EV_ERROR) |
394 (1 << FSCACHE_OBJECT_EV_RELEASE) |
395 (1 << FSCACHE_OBJECT_EV_RETIRE) |
396 (1 << FSCACHE_OBJECT_EV_WITHDRAW))) {
397 _debug("abort init %lx", object->events);
398 spin_lock(&object->lock);
399 object->state = FSCACHE_OBJECT_ABORT_INIT;
400 spin_unlock(&object->lock);
401 return;
402 }
403
404 spin_lock(&object->cookie->lock);
405 spin_lock_nested(&object->cookie->parent->lock, 1);
406
407 parent = object->parent;
408 if (!parent) {
409 _debug("no parent");
410 set_bit(FSCACHE_OBJECT_EV_WITHDRAW, &object->events);
411 } else {
412 spin_lock(&object->lock);
413 spin_lock_nested(&parent->lock, 1);
414 _debug("parent %s", fscache_object_states[parent->state]);
415
416 if (parent->state >= FSCACHE_OBJECT_DYING) {
417 _debug("bad parent");
418 set_bit(FSCACHE_OBJECT_EV_WITHDRAW, &object->events);
419 } else if (parent->state < FSCACHE_OBJECT_AVAILABLE) {
420 _debug("wait");
421
422 /* we may get woken up in this state by child objects
423 * binding on to us, so we need to make sure we don't
424 * add ourself to the list multiple times */
425 if (list_empty(&object->dep_link)) {
David Howells52bd75f2009-11-19 18:11:08 +0000426 fscache_stat(&fscache_n_cop_grab_object);
David Howells36c95592009-04-03 16:42:38 +0100427 object->cache->ops->grab_object(object);
David Howells52bd75f2009-11-19 18:11:08 +0000428 fscache_stat_d(&fscache_n_cop_grab_object);
David Howells36c95592009-04-03 16:42:38 +0100429 list_add(&object->dep_link,
430 &parent->dependents);
431
432 /* fscache_acquire_non_index_cookie() uses this
433 * to wake the chain up */
434 if (parent->state == FSCACHE_OBJECT_INIT)
435 fscache_enqueue_object(parent);
436 }
437 } else {
438 _debug("go");
439 parent->n_ops++;
440 parent->n_obj_ops++;
441 object->lookup_jif = jiffies;
442 object->state = FSCACHE_OBJECT_LOOKING_UP;
443 set_bit(FSCACHE_OBJECT_EV_REQUEUE, &object->events);
444 }
445
446 spin_unlock(&parent->lock);
447 spin_unlock(&object->lock);
448 }
449
450 spin_unlock(&object->cookie->parent->lock);
451 spin_unlock(&object->cookie->lock);
452 _leave("");
453}
454
455/*
456 * look an object up in the cache from which it was allocated
457 * - we hold an "access lock" on the parent object, so the parent object cannot
458 * be withdrawn by either party till we've finished
459 * - an object's cookie is pinned until we clear FSCACHE_COOKIE_CREATING on the
460 * leaf-most cookies of the object and all its children
461 */
462static void fscache_lookup_object(struct fscache_object *object)
463{
464 struct fscache_cookie *cookie = object->cookie;
465 struct fscache_object *parent;
David Howellsfee096d2009-11-19 18:12:05 +0000466 int ret;
David Howells36c95592009-04-03 16:42:38 +0100467
468 _enter("");
469
470 parent = object->parent;
471 ASSERT(parent != NULL);
472 ASSERTCMP(parent->n_ops, >, 0);
473 ASSERTCMP(parent->n_obj_ops, >, 0);
474
475 /* make sure the parent is still available */
476 ASSERTCMP(parent->state, >=, FSCACHE_OBJECT_AVAILABLE);
477
478 if (parent->state >= FSCACHE_OBJECT_DYING ||
479 test_bit(FSCACHE_IOERROR, &object->cache->flags)) {
480 _debug("unavailable");
481 set_bit(FSCACHE_OBJECT_EV_WITHDRAW, &object->events);
482 _leave("");
483 return;
484 }
485
486 _debug("LOOKUP \"%s/%s\" in \"%s\"",
487 parent->cookie->def->name, cookie->def->name,
488 object->cache->tag->name);
489
490 fscache_stat(&fscache_n_object_lookups);
David Howells52bd75f2009-11-19 18:11:08 +0000491 fscache_stat(&fscache_n_cop_lookup_object);
David Howellsfee096d2009-11-19 18:12:05 +0000492 ret = object->cache->ops->lookup_object(object);
David Howells52bd75f2009-11-19 18:11:08 +0000493 fscache_stat_d(&fscache_n_cop_lookup_object);
David Howells36c95592009-04-03 16:42:38 +0100494
495 if (test_bit(FSCACHE_OBJECT_EV_ERROR, &object->events))
496 set_bit(FSCACHE_COOKIE_UNAVAILABLE, &cookie->flags);
497
David Howellsfee096d2009-11-19 18:12:05 +0000498 if (ret == -ETIMEDOUT) {
499 /* probably stuck behind another object, so move this one to
500 * the back of the queue */
501 fscache_stat(&fscache_n_object_lookups_timed_out);
502 set_bit(FSCACHE_OBJECT_EV_REQUEUE, &object->events);
503 }
504
David Howells36c95592009-04-03 16:42:38 +0100505 _leave("");
506}
507
508/**
509 * fscache_object_lookup_negative - Note negative cookie lookup
510 * @object: Object pointing to cookie to mark
511 *
512 * Note negative lookup, permitting those waiting to read data from an already
513 * existing backing object to continue as there's no data for them to read.
514 */
515void fscache_object_lookup_negative(struct fscache_object *object)
516{
517 struct fscache_cookie *cookie = object->cookie;
518
519 _enter("{OBJ%x,%s}",
520 object->debug_id, fscache_object_states[object->state]);
521
522 spin_lock(&object->lock);
523 if (object->state == FSCACHE_OBJECT_LOOKING_UP) {
524 fscache_stat(&fscache_n_object_lookups_negative);
525
526 /* transit here to allow write requests to begin stacking up
527 * and read requests to begin returning ENODATA */
528 object->state = FSCACHE_OBJECT_CREATING;
529 spin_unlock(&object->lock);
530
531 set_bit(FSCACHE_COOKIE_PENDING_FILL, &cookie->flags);
532 set_bit(FSCACHE_COOKIE_NO_DATA_YET, &cookie->flags);
533
534 _debug("wake up lookup %p", &cookie->flags);
535 smp_mb__before_clear_bit();
536 clear_bit(FSCACHE_COOKIE_LOOKING_UP, &cookie->flags);
537 smp_mb__after_clear_bit();
538 wake_up_bit(&cookie->flags, FSCACHE_COOKIE_LOOKING_UP);
539 set_bit(FSCACHE_OBJECT_EV_REQUEUE, &object->events);
540 } else {
541 ASSERTCMP(object->state, ==, FSCACHE_OBJECT_CREATING);
542 spin_unlock(&object->lock);
543 }
544
545 _leave("");
546}
547EXPORT_SYMBOL(fscache_object_lookup_negative);
548
549/**
550 * fscache_obtained_object - Note successful object lookup or creation
551 * @object: Object pointing to cookie to mark
552 *
553 * Note successful lookup and/or creation, permitting those waiting to write
554 * data to a backing object to continue.
555 *
556 * Note that after calling this, an object's cookie may be relinquished by the
557 * netfs, and so must be accessed with object lock held.
558 */
559void fscache_obtained_object(struct fscache_object *object)
560{
561 struct fscache_cookie *cookie = object->cookie;
562
563 _enter("{OBJ%x,%s}",
564 object->debug_id, fscache_object_states[object->state]);
565
566 /* if we were still looking up, then we must have a positive lookup
567 * result, in which case there may be data available */
568 spin_lock(&object->lock);
569 if (object->state == FSCACHE_OBJECT_LOOKING_UP) {
570 fscache_stat(&fscache_n_object_lookups_positive);
571
572 clear_bit(FSCACHE_COOKIE_NO_DATA_YET, &cookie->flags);
573
574 object->state = FSCACHE_OBJECT_AVAILABLE;
575 spin_unlock(&object->lock);
576
577 smp_mb__before_clear_bit();
578 clear_bit(FSCACHE_COOKIE_LOOKING_UP, &cookie->flags);
579 smp_mb__after_clear_bit();
580 wake_up_bit(&cookie->flags, FSCACHE_COOKIE_LOOKING_UP);
581 set_bit(FSCACHE_OBJECT_EV_REQUEUE, &object->events);
582 } else {
583 ASSERTCMP(object->state, ==, FSCACHE_OBJECT_CREATING);
584 fscache_stat(&fscache_n_object_created);
585
586 object->state = FSCACHE_OBJECT_AVAILABLE;
587 spin_unlock(&object->lock);
588 set_bit(FSCACHE_OBJECT_EV_REQUEUE, &object->events);
589 smp_wmb();
590 }
591
592 if (test_and_clear_bit(FSCACHE_COOKIE_CREATING, &cookie->flags))
593 wake_up_bit(&cookie->flags, FSCACHE_COOKIE_CREATING);
594
595 _leave("");
596}
597EXPORT_SYMBOL(fscache_obtained_object);
598
599/*
600 * handle an object that has just become available
601 */
602static void fscache_object_available(struct fscache_object *object)
603{
604 _enter("{OBJ%x}", object->debug_id);
605
606 spin_lock(&object->lock);
607
David Howells6897e3d2009-11-19 18:11:22 +0000608 if (object->cookie &&
609 test_and_clear_bit(FSCACHE_COOKIE_CREATING, &object->cookie->flags))
David Howells36c95592009-04-03 16:42:38 +0100610 wake_up_bit(&object->cookie->flags, FSCACHE_COOKIE_CREATING);
611
612 fscache_done_parent_op(object);
613 if (object->n_in_progress == 0) {
614 if (object->n_ops > 0) {
615 ASSERTCMP(object->n_ops, >=, object->n_obj_ops);
David Howells36c95592009-04-03 16:42:38 +0100616 fscache_start_operations(object);
617 } else {
618 ASSERT(list_empty(&object->pending_ops));
619 }
620 }
621 spin_unlock(&object->lock);
622
David Howells52bd75f2009-11-19 18:11:08 +0000623 fscache_stat(&fscache_n_cop_lookup_complete);
David Howells36c95592009-04-03 16:42:38 +0100624 object->cache->ops->lookup_complete(object);
David Howells52bd75f2009-11-19 18:11:08 +0000625 fscache_stat_d(&fscache_n_cop_lookup_complete);
David Howells36c95592009-04-03 16:42:38 +0100626 fscache_enqueue_dependents(object);
627
628 fscache_hist(fscache_obj_instantiate_histogram, object->lookup_jif);
629 fscache_stat(&fscache_n_object_avail);
630
631 _leave("");
632}
633
634/*
635 * drop an object's attachments
636 */
637static void fscache_drop_object(struct fscache_object *object)
638{
639 struct fscache_object *parent = object->parent;
640 struct fscache_cache *cache = object->cache;
641
642 _enter("{OBJ%x,%d}", object->debug_id, object->n_children);
643
David Howells6897e3d2009-11-19 18:11:22 +0000644 ASSERTCMP(object->cookie, ==, NULL);
645 ASSERT(hlist_unhashed(&object->cookie_link));
646
David Howells36c95592009-04-03 16:42:38 +0100647 spin_lock(&cache->object_list_lock);
648 list_del_init(&object->cache_link);
649 spin_unlock(&cache->object_list_lock);
650
David Howells52bd75f2009-11-19 18:11:08 +0000651 fscache_stat(&fscache_n_cop_drop_object);
David Howells36c95592009-04-03 16:42:38 +0100652 cache->ops->drop_object(object);
David Howells52bd75f2009-11-19 18:11:08 +0000653 fscache_stat_d(&fscache_n_cop_drop_object);
David Howells36c95592009-04-03 16:42:38 +0100654
655 if (parent) {
656 _debug("release parent OBJ%x {%d}",
657 parent->debug_id, parent->n_children);
658
659 spin_lock(&parent->lock);
660 parent->n_children--;
661 if (parent->n_children == 0)
662 fscache_raise_event(parent, FSCACHE_OBJECT_EV_CLEARED);
663 spin_unlock(&parent->lock);
664 object->parent = NULL;
665 }
666
Tejun Heo8b8edef2010-07-20 22:09:01 +0200667 /* this just shifts the object release to the work processor */
668 fscache_put_object(object);
David Howells36c95592009-04-03 16:42:38 +0100669
670 _leave("");
671}
672
673/*
674 * release or recycle an object that the netfs has discarded
675 */
676static void fscache_release_object(struct fscache_object *object)
677{
678 _enter("");
679
680 fscache_drop_object(object);
681}
682
683/*
684 * withdraw an object from active service
685 */
686static void fscache_withdraw_object(struct fscache_object *object)
687{
688 struct fscache_cookie *cookie;
689 bool detached;
690
691 _enter("");
692
693 spin_lock(&object->lock);
694 cookie = object->cookie;
695 if (cookie) {
696 /* need to get the cookie lock before the object lock, starting
697 * from the object pointer */
698 atomic_inc(&cookie->usage);
699 spin_unlock(&object->lock);
700
701 detached = false;
702 spin_lock(&cookie->lock);
703 spin_lock(&object->lock);
704
705 if (object->cookie == cookie) {
706 hlist_del_init(&object->cookie_link);
707 object->cookie = NULL;
David Howellsef778e72012-12-20 21:52:36 +0000708 fscache_invalidation_complete(cookie);
David Howells36c95592009-04-03 16:42:38 +0100709 detached = true;
710 }
711 spin_unlock(&cookie->lock);
712 fscache_cookie_put(cookie);
713 if (detached)
714 fscache_cookie_put(cookie);
715 }
716
717 spin_unlock(&object->lock);
718
719 fscache_drop_object(object);
720}
721
722/*
723 * withdraw an object from active service at the behest of the cache
724 * - need break the links to a cached object cookie
725 * - called under two situations:
726 * (1) recycler decides to reclaim an in-use object
727 * (2) a cache is unmounted
728 * - have to take care as the cookie can be being relinquished by the netfs
729 * simultaneously
730 * - the object is pinned by the caller holding a refcount on it
731 */
732void fscache_withdrawing_object(struct fscache_cache *cache,
733 struct fscache_object *object)
734{
735 bool enqueue = false;
736
737 _enter(",OBJ%x", object->debug_id);
738
739 spin_lock(&object->lock);
740 if (object->state < FSCACHE_OBJECT_WITHDRAWING) {
741 object->state = FSCACHE_OBJECT_WITHDRAWING;
742 enqueue = true;
743 }
744 spin_unlock(&object->lock);
745
746 if (enqueue)
747 fscache_enqueue_object(object);
748
749 _leave("");
750}
751
752/*
Tejun Heo8b8edef2010-07-20 22:09:01 +0200753 * get a ref on an object
David Howells36c95592009-04-03 16:42:38 +0100754 */
Tejun Heo8b8edef2010-07-20 22:09:01 +0200755static int fscache_get_object(struct fscache_object *object)
David Howells36c95592009-04-03 16:42:38 +0100756{
David Howells52bd75f2009-11-19 18:11:08 +0000757 int ret;
David Howells36c95592009-04-03 16:42:38 +0100758
David Howells52bd75f2009-11-19 18:11:08 +0000759 fscache_stat(&fscache_n_cop_grab_object);
760 ret = object->cache->ops->grab_object(object) ? 0 : -EAGAIN;
761 fscache_stat_d(&fscache_n_cop_grab_object);
762 return ret;
David Howells36c95592009-04-03 16:42:38 +0100763}
764
765/*
Tejun Heo8b8edef2010-07-20 22:09:01 +0200766 * discard a ref on a work item
David Howells36c95592009-04-03 16:42:38 +0100767 */
Tejun Heo8b8edef2010-07-20 22:09:01 +0200768static void fscache_put_object(struct fscache_object *object)
David Howells36c95592009-04-03 16:42:38 +0100769{
David Howells52bd75f2009-11-19 18:11:08 +0000770 fscache_stat(&fscache_n_cop_put_object);
771 object->cache->ops->put_object(object);
772 fscache_stat_d(&fscache_n_cop_put_object);
David Howells36c95592009-04-03 16:42:38 +0100773}
774
775/*
776 * enqueue an object for metadata-type processing
777 */
778void fscache_enqueue_object(struct fscache_object *object)
779{
780 _enter("{OBJ%x}", object->debug_id);
781
Tejun Heo8b8edef2010-07-20 22:09:01 +0200782 if (fscache_get_object(object) >= 0) {
783 wait_queue_head_t *cong_wq =
784 &get_cpu_var(fscache_object_cong_wait);
785
786 if (queue_work(fscache_object_wq, &object->work)) {
787 if (fscache_object_congested())
788 wake_up(cong_wq);
789 } else
790 fscache_put_object(object);
791
792 put_cpu_var(fscache_object_cong_wait);
793 }
David Howells36c95592009-04-03 16:42:38 +0100794}
795
Tejun Heo8b8edef2010-07-20 22:09:01 +0200796/**
797 * fscache_object_sleep_till_congested - Sleep until object wq is congested
798 * @timoutp: Scheduler sleep timeout
799 *
800 * Allow an object handler to sleep until the object workqueue is congested.
801 *
802 * The caller must set up a wake up event before calling this and must have set
803 * the appropriate sleep mode (such as TASK_UNINTERRUPTIBLE) and tested its own
804 * condition before calling this function as no test is made here.
805 *
806 * %true is returned if the object wq is congested, %false otherwise.
807 */
808bool fscache_object_sleep_till_congested(signed long *timeoutp)
809{
810 wait_queue_head_t *cong_wq = &__get_cpu_var(fscache_object_cong_wait);
811 DEFINE_WAIT(wait);
812
813 if (fscache_object_congested())
814 return true;
815
816 add_wait_queue_exclusive(cong_wq, &wait);
817 if (!fscache_object_congested())
818 *timeoutp = schedule_timeout(*timeoutp);
819 finish_wait(cong_wq, &wait);
820
821 return fscache_object_congested();
822}
823EXPORT_SYMBOL_GPL(fscache_object_sleep_till_congested);
824
David Howells36c95592009-04-03 16:42:38 +0100825/*
826 * enqueue the dependents of an object for metadata-type processing
827 * - the caller must hold the object's lock
828 * - this may cause an already locked object to wind up being processed again
829 */
830static void fscache_enqueue_dependents(struct fscache_object *object)
831{
832 struct fscache_object *dep;
833
834 _enter("{OBJ%x}", object->debug_id);
835
836 if (list_empty(&object->dependents))
837 return;
838
839 spin_lock(&object->lock);
840
841 while (!list_empty(&object->dependents)) {
842 dep = list_entry(object->dependents.next,
843 struct fscache_object, dep_link);
844 list_del_init(&dep->dep_link);
845
846
847 /* sort onto appropriate lists */
848 fscache_enqueue_object(dep);
Tejun Heo8b8edef2010-07-20 22:09:01 +0200849 fscache_put_object(dep);
David Howells36c95592009-04-03 16:42:38 +0100850
851 if (!list_empty(&object->dependents))
852 cond_resched_lock(&object->lock);
853 }
854
855 spin_unlock(&object->lock);
856}
857
858/*
859 * remove an object from whatever queue it's waiting on
860 * - the caller must hold object->lock
861 */
862void fscache_dequeue_object(struct fscache_object *object)
863{
864 _enter("{OBJ%x}", object->debug_id);
865
866 if (!list_empty(&object->dep_link)) {
867 spin_lock(&object->parent->lock);
868 list_del_init(&object->dep_link);
869 spin_unlock(&object->parent->lock);
870 }
871
872 _leave("");
873}
874
875/**
876 * fscache_check_aux - Ask the netfs whether an object on disk is still valid
877 * @object: The object to ask about
878 * @data: The auxiliary data for the object
879 * @datalen: The size of the auxiliary data
880 *
881 * This function consults the netfs about the coherency state of an object
882 */
883enum fscache_checkaux fscache_check_aux(struct fscache_object *object,
884 const void *data, uint16_t datalen)
885{
886 enum fscache_checkaux result;
887
888 if (!object->cookie->def->check_aux) {
889 fscache_stat(&fscache_n_checkaux_none);
890 return FSCACHE_CHECKAUX_OKAY;
891 }
892
893 result = object->cookie->def->check_aux(object->cookie->netfs_data,
894 data, datalen);
895 switch (result) {
896 /* entry okay as is */
897 case FSCACHE_CHECKAUX_OKAY:
898 fscache_stat(&fscache_n_checkaux_okay);
899 break;
900
901 /* entry requires update */
902 case FSCACHE_CHECKAUX_NEEDS_UPDATE:
903 fscache_stat(&fscache_n_checkaux_update);
904 break;
905
906 /* entry requires deletion */
907 case FSCACHE_CHECKAUX_OBSOLETE:
908 fscache_stat(&fscache_n_checkaux_obsolete);
909 break;
910
911 default:
912 BUG();
913 }
914
915 return result;
916}
917EXPORT_SYMBOL(fscache_check_aux);
David Howellsef778e72012-12-20 21:52:36 +0000918
919/*
920 * Asynchronously invalidate an object.
921 */
922static void fscache_invalidate_object(struct fscache_object *object)
923{
924 struct fscache_operation *op;
925 struct fscache_cookie *cookie = object->cookie;
926
927 _enter("{OBJ%x}", object->debug_id);
928
929 /* Reject any new read/write ops and abort any that are pending. */
930 fscache_invalidate_writes(cookie);
931 clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags);
932 fscache_cancel_all_ops(object);
933
934 /* Now we have to wait for in-progress reads and writes */
935 op = kzalloc(sizeof(*op), GFP_KERNEL);
936 if (!op) {
937 fscache_raise_event(object, FSCACHE_OBJECT_EV_ERROR);
938 _leave(" [ENOMEM]");
939 return;
940 }
941
942 fscache_operation_init(op, object->cache->ops->invalidate_object, NULL);
943 op->flags = FSCACHE_OP_ASYNC | (1 << FSCACHE_OP_EXCLUSIVE);
944
945 spin_lock(&cookie->lock);
946 if (fscache_submit_exclusive_op(object, op) < 0)
947 BUG();
948 spin_unlock(&cookie->lock);
949 fscache_put_operation(op);
950
951 /* Once we've completed the invalidation, we know there will be no data
952 * stored in the cache and thus we can reinstate the data-check-skip
953 * optimisation.
954 */
955 set_bit(FSCACHE_COOKIE_NO_DATA_YET, &cookie->flags);
956
957 /* We can allow read and write requests to come in once again. They'll
958 * queue up behind our exclusive invalidation operation.
959 */
960 fscache_invalidation_complete(cookie);
961 _leave("");
962}