diff options
Diffstat (limited to 'fs/fscache/cookie.c')
-rw-r--r-- | fs/fscache/cookie.c | 186 |
1 files changed, 137 insertions, 49 deletions
diff --git a/fs/fscache/cookie.c b/fs/fscache/cookie.c index d851aa555d28..29d7feb62cf7 100644 --- a/fs/fscache/cookie.c +++ b/fs/fscache/cookie.c | |||
@@ -58,15 +58,16 @@ void fscache_cookie_init_once(void *_cookie) | |||
58 | struct fscache_cookie *__fscache_acquire_cookie( | 58 | struct fscache_cookie *__fscache_acquire_cookie( |
59 | struct fscache_cookie *parent, | 59 | struct fscache_cookie *parent, |
60 | const struct fscache_cookie_def *def, | 60 | const struct fscache_cookie_def *def, |
61 | void *netfs_data) | 61 | void *netfs_data, |
62 | bool enable) | ||
62 | { | 63 | { |
63 | struct fscache_cookie *cookie; | 64 | struct fscache_cookie *cookie; |
64 | 65 | ||
65 | BUG_ON(!def); | 66 | BUG_ON(!def); |
66 | 67 | ||
67 | _enter("{%s},{%s},%p", | 68 | _enter("{%s},{%s},%p,%u", |
68 | parent ? (char *) parent->def->name : "<no-parent>", | 69 | parent ? (char *) parent->def->name : "<no-parent>", |
69 | def->name, netfs_data); | 70 | def->name, netfs_data, enable); |
70 | 71 | ||
71 | fscache_stat(&fscache_n_acquires); | 72 | fscache_stat(&fscache_n_acquires); |
72 | 73 | ||
@@ -106,7 +107,7 @@ struct fscache_cookie *__fscache_acquire_cookie( | |||
106 | cookie->def = def; | 107 | cookie->def = def; |
107 | cookie->parent = parent; | 108 | cookie->parent = parent; |
108 | cookie->netfs_data = netfs_data; | 109 | cookie->netfs_data = netfs_data; |
109 | cookie->flags = 0; | 110 | cookie->flags = (1 << FSCACHE_COOKIE_NO_DATA_YET); |
110 | 111 | ||
111 | /* radix tree insertion won't use the preallocation pool unless it's | 112 | /* radix tree insertion won't use the preallocation pool unless it's |
112 | * told it may not wait */ | 113 | * told it may not wait */ |
@@ -124,16 +125,22 @@ struct fscache_cookie *__fscache_acquire_cookie( | |||
124 | break; | 125 | break; |
125 | } | 126 | } |
126 | 127 | ||
127 | /* if the object is an index then we need do nothing more here - we | 128 | if (enable) { |
128 | * create indices on disk when we need them as an index may exist in | 129 | /* if the object is an index then we need do nothing more here |
129 | * multiple caches */ | 130 | * - we create indices on disk when we need them as an index |
130 | if (cookie->def->type != FSCACHE_COOKIE_TYPE_INDEX) { | 131 | * may exist in multiple caches */ |
131 | if (fscache_acquire_non_index_cookie(cookie) < 0) { | 132 | if (cookie->def->type != FSCACHE_COOKIE_TYPE_INDEX) { |
132 | atomic_dec(&parent->n_children); | 133 | if (fscache_acquire_non_index_cookie(cookie) == 0) { |
133 | __fscache_cookie_put(cookie); | 134 | set_bit(FSCACHE_COOKIE_ENABLED, &cookie->flags); |
134 | fscache_stat(&fscache_n_acquires_nobufs); | 135 | } else { |
135 | _leave(" = NULL"); | 136 | atomic_dec(&parent->n_children); |
136 | return NULL; | 137 | __fscache_cookie_put(cookie); |
138 | fscache_stat(&fscache_n_acquires_nobufs); | ||
139 | _leave(" = NULL"); | ||
140 | return NULL; | ||
141 | } | ||
142 | } else { | ||
143 | set_bit(FSCACHE_COOKIE_ENABLED, &cookie->flags); | ||
137 | } | 144 | } |
138 | } | 145 | } |
139 | 146 | ||
@@ -144,6 +151,39 @@ struct fscache_cookie *__fscache_acquire_cookie( | |||
144 | EXPORT_SYMBOL(__fscache_acquire_cookie); | 151 | EXPORT_SYMBOL(__fscache_acquire_cookie); |
145 | 152 | ||
146 | /* | 153 | /* |
154 | * Enable a cookie to permit it to accept new operations. | ||
155 | */ | ||
156 | void __fscache_enable_cookie(struct fscache_cookie *cookie, | ||
157 | bool (*can_enable)(void *data), | ||
158 | void *data) | ||
159 | { | ||
160 | _enter("%p", cookie); | ||
161 | |||
162 | wait_on_bit_lock(&cookie->flags, FSCACHE_COOKIE_ENABLEMENT_LOCK, | ||
163 | fscache_wait_bit, TASK_UNINTERRUPTIBLE); | ||
164 | |||
165 | if (test_bit(FSCACHE_COOKIE_ENABLED, &cookie->flags)) | ||
166 | goto out_unlock; | ||
167 | |||
168 | if (can_enable && !can_enable(data)) { | ||
169 | /* The netfs decided it didn't want to enable after all */ | ||
170 | } else if (cookie->def->type != FSCACHE_COOKIE_TYPE_INDEX) { | ||
171 | /* Wait for outstanding disablement to complete */ | ||
172 | __fscache_wait_on_invalidate(cookie); | ||
173 | |||
174 | if (fscache_acquire_non_index_cookie(cookie) == 0) | ||
175 | set_bit(FSCACHE_COOKIE_ENABLED, &cookie->flags); | ||
176 | } else { | ||
177 | set_bit(FSCACHE_COOKIE_ENABLED, &cookie->flags); | ||
178 | } | ||
179 | |||
180 | out_unlock: | ||
181 | clear_bit_unlock(FSCACHE_COOKIE_ENABLEMENT_LOCK, &cookie->flags); | ||
182 | wake_up_bit(&cookie->flags, FSCACHE_COOKIE_ENABLEMENT_LOCK); | ||
183 | } | ||
184 | EXPORT_SYMBOL(__fscache_enable_cookie); | ||
185 | |||
186 | /* | ||
147 | * acquire a non-index cookie | 187 | * acquire a non-index cookie |
148 | * - this must make sure the index chain is instantiated and instantiate the | 188 | * - this must make sure the index chain is instantiated and instantiate the |
149 | * object representation too | 189 | * object representation too |
@@ -157,7 +197,7 @@ static int fscache_acquire_non_index_cookie(struct fscache_cookie *cookie) | |||
157 | 197 | ||
158 | _enter(""); | 198 | _enter(""); |
159 | 199 | ||
160 | cookie->flags = 1 << FSCACHE_COOKIE_UNAVAILABLE; | 200 | set_bit(FSCACHE_COOKIE_UNAVAILABLE, &cookie->flags); |
161 | 201 | ||
162 | /* now we need to see whether the backing objects for this cookie yet | 202 | /* now we need to see whether the backing objects for this cookie yet |
163 | * exist, if not there'll be nothing to search */ | 203 | * exist, if not there'll be nothing to search */ |
@@ -180,9 +220,7 @@ static int fscache_acquire_non_index_cookie(struct fscache_cookie *cookie) | |||
180 | 220 | ||
181 | _debug("cache %s", cache->tag->name); | 221 | _debug("cache %s", cache->tag->name); |
182 | 222 | ||
183 | cookie->flags = | 223 | set_bit(FSCACHE_COOKIE_LOOKING_UP, &cookie->flags); |
184 | (1 << FSCACHE_COOKIE_LOOKING_UP) | | ||
185 | (1 << FSCACHE_COOKIE_NO_DATA_YET); | ||
186 | 224 | ||
187 | /* ask the cache to allocate objects for this cookie and its parent | 225 | /* ask the cache to allocate objects for this cookie and its parent |
188 | * chain */ | 226 | * chain */ |
@@ -398,7 +436,8 @@ void __fscache_invalidate(struct fscache_cookie *cookie) | |||
398 | if (!hlist_empty(&cookie->backing_objects)) { | 436 | if (!hlist_empty(&cookie->backing_objects)) { |
399 | spin_lock(&cookie->lock); | 437 | spin_lock(&cookie->lock); |
400 | 438 | ||
401 | if (!hlist_empty(&cookie->backing_objects) && | 439 | if (fscache_cookie_enabled(cookie) && |
440 | !hlist_empty(&cookie->backing_objects) && | ||
402 | !test_and_set_bit(FSCACHE_COOKIE_INVALIDATING, | 441 | !test_and_set_bit(FSCACHE_COOKIE_INVALIDATING, |
403 | &cookie->flags)) { | 442 | &cookie->flags)) { |
404 | object = hlist_entry(cookie->backing_objects.first, | 443 | object = hlist_entry(cookie->backing_objects.first, |
@@ -452,10 +491,14 @@ void __fscache_update_cookie(struct fscache_cookie *cookie) | |||
452 | 491 | ||
453 | spin_lock(&cookie->lock); | 492 | spin_lock(&cookie->lock); |
454 | 493 | ||
455 | /* update the index entry on disk in each cache backing this cookie */ | 494 | if (fscache_cookie_enabled(cookie)) { |
456 | hlist_for_each_entry(object, | 495 | /* update the index entry on disk in each cache backing this |
457 | &cookie->backing_objects, cookie_link) { | 496 | * cookie. |
458 | fscache_raise_event(object, FSCACHE_OBJECT_EV_UPDATE); | 497 | */ |
498 | hlist_for_each_entry(object, | ||
499 | &cookie->backing_objects, cookie_link) { | ||
500 | fscache_raise_event(object, FSCACHE_OBJECT_EV_UPDATE); | ||
501 | } | ||
459 | } | 502 | } |
460 | 503 | ||
461 | spin_unlock(&cookie->lock); | 504 | spin_unlock(&cookie->lock); |
@@ -464,28 +507,14 @@ void __fscache_update_cookie(struct fscache_cookie *cookie) | |||
464 | EXPORT_SYMBOL(__fscache_update_cookie); | 507 | EXPORT_SYMBOL(__fscache_update_cookie); |
465 | 508 | ||
466 | /* | 509 | /* |
467 | * release a cookie back to the cache | 510 | * Disable a cookie to stop it from accepting new requests from the netfs. |
468 | * - the object will be marked as recyclable on disk if retire is true | ||
469 | * - all dependents of this cookie must have already been unregistered | ||
470 | * (indices/files/pages) | ||
471 | */ | 511 | */ |
472 | void __fscache_relinquish_cookie(struct fscache_cookie *cookie, int retire) | 512 | void __fscache_disable_cookie(struct fscache_cookie *cookie, bool invalidate) |
473 | { | 513 | { |
474 | struct fscache_object *object; | 514 | struct fscache_object *object; |
515 | bool awaken = false; | ||
475 | 516 | ||
476 | fscache_stat(&fscache_n_relinquishes); | 517 | _enter("%p,%u", cookie, invalidate); |
477 | if (retire) | ||
478 | fscache_stat(&fscache_n_relinquishes_retire); | ||
479 | |||
480 | if (!cookie) { | ||
481 | fscache_stat(&fscache_n_relinquishes_null); | ||
482 | _leave(" [no cookie]"); | ||
483 | return; | ||
484 | } | ||
485 | |||
486 | _enter("%p{%s,%p,%d},%d", | ||
487 | cookie, cookie->def->name, cookie->netfs_data, | ||
488 | atomic_read(&cookie->n_active), retire); | ||
489 | 518 | ||
490 | ASSERTCMP(atomic_read(&cookie->n_active), >, 0); | 519 | ASSERTCMP(atomic_read(&cookie->n_active), >, 0); |
491 | 520 | ||
@@ -495,24 +524,82 @@ void __fscache_relinquish_cookie(struct fscache_cookie *cookie, int retire) | |||
495 | BUG(); | 524 | BUG(); |
496 | } | 525 | } |
497 | 526 | ||
498 | /* No further netfs-accessing operations on this cookie permitted */ | 527 | wait_on_bit_lock(&cookie->flags, FSCACHE_COOKIE_ENABLEMENT_LOCK, |
499 | set_bit(FSCACHE_COOKIE_RELINQUISHED, &cookie->flags); | 528 | fscache_wait_bit, TASK_UNINTERRUPTIBLE); |
500 | if (retire) | 529 | if (!test_and_clear_bit(FSCACHE_COOKIE_ENABLED, &cookie->flags)) |
501 | set_bit(FSCACHE_COOKIE_RETIRED, &cookie->flags); | 530 | goto out_unlock_enable; |
531 | |||
532 | /* If the cookie is being invalidated, wait for that to complete first | ||
533 | * so that we can reuse the flag. | ||
534 | */ | ||
535 | __fscache_wait_on_invalidate(cookie); | ||
536 | |||
537 | /* Dispose of the backing objects */ | ||
538 | set_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags); | ||
502 | 539 | ||
503 | spin_lock(&cookie->lock); | 540 | spin_lock(&cookie->lock); |
504 | hlist_for_each_entry(object, &cookie->backing_objects, cookie_link) { | 541 | if (!hlist_empty(&cookie->backing_objects)) { |
505 | fscache_raise_event(object, FSCACHE_OBJECT_EV_KILL); | 542 | hlist_for_each_entry(object, &cookie->backing_objects, cookie_link) { |
543 | if (invalidate) | ||
544 | set_bit(FSCACHE_OBJECT_RETIRED, &object->flags); | ||
545 | fscache_raise_event(object, FSCACHE_OBJECT_EV_KILL); | ||
546 | } | ||
547 | } else { | ||
548 | if (test_and_clear_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags)) | ||
549 | awaken = true; | ||
506 | } | 550 | } |
507 | spin_unlock(&cookie->lock); | 551 | spin_unlock(&cookie->lock); |
552 | if (awaken) | ||
553 | wake_up_bit(&cookie->flags, FSCACHE_COOKIE_INVALIDATING); | ||
508 | 554 | ||
509 | /* Wait for cessation of activity requiring access to the netfs (when | 555 | /* Wait for cessation of activity requiring access to the netfs (when |
510 | * n_active reaches 0). | 556 | * n_active reaches 0). This makes sure outstanding reads and writes |
557 | * have completed. | ||
511 | */ | 558 | */ |
512 | if (!atomic_dec_and_test(&cookie->n_active)) | 559 | if (!atomic_dec_and_test(&cookie->n_active)) |
513 | wait_on_atomic_t(&cookie->n_active, fscache_wait_atomic_t, | 560 | wait_on_atomic_t(&cookie->n_active, fscache_wait_atomic_t, |
514 | TASK_UNINTERRUPTIBLE); | 561 | TASK_UNINTERRUPTIBLE); |
515 | 562 | ||
563 | /* Reset the cookie state if it wasn't relinquished */ | ||
564 | if (!test_bit(FSCACHE_COOKIE_RELINQUISHED, &cookie->flags)) { | ||
565 | atomic_inc(&cookie->n_active); | ||
566 | set_bit(FSCACHE_COOKIE_NO_DATA_YET, &cookie->flags); | ||
567 | } | ||
568 | |||
569 | out_unlock_enable: | ||
570 | clear_bit_unlock(FSCACHE_COOKIE_ENABLEMENT_LOCK, &cookie->flags); | ||
571 | wake_up_bit(&cookie->flags, FSCACHE_COOKIE_ENABLEMENT_LOCK); | ||
572 | _leave(""); | ||
573 | } | ||
574 | EXPORT_SYMBOL(__fscache_disable_cookie); | ||
575 | |||
576 | /* | ||
577 | * release a cookie back to the cache | ||
578 | * - the object will be marked as recyclable on disk if retire is true | ||
579 | * - all dependents of this cookie must have already been unregistered | ||
580 | * (indices/files/pages) | ||
581 | */ | ||
582 | void __fscache_relinquish_cookie(struct fscache_cookie *cookie, bool retire) | ||
583 | { | ||
584 | fscache_stat(&fscache_n_relinquishes); | ||
585 | if (retire) | ||
586 | fscache_stat(&fscache_n_relinquishes_retire); | ||
587 | |||
588 | if (!cookie) { | ||
589 | fscache_stat(&fscache_n_relinquishes_null); | ||
590 | _leave(" [no cookie]"); | ||
591 | return; | ||
592 | } | ||
593 | |||
594 | _enter("%p{%s,%p,%d},%d", | ||
595 | cookie, cookie->def->name, cookie->netfs_data, | ||
596 | atomic_read(&cookie->n_active), retire); | ||
597 | |||
598 | /* No further netfs-accessing operations on this cookie permitted */ | ||
599 | set_bit(FSCACHE_COOKIE_RELINQUISHED, &cookie->flags); | ||
600 | |||
601 | __fscache_disable_cookie(cookie, retire); | ||
602 | |||
516 | /* Clear pointers back to the netfs */ | 603 | /* Clear pointers back to the netfs */ |
517 | cookie->netfs_data = NULL; | 604 | cookie->netfs_data = NULL; |
518 | cookie->def = NULL; | 605 | cookie->def = NULL; |
@@ -592,7 +679,8 @@ int __fscache_check_consistency(struct fscache_cookie *cookie) | |||
592 | 679 | ||
593 | spin_lock(&cookie->lock); | 680 | spin_lock(&cookie->lock); |
594 | 681 | ||
595 | if (hlist_empty(&cookie->backing_objects)) | 682 | if (!fscache_cookie_enabled(cookie) || |
683 | hlist_empty(&cookie->backing_objects)) | ||
596 | goto inconsistent; | 684 | goto inconsistent; |
597 | object = hlist_entry(cookie->backing_objects.first, | 685 | object = hlist_entry(cookie->backing_objects.first, |
598 | struct fscache_object, cookie_link); | 686 | struct fscache_object, cookie_link); |