diff options
Diffstat (limited to 'fs/cachefiles')
-rw-r--r-- | fs/cachefiles/interface.c | 6 | ||||
-rw-r--r-- | fs/cachefiles/namei.c | 87 |
2 files changed, 72 insertions, 21 deletions
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 | } |