diff options
Diffstat (limited to 'fs/fscache')
-rw-r--r-- | fs/fscache/cache.c | 34 | ||||
-rw-r--r-- | fs/fscache/cookie.c | 93 | ||||
-rw-r--r-- | fs/fscache/fsdef.c | 1 | ||||
-rw-r--r-- | fs/fscache/internal.h | 11 | ||||
-rw-r--r-- | fs/fscache/main.c | 11 | ||||
-rw-r--r-- | fs/fscache/netfs.c | 1 | ||||
-rw-r--r-- | fs/fscache/object-list.c | 103 | ||||
-rw-r--r-- | fs/fscache/object.c | 1106 | ||||
-rw-r--r-- | fs/fscache/operation.c | 37 | ||||
-rw-r--r-- | fs/fscache/page.c | 65 |
10 files changed, 738 insertions, 724 deletions
diff --git a/fs/fscache/cache.c b/fs/fscache/cache.c index b52aed1dca97..f7cff367db7f 100644 --- a/fs/fscache/cache.c +++ b/fs/fscache/cache.c | |||
@@ -115,7 +115,7 @@ struct fscache_cache *fscache_select_cache_for_object( | |||
115 | struct fscache_object, cookie_link); | 115 | struct fscache_object, cookie_link); |
116 | 116 | ||
117 | cache = object->cache; | 117 | cache = object->cache; |
118 | if (object->state >= FSCACHE_OBJECT_DYING || | 118 | if (fscache_object_is_dying(object) || |
119 | test_bit(FSCACHE_IOERROR, &cache->flags)) | 119 | test_bit(FSCACHE_IOERROR, &cache->flags)) |
120 | cache = NULL; | 120 | cache = NULL; |
121 | 121 | ||
@@ -224,8 +224,10 @@ int fscache_add_cache(struct fscache_cache *cache, | |||
224 | BUG_ON(!ifsdef); | 224 | BUG_ON(!ifsdef); |
225 | 225 | ||
226 | cache->flags = 0; | 226 | cache->flags = 0; |
227 | ifsdef->event_mask = ULONG_MAX & ~(1 << FSCACHE_OBJECT_EV_CLEARED); | 227 | ifsdef->event_mask = |
228 | ifsdef->state = FSCACHE_OBJECT_ACTIVE; | 228 | ((1 << NR_FSCACHE_OBJECT_EVENTS) - 1) & |
229 | ~(1 << FSCACHE_OBJECT_EV_CLEARED); | ||
230 | __set_bit(FSCACHE_OBJECT_IS_AVAILABLE, &ifsdef->flags); | ||
229 | 231 | ||
230 | if (!tagname) | 232 | if (!tagname) |
231 | tagname = cache->identifier; | 233 | tagname = cache->identifier; |
@@ -330,25 +332,25 @@ static void fscache_withdraw_all_objects(struct fscache_cache *cache, | |||
330 | { | 332 | { |
331 | struct fscache_object *object; | 333 | struct fscache_object *object; |
332 | 334 | ||
333 | spin_lock(&cache->object_list_lock); | ||
334 | |||
335 | while (!list_empty(&cache->object_list)) { | 335 | while (!list_empty(&cache->object_list)) { |
336 | object = list_entry(cache->object_list.next, | 336 | spin_lock(&cache->object_list_lock); |
337 | struct fscache_object, cache_link); | ||
338 | list_move_tail(&object->cache_link, dying_objects); | ||
339 | 337 | ||
340 | _debug("withdraw %p", object->cookie); | 338 | if (!list_empty(&cache->object_list)) { |
339 | object = list_entry(cache->object_list.next, | ||
340 | struct fscache_object, cache_link); | ||
341 | list_move_tail(&object->cache_link, dying_objects); | ||
341 | 342 | ||
342 | spin_lock(&object->lock); | 343 | _debug("withdraw %p", object->cookie); |
343 | spin_unlock(&cache->object_list_lock); | 344 | |
344 | fscache_raise_event(object, FSCACHE_OBJECT_EV_WITHDRAW); | 345 | /* This must be done under object_list_lock to prevent |
345 | spin_unlock(&object->lock); | 346 | * a race with fscache_drop_object(). |
347 | */ | ||
348 | fscache_raise_event(object, FSCACHE_OBJECT_EV_KILL); | ||
349 | } | ||
346 | 350 | ||
351 | spin_unlock(&cache->object_list_lock); | ||
347 | cond_resched(); | 352 | cond_resched(); |
348 | spin_lock(&cache->object_list_lock); | ||
349 | } | 353 | } |
350 | |||
351 | spin_unlock(&cache->object_list_lock); | ||
352 | } | 354 | } |
353 | 355 | ||
354 | /** | 356 | /** |
diff --git a/fs/fscache/cookie.c b/fs/fscache/cookie.c index e2cba1f60c21..0e91a3c9fdb2 100644 --- a/fs/fscache/cookie.c +++ b/fs/fscache/cookie.c | |||
@@ -95,6 +95,11 @@ struct fscache_cookie *__fscache_acquire_cookie( | |||
95 | atomic_set(&cookie->usage, 1); | 95 | atomic_set(&cookie->usage, 1); |
96 | atomic_set(&cookie->n_children, 0); | 96 | atomic_set(&cookie->n_children, 0); |
97 | 97 | ||
98 | /* We keep the active count elevated until relinquishment to prevent an | ||
99 | * attempt to wake up every time the object operations queue quiesces. | ||
100 | */ | ||
101 | atomic_set(&cookie->n_active, 1); | ||
102 | |||
98 | atomic_inc(&parent->usage); | 103 | atomic_inc(&parent->usage); |
99 | atomic_inc(&parent->n_children); | 104 | atomic_inc(&parent->n_children); |
100 | 105 | ||
@@ -177,7 +182,6 @@ static int fscache_acquire_non_index_cookie(struct fscache_cookie *cookie) | |||
177 | 182 | ||
178 | cookie->flags = | 183 | cookie->flags = |
179 | (1 << FSCACHE_COOKIE_LOOKING_UP) | | 184 | (1 << FSCACHE_COOKIE_LOOKING_UP) | |
180 | (1 << FSCACHE_COOKIE_CREATING) | | ||
181 | (1 << FSCACHE_COOKIE_NO_DATA_YET); | 185 | (1 << FSCACHE_COOKIE_NO_DATA_YET); |
182 | 186 | ||
183 | /* ask the cache to allocate objects for this cookie and its parent | 187 | /* ask the cache to allocate objects for this cookie and its parent |
@@ -205,7 +209,7 @@ static int fscache_acquire_non_index_cookie(struct fscache_cookie *cookie) | |||
205 | 209 | ||
206 | /* initiate the process of looking up all the objects in the chain | 210 | /* initiate the process of looking up all the objects in the chain |
207 | * (done by fscache_initialise_object()) */ | 211 | * (done by fscache_initialise_object()) */ |
208 | fscache_enqueue_object(object); | 212 | fscache_raise_event(object, FSCACHE_OBJECT_EV_NEW_CHILD); |
209 | 213 | ||
210 | spin_unlock(&cookie->lock); | 214 | spin_unlock(&cookie->lock); |
211 | 215 | ||
@@ -285,7 +289,7 @@ static int fscache_alloc_object(struct fscache_cache *cache, | |||
285 | 289 | ||
286 | object_already_extant: | 290 | object_already_extant: |
287 | ret = -ENOBUFS; | 291 | ret = -ENOBUFS; |
288 | if (object->state >= FSCACHE_OBJECT_DYING) { | 292 | if (fscache_object_is_dead(object)) { |
289 | spin_unlock(&cookie->lock); | 293 | spin_unlock(&cookie->lock); |
290 | goto error; | 294 | goto error; |
291 | } | 295 | } |
@@ -321,7 +325,7 @@ static int fscache_attach_object(struct fscache_cookie *cookie, | |||
321 | ret = -EEXIST; | 325 | ret = -EEXIST; |
322 | hlist_for_each_entry(p, &cookie->backing_objects, cookie_link) { | 326 | hlist_for_each_entry(p, &cookie->backing_objects, cookie_link) { |
323 | if (p->cache == object->cache) { | 327 | if (p->cache == object->cache) { |
324 | if (p->state >= FSCACHE_OBJECT_DYING) | 328 | if (fscache_object_is_dying(p)) |
325 | ret = -ENOBUFS; | 329 | ret = -ENOBUFS; |
326 | goto cant_attach_object; | 330 | goto cant_attach_object; |
327 | } | 331 | } |
@@ -332,7 +336,7 @@ static int fscache_attach_object(struct fscache_cookie *cookie, | |||
332 | hlist_for_each_entry(p, &cookie->parent->backing_objects, | 336 | hlist_for_each_entry(p, &cookie->parent->backing_objects, |
333 | cookie_link) { | 337 | cookie_link) { |
334 | if (p->cache == object->cache) { | 338 | if (p->cache == object->cache) { |
335 | if (p->state >= FSCACHE_OBJECT_DYING) { | 339 | if (fscache_object_is_dying(p)) { |
336 | ret = -ENOBUFS; | 340 | ret = -ENOBUFS; |
337 | spin_unlock(&cookie->parent->lock); | 341 | spin_unlock(&cookie->parent->lock); |
338 | goto cant_attach_object; | 342 | goto cant_attach_object; |
@@ -400,7 +404,7 @@ void __fscache_invalidate(struct fscache_cookie *cookie) | |||
400 | object = hlist_entry(cookie->backing_objects.first, | 404 | object = hlist_entry(cookie->backing_objects.first, |
401 | struct fscache_object, | 405 | struct fscache_object, |
402 | cookie_link); | 406 | cookie_link); |
403 | if (object->state < FSCACHE_OBJECT_DYING) | 407 | if (fscache_object_is_live(object)) |
404 | fscache_raise_event( | 408 | fscache_raise_event( |
405 | object, FSCACHE_OBJECT_EV_INVALIDATE); | 409 | object, FSCACHE_OBJECT_EV_INVALIDATE); |
406 | } | 410 | } |
@@ -467,9 +471,7 @@ EXPORT_SYMBOL(__fscache_update_cookie); | |||
467 | */ | 471 | */ |
468 | void __fscache_relinquish_cookie(struct fscache_cookie *cookie, int retire) | 472 | void __fscache_relinquish_cookie(struct fscache_cookie *cookie, int retire) |
469 | { | 473 | { |
470 | struct fscache_cache *cache; | ||
471 | struct fscache_object *object; | 474 | struct fscache_object *object; |
472 | unsigned long event; | ||
473 | 475 | ||
474 | fscache_stat(&fscache_n_relinquishes); | 476 | fscache_stat(&fscache_n_relinquishes); |
475 | if (retire) | 477 | if (retire) |
@@ -481,8 +483,11 @@ void __fscache_relinquish_cookie(struct fscache_cookie *cookie, int retire) | |||
481 | return; | 483 | return; |
482 | } | 484 | } |
483 | 485 | ||
484 | _enter("%p{%s,%p},%d", | 486 | _enter("%p{%s,%p,%d},%d", |
485 | cookie, cookie->def->name, cookie->netfs_data, retire); | 487 | cookie, cookie->def->name, cookie->netfs_data, |
488 | atomic_read(&cookie->n_active), retire); | ||
489 | |||
490 | ASSERTCMP(atomic_read(&cookie->n_active), >, 0); | ||
486 | 491 | ||
487 | if (atomic_read(&cookie->n_children) != 0) { | 492 | if (atomic_read(&cookie->n_children) != 0) { |
488 | printk(KERN_ERR "FS-Cache: Cookie '%s' still has children\n", | 493 | printk(KERN_ERR "FS-Cache: Cookie '%s' still has children\n", |
@@ -490,62 +495,28 @@ void __fscache_relinquish_cookie(struct fscache_cookie *cookie, int retire) | |||
490 | BUG(); | 495 | BUG(); |
491 | } | 496 | } |
492 | 497 | ||
493 | /* wait for the cookie to finish being instantiated (or to fail) */ | 498 | /* No further netfs-accessing operations on this cookie permitted */ |
494 | if (test_bit(FSCACHE_COOKIE_CREATING, &cookie->flags)) { | 499 | set_bit(FSCACHE_COOKIE_RELINQUISHED, &cookie->flags); |
495 | fscache_stat(&fscache_n_relinquishes_waitcrt); | 500 | if (retire) |
496 | wait_on_bit(&cookie->flags, FSCACHE_COOKIE_CREATING, | 501 | set_bit(FSCACHE_COOKIE_RETIRED, &cookie->flags); |
497 | fscache_wait_bit, TASK_UNINTERRUPTIBLE); | ||
498 | } | ||
499 | |||
500 | event = retire ? FSCACHE_OBJECT_EV_RETIRE : FSCACHE_OBJECT_EV_RELEASE; | ||
501 | 502 | ||
502 | try_again: | ||
503 | spin_lock(&cookie->lock); | 503 | spin_lock(&cookie->lock); |
504 | 504 | hlist_for_each_entry(object, &cookie->backing_objects, cookie_link) { | |
505 | /* break links with all the active objects */ | 505 | fscache_raise_event(object, FSCACHE_OBJECT_EV_KILL); |
506 | while (!hlist_empty(&cookie->backing_objects)) { | ||
507 | int n_reads; | ||
508 | object = hlist_entry(cookie->backing_objects.first, | ||
509 | struct fscache_object, | ||
510 | cookie_link); | ||
511 | |||
512 | _debug("RELEASE OBJ%x", object->debug_id); | ||
513 | |||
514 | set_bit(FSCACHE_COOKIE_WAITING_ON_READS, &cookie->flags); | ||
515 | n_reads = atomic_read(&object->n_reads); | ||
516 | if (n_reads) { | ||
517 | int n_ops = object->n_ops; | ||
518 | int n_in_progress = object->n_in_progress; | ||
519 | spin_unlock(&cookie->lock); | ||
520 | printk(KERN_ERR "FS-Cache:" | ||
521 | " Cookie '%s' still has %d outstanding reads (%d,%d)\n", | ||
522 | cookie->def->name, | ||
523 | n_reads, n_ops, n_in_progress); | ||
524 | wait_on_bit(&cookie->flags, FSCACHE_COOKIE_WAITING_ON_READS, | ||
525 | fscache_wait_bit, TASK_UNINTERRUPTIBLE); | ||
526 | printk("Wait finished\n"); | ||
527 | goto try_again; | ||
528 | } | ||
529 | |||
530 | /* detach each cache object from the object cookie */ | ||
531 | spin_lock(&object->lock); | ||
532 | hlist_del_init(&object->cookie_link); | ||
533 | |||
534 | cache = object->cache; | ||
535 | object->cookie = NULL; | ||
536 | fscache_raise_event(object, event); | ||
537 | spin_unlock(&object->lock); | ||
538 | |||
539 | if (atomic_dec_and_test(&cookie->usage)) | ||
540 | /* the cookie refcount shouldn't be reduced to 0 yet */ | ||
541 | BUG(); | ||
542 | } | 506 | } |
507 | spin_unlock(&cookie->lock); | ||
543 | 508 | ||
544 | /* detach pointers back to the netfs */ | 509 | /* Wait for cessation of activity requiring access to the netfs (when |
510 | * n_active reaches 0). | ||
511 | */ | ||
512 | if (!atomic_dec_and_test(&cookie->n_active)) | ||
513 | wait_on_atomic_t(&cookie->n_active, fscache_wait_atomic_t, | ||
514 | TASK_UNINTERRUPTIBLE); | ||
515 | |||
516 | /* Clear pointers back to the netfs */ | ||
545 | cookie->netfs_data = NULL; | 517 | cookie->netfs_data = NULL; |
546 | cookie->def = NULL; | 518 | cookie->def = NULL; |
547 | 519 | BUG_ON(cookie->stores.rnode); | |
548 | spin_unlock(&cookie->lock); | ||
549 | 520 | ||
550 | if (cookie->parent) { | 521 | if (cookie->parent) { |
551 | ASSERTCMP(atomic_read(&cookie->parent->usage), >, 0); | 522 | ASSERTCMP(atomic_read(&cookie->parent->usage), >, 0); |
@@ -553,7 +524,7 @@ try_again: | |||
553 | atomic_dec(&cookie->parent->n_children); | 524 | atomic_dec(&cookie->parent->n_children); |
554 | } | 525 | } |
555 | 526 | ||
556 | /* finally dispose of the cookie */ | 527 | /* Dispose of the netfs's link to the cookie */ |
557 | ASSERTCMP(atomic_read(&cookie->usage), >, 0); | 528 | ASSERTCMP(atomic_read(&cookie->usage), >, 0); |
558 | fscache_cookie_put(cookie); | 529 | fscache_cookie_put(cookie); |
559 | 530 | ||
diff --git a/fs/fscache/fsdef.c b/fs/fscache/fsdef.c index f5b4baee7352..10a2ade0bdf8 100644 --- a/fs/fscache/fsdef.c +++ b/fs/fscache/fsdef.c | |||
@@ -55,6 +55,7 @@ static struct fscache_cookie_def fscache_fsdef_index_def = { | |||
55 | 55 | ||
56 | struct fscache_cookie fscache_fsdef_index = { | 56 | struct fscache_cookie fscache_fsdef_index = { |
57 | .usage = ATOMIC_INIT(1), | 57 | .usage = ATOMIC_INIT(1), |
58 | .n_active = ATOMIC_INIT(1), | ||
58 | .lock = __SPIN_LOCK_UNLOCKED(fscache_fsdef_index.lock), | 59 | .lock = __SPIN_LOCK_UNLOCKED(fscache_fsdef_index.lock), |
59 | .backing_objects = HLIST_HEAD_INIT, | 60 | .backing_objects = HLIST_HEAD_INIT, |
60 | .def = &fscache_fsdef_index_def, | 61 | .def = &fscache_fsdef_index_def, |
diff --git a/fs/fscache/internal.h b/fs/fscache/internal.h index ee38fef4be51..12d505bedb5c 100644 --- a/fs/fscache/internal.h +++ b/fs/fscache/internal.h | |||
@@ -93,14 +93,11 @@ static inline bool fscache_object_congested(void) | |||
93 | 93 | ||
94 | extern int fscache_wait_bit(void *); | 94 | extern int fscache_wait_bit(void *); |
95 | extern int fscache_wait_bit_interruptible(void *); | 95 | extern int fscache_wait_bit_interruptible(void *); |
96 | extern int fscache_wait_atomic_t(atomic_t *); | ||
96 | 97 | ||
97 | /* | 98 | /* |
98 | * object.c | 99 | * object.c |
99 | */ | 100 | */ |
100 | extern const char fscache_object_states_short[FSCACHE_OBJECT__NSTATES][5]; | ||
101 | |||
102 | extern void fscache_withdrawing_object(struct fscache_cache *, | ||
103 | struct fscache_object *); | ||
104 | extern void fscache_enqueue_object(struct fscache_object *); | 101 | extern void fscache_enqueue_object(struct fscache_object *); |
105 | 102 | ||
106 | /* | 103 | /* |
@@ -110,8 +107,10 @@ extern void fscache_enqueue_object(struct fscache_object *); | |||
110 | extern const struct file_operations fscache_objlist_fops; | 107 | extern const struct file_operations fscache_objlist_fops; |
111 | 108 | ||
112 | extern void fscache_objlist_add(struct fscache_object *); | 109 | extern void fscache_objlist_add(struct fscache_object *); |
110 | extern void fscache_objlist_remove(struct fscache_object *); | ||
113 | #else | 111 | #else |
114 | #define fscache_objlist_add(object) do {} while(0) | 112 | #define fscache_objlist_add(object) do {} while(0) |
113 | #define fscache_objlist_remove(object) do {} while(0) | ||
115 | #endif | 114 | #endif |
116 | 115 | ||
117 | /* | 116 | /* |
@@ -291,6 +290,10 @@ static inline void fscache_raise_event(struct fscache_object *object, | |||
291 | unsigned event) | 290 | unsigned event) |
292 | { | 291 | { |
293 | BUG_ON(event >= NR_FSCACHE_OBJECT_EVENTS); | 292 | BUG_ON(event >= NR_FSCACHE_OBJECT_EVENTS); |
293 | #if 0 | ||
294 | printk("*** fscache_raise_event(OBJ%d{%lx},%x)\n", | ||
295 | object->debug_id, object->event_mask, (1 << event)); | ||
296 | #endif | ||
294 | if (!test_and_set_bit(event, &object->events) && | 297 | if (!test_and_set_bit(event, &object->events) && |
295 | test_bit(event, &object->event_mask)) | 298 | test_bit(event, &object->event_mask)) |
296 | fscache_enqueue_object(object); | 299 | fscache_enqueue_object(object); |
diff --git a/fs/fscache/main.c b/fs/fscache/main.c index f9d856773f79..7c27907e650c 100644 --- a/fs/fscache/main.c +++ b/fs/fscache/main.c | |||
@@ -205,7 +205,6 @@ int fscache_wait_bit(void *flags) | |||
205 | schedule(); | 205 | schedule(); |
206 | return 0; | 206 | return 0; |
207 | } | 207 | } |
208 | EXPORT_SYMBOL(fscache_wait_bit); | ||
209 | 208 | ||
210 | /* | 209 | /* |
211 | * wait_on_bit() sleep function for interruptible waiting | 210 | * wait_on_bit() sleep function for interruptible waiting |
@@ -215,4 +214,12 @@ int fscache_wait_bit_interruptible(void *flags) | |||
215 | schedule(); | 214 | schedule(); |
216 | return signal_pending(current); | 215 | return signal_pending(current); |
217 | } | 216 | } |
218 | EXPORT_SYMBOL(fscache_wait_bit_interruptible); | 217 | |
218 | /* | ||
219 | * wait_on_atomic_t() sleep function for uninterruptible waiting | ||
220 | */ | ||
221 | int fscache_wait_atomic_t(atomic_t *p) | ||
222 | { | ||
223 | schedule(); | ||
224 | return 0; | ||
225 | } | ||
diff --git a/fs/fscache/netfs.c b/fs/fscache/netfs.c index e028b8eb1c40..b1bb6117473a 100644 --- a/fs/fscache/netfs.c +++ b/fs/fscache/netfs.c | |||
@@ -40,6 +40,7 @@ int __fscache_register_netfs(struct fscache_netfs *netfs) | |||
40 | /* initialise the primary index cookie */ | 40 | /* initialise the primary index cookie */ |
41 | atomic_set(&netfs->primary_index->usage, 1); | 41 | atomic_set(&netfs->primary_index->usage, 1); |
42 | atomic_set(&netfs->primary_index->n_children, 0); | 42 | atomic_set(&netfs->primary_index->n_children, 0); |
43 | atomic_set(&netfs->primary_index->n_active, 1); | ||
43 | 44 | ||
44 | netfs->primary_index->def = &fscache_fsdef_netfs_def; | 45 | netfs->primary_index->def = &fscache_fsdef_netfs_def; |
45 | netfs->primary_index->parent = &fscache_fsdef_index; | 46 | netfs->primary_index->parent = &fscache_fsdef_index; |
diff --git a/fs/fscache/object-list.c b/fs/fscache/object-list.c index f27c89d17885..e1959efad64f 100644 --- a/fs/fscache/object-list.c +++ b/fs/fscache/object-list.c | |||
@@ -70,13 +70,10 @@ void fscache_objlist_add(struct fscache_object *obj) | |||
70 | write_unlock(&fscache_object_list_lock); | 70 | write_unlock(&fscache_object_list_lock); |
71 | } | 71 | } |
72 | 72 | ||
73 | /** | 73 | /* |
74 | * fscache_object_destroy - Note that a cache object is about to be destroyed | 74 | * Remove an object from the object list. |
75 | * @object: The object to be destroyed | ||
76 | * | ||
77 | * Note the imminent destruction and deallocation of a cache object record. | ||
78 | */ | 75 | */ |
79 | void fscache_object_destroy(struct fscache_object *obj) | 76 | void fscache_objlist_remove(struct fscache_object *obj) |
80 | { | 77 | { |
81 | write_lock(&fscache_object_list_lock); | 78 | write_lock(&fscache_object_list_lock); |
82 | 79 | ||
@@ -85,7 +82,6 @@ void fscache_object_destroy(struct fscache_object *obj) | |||
85 | 82 | ||
86 | write_unlock(&fscache_object_list_lock); | 83 | write_unlock(&fscache_object_list_lock); |
87 | } | 84 | } |
88 | EXPORT_SYMBOL(fscache_object_destroy); | ||
89 | 85 | ||
90 | /* | 86 | /* |
91 | * find the object in the tree on or after the specified index | 87 | * find the object in the tree on or after the specified index |
@@ -166,15 +162,14 @@ static int fscache_objlist_show(struct seq_file *m, void *v) | |||
166 | { | 162 | { |
167 | struct fscache_objlist_data *data = m->private; | 163 | struct fscache_objlist_data *data = m->private; |
168 | struct fscache_object *obj = v; | 164 | struct fscache_object *obj = v; |
165 | struct fscache_cookie *cookie; | ||
169 | unsigned long config = data->config; | 166 | unsigned long config = data->config; |
170 | uint16_t keylen, auxlen; | ||
171 | char _type[3], *type; | 167 | char _type[3], *type; |
172 | bool no_cookie; | ||
173 | u8 *buf = data->buf, *p; | 168 | u8 *buf = data->buf, *p; |
174 | 169 | ||
175 | if ((unsigned long) v == 1) { | 170 | if ((unsigned long) v == 1) { |
176 | seq_puts(m, "OBJECT PARENT STAT CHLDN OPS OOP IPR EX READS" | 171 | seq_puts(m, "OBJECT PARENT STAT CHLDN OPS OOP IPR EX READS" |
177 | " EM EV F S" | 172 | " EM EV FL S" |
178 | " | NETFS_COOKIE_DEF TY FL NETFS_DATA"); | 173 | " | NETFS_COOKIE_DEF TY FL NETFS_DATA"); |
179 | if (config & (FSCACHE_OBJLIST_CONFIG_KEY | | 174 | if (config & (FSCACHE_OBJLIST_CONFIG_KEY | |
180 | FSCACHE_OBJLIST_CONFIG_AUX)) | 175 | FSCACHE_OBJLIST_CONFIG_AUX)) |
@@ -193,7 +188,7 @@ static int fscache_objlist_show(struct seq_file *m, void *v) | |||
193 | 188 | ||
194 | if ((unsigned long) v == 2) { | 189 | if ((unsigned long) v == 2) { |
195 | seq_puts(m, "======== ======== ==== ===== === === === == =====" | 190 | seq_puts(m, "======== ======== ==== ===== === === === == =====" |
196 | " == == = =" | 191 | " == == == =" |
197 | " | ================ == == ================"); | 192 | " | ================ == == ================"); |
198 | if (config & (FSCACHE_OBJLIST_CONFIG_KEY | | 193 | if (config & (FSCACHE_OBJLIST_CONFIG_KEY | |
199 | FSCACHE_OBJLIST_CONFIG_AUX)) | 194 | FSCACHE_OBJLIST_CONFIG_AUX)) |
@@ -216,10 +211,11 @@ static int fscache_objlist_show(struct seq_file *m, void *v) | |||
216 | } \ | 211 | } \ |
217 | } while(0) | 212 | } while(0) |
218 | 213 | ||
214 | cookie = obj->cookie; | ||
219 | if (~config) { | 215 | if (~config) { |
220 | FILTER(obj->cookie, | 216 | FILTER(cookie->def, |
221 | COOKIE, NOCOOKIE); | 217 | COOKIE, NOCOOKIE); |
222 | FILTER(obj->state != FSCACHE_OBJECT_ACTIVE || | 218 | FILTER(fscache_object_is_active(obj) || |
223 | obj->n_ops != 0 || | 219 | obj->n_ops != 0 || |
224 | obj->n_obj_ops != 0 || | 220 | obj->n_obj_ops != 0 || |
225 | obj->flags || | 221 | obj->flags || |
@@ -235,10 +231,10 @@ static int fscache_objlist_show(struct seq_file *m, void *v) | |||
235 | } | 231 | } |
236 | 232 | ||
237 | seq_printf(m, | 233 | seq_printf(m, |
238 | "%8x %8x %s %5u %3u %3u %3u %2u %5u %2lx %2lx %1lx %1x | ", | 234 | "%8x %8x %s %5u %3u %3u %3u %2u %5u %2lx %2lx %2lx %1x | ", |
239 | obj->debug_id, | 235 | obj->debug_id, |
240 | obj->parent ? obj->parent->debug_id : -1, | 236 | obj->parent ? obj->parent->debug_id : -1, |
241 | fscache_object_states_short[obj->state], | 237 | obj->state->short_name, |
242 | obj->n_children, | 238 | obj->n_children, |
243 | obj->n_ops, | 239 | obj->n_ops, |
244 | obj->n_obj_ops, | 240 | obj->n_obj_ops, |
@@ -250,48 +246,40 @@ static int fscache_objlist_show(struct seq_file *m, void *v) | |||
250 | obj->flags, | 246 | obj->flags, |
251 | work_busy(&obj->work)); | 247 | work_busy(&obj->work)); |
252 | 248 | ||
253 | no_cookie = true; | 249 | if (fscache_use_cookie(obj)) { |
254 | keylen = auxlen = 0; | 250 | uint16_t keylen = 0, auxlen = 0; |
255 | if (obj->cookie) { | ||
256 | spin_lock(&obj->lock); | ||
257 | if (obj->cookie) { | ||
258 | switch (obj->cookie->def->type) { | ||
259 | case 0: | ||
260 | type = "IX"; | ||
261 | break; | ||
262 | case 1: | ||
263 | type = "DT"; | ||
264 | break; | ||
265 | default: | ||
266 | sprintf(_type, "%02u", | ||
267 | obj->cookie->def->type); | ||
268 | type = _type; | ||
269 | break; | ||
270 | } | ||
271 | 251 | ||
272 | seq_printf(m, "%-16s %s %2lx %16p", | 252 | switch (cookie->def->type) { |
273 | obj->cookie->def->name, | 253 | case 0: |
274 | type, | 254 | type = "IX"; |
275 | obj->cookie->flags, | 255 | break; |
276 | obj->cookie->netfs_data); | 256 | case 1: |
277 | 257 | type = "DT"; | |
278 | if (obj->cookie->def->get_key && | 258 | break; |
279 | config & FSCACHE_OBJLIST_CONFIG_KEY) | 259 | default: |
280 | keylen = obj->cookie->def->get_key( | 260 | sprintf(_type, "%02u", cookie->def->type); |
281 | obj->cookie->netfs_data, | 261 | type = _type; |
282 | buf, 400); | 262 | break; |
283 | |||
284 | if (obj->cookie->def->get_aux && | ||
285 | config & FSCACHE_OBJLIST_CONFIG_AUX) | ||
286 | auxlen = obj->cookie->def->get_aux( | ||
287 | obj->cookie->netfs_data, | ||
288 | buf + keylen, 512 - keylen); | ||
289 | |||
290 | no_cookie = false; | ||
291 | } | 263 | } |
292 | spin_unlock(&obj->lock); | ||
293 | 264 | ||
294 | if (!no_cookie && (keylen > 0 || auxlen > 0)) { | 265 | seq_printf(m, "%-16s %s %2lx %16p", |
266 | cookie->def->name, | ||
267 | type, | ||
268 | cookie->flags, | ||
269 | cookie->netfs_data); | ||
270 | |||
271 | if (cookie->def->get_key && | ||
272 | config & FSCACHE_OBJLIST_CONFIG_KEY) | ||
273 | keylen = cookie->def->get_key(cookie->netfs_data, | ||
274 | buf, 400); | ||
275 | |||
276 | if (cookie->def->get_aux && | ||
277 | config & FSCACHE_OBJLIST_CONFIG_AUX) | ||
278 | auxlen = cookie->def->get_aux(cookie->netfs_data, | ||
279 | buf + keylen, 512 - keylen); | ||
280 | fscache_unuse_cookie(obj); | ||
281 | |||
282 | if (keylen > 0 || auxlen > 0) { | ||
295 | seq_printf(m, " "); | 283 | seq_printf(m, " "); |
296 | for (p = buf; keylen > 0; keylen--) | 284 | for (p = buf; keylen > 0; keylen--) |
297 | seq_printf(m, "%02x", *p++); | 285 | seq_printf(m, "%02x", *p++); |
@@ -302,12 +290,11 @@ static int fscache_objlist_show(struct seq_file *m, void *v) | |||
302 | seq_printf(m, "%02x", *p++); | 290 | seq_printf(m, "%02x", *p++); |
303 | } | 291 | } |
304 | } | 292 | } |
305 | } | ||
306 | 293 | ||
307 | if (no_cookie) | ||
308 | seq_printf(m, "<no_cookie>\n"); | ||
309 | else | ||
310 | seq_printf(m, "\n"); | 294 | seq_printf(m, "\n"); |
295 | } else { | ||
296 | seq_printf(m, "<no_netfs>\n"); | ||
297 | } | ||
311 | return 0; | 298 | return 0; |
312 | } | 299 | } |
313 | 300 | ||
diff --git a/fs/fscache/object.c b/fs/fscache/object.c index 50d41c180211..86d75a60b20c 100644 --- a/fs/fscache/object.c +++ b/fs/fscache/object.c | |||
@@ -15,52 +15,131 @@ | |||
15 | #define FSCACHE_DEBUG_LEVEL COOKIE | 15 | #define FSCACHE_DEBUG_LEVEL COOKIE |
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
18 | #include <linux/prefetch.h> | ||
18 | #include "internal.h" | 19 | #include "internal.h" |
19 | 20 | ||
20 | const char *fscache_object_states[FSCACHE_OBJECT__NSTATES] = { | 21 | static const struct fscache_state *fscache_abort_initialisation(struct fscache_object *, int); |
21 | [FSCACHE_OBJECT_INIT] = "OBJECT_INIT", | 22 | static const struct fscache_state *fscache_kill_dependents(struct fscache_object *, int); |
22 | [FSCACHE_OBJECT_LOOKING_UP] = "OBJECT_LOOKING_UP", | 23 | static const struct fscache_state *fscache_drop_object(struct fscache_object *, int); |
23 | [FSCACHE_OBJECT_CREATING] = "OBJECT_CREATING", | 24 | static const struct fscache_state *fscache_initialise_object(struct fscache_object *, int); |
24 | [FSCACHE_OBJECT_AVAILABLE] = "OBJECT_AVAILABLE", | 25 | static const struct fscache_state *fscache_invalidate_object(struct fscache_object *, int); |
25 | [FSCACHE_OBJECT_ACTIVE] = "OBJECT_ACTIVE", | 26 | static const struct fscache_state *fscache_jumpstart_dependents(struct fscache_object *, int); |
26 | [FSCACHE_OBJECT_INVALIDATING] = "OBJECT_INVALIDATING", | 27 | static const struct fscache_state *fscache_kill_object(struct fscache_object *, int); |
27 | [FSCACHE_OBJECT_UPDATING] = "OBJECT_UPDATING", | 28 | static const struct fscache_state *fscache_lookup_failure(struct fscache_object *, int); |
28 | [FSCACHE_OBJECT_DYING] = "OBJECT_DYING", | 29 | static const struct fscache_state *fscache_look_up_object(struct fscache_object *, int); |
29 | [FSCACHE_OBJECT_LC_DYING] = "OBJECT_LC_DYING", | 30 | static const struct fscache_state *fscache_object_available(struct fscache_object *, int); |
30 | [FSCACHE_OBJECT_ABORT_INIT] = "OBJECT_ABORT_INIT", | 31 | static const struct fscache_state *fscache_parent_ready(struct fscache_object *, int); |
31 | [FSCACHE_OBJECT_RELEASING] = "OBJECT_RELEASING", | 32 | static const struct fscache_state *fscache_update_object(struct fscache_object *, int); |
32 | [FSCACHE_OBJECT_RECYCLING] = "OBJECT_RECYCLING", | 33 | |
33 | [FSCACHE_OBJECT_WITHDRAWING] = "OBJECT_WITHDRAWING", | 34 | #define __STATE_NAME(n) fscache_osm_##n |
34 | [FSCACHE_OBJECT_DEAD] = "OBJECT_DEAD", | 35 | #define STATE(n) (&__STATE_NAME(n)) |
36 | |||
37 | /* | ||
38 | * Define a work state. Work states are execution states. No event processing | ||
39 | * is performed by them. The function attached to a work state returns a | ||
40 | * pointer indicating the next state to which the state machine should | ||
41 | * transition. Returning NO_TRANSIT repeats the current state, but goes back | ||
42 | * to the scheduler first. | ||
43 | */ | ||
44 | #define WORK_STATE(n, sn, f) \ | ||
45 | const struct fscache_state __STATE_NAME(n) = { \ | ||
46 | .name = #n, \ | ||
47 | .short_name = sn, \ | ||
48 | .work = f \ | ||
49 | } | ||
50 | |||
51 | /* | ||
52 | * Returns from work states. | ||
53 | */ | ||
54 | #define transit_to(state) ({ prefetch(&STATE(state)->work); STATE(state); }) | ||
55 | |||
56 | #define NO_TRANSIT ((struct fscache_state *)NULL) | ||
57 | |||
58 | /* | ||
59 | * Define a wait state. Wait states are event processing states. No execution | ||
60 | * is performed by them. Wait states are just tables of "if event X occurs, | ||
61 | * clear it and transition to state Y". The dispatcher returns to the | ||
62 | * scheduler if none of the events in which the wait state has an interest are | ||
63 | * currently pending. | ||
64 | */ | ||
65 | #define WAIT_STATE(n, sn, ...) \ | ||
66 | const struct fscache_state __STATE_NAME(n) = { \ | ||
67 | .name = #n, \ | ||
68 | .short_name = sn, \ | ||
69 | .work = NULL, \ | ||
70 | .transitions = { __VA_ARGS__, { 0, NULL } } \ | ||
71 | } | ||
72 | |||
73 | #define TRANSIT_TO(state, emask) \ | ||
74 | { .events = (emask), .transit_to = STATE(state) } | ||
75 | |||
76 | /* | ||
77 | * The object state machine. | ||
78 | */ | ||
79 | static WORK_STATE(INIT_OBJECT, "INIT", fscache_initialise_object); | ||
80 | static WORK_STATE(PARENT_READY, "PRDY", fscache_parent_ready); | ||
81 | static WORK_STATE(ABORT_INIT, "ABRT", fscache_abort_initialisation); | ||
82 | static WORK_STATE(LOOK_UP_OBJECT, "LOOK", fscache_look_up_object); | ||
83 | static WORK_STATE(CREATE_OBJECT, "CRTO", fscache_look_up_object); | ||
84 | static WORK_STATE(OBJECT_AVAILABLE, "AVBL", fscache_object_available); | ||
85 | static WORK_STATE(JUMPSTART_DEPS, "JUMP", fscache_jumpstart_dependents); | ||
86 | |||
87 | static WORK_STATE(INVALIDATE_OBJECT, "INVL", fscache_invalidate_object); | ||
88 | static WORK_STATE(UPDATE_OBJECT, "UPDT", fscache_update_object); | ||
89 | |||
90 | static WORK_STATE(LOOKUP_FAILURE, "LCFL", fscache_lookup_failure); | ||
91 | static WORK_STATE(KILL_OBJECT, "KILL", fscache_kill_object); | ||
92 | static WORK_STATE(KILL_DEPENDENTS, "KDEP", fscache_kill_dependents); | ||
93 | static WORK_STATE(DROP_OBJECT, "DROP", fscache_drop_object); | ||
94 | static WORK_STATE(OBJECT_DEAD, "DEAD", (void*)2UL); | ||
95 | |||
96 | static WAIT_STATE(WAIT_FOR_INIT, "?INI", | ||
97 | TRANSIT_TO(INIT_OBJECT, 1 << FSCACHE_OBJECT_EV_NEW_CHILD)); | ||
98 | |||
99 | static WAIT_STATE(WAIT_FOR_PARENT, "?PRN", | ||
100 | TRANSIT_TO(PARENT_READY, 1 << FSCACHE_OBJECT_EV_PARENT_READY)); | ||
101 | |||
102 | static WAIT_STATE(WAIT_FOR_CMD, "?CMD", | ||
103 | TRANSIT_TO(INVALIDATE_OBJECT, 1 << FSCACHE_OBJECT_EV_INVALIDATE), | ||
104 | TRANSIT_TO(UPDATE_OBJECT, 1 << FSCACHE_OBJECT_EV_UPDATE), | ||
105 | TRANSIT_TO(JUMPSTART_DEPS, 1 << FSCACHE_OBJECT_EV_NEW_CHILD)); | ||
106 | |||
107 | static WAIT_STATE(WAIT_FOR_CLEARANCE, "?CLR", | ||
108 | TRANSIT_TO(KILL_OBJECT, 1 << FSCACHE_OBJECT_EV_CLEARED)); | ||
109 | |||
110 | /* | ||
111 | * Out-of-band event transition tables. These are for handling unexpected | ||
112 | * events, such as an I/O error. If an OOB event occurs, the state machine | ||
113 | * clears and disables the event and forces a transition to the nominated work | ||
114 | * state (acurrently executing work states will complete first). | ||
115 | * | ||
116 | * In such a situation, object->state remembers the state the machine should | ||
117 | * have been in/gone to and returning NO_TRANSIT returns to that. | ||
118 | */ | ||
119 | static const struct fscache_transition fscache_osm_init_oob[] = { | ||
120 | TRANSIT_TO(ABORT_INIT, | ||
121 | (1 << FSCACHE_OBJECT_EV_ERROR) | | ||
122 | (1 << FSCACHE_OBJECT_EV_KILL)), | ||
123 | { 0, NULL } | ||
124 | }; | ||
125 | |||
126 | static const struct fscache_transition fscache_osm_lookup_oob[] = { | ||
127 | TRANSIT_TO(LOOKUP_FAILURE, | ||
128 | (1 << FSCACHE_OBJECT_EV_ERROR) | | ||
129 | (1 << FSCACHE_OBJECT_EV_KILL)), | ||
130 | { 0, NULL } | ||
35 | }; | 131 | }; |
36 | EXPORT_SYMBOL(fscache_object_states); | 132 | |
37 | 133 | static const struct fscache_transition fscache_osm_run_oob[] = { | |
38 | const char fscache_object_states_short[FSCACHE_OBJECT__NSTATES][5] = { | 134 | TRANSIT_TO(KILL_OBJECT, |
39 | [FSCACHE_OBJECT_INIT] = "INIT", | 135 | (1 << FSCACHE_OBJECT_EV_ERROR) | |
40 | [FSCACHE_OBJECT_LOOKING_UP] = "LOOK", | 136 | (1 << FSCACHE_OBJECT_EV_KILL)), |
41 | [FSCACHE_OBJECT_CREATING] = "CRTN", | 137 | { 0, NULL } |
42 | [FSCACHE_OBJECT_AVAILABLE] = "AVBL", | ||
43 | [FSCACHE_OBJECT_ACTIVE] = "ACTV", | ||
44 | [FSCACHE_OBJECT_INVALIDATING] = "INVL", | ||
45 | [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 | }; | 138 | }; |
54 | 139 | ||
55 | static int fscache_get_object(struct fscache_object *); | 140 | static int fscache_get_object(struct fscache_object *); |
56 | static void fscache_put_object(struct fscache_object *); | 141 | static void fscache_put_object(struct fscache_object *); |
57 | static void fscache_initialise_object(struct fscache_object *); | 142 | static bool fscache_enqueue_dependents(struct fscache_object *, int); |
58 | static void fscache_lookup_object(struct fscache_object *); | ||
59 | static void fscache_object_available(struct fscache_object *); | ||
60 | static void fscache_invalidate_object(struct fscache_object *); | ||
61 | static void fscache_release_object(struct fscache_object *); | ||
62 | static void fscache_withdraw_object(struct fscache_object *); | ||
63 | static void fscache_enqueue_dependents(struct fscache_object *); | ||
64 | static void fscache_dequeue_object(struct fscache_object *); | 143 | static void fscache_dequeue_object(struct fscache_object *); |
65 | 144 | ||
66 | /* | 145 | /* |
@@ -75,295 +154,116 @@ static inline void fscache_done_parent_op(struct fscache_object *object) | |||
75 | object->debug_id, parent->debug_id, parent->n_ops); | 154 | object->debug_id, parent->debug_id, parent->n_ops); |
76 | 155 | ||
77 | spin_lock_nested(&parent->lock, 1); | 156 | spin_lock_nested(&parent->lock, 1); |
78 | parent->n_ops--; | ||
79 | parent->n_obj_ops--; | 157 | parent->n_obj_ops--; |
158 | parent->n_ops--; | ||
80 | if (parent->n_ops == 0) | 159 | if (parent->n_ops == 0) |
81 | fscache_raise_event(parent, FSCACHE_OBJECT_EV_CLEARED); | 160 | fscache_raise_event(parent, FSCACHE_OBJECT_EV_CLEARED); |
82 | spin_unlock(&parent->lock); | 161 | spin_unlock(&parent->lock); |
83 | } | 162 | } |
84 | 163 | ||
85 | /* | 164 | /* |
86 | * Notify netfs of invalidation completion. | 165 | * Object state machine dispatcher. |
87 | */ | 166 | */ |
88 | static inline void fscache_invalidation_complete(struct fscache_cookie *cookie) | 167 | static void fscache_object_sm_dispatcher(struct fscache_object *object) |
89 | { | 168 | { |
90 | if (test_and_clear_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags)) | 169 | const struct fscache_transition *t; |
91 | wake_up_bit(&cookie->flags, FSCACHE_COOKIE_INVALIDATING); | 170 | const struct fscache_state *state, *new_state; |
92 | } | 171 | unsigned long events, event_mask; |
93 | 172 | int event = -1; | |
94 | /* | ||
95 | * 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 | */ | ||
102 | static void fscache_object_state_machine(struct fscache_object *object) | ||
103 | { | ||
104 | enum fscache_object_state new_state; | ||
105 | struct fscache_cookie *cookie; | ||
106 | int event; | ||
107 | 173 | ||
108 | ASSERT(object != NULL); | 174 | ASSERT(object != NULL); |
109 | 175 | ||
110 | _enter("{OBJ%x,%s,%lx}", | 176 | _enter("{OBJ%x,%s,%lx}", |
111 | object->debug_id, fscache_object_states[object->state], | 177 | object->debug_id, object->state->name, object->events); |
112 | object->events); | 178 | |
113 | 179 | event_mask = object->event_mask; | |
114 | switch (object->state) { | 180 | restart: |
115 | /* wait for the parent object to become ready */ | 181 | object->event_mask = 0; /* Mask normal event handling */ |
116 | case FSCACHE_OBJECT_INIT: | 182 | state = object->state; |
117 | object->event_mask = | 183 | restart_masked: |
118 | FSCACHE_OBJECT_EVENTS_MASK & | 184 | events = object->events; |
119 | ~(1 << FSCACHE_OBJECT_EV_CLEARED); | 185 | |
120 | fscache_initialise_object(object); | 186 | /* Handle any out-of-band events (typically an error) */ |
121 | goto done; | 187 | if (events & object->oob_event_mask) { |
122 | 188 | _debug("{OBJ%x} oob %lx", | |
123 | /* look up the object metadata on disk */ | 189 | object->debug_id, events & object->oob_event_mask); |
124 | case FSCACHE_OBJECT_LOOKING_UP: | 190 | for (t = object->oob_table; t->events; t++) { |
125 | fscache_lookup_object(object); | 191 | if (events & t->events) { |
126 | goto lookup_transit; | 192 | state = t->transit_to; |
127 | 193 | ASSERT(state->work != NULL); | |
128 | /* create the object metadata on disk */ | 194 | event = fls(events & t->events) - 1; |
129 | case FSCACHE_OBJECT_CREATING: | 195 | __clear_bit(event, &object->oob_event_mask); |
130 | fscache_lookup_object(object); | 196 | clear_bit(event, &object->events); |
131 | goto lookup_transit; | 197 | goto execute_work_state; |
132 | 198 | } | |
133 | /* handle an object becoming available; start pending | ||
134 | * operations and queue dependent operations for processing */ | ||
135 | case FSCACHE_OBJECT_AVAILABLE: | ||
136 | fscache_object_available(object); | ||
137 | goto active_transit; | ||
138 | |||
139 | /* normal running state */ | ||
140 | case FSCACHE_OBJECT_ACTIVE: | ||
141 | goto active_transit; | ||
142 | |||
143 | /* Invalidate an object on disk */ | ||
144 | case FSCACHE_OBJECT_INVALIDATING: | ||
145 | clear_bit(FSCACHE_OBJECT_EV_INVALIDATE, &object->events); | ||
146 | fscache_stat(&fscache_n_invalidates_run); | ||
147 | fscache_stat(&fscache_n_cop_invalidate_object); | ||
148 | fscache_invalidate_object(object); | ||
149 | fscache_stat_d(&fscache_n_cop_invalidate_object); | ||
150 | fscache_raise_event(object, FSCACHE_OBJECT_EV_UPDATE); | ||
151 | goto active_transit; | ||
152 | |||
153 | /* update the object metadata on disk */ | ||
154 | case FSCACHE_OBJECT_UPDATING: | ||
155 | clear_bit(FSCACHE_OBJECT_EV_UPDATE, &object->events); | ||
156 | fscache_stat(&fscache_n_updates_run); | ||
157 | fscache_stat(&fscache_n_cop_update_object); | ||
158 | object->cache->ops->update_object(object); | ||
159 | fscache_stat_d(&fscache_n_cop_update_object); | ||
160 | goto active_transit; | ||
161 | |||
162 | /* handle an object dying during lookup or creation */ | ||
163 | case FSCACHE_OBJECT_LC_DYING: | ||
164 | object->event_mask &= ~(1 << FSCACHE_OBJECT_EV_UPDATE); | ||
165 | fscache_stat(&fscache_n_cop_lookup_complete); | ||
166 | object->cache->ops->lookup_complete(object); | ||
167 | fscache_stat_d(&fscache_n_cop_lookup_complete); | ||
168 | |||
169 | spin_lock(&object->lock); | ||
170 | object->state = FSCACHE_OBJECT_DYING; | ||
171 | cookie = object->cookie; | ||
172 | if (cookie) { | ||
173 | if (test_and_clear_bit(FSCACHE_COOKIE_LOOKING_UP, | ||
174 | &cookie->flags)) | ||
175 | wake_up_bit(&cookie->flags, | ||
176 | FSCACHE_COOKIE_LOOKING_UP); | ||
177 | if (test_and_clear_bit(FSCACHE_COOKIE_CREATING, | ||
178 | &cookie->flags)) | ||
179 | wake_up_bit(&cookie->flags, | ||
180 | FSCACHE_COOKIE_CREATING); | ||
181 | } | 199 | } |
182 | spin_unlock(&object->lock); | 200 | } |
183 | 201 | ||
184 | fscache_done_parent_op(object); | 202 | /* Wait states are just transition tables */ |
203 | if (!state->work) { | ||
204 | if (events & event_mask) { | ||
205 | for (t = state->transitions; t->events; t++) { | ||
206 | if (events & t->events) { | ||
207 | new_state = t->transit_to; | ||
208 | event = fls(events & t->events) - 1; | ||
209 | clear_bit(event, &object->events); | ||
210 | _debug("{OBJ%x} ev %d: %s -> %s", | ||
211 | object->debug_id, event, | ||
212 | state->name, new_state->name); | ||
213 | object->state = state = new_state; | ||
214 | goto execute_work_state; | ||
215 | } | ||
216 | } | ||
185 | 217 | ||
186 | /* wait for completion of all active operations on this object | 218 | /* The event mask didn't include all the tabled bits */ |
187 | * and the death of all child objects of this object */ | 219 | BUG(); |
188 | case FSCACHE_OBJECT_DYING: | ||
189 | dying: | ||
190 | clear_bit(FSCACHE_OBJECT_EV_CLEARED, &object->events); | ||
191 | spin_lock(&object->lock); | ||
192 | _debug("dying OBJ%x {%d,%d}", | ||
193 | object->debug_id, object->n_ops, object->n_children); | ||
194 | if (object->n_ops == 0 && object->n_children == 0) { | ||
195 | object->event_mask &= | ||
196 | ~(1 << FSCACHE_OBJECT_EV_CLEARED); | ||
197 | object->event_mask |= | ||
198 | (1 << FSCACHE_OBJECT_EV_WITHDRAW) | | ||
199 | (1 << FSCACHE_OBJECT_EV_RETIRE) | | ||
200 | (1 << FSCACHE_OBJECT_EV_RELEASE) | | ||
201 | (1 << FSCACHE_OBJECT_EV_ERROR); | ||
202 | } else { | ||
203 | object->event_mask &= | ||
204 | ~((1 << FSCACHE_OBJECT_EV_WITHDRAW) | | ||
205 | (1 << FSCACHE_OBJECT_EV_RETIRE) | | ||
206 | (1 << FSCACHE_OBJECT_EV_RELEASE) | | ||
207 | (1 << FSCACHE_OBJECT_EV_ERROR)); | ||
208 | object->event_mask |= | ||
209 | 1 << FSCACHE_OBJECT_EV_CLEARED; | ||
210 | } | 220 | } |
211 | spin_unlock(&object->lock); | 221 | /* Randomly woke up */ |
212 | fscache_enqueue_dependents(object); | 222 | goto unmask_events; |
213 | fscache_start_operations(object); | ||
214 | goto terminal_transit; | ||
215 | |||
216 | /* handle an abort during initialisation */ | ||
217 | case FSCACHE_OBJECT_ABORT_INIT: | ||
218 | _debug("handle abort init %lx", object->events); | ||
219 | object->event_mask &= ~(1 << FSCACHE_OBJECT_EV_UPDATE); | ||
220 | |||
221 | spin_lock(&object->lock); | ||
222 | fscache_dequeue_object(object); | ||
223 | |||
224 | object->state = FSCACHE_OBJECT_DYING; | ||
225 | if (test_and_clear_bit(FSCACHE_COOKIE_CREATING, | ||
226 | &object->cookie->flags)) | ||
227 | wake_up_bit(&object->cookie->flags, | ||
228 | FSCACHE_COOKIE_CREATING); | ||
229 | spin_unlock(&object->lock); | ||
230 | goto dying; | ||
231 | |||
232 | /* handle the netfs releasing an object and possibly marking it | ||
233 | * obsolete too */ | ||
234 | case FSCACHE_OBJECT_RELEASING: | ||
235 | case FSCACHE_OBJECT_RECYCLING: | ||
236 | object->event_mask &= | ||
237 | ~((1 << FSCACHE_OBJECT_EV_WITHDRAW) | | ||
238 | (1 << FSCACHE_OBJECT_EV_RETIRE) | | ||
239 | (1 << FSCACHE_OBJECT_EV_RELEASE) | | ||
240 | (1 << FSCACHE_OBJECT_EV_ERROR)); | ||
241 | fscache_release_object(object); | ||
242 | spin_lock(&object->lock); | ||
243 | object->state = FSCACHE_OBJECT_DEAD; | ||
244 | spin_unlock(&object->lock); | ||
245 | fscache_stat(&fscache_n_object_dead); | ||
246 | goto terminal_transit; | ||
247 | |||
248 | /* handle the parent cache of this object being withdrawn from | ||
249 | * active service */ | ||
250 | case FSCACHE_OBJECT_WITHDRAWING: | ||
251 | object->event_mask &= | ||
252 | ~((1 << FSCACHE_OBJECT_EV_WITHDRAW) | | ||
253 | (1 << FSCACHE_OBJECT_EV_RETIRE) | | ||
254 | (1 << FSCACHE_OBJECT_EV_RELEASE) | | ||
255 | (1 << FSCACHE_OBJECT_EV_ERROR)); | ||
256 | fscache_withdraw_object(object); | ||
257 | spin_lock(&object->lock); | ||
258 | object->state = FSCACHE_OBJECT_DEAD; | ||
259 | spin_unlock(&object->lock); | ||
260 | fscache_stat(&fscache_n_object_dead); | ||
261 | goto terminal_transit; | ||
262 | |||
263 | /* complain about the object being woken up once it is | ||
264 | * deceased */ | ||
265 | case FSCACHE_OBJECT_DEAD: | ||
266 | printk(KERN_ERR "FS-Cache:" | ||
267 | " Unexpected event in dead state %lx\n", | ||
268 | object->events & object->event_mask); | ||
269 | BUG(); | ||
270 | |||
271 | default: | ||
272 | printk(KERN_ERR "FS-Cache: Unknown object state %u\n", | ||
273 | object->state); | ||
274 | BUG(); | ||
275 | } | ||
276 | |||
277 | /* determine the transition from a lookup state */ | ||
278 | lookup_transit: | ||
279 | event = fls(object->events & object->event_mask) - 1; | ||
280 | switch (event) { | ||
281 | case FSCACHE_OBJECT_EV_WITHDRAW: | ||
282 | case FSCACHE_OBJECT_EV_RETIRE: | ||
283 | case FSCACHE_OBJECT_EV_RELEASE: | ||
284 | case FSCACHE_OBJECT_EV_ERROR: | ||
285 | new_state = FSCACHE_OBJECT_LC_DYING; | ||
286 | goto change_state; | ||
287 | case FSCACHE_OBJECT_EV_INVALIDATE: | ||
288 | new_state = FSCACHE_OBJECT_INVALIDATING; | ||
289 | goto change_state; | ||
290 | case FSCACHE_OBJECT_EV_REQUEUE: | ||
291 | goto done; | ||
292 | case -1: | ||
293 | goto done; /* sleep until event */ | ||
294 | default: | ||
295 | goto unsupported_event; | ||
296 | } | 223 | } |
297 | 224 | ||
298 | /* determine the transition from an active state */ | 225 | execute_work_state: |
299 | active_transit: | 226 | _debug("{OBJ%x} exec %s", object->debug_id, state->name); |
300 | event = fls(object->events & object->event_mask) - 1; | ||
301 | switch (event) { | ||
302 | case FSCACHE_OBJECT_EV_WITHDRAW: | ||
303 | case FSCACHE_OBJECT_EV_RETIRE: | ||
304 | case FSCACHE_OBJECT_EV_RELEASE: | ||
305 | case FSCACHE_OBJECT_EV_ERROR: | ||
306 | new_state = FSCACHE_OBJECT_DYING; | ||
307 | goto change_state; | ||
308 | case FSCACHE_OBJECT_EV_INVALIDATE: | ||
309 | new_state = FSCACHE_OBJECT_INVALIDATING; | ||
310 | goto change_state; | ||
311 | case FSCACHE_OBJECT_EV_UPDATE: | ||
312 | new_state = FSCACHE_OBJECT_UPDATING; | ||
313 | goto change_state; | ||
314 | case -1: | ||
315 | new_state = FSCACHE_OBJECT_ACTIVE; | ||
316 | goto change_state; /* sleep until event */ | ||
317 | default: | ||
318 | goto unsupported_event; | ||
319 | } | ||
320 | 227 | ||
321 | /* determine the transition from a terminal state */ | 228 | new_state = state->work(object, event); |
322 | terminal_transit: | 229 | event = -1; |
323 | event = fls(object->events & object->event_mask) - 1; | 230 | if (new_state == NO_TRANSIT) { |
324 | switch (event) { | 231 | _debug("{OBJ%x} %s notrans", object->debug_id, state->name); |
325 | case FSCACHE_OBJECT_EV_WITHDRAW: | 232 | fscache_enqueue_object(object); |
326 | new_state = FSCACHE_OBJECT_WITHDRAWING; | 233 | event_mask = object->oob_event_mask; |
327 | goto change_state; | 234 | goto unmask_events; |
328 | case FSCACHE_OBJECT_EV_RETIRE: | ||
329 | new_state = FSCACHE_OBJECT_RECYCLING; | ||
330 | goto change_state; | ||
331 | case FSCACHE_OBJECT_EV_RELEASE: | ||
332 | new_state = FSCACHE_OBJECT_RELEASING; | ||
333 | goto change_state; | ||
334 | case FSCACHE_OBJECT_EV_ERROR: | ||
335 | new_state = FSCACHE_OBJECT_WITHDRAWING; | ||
336 | goto change_state; | ||
337 | case FSCACHE_OBJECT_EV_CLEARED: | ||
338 | new_state = FSCACHE_OBJECT_DYING; | ||
339 | goto change_state; | ||
340 | case -1: | ||
341 | goto done; /* sleep until event */ | ||
342 | default: | ||
343 | goto unsupported_event; | ||
344 | } | 235 | } |
345 | 236 | ||
346 | change_state: | 237 | _debug("{OBJ%x} %s -> %s", |
347 | spin_lock(&object->lock); | 238 | object->debug_id, state->name, new_state->name); |
348 | object->state = new_state; | 239 | object->state = state = new_state; |
349 | spin_unlock(&object->lock); | ||
350 | 240 | ||
351 | done: | 241 | if (state->work) { |
352 | _leave(" [->%s]", fscache_object_states[object->state]); | 242 | if (unlikely(state->work == ((void *)2UL))) { |
353 | return; | 243 | _leave(" [dead]"); |
244 | return; | ||
245 | } | ||
246 | goto restart_masked; | ||
247 | } | ||
354 | 248 | ||
355 | unsupported_event: | 249 | /* Transited to wait state */ |
356 | printk(KERN_ERR "FS-Cache:" | 250 | event_mask = object->oob_event_mask; |
357 | " Unsupported event %d [%lx/%lx] in state %s\n", | 251 | for (t = state->transitions; t->events; t++) |
358 | event, object->events, object->event_mask, | 252 | event_mask |= t->events; |
359 | fscache_object_states[object->state]); | 253 | |
360 | BUG(); | 254 | unmask_events: |
255 | object->event_mask = event_mask; | ||
256 | smp_mb(); | ||
257 | events = object->events; | ||
258 | if (events & event_mask) | ||
259 | goto restart; | ||
260 | _leave(" [msk %lx]", event_mask); | ||
361 | } | 261 | } |
362 | 262 | ||
363 | /* | 263 | /* |
364 | * execute an object | 264 | * execute an object |
365 | */ | 265 | */ |
366 | void fscache_object_work_func(struct work_struct *work) | 266 | static void fscache_object_work_func(struct work_struct *work) |
367 | { | 267 | { |
368 | struct fscache_object *object = | 268 | struct fscache_object *object = |
369 | container_of(work, struct fscache_object, work); | 269 | container_of(work, struct fscache_object, work); |
@@ -372,14 +272,70 @@ void fscache_object_work_func(struct work_struct *work) | |||
372 | _enter("{OBJ%x}", object->debug_id); | 272 | _enter("{OBJ%x}", object->debug_id); |
373 | 273 | ||
374 | start = jiffies; | 274 | start = jiffies; |
375 | fscache_object_state_machine(object); | 275 | fscache_object_sm_dispatcher(object); |
376 | fscache_hist(fscache_objs_histogram, start); | 276 | fscache_hist(fscache_objs_histogram, start); |
377 | if (object->events & object->event_mask) | ||
378 | fscache_enqueue_object(object); | ||
379 | clear_bit(FSCACHE_OBJECT_EV_REQUEUE, &object->events); | ||
380 | fscache_put_object(object); | 277 | fscache_put_object(object); |
381 | } | 278 | } |
382 | EXPORT_SYMBOL(fscache_object_work_func); | 279 | |
280 | /** | ||
281 | * fscache_object_init - Initialise a cache object description | ||
282 | * @object: Object description | ||
283 | * @cookie: Cookie object will be attached to | ||
284 | * @cache: Cache in which backing object will be found | ||
285 | * | ||
286 | * Initialise a cache object description to its basic values. | ||
287 | * | ||
288 | * See Documentation/filesystems/caching/backend-api.txt for a complete | ||
289 | * description. | ||
290 | */ | ||
291 | void fscache_object_init(struct fscache_object *object, | ||
292 | struct fscache_cookie *cookie, | ||
293 | struct fscache_cache *cache) | ||
294 | { | ||
295 | const struct fscache_transition *t; | ||
296 | |||
297 | atomic_inc(&cache->object_count); | ||
298 | |||
299 | object->state = STATE(WAIT_FOR_INIT); | ||
300 | object->oob_table = fscache_osm_init_oob; | ||
301 | object->flags = 1 << FSCACHE_OBJECT_IS_LIVE; | ||
302 | spin_lock_init(&object->lock); | ||
303 | INIT_LIST_HEAD(&object->cache_link); | ||
304 | INIT_HLIST_NODE(&object->cookie_link); | ||
305 | INIT_WORK(&object->work, fscache_object_work_func); | ||
306 | INIT_LIST_HEAD(&object->dependents); | ||
307 | INIT_LIST_HEAD(&object->dep_link); | ||
308 | INIT_LIST_HEAD(&object->pending_ops); | ||
309 | object->n_children = 0; | ||
310 | object->n_ops = object->n_in_progress = object->n_exclusive = 0; | ||
311 | object->events = 0; | ||
312 | object->store_limit = 0; | ||
313 | object->store_limit_l = 0; | ||
314 | object->cache = cache; | ||
315 | object->cookie = cookie; | ||
316 | object->parent = NULL; | ||
317 | |||
318 | object->oob_event_mask = 0; | ||
319 | for (t = object->oob_table; t->events; t++) | ||
320 | object->oob_event_mask |= t->events; | ||
321 | object->event_mask = object->oob_event_mask; | ||
322 | for (t = object->state->transitions; t->events; t++) | ||
323 | object->event_mask |= t->events; | ||
324 | } | ||
325 | EXPORT_SYMBOL(fscache_object_init); | ||
326 | |||
327 | /* | ||
328 | * Abort object initialisation before we start it. | ||
329 | */ | ||
330 | static const struct fscache_state *fscache_abort_initialisation(struct fscache_object *object, | ||
331 | int event) | ||
332 | { | ||
333 | _enter("{OBJ%x},%d", object->debug_id, event); | ||
334 | |||
335 | object->oob_event_mask = 0; | ||
336 | fscache_dequeue_object(object); | ||
337 | return transit_to(KILL_OBJECT); | ||
338 | } | ||
383 | 339 | ||
384 | /* | 340 | /* |
385 | * initialise an object | 341 | * initialise an object |
@@ -387,130 +343,136 @@ EXPORT_SYMBOL(fscache_object_work_func); | |||
387 | * immediately to do a creation | 343 | * immediately to do a creation |
388 | * - we may need to start the process of creating a parent and we need to wait | 344 | * - we may need to start the process of creating a parent and we need to wait |
389 | * for the parent's lookup and creation to complete if it's not there yet | 345 | * for the parent's lookup and creation to complete if it's not there yet |
390 | * - an object's cookie is pinned until we clear FSCACHE_COOKIE_CREATING on the | ||
391 | * leaf-most cookies of the object and all its children | ||
392 | */ | 346 | */ |
393 | static void fscache_initialise_object(struct fscache_object *object) | 347 | static const struct fscache_state *fscache_initialise_object(struct fscache_object *object, |
348 | int event) | ||
394 | { | 349 | { |
395 | struct fscache_object *parent; | 350 | struct fscache_object *parent; |
351 | bool success; | ||
396 | 352 | ||
397 | _enter(""); | 353 | _enter("{OBJ%x},%d", object->debug_id, event); |
398 | ASSERT(object->cookie != NULL); | ||
399 | ASSERT(object->cookie->parent != NULL); | ||
400 | |||
401 | if (object->events & ((1 << FSCACHE_OBJECT_EV_ERROR) | | ||
402 | (1 << FSCACHE_OBJECT_EV_RELEASE) | | ||
403 | (1 << FSCACHE_OBJECT_EV_RETIRE) | | ||
404 | (1 << FSCACHE_OBJECT_EV_WITHDRAW))) { | ||
405 | _debug("abort init %lx", object->events); | ||
406 | spin_lock(&object->lock); | ||
407 | object->state = FSCACHE_OBJECT_ABORT_INIT; | ||
408 | spin_unlock(&object->lock); | ||
409 | return; | ||
410 | } | ||
411 | 354 | ||
412 | spin_lock(&object->cookie->lock); | 355 | ASSERT(list_empty(&object->dep_link)); |
413 | spin_lock_nested(&object->cookie->parent->lock, 1); | ||
414 | 356 | ||
415 | parent = object->parent; | 357 | parent = object->parent; |
416 | if (!parent) { | 358 | if (!parent) { |
417 | _debug("no parent"); | 359 | _leave(" [no parent]"); |
418 | set_bit(FSCACHE_OBJECT_EV_WITHDRAW, &object->events); | 360 | return transit_to(DROP_OBJECT); |
419 | } else { | 361 | } |
420 | spin_lock(&object->lock); | ||
421 | spin_lock_nested(&parent->lock, 1); | ||
422 | _debug("parent %s", fscache_object_states[parent->state]); | ||
423 | |||
424 | if (parent->state >= FSCACHE_OBJECT_DYING) { | ||
425 | _debug("bad parent"); | ||
426 | set_bit(FSCACHE_OBJECT_EV_WITHDRAW, &object->events); | ||
427 | } else if (parent->state < FSCACHE_OBJECT_AVAILABLE) { | ||
428 | _debug("wait"); | ||
429 | |||
430 | /* we may get woken up in this state by child objects | ||
431 | * binding on to us, so we need to make sure we don't | ||
432 | * add ourself to the list multiple times */ | ||
433 | if (list_empty(&object->dep_link)) { | ||
434 | fscache_stat(&fscache_n_cop_grab_object); | ||
435 | object->cache->ops->grab_object(object); | ||
436 | fscache_stat_d(&fscache_n_cop_grab_object); | ||
437 | list_add(&object->dep_link, | ||
438 | &parent->dependents); | ||
439 | |||
440 | /* fscache_acquire_non_index_cookie() uses this | ||
441 | * to wake the chain up */ | ||
442 | if (parent->state == FSCACHE_OBJECT_INIT) | ||
443 | fscache_enqueue_object(parent); | ||
444 | } | ||
445 | } else { | ||
446 | _debug("go"); | ||
447 | parent->n_ops++; | ||
448 | parent->n_obj_ops++; | ||
449 | object->lookup_jif = jiffies; | ||
450 | object->state = FSCACHE_OBJECT_LOOKING_UP; | ||
451 | set_bit(FSCACHE_OBJECT_EV_REQUEUE, &object->events); | ||
452 | } | ||
453 | 362 | ||
454 | spin_unlock(&parent->lock); | 363 | _debug("parent: %s of:%lx", parent->state->name, parent->flags); |
455 | spin_unlock(&object->lock); | 364 | |
365 | if (fscache_object_is_dying(parent)) { | ||
366 | _leave(" [bad parent]"); | ||
367 | return transit_to(DROP_OBJECT); | ||
456 | } | 368 | } |
457 | 369 | ||
458 | spin_unlock(&object->cookie->parent->lock); | 370 | if (fscache_object_is_available(parent)) { |
459 | spin_unlock(&object->cookie->lock); | 371 | _leave(" [ready]"); |
372 | return transit_to(PARENT_READY); | ||
373 | } | ||
374 | |||
375 | _debug("wait"); | ||
376 | |||
377 | spin_lock(&parent->lock); | ||
378 | fscache_stat(&fscache_n_cop_grab_object); | ||
379 | success = false; | ||
380 | if (fscache_object_is_live(parent) && | ||
381 | object->cache->ops->grab_object(object)) { | ||
382 | list_add(&object->dep_link, &parent->dependents); | ||
383 | success = true; | ||
384 | } | ||
385 | fscache_stat_d(&fscache_n_cop_grab_object); | ||
386 | spin_unlock(&parent->lock); | ||
387 | if (!success) { | ||
388 | _leave(" [grab failed]"); | ||
389 | return transit_to(DROP_OBJECT); | ||
390 | } | ||
391 | |||
392 | /* fscache_acquire_non_index_cookie() uses this | ||
393 | * to wake the chain up */ | ||
394 | fscache_raise_event(parent, FSCACHE_OBJECT_EV_NEW_CHILD); | ||
395 | _leave(" [wait]"); | ||
396 | return transit_to(WAIT_FOR_PARENT); | ||
397 | } | ||
398 | |||
399 | /* | ||
400 | * Once the parent object is ready, we should kick off our lookup op. | ||
401 | */ | ||
402 | static const struct fscache_state *fscache_parent_ready(struct fscache_object *object, | ||
403 | int event) | ||
404 | { | ||
405 | struct fscache_object *parent = object->parent; | ||
406 | |||
407 | _enter("{OBJ%x},%d", object->debug_id, event); | ||
408 | |||
409 | ASSERT(parent != NULL); | ||
410 | |||
411 | spin_lock(&parent->lock); | ||
412 | parent->n_ops++; | ||
413 | parent->n_obj_ops++; | ||
414 | object->lookup_jif = jiffies; | ||
415 | spin_unlock(&parent->lock); | ||
416 | |||
460 | _leave(""); | 417 | _leave(""); |
418 | return transit_to(LOOK_UP_OBJECT); | ||
461 | } | 419 | } |
462 | 420 | ||
463 | /* | 421 | /* |
464 | * look an object up in the cache from which it was allocated | 422 | * look an object up in the cache from which it was allocated |
465 | * - we hold an "access lock" on the parent object, so the parent object cannot | 423 | * - we hold an "access lock" on the parent object, so the parent object cannot |
466 | * be withdrawn by either party till we've finished | 424 | * be withdrawn by either party till we've finished |
467 | * - an object's cookie is pinned until we clear FSCACHE_COOKIE_CREATING on the | ||
468 | * leaf-most cookies of the object and all its children | ||
469 | */ | 425 | */ |
470 | static void fscache_lookup_object(struct fscache_object *object) | 426 | static const struct fscache_state *fscache_look_up_object(struct fscache_object *object, |
427 | int event) | ||
471 | { | 428 | { |
472 | struct fscache_cookie *cookie = object->cookie; | 429 | struct fscache_cookie *cookie = object->cookie; |
473 | struct fscache_object *parent; | 430 | struct fscache_object *parent = object->parent; |
474 | int ret; | 431 | int ret; |
475 | 432 | ||
476 | _enter(""); | 433 | _enter("{OBJ%x},%d", object->debug_id, event); |
434 | |||
435 | object->oob_table = fscache_osm_lookup_oob; | ||
477 | 436 | ||
478 | parent = object->parent; | ||
479 | ASSERT(parent != NULL); | 437 | ASSERT(parent != NULL); |
480 | ASSERTCMP(parent->n_ops, >, 0); | 438 | ASSERTCMP(parent->n_ops, >, 0); |
481 | ASSERTCMP(parent->n_obj_ops, >, 0); | 439 | ASSERTCMP(parent->n_obj_ops, >, 0); |
482 | 440 | ||
483 | /* make sure the parent is still available */ | 441 | /* make sure the parent is still available */ |
484 | ASSERTCMP(parent->state, >=, FSCACHE_OBJECT_AVAILABLE); | 442 | ASSERT(fscache_object_is_available(parent)); |
485 | 443 | ||
486 | if (parent->state >= FSCACHE_OBJECT_DYING || | 444 | if (fscache_object_is_dying(parent) || |
487 | test_bit(FSCACHE_IOERROR, &object->cache->flags)) { | 445 | test_bit(FSCACHE_IOERROR, &object->cache->flags) || |
488 | _debug("unavailable"); | 446 | !fscache_use_cookie(object)) { |
489 | set_bit(FSCACHE_OBJECT_EV_WITHDRAW, &object->events); | 447 | _leave(" [unavailable]"); |
490 | _leave(""); | 448 | return transit_to(LOOKUP_FAILURE); |
491 | return; | ||
492 | } | 449 | } |
493 | 450 | ||
494 | _debug("LOOKUP \"%s/%s\" in \"%s\"", | 451 | _debug("LOOKUP \"%s\" in \"%s\"", |
495 | parent->cookie->def->name, cookie->def->name, | 452 | cookie->def->name, object->cache->tag->name); |
496 | object->cache->tag->name); | ||
497 | 453 | ||
498 | fscache_stat(&fscache_n_object_lookups); | 454 | fscache_stat(&fscache_n_object_lookups); |
499 | fscache_stat(&fscache_n_cop_lookup_object); | 455 | fscache_stat(&fscache_n_cop_lookup_object); |
500 | ret = object->cache->ops->lookup_object(object); | 456 | ret = object->cache->ops->lookup_object(object); |
501 | fscache_stat_d(&fscache_n_cop_lookup_object); | 457 | fscache_stat_d(&fscache_n_cop_lookup_object); |
502 | 458 | ||
503 | if (test_bit(FSCACHE_OBJECT_EV_ERROR, &object->events)) | 459 | fscache_unuse_cookie(object); |
504 | set_bit(FSCACHE_COOKIE_UNAVAILABLE, &cookie->flags); | ||
505 | 460 | ||
506 | if (ret == -ETIMEDOUT) { | 461 | if (ret == -ETIMEDOUT) { |
507 | /* probably stuck behind another object, so move this one to | 462 | /* probably stuck behind another object, so move this one to |
508 | * the back of the queue */ | 463 | * the back of the queue */ |
509 | fscache_stat(&fscache_n_object_lookups_timed_out); | 464 | fscache_stat(&fscache_n_object_lookups_timed_out); |
510 | set_bit(FSCACHE_OBJECT_EV_REQUEUE, &object->events); | 465 | _leave(" [timeout]"); |
466 | return NO_TRANSIT; | ||
511 | } | 467 | } |
512 | 468 | ||
513 | _leave(""); | 469 | if (ret < 0) { |
470 | _leave(" [error]"); | ||
471 | return transit_to(LOOKUP_FAILURE); | ||
472 | } | ||
473 | |||
474 | _leave(" [ok]"); | ||
475 | return transit_to(OBJECT_AVAILABLE); | ||
514 | } | 476 | } |
515 | 477 | ||
516 | /** | 478 | /** |
@@ -524,32 +486,20 @@ void fscache_object_lookup_negative(struct fscache_object *object) | |||
524 | { | 486 | { |
525 | struct fscache_cookie *cookie = object->cookie; | 487 | struct fscache_cookie *cookie = object->cookie; |
526 | 488 | ||
527 | _enter("{OBJ%x,%s}", | 489 | _enter("{OBJ%x,%s}", object->debug_id, object->state->name); |
528 | object->debug_id, fscache_object_states[object->state]); | ||
529 | 490 | ||
530 | spin_lock(&object->lock); | 491 | if (!test_and_set_bit(FSCACHE_OBJECT_IS_LOOKED_UP, &object->flags)) { |
531 | if (object->state == FSCACHE_OBJECT_LOOKING_UP) { | ||
532 | fscache_stat(&fscache_n_object_lookups_negative); | 492 | fscache_stat(&fscache_n_object_lookups_negative); |
533 | 493 | ||
534 | /* transit here to allow write requests to begin stacking up | 494 | /* Allow write requests to begin stacking up and read requests to begin |
535 | * and read requests to begin returning ENODATA */ | 495 | * returning ENODATA. |
536 | object->state = FSCACHE_OBJECT_CREATING; | 496 | */ |
537 | spin_unlock(&object->lock); | ||
538 | |||
539 | set_bit(FSCACHE_COOKIE_PENDING_FILL, &cookie->flags); | ||
540 | set_bit(FSCACHE_COOKIE_NO_DATA_YET, &cookie->flags); | 497 | set_bit(FSCACHE_COOKIE_NO_DATA_YET, &cookie->flags); |
541 | 498 | ||
542 | _debug("wake up lookup %p", &cookie->flags); | 499 | _debug("wake up lookup %p", &cookie->flags); |
543 | smp_mb__before_clear_bit(); | 500 | clear_bit_unlock(FSCACHE_COOKIE_LOOKING_UP, &cookie->flags); |
544 | clear_bit(FSCACHE_COOKIE_LOOKING_UP, &cookie->flags); | ||
545 | smp_mb__after_clear_bit(); | ||
546 | wake_up_bit(&cookie->flags, FSCACHE_COOKIE_LOOKING_UP); | 501 | wake_up_bit(&cookie->flags, FSCACHE_COOKIE_LOOKING_UP); |
547 | set_bit(FSCACHE_OBJECT_EV_REQUEUE, &object->events); | ||
548 | } else { | ||
549 | ASSERTCMP(object->state, ==, FSCACHE_OBJECT_CREATING); | ||
550 | spin_unlock(&object->lock); | ||
551 | } | 502 | } |
552 | |||
553 | _leave(""); | 503 | _leave(""); |
554 | } | 504 | } |
555 | EXPORT_SYMBOL(fscache_object_lookup_negative); | 505 | EXPORT_SYMBOL(fscache_object_lookup_negative); |
@@ -568,38 +518,26 @@ void fscache_obtained_object(struct fscache_object *object) | |||
568 | { | 518 | { |
569 | struct fscache_cookie *cookie = object->cookie; | 519 | struct fscache_cookie *cookie = object->cookie; |
570 | 520 | ||
571 | _enter("{OBJ%x,%s}", | 521 | _enter("{OBJ%x,%s}", object->debug_id, object->state->name); |
572 | object->debug_id, fscache_object_states[object->state]); | ||
573 | 522 | ||
574 | /* if we were still looking up, then we must have a positive lookup | 523 | /* if we were still looking up, then we must have a positive lookup |
575 | * result, in which case there may be data available */ | 524 | * result, in which case there may be data available */ |
576 | spin_lock(&object->lock); | 525 | if (!test_and_set_bit(FSCACHE_OBJECT_IS_LOOKED_UP, &object->flags)) { |
577 | if (object->state == FSCACHE_OBJECT_LOOKING_UP) { | ||
578 | fscache_stat(&fscache_n_object_lookups_positive); | 526 | fscache_stat(&fscache_n_object_lookups_positive); |
579 | 527 | ||
580 | clear_bit(FSCACHE_COOKIE_NO_DATA_YET, &cookie->flags); | 528 | /* We do (presumably) have data */ |
529 | clear_bit_unlock(FSCACHE_COOKIE_NO_DATA_YET, &cookie->flags); | ||
581 | 530 | ||
582 | object->state = FSCACHE_OBJECT_AVAILABLE; | 531 | /* Allow write requests to begin stacking up and read requests |
583 | spin_unlock(&object->lock); | 532 | * to begin shovelling data. |
584 | 533 | */ | |
585 | smp_mb__before_clear_bit(); | 534 | clear_bit_unlock(FSCACHE_COOKIE_LOOKING_UP, &cookie->flags); |
586 | clear_bit(FSCACHE_COOKIE_LOOKING_UP, &cookie->flags); | ||
587 | smp_mb__after_clear_bit(); | ||
588 | wake_up_bit(&cookie->flags, FSCACHE_COOKIE_LOOKING_UP); | 535 | wake_up_bit(&cookie->flags, FSCACHE_COOKIE_LOOKING_UP); |
589 | set_bit(FSCACHE_OBJECT_EV_REQUEUE, &object->events); | ||
590 | } else { | 536 | } else { |
591 | ASSERTCMP(object->state, ==, FSCACHE_OBJECT_CREATING); | ||
592 | fscache_stat(&fscache_n_object_created); | 537 | fscache_stat(&fscache_n_object_created); |
593 | |||
594 | object->state = FSCACHE_OBJECT_AVAILABLE; | ||
595 | spin_unlock(&object->lock); | ||
596 | set_bit(FSCACHE_OBJECT_EV_REQUEUE, &object->events); | ||
597 | smp_wmb(); | ||
598 | } | 538 | } |
599 | 539 | ||
600 | if (test_and_clear_bit(FSCACHE_COOKIE_CREATING, &cookie->flags)) | 540 | set_bit(FSCACHE_OBJECT_IS_AVAILABLE, &object->flags); |
601 | wake_up_bit(&cookie->flags, FSCACHE_COOKIE_CREATING); | ||
602 | |||
603 | _leave(""); | 541 | _leave(""); |
604 | } | 542 | } |
605 | EXPORT_SYMBOL(fscache_obtained_object); | 543 | EXPORT_SYMBOL(fscache_obtained_object); |
@@ -607,15 +545,14 @@ EXPORT_SYMBOL(fscache_obtained_object); | |||
607 | /* | 545 | /* |
608 | * handle an object that has just become available | 546 | * handle an object that has just become available |
609 | */ | 547 | */ |
610 | static void fscache_object_available(struct fscache_object *object) | 548 | static const struct fscache_state *fscache_object_available(struct fscache_object *object, |
549 | int event) | ||
611 | { | 550 | { |
612 | _enter("{OBJ%x}", object->debug_id); | 551 | _enter("{OBJ%x},%d", object->debug_id, event); |
613 | 552 | ||
614 | spin_lock(&object->lock); | 553 | object->oob_table = fscache_osm_run_oob; |
615 | 554 | ||
616 | if (object->cookie && | 555 | spin_lock(&object->lock); |
617 | test_and_clear_bit(FSCACHE_COOKIE_CREATING, &object->cookie->flags)) | ||
618 | wake_up_bit(&object->cookie->flags, FSCACHE_COOKIE_CREATING); | ||
619 | 556 | ||
620 | fscache_done_parent_op(object); | 557 | fscache_done_parent_op(object); |
621 | if (object->n_in_progress == 0) { | 558 | if (object->n_in_progress == 0) { |
@@ -631,130 +568,158 @@ static void fscache_object_available(struct fscache_object *object) | |||
631 | fscache_stat(&fscache_n_cop_lookup_complete); | 568 | fscache_stat(&fscache_n_cop_lookup_complete); |
632 | object->cache->ops->lookup_complete(object); | 569 | object->cache->ops->lookup_complete(object); |
633 | fscache_stat_d(&fscache_n_cop_lookup_complete); | 570 | fscache_stat_d(&fscache_n_cop_lookup_complete); |
634 | fscache_enqueue_dependents(object); | ||
635 | 571 | ||
636 | fscache_hist(fscache_obj_instantiate_histogram, object->lookup_jif); | 572 | fscache_hist(fscache_obj_instantiate_histogram, object->lookup_jif); |
637 | fscache_stat(&fscache_n_object_avail); | 573 | fscache_stat(&fscache_n_object_avail); |
638 | 574 | ||
639 | _leave(""); | 575 | _leave(""); |
576 | return transit_to(JUMPSTART_DEPS); | ||
640 | } | 577 | } |
641 | 578 | ||
642 | /* | 579 | /* |
643 | * drop an object's attachments | 580 | * Wake up this object's dependent objects now that we've become available. |
644 | */ | 581 | */ |
645 | static void fscache_drop_object(struct fscache_object *object) | 582 | static const struct fscache_state *fscache_jumpstart_dependents(struct fscache_object *object, |
583 | int event) | ||
646 | { | 584 | { |
647 | struct fscache_object *parent = object->parent; | 585 | _enter("{OBJ%x},%d", object->debug_id, event); |
648 | struct fscache_cache *cache = object->cache; | ||
649 | 586 | ||
650 | _enter("{OBJ%x,%d}", object->debug_id, object->n_children); | 587 | if (!fscache_enqueue_dependents(object, FSCACHE_OBJECT_EV_PARENT_READY)) |
588 | return NO_TRANSIT; /* Not finished; requeue */ | ||
589 | return transit_to(WAIT_FOR_CMD); | ||
590 | } | ||
651 | 591 | ||
652 | ASSERTCMP(object->cookie, ==, NULL); | 592 | /* |
653 | ASSERT(hlist_unhashed(&object->cookie_link)); | 593 | * Handle lookup or creation failute. |
594 | */ | ||
595 | static const struct fscache_state *fscache_lookup_failure(struct fscache_object *object, | ||
596 | int event) | ||
597 | { | ||
598 | struct fscache_cookie *cookie; | ||
654 | 599 | ||
655 | spin_lock(&cache->object_list_lock); | 600 | _enter("{OBJ%x},%d", object->debug_id, event); |
656 | list_del_init(&object->cache_link); | ||
657 | spin_unlock(&cache->object_list_lock); | ||
658 | 601 | ||
659 | fscache_stat(&fscache_n_cop_drop_object); | 602 | object->oob_event_mask = 0; |
660 | cache->ops->drop_object(object); | ||
661 | fscache_stat_d(&fscache_n_cop_drop_object); | ||
662 | 603 | ||
663 | if (parent) { | 604 | fscache_stat(&fscache_n_cop_lookup_complete); |
664 | _debug("release parent OBJ%x {%d}", | 605 | object->cache->ops->lookup_complete(object); |
665 | parent->debug_id, parent->n_children); | 606 | fscache_stat_d(&fscache_n_cop_lookup_complete); |
666 | 607 | ||
667 | spin_lock(&parent->lock); | 608 | cookie = object->cookie; |
668 | parent->n_children--; | 609 | set_bit(FSCACHE_COOKIE_UNAVAILABLE, &cookie->flags); |
669 | if (parent->n_children == 0) | 610 | if (test_and_clear_bit(FSCACHE_COOKIE_LOOKING_UP, &cookie->flags)) |
670 | fscache_raise_event(parent, FSCACHE_OBJECT_EV_CLEARED); | 611 | wake_up_bit(&cookie->flags, FSCACHE_COOKIE_LOOKING_UP); |
671 | spin_unlock(&parent->lock); | 612 | |
672 | object->parent = NULL; | 613 | fscache_done_parent_op(object); |
614 | return transit_to(KILL_OBJECT); | ||
615 | } | ||
616 | |||
617 | /* | ||
618 | * Wait for completion of all active operations on this object and the death of | ||
619 | * all child objects of this object. | ||
620 | */ | ||
621 | static const struct fscache_state *fscache_kill_object(struct fscache_object *object, | ||
622 | int event) | ||
623 | { | ||
624 | _enter("{OBJ%x,%d,%d},%d", | ||
625 | object->debug_id, object->n_ops, object->n_children, event); | ||
626 | |||
627 | clear_bit(FSCACHE_OBJECT_IS_LIVE, &object->flags); | ||
628 | object->oob_event_mask = 0; | ||
629 | |||
630 | if (list_empty(&object->dependents) && | ||
631 | object->n_ops == 0 && | ||
632 | object->n_children == 0) | ||
633 | return transit_to(DROP_OBJECT); | ||
634 | |||
635 | if (object->n_in_progress == 0) { | ||
636 | spin_lock(&object->lock); | ||
637 | if (object->n_ops > 0 && object->n_in_progress == 0) | ||
638 | fscache_start_operations(object); | ||
639 | spin_unlock(&object->lock); | ||
673 | } | 640 | } |
674 | 641 | ||
675 | /* this just shifts the object release to the work processor */ | 642 | if (!list_empty(&object->dependents)) |
676 | fscache_put_object(object); | 643 | return transit_to(KILL_DEPENDENTS); |
677 | 644 | ||
678 | _leave(""); | 645 | return transit_to(WAIT_FOR_CLEARANCE); |
679 | } | 646 | } |
680 | 647 | ||
681 | /* | 648 | /* |
682 | * release or recycle an object that the netfs has discarded | 649 | * Kill dependent objects. |
683 | */ | 650 | */ |
684 | static void fscache_release_object(struct fscache_object *object) | 651 | static const struct fscache_state *fscache_kill_dependents(struct fscache_object *object, |
652 | int event) | ||
685 | { | 653 | { |
686 | _enter(""); | 654 | _enter("{OBJ%x},%d", object->debug_id, event); |
687 | 655 | ||
688 | fscache_drop_object(object); | 656 | if (!fscache_enqueue_dependents(object, FSCACHE_OBJECT_EV_KILL)) |
657 | return NO_TRANSIT; /* Not finished */ | ||
658 | return transit_to(WAIT_FOR_CLEARANCE); | ||
689 | } | 659 | } |
690 | 660 | ||
691 | /* | 661 | /* |
692 | * withdraw an object from active service | 662 | * Drop an object's attachments |
693 | */ | 663 | */ |
694 | static void fscache_withdraw_object(struct fscache_object *object) | 664 | static const struct fscache_state *fscache_drop_object(struct fscache_object *object, |
665 | int event) | ||
695 | { | 666 | { |
696 | struct fscache_cookie *cookie; | 667 | struct fscache_object *parent = object->parent; |
697 | bool detached; | 668 | struct fscache_cookie *cookie = object->cookie; |
669 | struct fscache_cache *cache = object->cache; | ||
670 | bool awaken = false; | ||
698 | 671 | ||
699 | _enter(""); | 672 | _enter("{OBJ%x,%d},%d", object->debug_id, object->n_children, event); |
700 | 673 | ||
701 | spin_lock(&object->lock); | 674 | ASSERT(cookie != NULL); |
702 | cookie = object->cookie; | 675 | ASSERT(!hlist_unhashed(&object->cookie_link)); |
703 | if (cookie) { | ||
704 | /* need to get the cookie lock before the object lock, starting | ||
705 | * from the object pointer */ | ||
706 | atomic_inc(&cookie->usage); | ||
707 | spin_unlock(&object->lock); | ||
708 | 676 | ||
709 | detached = false; | 677 | /* Make sure the cookie no longer points here and that the netfs isn't |
710 | spin_lock(&cookie->lock); | 678 | * waiting for us. |
711 | spin_lock(&object->lock); | 679 | */ |
680 | spin_lock(&cookie->lock); | ||
681 | hlist_del_init(&object->cookie_link); | ||
682 | if (test_and_clear_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags)) | ||
683 | awaken = true; | ||
684 | spin_unlock(&cookie->lock); | ||
712 | 685 | ||
713 | if (object->cookie == cookie) { | 686 | if (awaken) |
714 | hlist_del_init(&object->cookie_link); | 687 | wake_up_bit(&cookie->flags, FSCACHE_COOKIE_INVALIDATING); |
715 | object->cookie = NULL; | ||
716 | fscache_invalidation_complete(cookie); | ||
717 | detached = true; | ||
718 | } | ||
719 | spin_unlock(&cookie->lock); | ||
720 | fscache_cookie_put(cookie); | ||
721 | if (detached) | ||
722 | fscache_cookie_put(cookie); | ||
723 | } | ||
724 | 688 | ||
689 | /* Prevent a race with our last child, which has to signal EV_CLEARED | ||
690 | * before dropping our spinlock. | ||
691 | */ | ||
692 | spin_lock(&object->lock); | ||
725 | spin_unlock(&object->lock); | 693 | spin_unlock(&object->lock); |
726 | 694 | ||
727 | fscache_drop_object(object); | 695 | /* Discard from the cache's collection of objects */ |
728 | } | 696 | spin_lock(&cache->object_list_lock); |
697 | list_del_init(&object->cache_link); | ||
698 | spin_unlock(&cache->object_list_lock); | ||
729 | 699 | ||
730 | /* | 700 | fscache_stat(&fscache_n_cop_drop_object); |
731 | * withdraw an object from active service at the behest of the cache | 701 | cache->ops->drop_object(object); |
732 | * - need break the links to a cached object cookie | 702 | fscache_stat_d(&fscache_n_cop_drop_object); |
733 | * - called under two situations: | ||
734 | * (1) recycler decides to reclaim an in-use object | ||
735 | * (2) a cache is unmounted | ||
736 | * - have to take care as the cookie can be being relinquished by the netfs | ||
737 | * simultaneously | ||
738 | * - the object is pinned by the caller holding a refcount on it | ||
739 | */ | ||
740 | void fscache_withdrawing_object(struct fscache_cache *cache, | ||
741 | struct fscache_object *object) | ||
742 | { | ||
743 | bool enqueue = false; | ||
744 | 703 | ||
745 | _enter(",OBJ%x", object->debug_id); | 704 | /* The parent object wants to know when all it dependents have gone */ |
705 | if (parent) { | ||
706 | _debug("release parent OBJ%x {%d}", | ||
707 | parent->debug_id, parent->n_children); | ||
746 | 708 | ||
747 | spin_lock(&object->lock); | 709 | spin_lock(&parent->lock); |
748 | if (object->state < FSCACHE_OBJECT_WITHDRAWING) { | 710 | parent->n_children--; |
749 | object->state = FSCACHE_OBJECT_WITHDRAWING; | 711 | if (parent->n_children == 0) |
750 | enqueue = true; | 712 | fscache_raise_event(parent, FSCACHE_OBJECT_EV_CLEARED); |
713 | spin_unlock(&parent->lock); | ||
714 | object->parent = NULL; | ||
751 | } | 715 | } |
752 | spin_unlock(&object->lock); | ||
753 | 716 | ||
754 | if (enqueue) | 717 | /* this just shifts the object release to the work processor */ |
755 | fscache_enqueue_object(object); | 718 | fscache_put_object(object); |
719 | fscache_stat(&fscache_n_object_dead); | ||
756 | 720 | ||
757 | _leave(""); | 721 | _leave(""); |
722 | return transit_to(OBJECT_DEAD); | ||
758 | } | 723 | } |
759 | 724 | ||
760 | /* | 725 | /* |
@@ -771,7 +736,7 @@ static int fscache_get_object(struct fscache_object *object) | |||
771 | } | 736 | } |
772 | 737 | ||
773 | /* | 738 | /* |
774 | * discard a ref on a work item | 739 | * Discard a ref on an object |
775 | */ | 740 | */ |
776 | static void fscache_put_object(struct fscache_object *object) | 741 | static void fscache_put_object(struct fscache_object *object) |
777 | { | 742 | { |
@@ -780,6 +745,22 @@ static void fscache_put_object(struct fscache_object *object) | |||
780 | fscache_stat_d(&fscache_n_cop_put_object); | 745 | fscache_stat_d(&fscache_n_cop_put_object); |
781 | } | 746 | } |
782 | 747 | ||
748 | /** | ||
749 | * fscache_object_destroy - Note that a cache object is about to be destroyed | ||
750 | * @object: The object to be destroyed | ||
751 | * | ||
752 | * Note the imminent destruction and deallocation of a cache object record. | ||
753 | */ | ||
754 | void fscache_object_destroy(struct fscache_object *object) | ||
755 | { | ||
756 | fscache_objlist_remove(object); | ||
757 | |||
758 | /* We can get rid of the cookie now */ | ||
759 | fscache_cookie_put(object->cookie); | ||
760 | object->cookie = NULL; | ||
761 | } | ||
762 | EXPORT_SYMBOL(fscache_object_destroy); | ||
763 | |||
783 | /* | 764 | /* |
784 | * enqueue an object for metadata-type processing | 765 | * enqueue an object for metadata-type processing |
785 | */ | 766 | */ |
@@ -803,7 +784,7 @@ void fscache_enqueue_object(struct fscache_object *object) | |||
803 | 784 | ||
804 | /** | 785 | /** |
805 | * fscache_object_sleep_till_congested - Sleep until object wq is congested | 786 | * fscache_object_sleep_till_congested - Sleep until object wq is congested |
806 | * @timoutp: Scheduler sleep timeout | 787 | * @timeoutp: Scheduler sleep timeout |
807 | * | 788 | * |
808 | * Allow an object handler to sleep until the object workqueue is congested. | 789 | * Allow an object handler to sleep until the object workqueue is congested. |
809 | * | 790 | * |
@@ -831,18 +812,21 @@ bool fscache_object_sleep_till_congested(signed long *timeoutp) | |||
831 | EXPORT_SYMBOL_GPL(fscache_object_sleep_till_congested); | 812 | EXPORT_SYMBOL_GPL(fscache_object_sleep_till_congested); |
832 | 813 | ||
833 | /* | 814 | /* |
834 | * enqueue the dependents of an object for metadata-type processing | 815 | * Enqueue the dependents of an object for metadata-type processing. |
835 | * - the caller must hold the object's lock | 816 | * |
836 | * - this may cause an already locked object to wind up being processed again | 817 | * If we don't manage to finish the list before the scheduler wants to run |
818 | * again then return false immediately. We return true if the list was | ||
819 | * cleared. | ||
837 | */ | 820 | */ |
838 | static void fscache_enqueue_dependents(struct fscache_object *object) | 821 | static bool fscache_enqueue_dependents(struct fscache_object *object, int event) |
839 | { | 822 | { |
840 | struct fscache_object *dep; | 823 | struct fscache_object *dep; |
824 | bool ret = true; | ||
841 | 825 | ||
842 | _enter("{OBJ%x}", object->debug_id); | 826 | _enter("{OBJ%x}", object->debug_id); |
843 | 827 | ||
844 | if (list_empty(&object->dependents)) | 828 | if (list_empty(&object->dependents)) |
845 | return; | 829 | return true; |
846 | 830 | ||
847 | spin_lock(&object->lock); | 831 | spin_lock(&object->lock); |
848 | 832 | ||
@@ -851,23 +835,23 @@ static void fscache_enqueue_dependents(struct fscache_object *object) | |||
851 | struct fscache_object, dep_link); | 835 | struct fscache_object, dep_link); |
852 | list_del_init(&dep->dep_link); | 836 | list_del_init(&dep->dep_link); |
853 | 837 | ||
854 | 838 | fscache_raise_event(dep, event); | |
855 | /* sort onto appropriate lists */ | ||
856 | fscache_enqueue_object(dep); | ||
857 | fscache_put_object(dep); | 839 | fscache_put_object(dep); |
858 | 840 | ||
859 | if (!list_empty(&object->dependents)) | 841 | if (!list_empty(&object->dependents) && need_resched()) { |
860 | cond_resched_lock(&object->lock); | 842 | ret = false; |
843 | break; | ||
844 | } | ||
861 | } | 845 | } |
862 | 846 | ||
863 | spin_unlock(&object->lock); | 847 | spin_unlock(&object->lock); |
848 | return ret; | ||
864 | } | 849 | } |
865 | 850 | ||
866 | /* | 851 | /* |
867 | * remove an object from whatever queue it's waiting on | 852 | * remove an object from whatever queue it's waiting on |
868 | * - the caller must hold object->lock | ||
869 | */ | 853 | */ |
870 | void fscache_dequeue_object(struct fscache_object *object) | 854 | static void fscache_dequeue_object(struct fscache_object *object) |
871 | { | 855 | { |
872 | _enter("{OBJ%x}", object->debug_id); | 856 | _enter("{OBJ%x}", object->debug_id); |
873 | 857 | ||
@@ -886,7 +870,10 @@ void fscache_dequeue_object(struct fscache_object *object) | |||
886 | * @data: The auxiliary data for the object | 870 | * @data: The auxiliary data for the object |
887 | * @datalen: The size of the auxiliary data | 871 | * @datalen: The size of the auxiliary data |
888 | * | 872 | * |
889 | * This function consults the netfs about the coherency state of an object | 873 | * This function consults the netfs about the coherency state of an object. |
874 | * The caller must be holding a ref on cookie->n_active (held by | ||
875 | * fscache_look_up_object() on behalf of the cache backend during object lookup | ||
876 | * and creation). | ||
890 | */ | 877 | */ |
891 | enum fscache_checkaux fscache_check_aux(struct fscache_object *object, | 878 | enum fscache_checkaux fscache_check_aux(struct fscache_object *object, |
892 | const void *data, uint16_t datalen) | 879 | const void *data, uint16_t datalen) |
@@ -927,12 +914,23 @@ EXPORT_SYMBOL(fscache_check_aux); | |||
927 | /* | 914 | /* |
928 | * Asynchronously invalidate an object. | 915 | * Asynchronously invalidate an object. |
929 | */ | 916 | */ |
930 | static void fscache_invalidate_object(struct fscache_object *object) | 917 | static const struct fscache_state *_fscache_invalidate_object(struct fscache_object *object, |
918 | int event) | ||
931 | { | 919 | { |
932 | struct fscache_operation *op; | 920 | struct fscache_operation *op; |
933 | struct fscache_cookie *cookie = object->cookie; | 921 | struct fscache_cookie *cookie = object->cookie; |
934 | 922 | ||
935 | _enter("{OBJ%x}", object->debug_id); | 923 | _enter("{OBJ%x},%d", object->debug_id, event); |
924 | |||
925 | /* We're going to need the cookie. If the cookie is not available then | ||
926 | * retire the object instead. | ||
927 | */ | ||
928 | if (!fscache_use_cookie(object)) { | ||
929 | ASSERT(object->cookie->stores.rnode == NULL); | ||
930 | set_bit(FSCACHE_COOKIE_RETIRED, &cookie->flags); | ||
931 | _leave(" [no cookie]"); | ||
932 | return transit_to(KILL_OBJECT); | ||
933 | } | ||
936 | 934 | ||
937 | /* Reject any new read/write ops and abort any that are pending. */ | 935 | /* Reject any new read/write ops and abort any that are pending. */ |
938 | fscache_invalidate_writes(cookie); | 936 | fscache_invalidate_writes(cookie); |
@@ -941,14 +939,13 @@ static void fscache_invalidate_object(struct fscache_object *object) | |||
941 | 939 | ||
942 | /* Now we have to wait for in-progress reads and writes */ | 940 | /* Now we have to wait for in-progress reads and writes */ |
943 | op = kzalloc(sizeof(*op), GFP_KERNEL); | 941 | op = kzalloc(sizeof(*op), GFP_KERNEL); |
944 | if (!op) { | 942 | if (!op) |
945 | fscache_raise_event(object, FSCACHE_OBJECT_EV_ERROR); | 943 | goto nomem; |
946 | _leave(" [ENOMEM]"); | ||
947 | return; | ||
948 | } | ||
949 | 944 | ||
950 | fscache_operation_init(op, object->cache->ops->invalidate_object, NULL); | 945 | fscache_operation_init(op, object->cache->ops->invalidate_object, NULL); |
951 | op->flags = FSCACHE_OP_ASYNC | (1 << FSCACHE_OP_EXCLUSIVE); | 946 | op->flags = FSCACHE_OP_ASYNC | |
947 | (1 << FSCACHE_OP_EXCLUSIVE) | | ||
948 | (1 << FSCACHE_OP_UNUSE_COOKIE); | ||
952 | 949 | ||
953 | spin_lock(&cookie->lock); | 950 | spin_lock(&cookie->lock); |
954 | if (fscache_submit_exclusive_op(object, op) < 0) | 951 | if (fscache_submit_exclusive_op(object, op) < 0) |
@@ -965,13 +962,50 @@ static void fscache_invalidate_object(struct fscache_object *object) | |||
965 | /* We can allow read and write requests to come in once again. They'll | 962 | /* We can allow read and write requests to come in once again. They'll |
966 | * queue up behind our exclusive invalidation operation. | 963 | * queue up behind our exclusive invalidation operation. |
967 | */ | 964 | */ |
968 | fscache_invalidation_complete(cookie); | 965 | if (test_and_clear_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags)) |
969 | _leave(""); | 966 | wake_up_bit(&cookie->flags, FSCACHE_COOKIE_INVALIDATING); |
970 | return; | 967 | _leave(" [ok]"); |
968 | return transit_to(UPDATE_OBJECT); | ||
969 | |||
970 | nomem: | ||
971 | clear_bit(FSCACHE_OBJECT_IS_LIVE, &object->flags); | ||
972 | fscache_unuse_cookie(object); | ||
973 | _leave(" [ENOMEM]"); | ||
974 | return transit_to(KILL_OBJECT); | ||
971 | 975 | ||
972 | submit_op_failed: | 976 | submit_op_failed: |
977 | clear_bit(FSCACHE_OBJECT_IS_LIVE, &object->flags); | ||
973 | spin_unlock(&cookie->lock); | 978 | spin_unlock(&cookie->lock); |
974 | kfree(op); | 979 | kfree(op); |
975 | fscache_raise_event(object, FSCACHE_OBJECT_EV_ERROR); | ||
976 | _leave(" [EIO]"); | 980 | _leave(" [EIO]"); |
981 | return transit_to(KILL_OBJECT); | ||
982 | } | ||
983 | |||
984 | static const struct fscache_state *fscache_invalidate_object(struct fscache_object *object, | ||
985 | int event) | ||
986 | { | ||
987 | const struct fscache_state *s; | ||
988 | |||
989 | fscache_stat(&fscache_n_invalidates_run); | ||
990 | fscache_stat(&fscache_n_cop_invalidate_object); | ||
991 | s = _fscache_invalidate_object(object, event); | ||
992 | fscache_stat_d(&fscache_n_cop_invalidate_object); | ||
993 | return s; | ||
994 | } | ||
995 | |||
996 | /* | ||
997 | * Asynchronously update an object. | ||
998 | */ | ||
999 | static const struct fscache_state *fscache_update_object(struct fscache_object *object, | ||
1000 | int event) | ||
1001 | { | ||
1002 | _enter("{OBJ%x},%d", object->debug_id, event); | ||
1003 | |||
1004 | fscache_stat(&fscache_n_updates_run); | ||
1005 | fscache_stat(&fscache_n_cop_update_object); | ||
1006 | object->cache->ops->update_object(object); | ||
1007 | fscache_stat_d(&fscache_n_cop_update_object); | ||
1008 | |||
1009 | _leave(""); | ||
1010 | return transit_to(WAIT_FOR_CMD); | ||
977 | } | 1011 | } |
diff --git a/fs/fscache/operation.c b/fs/fscache/operation.c index 762a9ec4ffa4..318071aca217 100644 --- a/fs/fscache/operation.c +++ b/fs/fscache/operation.c | |||
@@ -35,7 +35,7 @@ void fscache_enqueue_operation(struct fscache_operation *op) | |||
35 | 35 | ||
36 | ASSERT(list_empty(&op->pend_link)); | 36 | ASSERT(list_empty(&op->pend_link)); |
37 | ASSERT(op->processor != NULL); | 37 | ASSERT(op->processor != NULL); |
38 | ASSERTCMP(op->object->state, >=, FSCACHE_OBJECT_AVAILABLE); | 38 | ASSERT(fscache_object_is_available(op->object)); |
39 | ASSERTCMP(atomic_read(&op->usage), >, 0); | 39 | ASSERTCMP(atomic_read(&op->usage), >, 0); |
40 | ASSERTCMP(op->state, ==, FSCACHE_OP_ST_IN_PROGRESS); | 40 | ASSERTCMP(op->state, ==, FSCACHE_OP_ST_IN_PROGRESS); |
41 | 41 | ||
@@ -119,7 +119,7 @@ int fscache_submit_exclusive_op(struct fscache_object *object, | |||
119 | /* need to issue a new write op after this */ | 119 | /* need to issue a new write op after this */ |
120 | clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags); | 120 | clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags); |
121 | ret = 0; | 121 | ret = 0; |
122 | } else if (object->state == FSCACHE_OBJECT_CREATING) { | 122 | } else if (test_bit(FSCACHE_OBJECT_IS_LOOKED_UP, &object->flags)) { |
123 | op->object = object; | 123 | op->object = object; |
124 | object->n_ops++; | 124 | object->n_ops++; |
125 | object->n_exclusive++; /* reads and writes must wait */ | 125 | object->n_exclusive++; /* reads and writes must wait */ |
@@ -144,7 +144,7 @@ int fscache_submit_exclusive_op(struct fscache_object *object, | |||
144 | */ | 144 | */ |
145 | static void fscache_report_unexpected_submission(struct fscache_object *object, | 145 | static void fscache_report_unexpected_submission(struct fscache_object *object, |
146 | struct fscache_operation *op, | 146 | struct fscache_operation *op, |
147 | unsigned long ostate) | 147 | const struct fscache_state *ostate) |
148 | { | 148 | { |
149 | static bool once_only; | 149 | static bool once_only; |
150 | struct fscache_operation *p; | 150 | struct fscache_operation *p; |
@@ -155,11 +155,8 @@ static void fscache_report_unexpected_submission(struct fscache_object *object, | |||
155 | once_only = true; | 155 | once_only = true; |
156 | 156 | ||
157 | kdebug("unexpected submission OP%x [OBJ%x %s]", | 157 | kdebug("unexpected submission OP%x [OBJ%x %s]", |
158 | op->debug_id, object->debug_id, | 158 | op->debug_id, object->debug_id, object->state->name); |
159 | fscache_object_states[object->state]); | 159 | kdebug("objstate=%s [%s]", object->state->name, ostate->name); |
160 | kdebug("objstate=%s [%s]", | ||
161 | fscache_object_states[object->state], | ||
162 | fscache_object_states[ostate]); | ||
163 | kdebug("objflags=%lx", object->flags); | 160 | kdebug("objflags=%lx", object->flags); |
164 | kdebug("objevent=%lx [%lx]", object->events, object->event_mask); | 161 | kdebug("objevent=%lx [%lx]", object->events, object->event_mask); |
165 | kdebug("ops=%u inp=%u exc=%u", | 162 | kdebug("ops=%u inp=%u exc=%u", |
@@ -190,7 +187,7 @@ static void fscache_report_unexpected_submission(struct fscache_object *object, | |||
190 | int fscache_submit_op(struct fscache_object *object, | 187 | int fscache_submit_op(struct fscache_object *object, |
191 | struct fscache_operation *op) | 188 | struct fscache_operation *op) |
192 | { | 189 | { |
193 | unsigned long ostate; | 190 | const struct fscache_state *ostate; |
194 | int ret; | 191 | int ret; |
195 | 192 | ||
196 | _enter("{OBJ%x OP%x},{%u}", | 193 | _enter("{OBJ%x OP%x},{%u}", |
@@ -226,16 +223,14 @@ int fscache_submit_op(struct fscache_object *object, | |||
226 | fscache_run_op(object, op); | 223 | fscache_run_op(object, op); |
227 | } | 224 | } |
228 | ret = 0; | 225 | ret = 0; |
229 | } else if (object->state == FSCACHE_OBJECT_CREATING) { | 226 | } else if (test_bit(FSCACHE_OBJECT_IS_LOOKED_UP, &object->flags)) { |
230 | op->object = object; | 227 | op->object = object; |
231 | object->n_ops++; | 228 | object->n_ops++; |
232 | atomic_inc(&op->usage); | 229 | atomic_inc(&op->usage); |
233 | list_add_tail(&op->pend_link, &object->pending_ops); | 230 | list_add_tail(&op->pend_link, &object->pending_ops); |
234 | fscache_stat(&fscache_n_op_pend); | 231 | fscache_stat(&fscache_n_op_pend); |
235 | ret = 0; | 232 | ret = 0; |
236 | } else if (object->state == FSCACHE_OBJECT_DYING || | 233 | } else if (fscache_object_is_dying(object)) { |
237 | object->state == FSCACHE_OBJECT_LC_DYING || | ||
238 | object->state == FSCACHE_OBJECT_WITHDRAWING) { | ||
239 | fscache_stat(&fscache_n_op_rejected); | 234 | fscache_stat(&fscache_n_op_rejected); |
240 | op->state = FSCACHE_OP_ST_CANCELLED; | 235 | op->state = FSCACHE_OP_ST_CANCELLED; |
241 | ret = -ENOBUFS; | 236 | ret = -ENOBUFS; |
@@ -265,8 +260,8 @@ void fscache_abort_object(struct fscache_object *object) | |||
265 | } | 260 | } |
266 | 261 | ||
267 | /* | 262 | /* |
268 | * jump start the operation processing on an object | 263 | * Jump start the operation processing on an object. The caller must hold |
269 | * - caller must hold object->lock | 264 | * object->lock. |
270 | */ | 265 | */ |
271 | void fscache_start_operations(struct fscache_object *object) | 266 | void fscache_start_operations(struct fscache_object *object) |
272 | { | 267 | { |
@@ -428,14 +423,10 @@ void fscache_put_operation(struct fscache_operation *op) | |||
428 | 423 | ||
429 | object = op->object; | 424 | object = op->object; |
430 | 425 | ||
431 | if (test_bit(FSCACHE_OP_DEC_READ_CNT, &op->flags)) { | 426 | if (test_bit(FSCACHE_OP_DEC_READ_CNT, &op->flags)) |
432 | if (atomic_dec_and_test(&object->n_reads)) { | 427 | atomic_dec(&object->n_reads); |
433 | clear_bit(FSCACHE_COOKIE_WAITING_ON_READS, | 428 | if (test_bit(FSCACHE_OP_UNUSE_COOKIE, &op->flags)) |
434 | &object->cookie->flags); | 429 | fscache_unuse_cookie(object); |
435 | wake_up_bit(&object->cookie->flags, | ||
436 | FSCACHE_COOKIE_WAITING_ON_READS); | ||
437 | } | ||
438 | } | ||
439 | 430 | ||
440 | /* now... we may get called with the object spinlock held, so we | 431 | /* now... we may get called with the object spinlock held, so we |
441 | * complete the cleanup here only if we can immediately acquire the | 432 | * complete the cleanup here only if we can immediately acquire the |
diff --git a/fs/fscache/page.c b/fs/fscache/page.c index ff000e52072d..d479ab3c63e4 100644 --- a/fs/fscache/page.c +++ b/fs/fscache/page.c | |||
@@ -109,7 +109,7 @@ page_busy: | |||
109 | * allocator as the work threads writing to the cache may all end up | 109 | * allocator as the work threads writing to the cache may all end up |
110 | * sleeping on memory allocation, so we may need to impose a timeout | 110 | * sleeping on memory allocation, so we may need to impose a timeout |
111 | * too. */ | 111 | * too. */ |
112 | if (!(gfp & __GFP_WAIT)) { | 112 | if (!(gfp & __GFP_WAIT) || !(gfp & __GFP_FS)) { |
113 | fscache_stat(&fscache_n_store_vmscan_busy); | 113 | fscache_stat(&fscache_n_store_vmscan_busy); |
114 | return false; | 114 | return false; |
115 | } | 115 | } |
@@ -163,10 +163,12 @@ static void fscache_attr_changed_op(struct fscache_operation *op) | |||
163 | 163 | ||
164 | fscache_stat(&fscache_n_attr_changed_calls); | 164 | fscache_stat(&fscache_n_attr_changed_calls); |
165 | 165 | ||
166 | if (fscache_object_is_active(object)) { | 166 | if (fscache_object_is_active(object) && |
167 | fscache_use_cookie(object)) { | ||
167 | fscache_stat(&fscache_n_cop_attr_changed); | 168 | fscache_stat(&fscache_n_cop_attr_changed); |
168 | ret = object->cache->ops->attr_changed(object); | 169 | ret = object->cache->ops->attr_changed(object); |
169 | fscache_stat_d(&fscache_n_cop_attr_changed); | 170 | fscache_stat_d(&fscache_n_cop_attr_changed); |
171 | fscache_unuse_cookie(object); | ||
170 | if (ret < 0) | 172 | if (ret < 0) |
171 | fscache_abort_object(object); | 173 | fscache_abort_object(object); |
172 | } | 174 | } |
@@ -233,7 +235,7 @@ static void fscache_release_retrieval_op(struct fscache_operation *_op) | |||
233 | 235 | ||
234 | _enter("{OP%x}", op->op.debug_id); | 236 | _enter("{OP%x}", op->op.debug_id); |
235 | 237 | ||
236 | ASSERTCMP(op->n_pages, ==, 0); | 238 | ASSERTCMP(atomic_read(&op->n_pages), ==, 0); |
237 | 239 | ||
238 | fscache_hist(fscache_retrieval_histogram, op->start_time); | 240 | fscache_hist(fscache_retrieval_histogram, op->start_time); |
239 | if (op->context) | 241 | if (op->context) |
@@ -246,6 +248,7 @@ static void fscache_release_retrieval_op(struct fscache_operation *_op) | |||
246 | * allocate a retrieval op | 248 | * allocate a retrieval op |
247 | */ | 249 | */ |
248 | static struct fscache_retrieval *fscache_alloc_retrieval( | 250 | static struct fscache_retrieval *fscache_alloc_retrieval( |
251 | struct fscache_cookie *cookie, | ||
249 | struct address_space *mapping, | 252 | struct address_space *mapping, |
250 | fscache_rw_complete_t end_io_func, | 253 | fscache_rw_complete_t end_io_func, |
251 | void *context) | 254 | void *context) |
@@ -260,7 +263,10 @@ static struct fscache_retrieval *fscache_alloc_retrieval( | |||
260 | } | 263 | } |
261 | 264 | ||
262 | fscache_operation_init(&op->op, NULL, fscache_release_retrieval_op); | 265 | fscache_operation_init(&op->op, NULL, fscache_release_retrieval_op); |
263 | op->op.flags = FSCACHE_OP_MYTHREAD | (1 << FSCACHE_OP_WAITING); | 266 | atomic_inc(&cookie->n_active); |
267 | op->op.flags = FSCACHE_OP_MYTHREAD | | ||
268 | (1UL << FSCACHE_OP_WAITING) | | ||
269 | (1UL << FSCACHE_OP_UNUSE_COOKIE); | ||
264 | op->mapping = mapping; | 270 | op->mapping = mapping; |
265 | op->end_io_func = end_io_func; | 271 | op->end_io_func = end_io_func; |
266 | op->context = context; | 272 | op->context = context; |
@@ -310,7 +316,7 @@ static void fscache_do_cancel_retrieval(struct fscache_operation *_op) | |||
310 | struct fscache_retrieval *op = | 316 | struct fscache_retrieval *op = |
311 | container_of(_op, struct fscache_retrieval, op); | 317 | container_of(_op, struct fscache_retrieval, op); |
312 | 318 | ||
313 | op->n_pages = 0; | 319 | atomic_set(&op->n_pages, 0); |
314 | } | 320 | } |
315 | 321 | ||
316 | /* | 322 | /* |
@@ -394,12 +400,13 @@ int __fscache_read_or_alloc_page(struct fscache_cookie *cookie, | |||
394 | if (fscache_wait_for_deferred_lookup(cookie) < 0) | 400 | if (fscache_wait_for_deferred_lookup(cookie) < 0) |
395 | return -ERESTARTSYS; | 401 | return -ERESTARTSYS; |
396 | 402 | ||
397 | op = fscache_alloc_retrieval(page->mapping, end_io_func, context); | 403 | op = fscache_alloc_retrieval(cookie, page->mapping, |
404 | end_io_func,context); | ||
398 | if (!op) { | 405 | if (!op) { |
399 | _leave(" = -ENOMEM"); | 406 | _leave(" = -ENOMEM"); |
400 | return -ENOMEM; | 407 | return -ENOMEM; |
401 | } | 408 | } |
402 | op->n_pages = 1; | 409 | atomic_set(&op->n_pages, 1); |
403 | 410 | ||
404 | spin_lock(&cookie->lock); | 411 | spin_lock(&cookie->lock); |
405 | 412 | ||
@@ -408,7 +415,7 @@ int __fscache_read_or_alloc_page(struct fscache_cookie *cookie, | |||
408 | object = hlist_entry(cookie->backing_objects.first, | 415 | object = hlist_entry(cookie->backing_objects.first, |
409 | struct fscache_object, cookie_link); | 416 | struct fscache_object, cookie_link); |
410 | 417 | ||
411 | ASSERTCMP(object->state, >, FSCACHE_OBJECT_LOOKING_UP); | 418 | ASSERT(test_bit(FSCACHE_OBJECT_IS_LOOKED_UP, &object->flags)); |
412 | 419 | ||
413 | atomic_inc(&object->n_reads); | 420 | atomic_inc(&object->n_reads); |
414 | __set_bit(FSCACHE_OP_DEC_READ_CNT, &op->op.flags); | 421 | __set_bit(FSCACHE_OP_DEC_READ_CNT, &op->op.flags); |
@@ -465,6 +472,7 @@ nobufs_unlock_dec: | |||
465 | atomic_dec(&object->n_reads); | 472 | atomic_dec(&object->n_reads); |
466 | nobufs_unlock: | 473 | nobufs_unlock: |
467 | spin_unlock(&cookie->lock); | 474 | spin_unlock(&cookie->lock); |
475 | atomic_dec(&cookie->n_active); | ||
468 | kfree(op); | 476 | kfree(op); |
469 | nobufs: | 477 | nobufs: |
470 | fscache_stat(&fscache_n_retrievals_nobufs); | 478 | fscache_stat(&fscache_n_retrievals_nobufs); |
@@ -522,10 +530,10 @@ int __fscache_read_or_alloc_pages(struct fscache_cookie *cookie, | |||
522 | if (fscache_wait_for_deferred_lookup(cookie) < 0) | 530 | if (fscache_wait_for_deferred_lookup(cookie) < 0) |
523 | return -ERESTARTSYS; | 531 | return -ERESTARTSYS; |
524 | 532 | ||
525 | op = fscache_alloc_retrieval(mapping, end_io_func, context); | 533 | op = fscache_alloc_retrieval(cookie, mapping, end_io_func, context); |
526 | if (!op) | 534 | if (!op) |
527 | return -ENOMEM; | 535 | return -ENOMEM; |
528 | op->n_pages = *nr_pages; | 536 | atomic_set(&op->n_pages, *nr_pages); |
529 | 537 | ||
530 | spin_lock(&cookie->lock); | 538 | spin_lock(&cookie->lock); |
531 | 539 | ||
@@ -589,6 +597,7 @@ nobufs_unlock_dec: | |||
589 | atomic_dec(&object->n_reads); | 597 | atomic_dec(&object->n_reads); |
590 | nobufs_unlock: | 598 | nobufs_unlock: |
591 | spin_unlock(&cookie->lock); | 599 | spin_unlock(&cookie->lock); |
600 | atomic_dec(&cookie->n_active); | ||
592 | kfree(op); | 601 | kfree(op); |
593 | nobufs: | 602 | nobufs: |
594 | fscache_stat(&fscache_n_retrievals_nobufs); | 603 | fscache_stat(&fscache_n_retrievals_nobufs); |
@@ -631,10 +640,10 @@ int __fscache_alloc_page(struct fscache_cookie *cookie, | |||
631 | if (fscache_wait_for_deferred_lookup(cookie) < 0) | 640 | if (fscache_wait_for_deferred_lookup(cookie) < 0) |
632 | return -ERESTARTSYS; | 641 | return -ERESTARTSYS; |
633 | 642 | ||
634 | op = fscache_alloc_retrieval(page->mapping, NULL, NULL); | 643 | op = fscache_alloc_retrieval(cookie, page->mapping, NULL, NULL); |
635 | if (!op) | 644 | if (!op) |
636 | return -ENOMEM; | 645 | return -ENOMEM; |
637 | op->n_pages = 1; | 646 | atomic_set(&op->n_pages, 1); |
638 | 647 | ||
639 | spin_lock(&cookie->lock); | 648 | spin_lock(&cookie->lock); |
640 | 649 | ||
@@ -675,6 +684,7 @@ error: | |||
675 | 684 | ||
676 | nobufs_unlock: | 685 | nobufs_unlock: |
677 | spin_unlock(&cookie->lock); | 686 | spin_unlock(&cookie->lock); |
687 | atomic_dec(&cookie->n_active); | ||
678 | kfree(op); | 688 | kfree(op); |
679 | nobufs: | 689 | nobufs: |
680 | fscache_stat(&fscache_n_allocs_nobufs); | 690 | fscache_stat(&fscache_n_allocs_nobufs); |
@@ -729,8 +739,9 @@ static void fscache_write_op(struct fscache_operation *_op) | |||
729 | */ | 739 | */ |
730 | spin_unlock(&object->lock); | 740 | spin_unlock(&object->lock); |
731 | fscache_op_complete(&op->op, false); | 741 | fscache_op_complete(&op->op, false); |
732 | _leave(" [cancel] op{f=%lx s=%u} obj{s=%u f=%lx}", | 742 | _leave(" [cancel] op{f=%lx s=%u} obj{s=%s f=%lx}", |
733 | _op->flags, _op->state, object->state, object->flags); | 743 | _op->flags, _op->state, object->state->short_name, |
744 | object->flags); | ||
734 | return; | 745 | return; |
735 | } | 746 | } |
736 | 747 | ||
@@ -796,11 +807,16 @@ void fscache_invalidate_writes(struct fscache_cookie *cookie) | |||
796 | 807 | ||
797 | _enter(""); | 808 | _enter(""); |
798 | 809 | ||
799 | while (spin_lock(&cookie->stores_lock), | 810 | for (;;) { |
800 | n = radix_tree_gang_lookup_tag(&cookie->stores, results, 0, | 811 | spin_lock(&cookie->stores_lock); |
801 | ARRAY_SIZE(results), | 812 | n = radix_tree_gang_lookup_tag(&cookie->stores, results, 0, |
802 | FSCACHE_COOKIE_PENDING_TAG), | 813 | ARRAY_SIZE(results), |
803 | n > 0) { | 814 | FSCACHE_COOKIE_PENDING_TAG); |
815 | if (n == 0) { | ||
816 | spin_unlock(&cookie->stores_lock); | ||
817 | break; | ||
818 | } | ||
819 | |||
804 | for (i = n - 1; i >= 0; i--) { | 820 | for (i = n - 1; i >= 0; i--) { |
805 | page = results[i]; | 821 | page = results[i]; |
806 | radix_tree_delete(&cookie->stores, page->index); | 822 | radix_tree_delete(&cookie->stores, page->index); |
@@ -812,7 +828,6 @@ void fscache_invalidate_writes(struct fscache_cookie *cookie) | |||
812 | page_cache_release(results[i]); | 828 | page_cache_release(results[i]); |
813 | } | 829 | } |
814 | 830 | ||
815 | spin_unlock(&cookie->stores_lock); | ||
816 | _leave(""); | 831 | _leave(""); |
817 | } | 832 | } |
818 | 833 | ||
@@ -829,14 +844,12 @@ void fscache_invalidate_writes(struct fscache_cookie *cookie) | |||
829 | * (1) negative lookup, object not yet created (FSCACHE_COOKIE_CREATING is | 844 | * (1) negative lookup, object not yet created (FSCACHE_COOKIE_CREATING is |
830 | * set) | 845 | * set) |
831 | * | 846 | * |
832 | * (a) no writes yet (set FSCACHE_COOKIE_PENDING_FILL and queue deferred | 847 | * (a) no writes yet |
833 | * fill op) | ||
834 | * | 848 | * |
835 | * (b) writes deferred till post-creation (mark page for writing and | 849 | * (b) writes deferred till post-creation (mark page for writing and |
836 | * return immediately) | 850 | * return immediately) |
837 | * | 851 | * |
838 | * (2) negative lookup, object created, initial fill being made from netfs | 852 | * (2) negative lookup, object created, initial fill being made from netfs |
839 | * (FSCACHE_COOKIE_INITIAL_FILL is set) | ||
840 | * | 853 | * |
841 | * (a) fill point not yet reached this page (mark page for writing and | 854 | * (a) fill point not yet reached this page (mark page for writing and |
842 | * return) | 855 | * return) |
@@ -873,7 +886,9 @@ int __fscache_write_page(struct fscache_cookie *cookie, | |||
873 | 886 | ||
874 | fscache_operation_init(&op->op, fscache_write_op, | 887 | fscache_operation_init(&op->op, fscache_write_op, |
875 | fscache_release_write_op); | 888 | fscache_release_write_op); |
876 | op->op.flags = FSCACHE_OP_ASYNC | (1 << FSCACHE_OP_WAITING); | 889 | op->op.flags = FSCACHE_OP_ASYNC | |
890 | (1 << FSCACHE_OP_WAITING) | | ||
891 | (1 << FSCACHE_OP_UNUSE_COOKIE); | ||
877 | 892 | ||
878 | ret = radix_tree_preload(gfp & ~__GFP_HIGHMEM); | 893 | ret = radix_tree_preload(gfp & ~__GFP_HIGHMEM); |
879 | if (ret < 0) | 894 | if (ret < 0) |
@@ -919,6 +934,7 @@ int __fscache_write_page(struct fscache_cookie *cookie, | |||
919 | op->op.debug_id = atomic_inc_return(&fscache_op_debug_id); | 934 | op->op.debug_id = atomic_inc_return(&fscache_op_debug_id); |
920 | op->store_limit = object->store_limit; | 935 | op->store_limit = object->store_limit; |
921 | 936 | ||
937 | atomic_inc(&cookie->n_active); | ||
922 | if (fscache_submit_op(object, &op->op) < 0) | 938 | if (fscache_submit_op(object, &op->op) < 0) |
923 | goto submit_failed; | 939 | goto submit_failed; |
924 | 940 | ||
@@ -945,6 +961,7 @@ already_pending: | |||
945 | return 0; | 961 | return 0; |
946 | 962 | ||
947 | submit_failed: | 963 | submit_failed: |
964 | atomic_dec(&cookie->n_active); | ||
948 | spin_lock(&cookie->stores_lock); | 965 | spin_lock(&cookie->stores_lock); |
949 | radix_tree_delete(&cookie->stores, page->index); | 966 | radix_tree_delete(&cookie->stores, page->index); |
950 | spin_unlock(&cookie->stores_lock); | 967 | spin_unlock(&cookie->stores_lock); |