diff options
-rw-r--r-- | Documentation/filesystems/caching/fscache.txt | 1 | ||||
-rw-r--r-- | fs/cachefiles/interface.c | 6 | ||||
-rw-r--r-- | fs/cachefiles/namei.c | 87 | ||||
-rw-r--r-- | fs/fscache/internal.h | 1 | ||||
-rw-r--r-- | fs/fscache/object.c | 10 | ||||
-rw-r--r-- | fs/fscache/stats.c | 4 | ||||
-rw-r--r-- | include/linux/fscache-cache.h | 6 |
7 files changed, 90 insertions, 25 deletions
diff --git a/Documentation/filesystems/caching/fscache.txt b/Documentation/filesystems/caching/fscache.txt index 3c23411956bb..a91e2e2095b0 100644 --- a/Documentation/filesystems/caching/fscache.txt +++ b/Documentation/filesystems/caching/fscache.txt | |||
@@ -235,6 +235,7 @@ proc files. | |||
235 | neg=N Number of negative lookups made | 235 | neg=N Number of negative lookups made |
236 | pos=N Number of positive lookups made | 236 | pos=N Number of positive lookups made |
237 | crt=N Number of objects created by lookup | 237 | crt=N Number of objects created by lookup |
238 | tmo=N Number of lookups timed out and requeued | ||
238 | Updates n=N Number of update cookie requests seen | 239 | Updates n=N Number of update cookie requests seen |
239 | nul=N Number of upd reqs given a NULL parent | 240 | nul=N Number of upd reqs given a NULL parent |
240 | run=N Number of upd reqs granted CPU time | 241 | run=N Number of upd reqs granted CPU time |
diff --git a/fs/cachefiles/interface.c b/fs/cachefiles/interface.c index 8e67abf05985..9d3c426044ae 100644 --- a/fs/cachefiles/interface.c +++ b/fs/cachefiles/interface.c | |||
@@ -114,8 +114,9 @@ nomem_lookup_data: | |||
114 | 114 | ||
115 | /* | 115 | /* |
116 | * attempt to look up the nominated node in this cache | 116 | * attempt to look up the nominated node in this cache |
117 | * - return -ETIMEDOUT to be scheduled again | ||
117 | */ | 118 | */ |
118 | static void cachefiles_lookup_object(struct fscache_object *_object) | 119 | static int cachefiles_lookup_object(struct fscache_object *_object) |
119 | { | 120 | { |
120 | struct cachefiles_lookup_data *lookup_data; | 121 | struct cachefiles_lookup_data *lookup_data; |
121 | struct cachefiles_object *parent, *object; | 122 | struct cachefiles_object *parent, *object; |
@@ -145,13 +146,14 @@ static void cachefiles_lookup_object(struct fscache_object *_object) | |||
145 | object->fscache.cookie->def->type != FSCACHE_COOKIE_TYPE_INDEX) | 146 | object->fscache.cookie->def->type != FSCACHE_COOKIE_TYPE_INDEX) |
146 | cachefiles_attr_changed(&object->fscache); | 147 | cachefiles_attr_changed(&object->fscache); |
147 | 148 | ||
148 | if (ret < 0) { | 149 | if (ret < 0 && ret != -ETIMEDOUT) { |
149 | printk(KERN_WARNING "CacheFiles: Lookup failed error %d\n", | 150 | printk(KERN_WARNING "CacheFiles: Lookup failed error %d\n", |
150 | ret); | 151 | ret); |
151 | fscache_object_lookup_error(&object->fscache); | 152 | fscache_object_lookup_error(&object->fscache); |
152 | } | 153 | } |
153 | 154 | ||
154 | _leave(" [%d]", ret); | 155 | _leave(" [%d]", ret); |
156 | return ret; | ||
155 | } | 157 | } |
156 | 158 | ||
157 | /* | 159 | /* |
diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c index 00a0cda8f47a..14ac4806e291 100644 --- a/fs/cachefiles/namei.c +++ b/fs/cachefiles/namei.c | |||
@@ -21,12 +21,6 @@ | |||
21 | #include <linux/security.h> | 21 | #include <linux/security.h> |
22 | #include "internal.h" | 22 | #include "internal.h" |
23 | 23 | ||
24 | static int cachefiles_wait_bit(void *flags) | ||
25 | { | ||
26 | schedule(); | ||
27 | return 0; | ||
28 | } | ||
29 | |||
30 | #define CACHEFILES_KEYBUF_SIZE 512 | 24 | #define CACHEFILES_KEYBUF_SIZE 512 |
31 | 25 | ||
32 | /* | 26 | /* |
@@ -100,8 +94,8 @@ static noinline void cachefiles_printk_object(struct cachefiles_object *object, | |||
100 | /* | 94 | /* |
101 | * record the fact that an object is now active | 95 | * record the fact that an object is now active |
102 | */ | 96 | */ |
103 | static void cachefiles_mark_object_active(struct cachefiles_cache *cache, | 97 | static int cachefiles_mark_object_active(struct cachefiles_cache *cache, |
104 | struct cachefiles_object *object) | 98 | struct cachefiles_object *object) |
105 | { | 99 | { |
106 | struct cachefiles_object *xobject; | 100 | struct cachefiles_object *xobject; |
107 | struct rb_node **_p, *_parent = NULL; | 101 | struct rb_node **_p, *_parent = NULL; |
@@ -139,8 +133,8 @@ try_again: | |||
139 | rb_insert_color(&object->active_node, &cache->active_nodes); | 133 | rb_insert_color(&object->active_node, &cache->active_nodes); |
140 | 134 | ||
141 | write_unlock(&cache->active_lock); | 135 | write_unlock(&cache->active_lock); |
142 | _leave(""); | 136 | _leave(" = 0"); |
143 | return; | 137 | return 0; |
144 | 138 | ||
145 | /* an old object from a previous incarnation is hogging the slot - we | 139 | /* an old object from a previous incarnation is hogging the slot - we |
146 | * need to wait for it to be destroyed */ | 140 | * need to wait for it to be destroyed */ |
@@ -155,13 +149,64 @@ wait_for_old_object: | |||
155 | atomic_inc(&xobject->usage); | 149 | atomic_inc(&xobject->usage); |
156 | write_unlock(&cache->active_lock); | 150 | write_unlock(&cache->active_lock); |
157 | 151 | ||
158 | _debug(">>> wait"); | 152 | if (test_bit(CACHEFILES_OBJECT_ACTIVE, &xobject->flags)) { |
159 | wait_on_bit(&xobject->flags, CACHEFILES_OBJECT_ACTIVE, | 153 | wait_queue_head_t *wq; |
160 | cachefiles_wait_bit, TASK_UNINTERRUPTIBLE); | 154 | |
161 | _debug("<<< waited"); | 155 | signed long timeout = 60 * HZ; |
156 | wait_queue_t wait; | ||
157 | bool requeue; | ||
158 | |||
159 | /* if the object we're waiting for is queued for processing, | ||
160 | * then just put ourselves on the queue behind it */ | ||
161 | if (slow_work_is_queued(&xobject->fscache.work)) { | ||
162 | _debug("queue OBJ%x behind OBJ%x immediately", | ||
163 | object->fscache.debug_id, | ||
164 | xobject->fscache.debug_id); | ||
165 | goto requeue; | ||
166 | } | ||
167 | |||
168 | /* otherwise we sleep until either the object we're waiting for | ||
169 | * is done, or the slow-work facility wants the thread back to | ||
170 | * do other work */ | ||
171 | wq = bit_waitqueue(&xobject->flags, CACHEFILES_OBJECT_ACTIVE); | ||
172 | init_wait(&wait); | ||
173 | requeue = false; | ||
174 | do { | ||
175 | prepare_to_wait(wq, &wait, TASK_UNINTERRUPTIBLE); | ||
176 | if (!test_bit(CACHEFILES_OBJECT_ACTIVE, &xobject->flags)) | ||
177 | break; | ||
178 | requeue = slow_work_sleep_till_thread_needed( | ||
179 | &object->fscache.work, &timeout); | ||
180 | } while (timeout > 0 && !requeue); | ||
181 | finish_wait(wq, &wait); | ||
182 | |||
183 | if (requeue && | ||
184 | test_bit(CACHEFILES_OBJECT_ACTIVE, &xobject->flags)) { | ||
185 | _debug("queue OBJ%x behind OBJ%x after wait", | ||
186 | object->fscache.debug_id, | ||
187 | xobject->fscache.debug_id); | ||
188 | goto requeue; | ||
189 | } | ||
190 | |||
191 | if (timeout <= 0) { | ||
192 | printk(KERN_ERR "\n"); | ||
193 | printk(KERN_ERR "CacheFiles: Error: Overlong" | ||
194 | " wait for old active object to go away\n"); | ||
195 | cachefiles_printk_object(object, xobject); | ||
196 | goto requeue; | ||
197 | } | ||
198 | } | ||
199 | |||
200 | ASSERT(!test_bit(CACHEFILES_OBJECT_ACTIVE, &xobject->flags)); | ||
162 | 201 | ||
163 | cache->cache.ops->put_object(&xobject->fscache); | 202 | cache->cache.ops->put_object(&xobject->fscache); |
164 | goto try_again; | 203 | goto try_again; |
204 | |||
205 | requeue: | ||
206 | clear_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags); | ||
207 | cache->cache.ops->put_object(&xobject->fscache); | ||
208 | _leave(" = -ETIMEDOUT"); | ||
209 | return -ETIMEDOUT; | ||
165 | } | 210 | } |
166 | 211 | ||
167 | /* | 212 | /* |
@@ -466,12 +511,15 @@ lookup_again: | |||
466 | } | 511 | } |
467 | 512 | ||
468 | /* note that we're now using this object */ | 513 | /* note that we're now using this object */ |
469 | cachefiles_mark_object_active(cache, object); | 514 | ret = cachefiles_mark_object_active(cache, object); |
470 | 515 | ||
471 | mutex_unlock(&dir->d_inode->i_mutex); | 516 | mutex_unlock(&dir->d_inode->i_mutex); |
472 | dput(dir); | 517 | dput(dir); |
473 | dir = NULL; | 518 | dir = NULL; |
474 | 519 | ||
520 | if (ret == -ETIMEDOUT) | ||
521 | goto mark_active_timed_out; | ||
522 | |||
475 | _debug("=== OBTAINED_OBJECT ==="); | 523 | _debug("=== OBTAINED_OBJECT ==="); |
476 | 524 | ||
477 | if (object->new) { | 525 | if (object->new) { |
@@ -515,6 +563,10 @@ create_error: | |||
515 | cachefiles_io_error(cache, "Create/mkdir failed"); | 563 | cachefiles_io_error(cache, "Create/mkdir failed"); |
516 | goto error; | 564 | goto error; |
517 | 565 | ||
566 | mark_active_timed_out: | ||
567 | _debug("mark active timed out"); | ||
568 | goto release_dentry; | ||
569 | |||
518 | check_error: | 570 | check_error: |
519 | _debug("check error %d", ret); | 571 | _debug("check error %d", ret); |
520 | write_lock(&cache->active_lock); | 572 | write_lock(&cache->active_lock); |
@@ -522,7 +574,7 @@ check_error: | |||
522 | clear_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags); | 574 | clear_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags); |
523 | wake_up_bit(&object->flags, CACHEFILES_OBJECT_ACTIVE); | 575 | wake_up_bit(&object->flags, CACHEFILES_OBJECT_ACTIVE); |
524 | write_unlock(&cache->active_lock); | 576 | write_unlock(&cache->active_lock); |
525 | 577 | release_dentry: | |
526 | dput(object->dentry); | 578 | dput(object->dentry); |
527 | object->dentry = NULL; | 579 | object->dentry = NULL; |
528 | goto error_out; | 580 | goto error_out; |
@@ -543,9 +595,6 @@ error: | |||
543 | error_out2: | 595 | error_out2: |
544 | dput(dir); | 596 | dput(dir); |
545 | error_out: | 597 | error_out: |
546 | if (ret == -ENOSPC) | ||
547 | ret = -ENOBUFS; | ||
548 | |||
549 | _leave(" = error %d", -ret); | 598 | _leave(" = error %d", -ret); |
550 | return ret; | 599 | return ret; |
551 | } | 600 | } |
diff --git a/fs/fscache/internal.h b/fs/fscache/internal.h index 5b49a373689b..0ca2566e038c 100644 --- a/fs/fscache/internal.h +++ b/fs/fscache/internal.h | |||
@@ -215,6 +215,7 @@ extern atomic_t fscache_n_object_no_alloc; | |||
215 | extern atomic_t fscache_n_object_lookups; | 215 | extern atomic_t fscache_n_object_lookups; |
216 | extern atomic_t fscache_n_object_lookups_negative; | 216 | extern atomic_t fscache_n_object_lookups_negative; |
217 | extern atomic_t fscache_n_object_lookups_positive; | 217 | extern atomic_t fscache_n_object_lookups_positive; |
218 | extern atomic_t fscache_n_object_lookups_timed_out; | ||
218 | extern atomic_t fscache_n_object_created; | 219 | extern atomic_t fscache_n_object_created; |
219 | extern atomic_t fscache_n_object_avail; | 220 | extern atomic_t fscache_n_object_avail; |
220 | extern atomic_t fscache_n_object_dead; | 221 | extern atomic_t fscache_n_object_dead; |
diff --git a/fs/fscache/object.c b/fs/fscache/object.c index f3f952cf887e..e513ac599c8e 100644 --- a/fs/fscache/object.c +++ b/fs/fscache/object.c | |||
@@ -468,6 +468,7 @@ static void fscache_lookup_object(struct fscache_object *object) | |||
468 | { | 468 | { |
469 | struct fscache_cookie *cookie = object->cookie; | 469 | struct fscache_cookie *cookie = object->cookie; |
470 | struct fscache_object *parent; | 470 | struct fscache_object *parent; |
471 | int ret; | ||
471 | 472 | ||
472 | _enter(""); | 473 | _enter(""); |
473 | 474 | ||
@@ -493,12 +494,19 @@ static void fscache_lookup_object(struct fscache_object *object) | |||
493 | 494 | ||
494 | fscache_stat(&fscache_n_object_lookups); | 495 | fscache_stat(&fscache_n_object_lookups); |
495 | fscache_stat(&fscache_n_cop_lookup_object); | 496 | fscache_stat(&fscache_n_cop_lookup_object); |
496 | object->cache->ops->lookup_object(object); | 497 | ret = object->cache->ops->lookup_object(object); |
497 | fscache_stat_d(&fscache_n_cop_lookup_object); | 498 | fscache_stat_d(&fscache_n_cop_lookup_object); |
498 | 499 | ||
499 | if (test_bit(FSCACHE_OBJECT_EV_ERROR, &object->events)) | 500 | if (test_bit(FSCACHE_OBJECT_EV_ERROR, &object->events)) |
500 | set_bit(FSCACHE_COOKIE_UNAVAILABLE, &cookie->flags); | 501 | set_bit(FSCACHE_COOKIE_UNAVAILABLE, &cookie->flags); |
501 | 502 | ||
503 | if (ret == -ETIMEDOUT) { | ||
504 | /* probably stuck behind another object, so move this one to | ||
505 | * the back of the queue */ | ||
506 | fscache_stat(&fscache_n_object_lookups_timed_out); | ||
507 | set_bit(FSCACHE_OBJECT_EV_REQUEUE, &object->events); | ||
508 | } | ||
509 | |||
502 | _leave(""); | 510 | _leave(""); |
503 | } | 511 | } |
504 | 512 | ||
diff --git a/fs/fscache/stats.c b/fs/fscache/stats.c index 05f77caf4a2d..46435f3aae68 100644 --- a/fs/fscache/stats.c +++ b/fs/fscache/stats.c | |||
@@ -98,6 +98,7 @@ atomic_t fscache_n_object_no_alloc; | |||
98 | atomic_t fscache_n_object_lookups; | 98 | atomic_t fscache_n_object_lookups; |
99 | atomic_t fscache_n_object_lookups_negative; | 99 | atomic_t fscache_n_object_lookups_negative; |
100 | atomic_t fscache_n_object_lookups_positive; | 100 | atomic_t fscache_n_object_lookups_positive; |
101 | atomic_t fscache_n_object_lookups_timed_out; | ||
101 | atomic_t fscache_n_object_created; | 102 | atomic_t fscache_n_object_created; |
102 | atomic_t fscache_n_object_avail; | 103 | atomic_t fscache_n_object_avail; |
103 | atomic_t fscache_n_object_dead; | 104 | atomic_t fscache_n_object_dead; |
@@ -160,10 +161,11 @@ static int fscache_stats_show(struct seq_file *m, void *v) | |||
160 | atomic_read(&fscache_n_acquires_nobufs), | 161 | atomic_read(&fscache_n_acquires_nobufs), |
161 | atomic_read(&fscache_n_acquires_oom)); | 162 | atomic_read(&fscache_n_acquires_oom)); |
162 | 163 | ||
163 | seq_printf(m, "Lookups: n=%u neg=%u pos=%u crt=%u\n", | 164 | seq_printf(m, "Lookups: n=%u neg=%u pos=%u crt=%u tmo=%u\n", |
164 | atomic_read(&fscache_n_object_lookups), | 165 | atomic_read(&fscache_n_object_lookups), |
165 | atomic_read(&fscache_n_object_lookups_negative), | 166 | atomic_read(&fscache_n_object_lookups_negative), |
166 | atomic_read(&fscache_n_object_lookups_positive), | 167 | atomic_read(&fscache_n_object_lookups_positive), |
168 | atomic_read(&fscache_n_object_lookups_timed_out), | ||
167 | atomic_read(&fscache_n_object_created)); | 169 | atomic_read(&fscache_n_object_created)); |
168 | 170 | ||
169 | seq_printf(m, "Updates: n=%u nul=%u run=%u\n", | 171 | seq_printf(m, "Updates: n=%u nul=%u run=%u\n", |
diff --git a/include/linux/fscache-cache.h b/include/linux/fscache-cache.h index 5db50002f3b5..7be0c6fbe880 100644 --- a/include/linux/fscache-cache.h +++ b/include/linux/fscache-cache.h | |||
@@ -234,8 +234,10 @@ struct fscache_cache_ops { | |||
234 | struct fscache_object *(*alloc_object)(struct fscache_cache *cache, | 234 | struct fscache_object *(*alloc_object)(struct fscache_cache *cache, |
235 | struct fscache_cookie *cookie); | 235 | struct fscache_cookie *cookie); |
236 | 236 | ||
237 | /* look up the object for a cookie */ | 237 | /* look up the object for a cookie |
238 | void (*lookup_object)(struct fscache_object *object); | 238 | * - return -ETIMEDOUT to be requeued |
239 | */ | ||
240 | int (*lookup_object)(struct fscache_object *object); | ||
239 | 241 | ||
240 | /* finished looking up */ | 242 | /* finished looking up */ |
241 | void (*lookup_complete)(struct fscache_object *object); | 243 | void (*lookup_complete)(struct fscache_object *object); |