aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fscache/cookie.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/fscache/cookie.c')
-rw-r--r--fs/fscache/cookie.c186
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)
58struct fscache_cookie *__fscache_acquire_cookie( 58struct 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(
144EXPORT_SYMBOL(__fscache_acquire_cookie); 151EXPORT_SYMBOL(__fscache_acquire_cookie);
145 152
146/* 153/*
154 * Enable a cookie to permit it to accept new operations.
155 */
156void __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
180out_unlock:
181 clear_bit_unlock(FSCACHE_COOKIE_ENABLEMENT_LOCK, &cookie->flags);
182 wake_up_bit(&cookie->flags, FSCACHE_COOKIE_ENABLEMENT_LOCK);
183}
184EXPORT_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)
464EXPORT_SYMBOL(__fscache_update_cookie); 507EXPORT_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 */
472void __fscache_relinquish_cookie(struct fscache_cookie *cookie, int retire) 512void __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
569out_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}
574EXPORT_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 */
582void __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);