diff options
-rw-r--r-- | fs/cachefiles/interface.c | 11 | ||||
-rw-r--r-- | fs/cachefiles/xattr.c | 6 | ||||
-rw-r--r-- | fs/fscache/cookie.c | 80 | ||||
-rw-r--r-- | fs/fscache/fsdef.c | 1 | ||||
-rw-r--r-- | fs/fscache/internal.h | 3 | ||||
-rw-r--r-- | fs/fscache/main.c | 11 | ||||
-rw-r--r-- | fs/fscache/netfs.c | 1 | ||||
-rw-r--r-- | fs/fscache/object-list.c | 93 | ||||
-rw-r--r-- | fs/fscache/object.c | 188 | ||||
-rw-r--r-- | fs/fscache/operation.c | 12 | ||||
-rw-r--r-- | fs/fscache/page.c | 26 | ||||
-rw-r--r-- | include/linux/fscache-cache.h | 55 |
12 files changed, 230 insertions, 257 deletions
diff --git a/fs/cachefiles/interface.c b/fs/cachefiles/interface.c index 3d763217faf3..eeb3f7d0e1a7 100644 --- a/fs/cachefiles/interface.c +++ b/fs/cachefiles/interface.c | |||
@@ -212,20 +212,29 @@ static void cachefiles_update_object(struct fscache_object *_object) | |||
212 | object = container_of(_object, struct cachefiles_object, fscache); | 212 | object = container_of(_object, struct cachefiles_object, fscache); |
213 | cache = container_of(object->fscache.cache, struct cachefiles_cache, | 213 | cache = container_of(object->fscache.cache, struct cachefiles_cache, |
214 | cache); | 214 | cache); |
215 | |||
216 | if (!fscache_use_cookie(_object)) { | ||
217 | _leave(" [relinq]"); | ||
218 | return; | ||
219 | } | ||
220 | |||
215 | cookie = object->fscache.cookie; | 221 | cookie = object->fscache.cookie; |
216 | 222 | ||
217 | if (!cookie->def->get_aux) { | 223 | if (!cookie->def->get_aux) { |
224 | fscache_unuse_cookie(_object); | ||
218 | _leave(" [no aux]"); | 225 | _leave(" [no aux]"); |
219 | return; | 226 | return; |
220 | } | 227 | } |
221 | 228 | ||
222 | auxdata = kmalloc(2 + 512 + 3, cachefiles_gfp); | 229 | auxdata = kmalloc(2 + 512 + 3, cachefiles_gfp); |
223 | if (!auxdata) { | 230 | if (!auxdata) { |
231 | fscache_unuse_cookie(_object); | ||
224 | _leave(" [nomem]"); | 232 | _leave(" [nomem]"); |
225 | return; | 233 | return; |
226 | } | 234 | } |
227 | 235 | ||
228 | auxlen = cookie->def->get_aux(cookie->netfs_data, auxdata->data, 511); | 236 | auxlen = cookie->def->get_aux(cookie->netfs_data, auxdata->data, 511); |
237 | fscache_unuse_cookie(_object); | ||
229 | ASSERTCMP(auxlen, <, 511); | 238 | ASSERTCMP(auxlen, <, 511); |
230 | 239 | ||
231 | auxdata->len = auxlen + 1; | 240 | auxdata->len = auxlen + 1; |
@@ -263,7 +272,7 @@ static void cachefiles_drop_object(struct fscache_object *_object) | |||
263 | #endif | 272 | #endif |
264 | 273 | ||
265 | /* delete retired objects */ | 274 | /* delete retired objects */ |
266 | if (test_bit(FSCACHE_OBJECT_RETIRE, &object->fscache.flags) && | 275 | if (test_bit(FSCACHE_COOKIE_RETIRED, &object->fscache.cookie->flags) && |
267 | _object != cache->cache.fsdef | 276 | _object != cache->cache.fsdef |
268 | ) { | 277 | ) { |
269 | _debug("- retire object OBJ%x", object->fscache.debug_id); | 278 | _debug("- retire object OBJ%x", object->fscache.debug_id); |
diff --git a/fs/cachefiles/xattr.c b/fs/cachefiles/xattr.c index 73b46288b54b..2476e5162609 100644 --- a/fs/cachefiles/xattr.c +++ b/fs/cachefiles/xattr.c | |||
@@ -109,13 +109,12 @@ int cachefiles_set_object_xattr(struct cachefiles_object *object, | |||
109 | struct dentry *dentry = object->dentry; | 109 | struct dentry *dentry = object->dentry; |
110 | int ret; | 110 | int ret; |
111 | 111 | ||
112 | ASSERT(object->fscache.cookie); | ||
113 | ASSERT(dentry); | 112 | ASSERT(dentry); |
114 | 113 | ||
115 | _enter("%p,#%d", object, auxdata->len); | 114 | _enter("%p,#%d", object, auxdata->len); |
116 | 115 | ||
117 | /* attempt to install the cache metadata directly */ | 116 | /* attempt to install the cache metadata directly */ |
118 | _debug("SET %s #%u", object->fscache.cookie->def->name, auxdata->len); | 117 | _debug("SET #%u", auxdata->len); |
119 | 118 | ||
120 | ret = vfs_setxattr(dentry, cachefiles_xattr_cache, | 119 | ret = vfs_setxattr(dentry, cachefiles_xattr_cache, |
121 | &auxdata->type, auxdata->len, | 120 | &auxdata->type, auxdata->len, |
@@ -138,13 +137,12 @@ int cachefiles_update_object_xattr(struct cachefiles_object *object, | |||
138 | struct dentry *dentry = object->dentry; | 137 | struct dentry *dentry = object->dentry; |
139 | int ret; | 138 | int ret; |
140 | 139 | ||
141 | ASSERT(object->fscache.cookie); | ||
142 | ASSERT(dentry); | 140 | ASSERT(dentry); |
143 | 141 | ||
144 | _enter("%p,#%d", object, auxdata->len); | 142 | _enter("%p,#%d", object, auxdata->len); |
145 | 143 | ||
146 | /* attempt to install the cache metadata directly */ | 144 | /* attempt to install the cache metadata directly */ |
147 | _debug("SET %s #%u", object->fscache.cookie->def->name, auxdata->len); | 145 | _debug("SET #%u", auxdata->len); |
148 | 146 | ||
149 | ret = vfs_setxattr(dentry, cachefiles_xattr_cache, | 147 | ret = vfs_setxattr(dentry, cachefiles_xattr_cache, |
150 | &auxdata->type, auxdata->len, | 148 | &auxdata->type, auxdata->len, |
diff --git a/fs/fscache/cookie.c b/fs/fscache/cookie.c index eee436646989..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 |
@@ -467,7 +471,6 @@ 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 | 475 | ||
473 | fscache_stat(&fscache_n_relinquishes); | 476 | fscache_stat(&fscache_n_relinquishes); |
@@ -480,8 +483,11 @@ void __fscache_relinquish_cookie(struct fscache_cookie *cookie, int retire) | |||
480 | return; | 483 | return; |
481 | } | 484 | } |
482 | 485 | ||
483 | _enter("%p{%s,%p},%d", | 486 | _enter("%p{%s,%p,%d},%d", |
484 | 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); | ||
485 | 491 | ||
486 | if (atomic_read(&cookie->n_children) != 0) { | 492 | if (atomic_read(&cookie->n_children) != 0) { |
487 | printk(KERN_ERR "FS-Cache: Cookie '%s' still has children\n", | 493 | printk(KERN_ERR "FS-Cache: Cookie '%s' still has children\n", |
@@ -489,62 +495,28 @@ void __fscache_relinquish_cookie(struct fscache_cookie *cookie, int retire) | |||
489 | BUG(); | 495 | BUG(); |
490 | } | 496 | } |
491 | 497 | ||
492 | /* wait for the cookie to finish being instantiated (or to fail) */ | 498 | /* No further netfs-accessing operations on this cookie permitted */ |
493 | if (test_bit(FSCACHE_COOKIE_CREATING, &cookie->flags)) { | 499 | set_bit(FSCACHE_COOKIE_RELINQUISHED, &cookie->flags); |
494 | fscache_stat(&fscache_n_relinquishes_waitcrt); | 500 | if (retire) |
495 | wait_on_bit(&cookie->flags, FSCACHE_COOKIE_CREATING, | 501 | set_bit(FSCACHE_COOKIE_RETIRED, &cookie->flags); |
496 | fscache_wait_bit, TASK_UNINTERRUPTIBLE); | ||
497 | } | ||
498 | 502 | ||
499 | try_again: | ||
500 | spin_lock(&cookie->lock); | 503 | spin_lock(&cookie->lock); |
501 | 504 | hlist_for_each_entry(object, &cookie->backing_objects, cookie_link) { | |
502 | /* break links with all the active objects */ | ||
503 | while (!hlist_empty(&cookie->backing_objects)) { | ||
504 | int n_reads; | ||
505 | object = hlist_entry(cookie->backing_objects.first, | ||
506 | struct fscache_object, | ||
507 | cookie_link); | ||
508 | |||
509 | _debug("RELEASE OBJ%x", object->debug_id); | ||
510 | |||
511 | set_bit(FSCACHE_COOKIE_WAITING_ON_READS, &cookie->flags); | ||
512 | n_reads = atomic_read(&object->n_reads); | ||
513 | if (n_reads) { | ||
514 | int n_ops = object->n_ops; | ||
515 | int n_in_progress = object->n_in_progress; | ||
516 | spin_unlock(&cookie->lock); | ||
517 | printk(KERN_ERR "FS-Cache:" | ||
518 | " Cookie '%s' still has %d outstanding reads (%d,%d)\n", | ||
519 | cookie->def->name, | ||
520 | n_reads, n_ops, n_in_progress); | ||
521 | wait_on_bit(&cookie->flags, FSCACHE_COOKIE_WAITING_ON_READS, | ||
522 | fscache_wait_bit, TASK_UNINTERRUPTIBLE); | ||
523 | printk("Wait finished\n"); | ||
524 | goto try_again; | ||
525 | } | ||
526 | |||
527 | /* detach each cache object from the object cookie */ | ||
528 | spin_lock(&object->lock); | ||
529 | hlist_del_init(&object->cookie_link); | ||
530 | |||
531 | cache = object->cache; | ||
532 | object->cookie = NULL; | ||
533 | if (retire) | ||
534 | set_bit(FSCACHE_OBJECT_RETIRE, &object->flags); | ||
535 | fscache_raise_event(object, FSCACHE_OBJECT_EV_KILL); | 505 | fscache_raise_event(object, FSCACHE_OBJECT_EV_KILL); |
536 | spin_unlock(&object->lock); | ||
537 | |||
538 | if (atomic_dec_and_test(&cookie->usage)) | ||
539 | /* the cookie refcount shouldn't be reduced to 0 yet */ | ||
540 | BUG(); | ||
541 | } | 506 | } |
507 | spin_unlock(&cookie->lock); | ||
542 | 508 | ||
543 | /* 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 */ | ||
544 | cookie->netfs_data = NULL; | 517 | cookie->netfs_data = NULL; |
545 | cookie->def = NULL; | 518 | cookie->def = NULL; |
546 | 519 | BUG_ON(cookie->stores.rnode); | |
547 | spin_unlock(&cookie->lock); | ||
548 | 520 | ||
549 | if (cookie->parent) { | 521 | if (cookie->parent) { |
550 | ASSERTCMP(atomic_read(&cookie->parent->usage), >, 0); | 522 | ASSERTCMP(atomic_read(&cookie->parent->usage), >, 0); |
@@ -552,7 +524,7 @@ try_again: | |||
552 | atomic_dec(&cookie->parent->n_children); | 524 | atomic_dec(&cookie->parent->n_children); |
553 | } | 525 | } |
554 | 526 | ||
555 | /* finally dispose of the cookie */ | 527 | /* Dispose of the netfs's link to the cookie */ |
556 | ASSERTCMP(atomic_read(&cookie->usage), >, 0); | 528 | ASSERTCMP(atomic_read(&cookie->usage), >, 0); |
557 | fscache_cookie_put(cookie); | 529 | fscache_cookie_put(cookie); |
558 | 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 3322d3c42ba8..12d505bedb5c 100644 --- a/fs/fscache/internal.h +++ b/fs/fscache/internal.h | |||
@@ -93,6 +93,7 @@ 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 |
@@ -106,8 +107,10 @@ extern void fscache_enqueue_object(struct fscache_object *); | |||
106 | extern const struct file_operations fscache_objlist_fops; | 107 | extern const struct file_operations fscache_objlist_fops; |
107 | 108 | ||
108 | 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 *); | ||
109 | #else | 111 | #else |
110 | #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) | ||
111 | #endif | 114 | #endif |
112 | 115 | ||
113 | /* | 116 | /* |
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 4a386b080e03..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,10 +162,9 @@ 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) { |
@@ -216,8 +211,9 @@ 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(fscache_object_is_active(obj) || | 218 | FILTER(fscache_object_is_active(obj) || |
223 | obj->n_ops != 0 || | 219 | obj->n_ops != 0 || |
@@ -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 8f17debd7979..86d75a60b20c 100644 --- a/fs/fscache/object.c +++ b/fs/fscache/object.c | |||
@@ -30,7 +30,6 @@ static const struct fscache_state *fscache_look_up_object(struct fscache_object | |||
30 | static const struct fscache_state *fscache_object_available(struct fscache_object *, int); | 30 | static const struct fscache_state *fscache_object_available(struct fscache_object *, int); |
31 | static const struct fscache_state *fscache_parent_ready(struct fscache_object *, int); | 31 | static const struct fscache_state *fscache_parent_ready(struct fscache_object *, int); |
32 | static const struct fscache_state *fscache_update_object(struct fscache_object *, int); | 32 | static const struct fscache_state *fscache_update_object(struct fscache_object *, int); |
33 | static const struct fscache_state *fscache_detach_from_cookie(struct fscache_object *, int); | ||
34 | 33 | ||
35 | #define __STATE_NAME(n) fscache_osm_##n | 34 | #define __STATE_NAME(n) fscache_osm_##n |
36 | #define STATE(n) (&__STATE_NAME(n)) | 35 | #define STATE(n) (&__STATE_NAME(n)) |
@@ -92,7 +91,6 @@ static WORK_STATE(LOOKUP_FAILURE, "LCFL", fscache_lookup_failure); | |||
92 | static WORK_STATE(KILL_OBJECT, "KILL", fscache_kill_object); | 91 | static WORK_STATE(KILL_OBJECT, "KILL", fscache_kill_object); |
93 | static WORK_STATE(KILL_DEPENDENTS, "KDEP", fscache_kill_dependents); | 92 | static WORK_STATE(KILL_DEPENDENTS, "KDEP", fscache_kill_dependents); |
94 | static WORK_STATE(DROP_OBJECT, "DROP", fscache_drop_object); | 93 | static WORK_STATE(DROP_OBJECT, "DROP", fscache_drop_object); |
95 | static WORK_STATE(DETACH_FROM_COOKIE, "DTCH", fscache_detach_from_cookie); | ||
96 | static WORK_STATE(OBJECT_DEAD, "DEAD", (void*)2UL); | 94 | static WORK_STATE(OBJECT_DEAD, "DEAD", (void*)2UL); |
97 | 95 | ||
98 | static WAIT_STATE(WAIT_FOR_INIT, "?INI", | 96 | static WAIT_STATE(WAIT_FOR_INIT, "?INI", |
@@ -156,8 +154,8 @@ static inline void fscache_done_parent_op(struct fscache_object *object) | |||
156 | object->debug_id, parent->debug_id, parent->n_ops); | 154 | object->debug_id, parent->debug_id, parent->n_ops); |
157 | 155 | ||
158 | spin_lock_nested(&parent->lock, 1); | 156 | spin_lock_nested(&parent->lock, 1); |
159 | parent->n_ops--; | ||
160 | parent->n_obj_ops--; | 157 | parent->n_obj_ops--; |
158 | parent->n_ops--; | ||
161 | if (parent->n_ops == 0) | 159 | if (parent->n_ops == 0) |
162 | fscache_raise_event(parent, FSCACHE_OBJECT_EV_CLEARED); | 160 | fscache_raise_event(parent, FSCACHE_OBJECT_EV_CLEARED); |
163 | spin_unlock(&parent->lock); | 161 | spin_unlock(&parent->lock); |
@@ -332,22 +330,10 @@ EXPORT_SYMBOL(fscache_object_init); | |||
332 | static const struct fscache_state *fscache_abort_initialisation(struct fscache_object *object, | 330 | static const struct fscache_state *fscache_abort_initialisation(struct fscache_object *object, |
333 | int event) | 331 | int event) |
334 | { | 332 | { |
335 | struct fscache_cookie *cookie; | ||
336 | |||
337 | _enter("{OBJ%x},%d", object->debug_id, event); | 333 | _enter("{OBJ%x},%d", object->debug_id, event); |
338 | 334 | ||
339 | object->oob_event_mask = 0; | 335 | object->oob_event_mask = 0; |
340 | clear_bit(FSCACHE_OBJECT_IS_LIVE, &object->flags); | ||
341 | |||
342 | fscache_dequeue_object(object); | 336 | fscache_dequeue_object(object); |
343 | |||
344 | spin_lock(&object->lock); | ||
345 | cookie = object->cookie; | ||
346 | clear_bit_unlock(FSCACHE_COOKIE_CREATING, &cookie->flags); | ||
347 | spin_unlock(&object->lock); | ||
348 | |||
349 | wake_up_bit(&cookie->flags, FSCACHE_COOKIE_CREATING); | ||
350 | |||
351 | return transit_to(KILL_OBJECT); | 337 | return transit_to(KILL_OBJECT); |
352 | } | 338 | } |
353 | 339 | ||
@@ -357,8 +343,6 @@ static const struct fscache_state *fscache_abort_initialisation(struct fscache_o | |||
357 | * immediately to do a creation | 343 | * immediately to do a creation |
358 | * - 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 |
359 | * 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 |
360 | * - an object's cookie is pinned until we clear FSCACHE_COOKIE_CREATING on the | ||
361 | * leaf-most cookies of the object and all its children | ||
362 | */ | 346 | */ |
363 | static const struct fscache_state *fscache_initialise_object(struct fscache_object *object, | 347 | static const struct fscache_state *fscache_initialise_object(struct fscache_object *object, |
364 | int event) | 348 | int event) |
@@ -373,14 +357,14 @@ static const struct fscache_state *fscache_initialise_object(struct fscache_obje | |||
373 | parent = object->parent; | 357 | parent = object->parent; |
374 | if (!parent) { | 358 | if (!parent) { |
375 | _leave(" [no parent]"); | 359 | _leave(" [no parent]"); |
376 | return transit_to(DETACH_FROM_COOKIE); | 360 | return transit_to(DROP_OBJECT); |
377 | } | 361 | } |
378 | 362 | ||
379 | _debug("parent %s", parent->state->name); | 363 | _debug("parent: %s of:%lx", parent->state->name, parent->flags); |
380 | 364 | ||
381 | if (fscache_object_is_dying(parent)) { | 365 | if (fscache_object_is_dying(parent)) { |
382 | _leave(" [bad parent]"); | 366 | _leave(" [bad parent]"); |
383 | return transit_to(DETACH_FROM_COOKIE); | 367 | return transit_to(DROP_OBJECT); |
384 | } | 368 | } |
385 | 369 | ||
386 | if (fscache_object_is_available(parent)) { | 370 | if (fscache_object_is_available(parent)) { |
@@ -402,7 +386,7 @@ static const struct fscache_state *fscache_initialise_object(struct fscache_obje | |||
402 | spin_unlock(&parent->lock); | 386 | spin_unlock(&parent->lock); |
403 | if (!success) { | 387 | if (!success) { |
404 | _leave(" [grab failed]"); | 388 | _leave(" [grab failed]"); |
405 | return transit_to(DETACH_FROM_COOKIE); | 389 | return transit_to(DROP_OBJECT); |
406 | } | 390 | } |
407 | 391 | ||
408 | /* fscache_acquire_non_index_cookie() uses this | 392 | /* fscache_acquire_non_index_cookie() uses this |
@@ -438,8 +422,6 @@ static const struct fscache_state *fscache_parent_ready(struct fscache_object *o | |||
438 | * 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 |
439 | * - 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 |
440 | * be withdrawn by either party till we've finished | 424 | * be withdrawn by either party till we've finished |
441 | * - an object's cookie is pinned until we clear FSCACHE_COOKIE_CREATING on the | ||
442 | * leaf-most cookies of the object and all its children | ||
443 | */ | 425 | */ |
444 | static const struct fscache_state *fscache_look_up_object(struct fscache_object *object, | 426 | static const struct fscache_state *fscache_look_up_object(struct fscache_object *object, |
445 | int event) | 427 | int event) |
@@ -460,22 +442,21 @@ static const struct fscache_state *fscache_look_up_object(struct fscache_object | |||
460 | ASSERT(fscache_object_is_available(parent)); | 442 | ASSERT(fscache_object_is_available(parent)); |
461 | 443 | ||
462 | if (fscache_object_is_dying(parent) || | 444 | if (fscache_object_is_dying(parent) || |
463 | test_bit(FSCACHE_IOERROR, &object->cache->flags)) { | 445 | test_bit(FSCACHE_IOERROR, &object->cache->flags) || |
446 | !fscache_use_cookie(object)) { | ||
464 | _leave(" [unavailable]"); | 447 | _leave(" [unavailable]"); |
465 | return transit_to(LOOKUP_FAILURE); | 448 | return transit_to(LOOKUP_FAILURE); |
466 | } | 449 | } |
467 | 450 | ||
468 | _debug("LOOKUP \"%s/%s\" in \"%s\"", | 451 | _debug("LOOKUP \"%s\" in \"%s\"", |
469 | parent->cookie->def->name, cookie->def->name, | 452 | cookie->def->name, object->cache->tag->name); |
470 | object->cache->tag->name); | ||
471 | 453 | ||
472 | fscache_stat(&fscache_n_object_lookups); | 454 | fscache_stat(&fscache_n_object_lookups); |
473 | fscache_stat(&fscache_n_cop_lookup_object); | 455 | fscache_stat(&fscache_n_cop_lookup_object); |
474 | ret = object->cache->ops->lookup_object(object); | 456 | ret = object->cache->ops->lookup_object(object); |
475 | fscache_stat_d(&fscache_n_cop_lookup_object); | 457 | fscache_stat_d(&fscache_n_cop_lookup_object); |
476 | 458 | ||
477 | if (test_bit(FSCACHE_OBJECT_EV_ERROR, &object->events)) | 459 | fscache_unuse_cookie(object); |
478 | set_bit(FSCACHE_COOKIE_UNAVAILABLE, &cookie->flags); | ||
479 | 460 | ||
480 | if (ret == -ETIMEDOUT) { | 461 | if (ret == -ETIMEDOUT) { |
481 | /* probably stuck behind another object, so move this one to | 462 | /* probably stuck behind another object, so move this one to |
@@ -557,11 +538,6 @@ void fscache_obtained_object(struct fscache_object *object) | |||
557 | } | 538 | } |
558 | 539 | ||
559 | set_bit(FSCACHE_OBJECT_IS_AVAILABLE, &object->flags); | 540 | set_bit(FSCACHE_OBJECT_IS_AVAILABLE, &object->flags); |
560 | |||
561 | /* Permit __fscache_relinquish_cookie() to proceed */ | ||
562 | clear_bit_unlock(FSCACHE_COOKIE_CREATING, &cookie->flags); | ||
563 | wake_up_bit(&cookie->flags, FSCACHE_COOKIE_CREATING); | ||
564 | |||
565 | _leave(""); | 541 | _leave(""); |
566 | } | 542 | } |
567 | EXPORT_SYMBOL(fscache_obtained_object); | 543 | EXPORT_SYMBOL(fscache_obtained_object); |
@@ -572,16 +548,12 @@ EXPORT_SYMBOL(fscache_obtained_object); | |||
572 | static const struct fscache_state *fscache_object_available(struct fscache_object *object, | 548 | static const struct fscache_state *fscache_object_available(struct fscache_object *object, |
573 | int event) | 549 | int event) |
574 | { | 550 | { |
575 | struct fscache_cookie *cookie = object->cookie; | ||
576 | |||
577 | _enter("{OBJ%x},%d", object->debug_id, event); | 551 | _enter("{OBJ%x},%d", object->debug_id, event); |
578 | 552 | ||
579 | object->oob_table = fscache_osm_run_oob; | 553 | object->oob_table = fscache_osm_run_oob; |
580 | 554 | ||
581 | spin_lock(&object->lock); | 555 | spin_lock(&object->lock); |
582 | 556 | ||
583 | ASSERTIF(cookie, !test_bit(FSCACHE_COOKIE_CREATING, &object->cookie->flags)); | ||
584 | |||
585 | fscache_done_parent_op(object); | 557 | fscache_done_parent_op(object); |
586 | if (object->n_in_progress == 0) { | 558 | if (object->n_in_progress == 0) { |
587 | if (object->n_ops > 0) { | 559 | if (object->n_ops > 0) { |
@@ -624,7 +596,6 @@ static const struct fscache_state *fscache_lookup_failure(struct fscache_object | |||
624 | int event) | 596 | int event) |
625 | { | 597 | { |
626 | struct fscache_cookie *cookie; | 598 | struct fscache_cookie *cookie; |
627 | bool wake_looking_up = false; | ||
628 | 599 | ||
629 | _enter("{OBJ%x},%d", object->debug_id, event); | 600 | _enter("{OBJ%x},%d", object->debug_id, event); |
630 | 601 | ||
@@ -634,19 +605,10 @@ static const struct fscache_state *fscache_lookup_failure(struct fscache_object | |||
634 | object->cache->ops->lookup_complete(object); | 605 | object->cache->ops->lookup_complete(object); |
635 | fscache_stat_d(&fscache_n_cop_lookup_complete); | 606 | fscache_stat_d(&fscache_n_cop_lookup_complete); |
636 | 607 | ||
637 | spin_lock(&object->lock); | ||
638 | cookie = object->cookie; | 608 | cookie = object->cookie; |
639 | set_bit(FSCACHE_COOKIE_UNAVAILABLE, &cookie->flags); | 609 | set_bit(FSCACHE_COOKIE_UNAVAILABLE, &cookie->flags); |
640 | if (cookie) { | 610 | if (test_and_clear_bit(FSCACHE_COOKIE_LOOKING_UP, &cookie->flags)) |
641 | if (test_and_clear_bit(FSCACHE_COOKIE_LOOKING_UP, &cookie->flags)) | ||
642 | wake_looking_up = true; | ||
643 | clear_bit_unlock(FSCACHE_COOKIE_CREATING, &cookie->flags); | ||
644 | } | ||
645 | spin_unlock(&object->lock); | ||
646 | |||
647 | if (wake_looking_up) | ||
648 | wake_up_bit(&cookie->flags, FSCACHE_COOKIE_LOOKING_UP); | 611 | wake_up_bit(&cookie->flags, FSCACHE_COOKIE_LOOKING_UP); |
649 | wake_up_bit(&cookie->flags, FSCACHE_COOKIE_CREATING); | ||
650 | 612 | ||
651 | fscache_done_parent_op(object); | 613 | fscache_done_parent_op(object); |
652 | return transit_to(KILL_OBJECT); | 614 | return transit_to(KILL_OBJECT); |
@@ -662,21 +624,20 @@ static const struct fscache_state *fscache_kill_object(struct fscache_object *ob | |||
662 | _enter("{OBJ%x,%d,%d},%d", | 624 | _enter("{OBJ%x,%d,%d},%d", |
663 | object->debug_id, object->n_ops, object->n_children, event); | 625 | object->debug_id, object->n_ops, object->n_children, event); |
664 | 626 | ||
665 | object->oob_event_mask = 0; | ||
666 | |||
667 | spin_lock(&object->lock); | ||
668 | clear_bit(FSCACHE_OBJECT_IS_LIVE, &object->flags); | 627 | clear_bit(FSCACHE_OBJECT_IS_LIVE, &object->flags); |
669 | spin_unlock(&object->lock); | 628 | object->oob_event_mask = 0; |
670 | 629 | ||
671 | if (list_empty(&object->dependents) && | 630 | if (list_empty(&object->dependents) && |
672 | object->n_ops == 0 && | 631 | object->n_ops == 0 && |
673 | object->n_children == 0) | 632 | object->n_children == 0) |
674 | return object->cookie ? | 633 | return transit_to(DROP_OBJECT); |
675 | transit_to(DETACH_FROM_COOKIE) : transit_to(DROP_OBJECT); | ||
676 | 634 | ||
677 | spin_lock(&object->lock); | 635 | if (object->n_in_progress == 0) { |
678 | fscache_start_operations(object); | 636 | spin_lock(&object->lock); |
679 | spin_unlock(&object->lock); | 637 | if (object->n_ops > 0 && object->n_in_progress == 0) |
638 | fscache_start_operations(object); | ||
639 | spin_unlock(&object->lock); | ||
640 | } | ||
680 | 641 | ||
681 | if (!list_empty(&object->dependents)) | 642 | if (!list_empty(&object->dependents)) |
682 | return transit_to(KILL_DEPENDENTS); | 643 | return transit_to(KILL_DEPENDENTS); |
@@ -698,64 +659,32 @@ static const struct fscache_state *fscache_kill_dependents(struct fscache_object | |||
698 | } | 659 | } |
699 | 660 | ||
700 | /* | 661 | /* |
701 | * withdraw an object from active service | ||
702 | */ | ||
703 | static const struct fscache_state *fscache_detach_from_cookie(struct fscache_object *object, | ||
704 | int event) | ||
705 | { | ||
706 | struct fscache_cookie *cookie; | ||
707 | bool detached = false, awaken = false; | ||
708 | |||
709 | _enter("{OBJ%x},%d", object->debug_id, event); | ||
710 | |||
711 | spin_lock(&object->lock); | ||
712 | cookie = object->cookie; | ||
713 | if (cookie) { | ||
714 | /* need to get the cookie lock before the object lock, starting | ||
715 | * from the object pointer */ | ||
716 | atomic_inc(&cookie->usage); | ||
717 | spin_unlock(&object->lock); | ||
718 | |||
719 | spin_lock(&cookie->lock); | ||
720 | spin_lock(&object->lock); | ||
721 | |||
722 | if (object->cookie == cookie) { | ||
723 | hlist_del_init(&object->cookie_link); | ||
724 | object->cookie = NULL; | ||
725 | if (test_and_clear_bit(FSCACHE_COOKIE_INVALIDATING, | ||
726 | &cookie->flags)) | ||
727 | awaken = true; | ||
728 | detached = true; | ||
729 | } | ||
730 | spin_unlock(&cookie->lock); | ||
731 | fscache_cookie_put(cookie); | ||
732 | if (detached) | ||
733 | fscache_cookie_put(cookie); | ||
734 | } | ||
735 | |||
736 | spin_unlock(&object->lock); | ||
737 | |||
738 | if (awaken) | ||
739 | wake_up_bit(&cookie->flags, FSCACHE_COOKIE_INVALIDATING); | ||
740 | |||
741 | fscache_stat(&fscache_n_object_dead); | ||
742 | _leave(""); | ||
743 | return transit_to(DROP_OBJECT); | ||
744 | } | ||
745 | |||
746 | /* | ||
747 | * Drop an object's attachments | 662 | * Drop an object's attachments |
748 | */ | 663 | */ |
749 | static const struct fscache_state *fscache_drop_object(struct fscache_object *object, | 664 | static const struct fscache_state *fscache_drop_object(struct fscache_object *object, |
750 | int event) | 665 | int event) |
751 | { | 666 | { |
752 | struct fscache_object *parent = object->parent; | 667 | struct fscache_object *parent = object->parent; |
668 | struct fscache_cookie *cookie = object->cookie; | ||
753 | struct fscache_cache *cache = object->cache; | 669 | struct fscache_cache *cache = object->cache; |
670 | bool awaken = false; | ||
754 | 671 | ||
755 | _enter("{OBJ%x,%d},%d", object->debug_id, object->n_children, event); | 672 | _enter("{OBJ%x,%d},%d", object->debug_id, object->n_children, event); |
756 | 673 | ||
757 | ASSERTCMP(object->cookie, ==, NULL); | 674 | ASSERT(cookie != NULL); |
758 | ASSERT(hlist_unhashed(&object->cookie_link)); | 675 | ASSERT(!hlist_unhashed(&object->cookie_link)); |
676 | |||
677 | /* Make sure the cookie no longer points here and that the netfs isn't | ||
678 | * waiting for us. | ||
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); | ||
685 | |||
686 | if (awaken) | ||
687 | wake_up_bit(&cookie->flags, FSCACHE_COOKIE_INVALIDATING); | ||
759 | 688 | ||
760 | /* Prevent a race with our last child, which has to signal EV_CLEARED | 689 | /* Prevent a race with our last child, which has to signal EV_CLEARED |
761 | * before dropping our spinlock. | 690 | * before dropping our spinlock. |
@@ -816,6 +745,22 @@ static void fscache_put_object(struct fscache_object *object) | |||
816 | fscache_stat_d(&fscache_n_cop_put_object); | 745 | fscache_stat_d(&fscache_n_cop_put_object); |
817 | } | 746 | } |
818 | 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 | |||
819 | /* | 764 | /* |
820 | * enqueue an object for metadata-type processing | 765 | * enqueue an object for metadata-type processing |
821 | */ | 766 | */ |
@@ -925,7 +870,10 @@ static void fscache_dequeue_object(struct fscache_object *object) | |||
925 | * @data: The auxiliary data for the object | 870 | * @data: The auxiliary data for the object |
926 | * @datalen: The size of the auxiliary data | 871 | * @datalen: The size of the auxiliary data |
927 | * | 872 | * |
928 | * 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). | ||
929 | */ | 877 | */ |
930 | enum fscache_checkaux fscache_check_aux(struct fscache_object *object, | 878 | enum fscache_checkaux fscache_check_aux(struct fscache_object *object, |
931 | const void *data, uint16_t datalen) | 879 | const void *data, uint16_t datalen) |
@@ -974,6 +922,15 @@ static const struct fscache_state *_fscache_invalidate_object(struct fscache_obj | |||
974 | 922 | ||
975 | _enter("{OBJ%x},%d", object->debug_id, event); | 923 | _enter("{OBJ%x},%d", object->debug_id, event); |
976 | 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 | } | ||
977 | 934 | ||
978 | /* 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. */ |
979 | fscache_invalidate_writes(cookie); | 936 | fscache_invalidate_writes(cookie); |
@@ -982,14 +939,13 @@ static const struct fscache_state *_fscache_invalidate_object(struct fscache_obj | |||
982 | 939 | ||
983 | /* Now we have to wait for in-progress reads and writes */ | 940 | /* Now we have to wait for in-progress reads and writes */ |
984 | op = kzalloc(sizeof(*op), GFP_KERNEL); | 941 | op = kzalloc(sizeof(*op), GFP_KERNEL); |
985 | if (!op) { | 942 | if (!op) |
986 | clear_bit(FSCACHE_OBJECT_IS_LIVE, &object->flags); | 943 | goto nomem; |
987 | _leave(" [ENOMEM]"); | ||
988 | return transit_to(KILL_OBJECT); | ||
989 | } | ||
990 | 944 | ||
991 | fscache_operation_init(op, object->cache->ops->invalidate_object, NULL); | 945 | fscache_operation_init(op, object->cache->ops->invalidate_object, NULL); |
992 | 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); | ||
993 | 949 | ||
994 | spin_lock(&cookie->lock); | 950 | spin_lock(&cookie->lock); |
995 | if (fscache_submit_exclusive_op(object, op) < 0) | 951 | if (fscache_submit_exclusive_op(object, op) < 0) |
@@ -1011,6 +967,12 @@ static const struct fscache_state *_fscache_invalidate_object(struct fscache_obj | |||
1011 | _leave(" [ok]"); | 967 | _leave(" [ok]"); |
1012 | return transit_to(UPDATE_OBJECT); | 968 | return transit_to(UPDATE_OBJECT); |
1013 | 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); | ||
975 | |||
1014 | submit_op_failed: | 976 | submit_op_failed: |
1015 | clear_bit(FSCACHE_OBJECT_IS_LIVE, &object->flags); | 977 | clear_bit(FSCACHE_OBJECT_IS_LIVE, &object->flags); |
1016 | spin_unlock(&cookie->lock); | 978 | spin_unlock(&cookie->lock); |
diff --git a/fs/fscache/operation.c b/fs/fscache/operation.c index 4da211b21ddf..6935901bce38 100644 --- a/fs/fscache/operation.c +++ b/fs/fscache/operation.c | |||
@@ -424,14 +424,10 @@ void fscache_put_operation(struct fscache_operation *op) | |||
424 | 424 | ||
425 | object = op->object; | 425 | object = op->object; |
426 | 426 | ||
427 | if (test_bit(FSCACHE_OP_DEC_READ_CNT, &op->flags)) { | 427 | if (test_bit(FSCACHE_OP_DEC_READ_CNT, &op->flags)) |
428 | if (atomic_dec_and_test(&object->n_reads)) { | 428 | atomic_dec(&object->n_reads); |
429 | clear_bit(FSCACHE_COOKIE_WAITING_ON_READS, | 429 | if (test_bit(FSCACHE_OP_UNUSE_COOKIE, &op->flags)) |
430 | &object->cookie->flags); | 430 | fscache_unuse_cookie(object); |
431 | wake_up_bit(&object->cookie->flags, | ||
432 | FSCACHE_COOKIE_WAITING_ON_READS); | ||
433 | } | ||
434 | } | ||
435 | 431 | ||
436 | /* now... we may get called with the object spinlock held, so we | 432 | /* now... we may get called with the object spinlock held, so we |
437 | * complete the cleanup here only if we can immediately acquire the | 433 | * complete the cleanup here only if we can immediately acquire the |
diff --git a/fs/fscache/page.c b/fs/fscache/page.c index b4e4b424160a..780bac6ffde5 100644 --- a/fs/fscache/page.c +++ b/fs/fscache/page.c | |||
@@ -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 | } |
@@ -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; |
@@ -394,7 +400,8 @@ 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; |
@@ -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,7 +530,7 @@ 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 | op->n_pages = *nr_pages; |
@@ -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,7 +640,7 @@ 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 | op->n_pages = 1; |
@@ -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); |
@@ -876,7 +886,9 @@ int __fscache_write_page(struct fscache_cookie *cookie, | |||
876 | 886 | ||
877 | fscache_operation_init(&op->op, fscache_write_op, | 887 | fscache_operation_init(&op->op, fscache_write_op, |
878 | fscache_release_write_op); | 888 | fscache_release_write_op); |
879 | 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); | ||
880 | 892 | ||
881 | ret = radix_tree_preload(gfp & ~__GFP_HIGHMEM); | 893 | ret = radix_tree_preload(gfp & ~__GFP_HIGHMEM); |
882 | if (ret < 0) | 894 | if (ret < 0) |
@@ -922,6 +934,7 @@ int __fscache_write_page(struct fscache_cookie *cookie, | |||
922 | op->op.debug_id = atomic_inc_return(&fscache_op_debug_id); | 934 | op->op.debug_id = atomic_inc_return(&fscache_op_debug_id); |
923 | op->store_limit = object->store_limit; | 935 | op->store_limit = object->store_limit; |
924 | 936 | ||
937 | atomic_inc(&cookie->n_active); | ||
925 | if (fscache_submit_op(object, &op->op) < 0) | 938 | if (fscache_submit_op(object, &op->op) < 0) |
926 | goto submit_failed; | 939 | goto submit_failed; |
927 | 940 | ||
@@ -948,6 +961,7 @@ already_pending: | |||
948 | return 0; | 961 | return 0; |
949 | 962 | ||
950 | submit_failed: | 963 | submit_failed: |
964 | atomic_dec(&cookie->n_active); | ||
951 | spin_lock(&cookie->stores_lock); | 965 | spin_lock(&cookie->stores_lock); |
952 | radix_tree_delete(&cookie->stores, page->index); | 966 | radix_tree_delete(&cookie->stores, page->index); |
953 | spin_unlock(&cookie->stores_lock); | 967 | spin_unlock(&cookie->stores_lock); |
diff --git a/include/linux/fscache-cache.h b/include/linux/fscache-cache.h index 9ff516b1b9a0..d32f70611a00 100644 --- a/include/linux/fscache-cache.h +++ b/include/linux/fscache-cache.h | |||
@@ -97,7 +97,8 @@ struct fscache_operation { | |||
97 | #define FSCACHE_OP_WAITING 4 /* cleared when op is woken */ | 97 | #define FSCACHE_OP_WAITING 4 /* cleared when op is woken */ |
98 | #define FSCACHE_OP_EXCLUSIVE 5 /* exclusive op, other ops must wait */ | 98 | #define FSCACHE_OP_EXCLUSIVE 5 /* exclusive op, other ops must wait */ |
99 | #define FSCACHE_OP_DEC_READ_CNT 6 /* decrement object->n_reads on destruction */ | 99 | #define FSCACHE_OP_DEC_READ_CNT 6 /* decrement object->n_reads on destruction */ |
100 | #define FSCACHE_OP_KEEP_FLAGS 0x0070 /* flags to keep when repurposing an op */ | 100 | #define FSCACHE_OP_UNUSE_COOKIE 7 /* call fscache_unuse_cookie() on completion */ |
101 | #define FSCACHE_OP_KEEP_FLAGS 0x00f0 /* flags to keep when repurposing an op */ | ||
101 | 102 | ||
102 | enum fscache_operation_state state; | 103 | enum fscache_operation_state state; |
103 | atomic_t usage; | 104 | atomic_t usage; |
@@ -314,6 +315,7 @@ struct fscache_cache_ops { | |||
314 | struct fscache_cookie { | 315 | struct fscache_cookie { |
315 | atomic_t usage; /* number of users of this cookie */ | 316 | atomic_t usage; /* number of users of this cookie */ |
316 | atomic_t n_children; /* number of children of this cookie */ | 317 | atomic_t n_children; /* number of children of this cookie */ |
318 | atomic_t n_active; /* number of active users of netfs ptrs */ | ||
317 | spinlock_t lock; | 319 | spinlock_t lock; |
318 | spinlock_t stores_lock; /* lock on page store tree */ | 320 | spinlock_t stores_lock; /* lock on page store tree */ |
319 | struct hlist_head backing_objects; /* object(s) backing this file/index */ | 321 | struct hlist_head backing_objects; /* object(s) backing this file/index */ |
@@ -326,11 +328,11 @@ struct fscache_cookie { | |||
326 | 328 | ||
327 | unsigned long flags; | 329 | unsigned long flags; |
328 | #define FSCACHE_COOKIE_LOOKING_UP 0 /* T if non-index cookie being looked up still */ | 330 | #define FSCACHE_COOKIE_LOOKING_UP 0 /* T if non-index cookie being looked up still */ |
329 | #define FSCACHE_COOKIE_CREATING 1 /* T if non-index object being created still */ | 331 | #define FSCACHE_COOKIE_NO_DATA_YET 1 /* T if new object with no cached data yet */ |
330 | #define FSCACHE_COOKIE_NO_DATA_YET 2 /* T if new object with no cached data yet */ | 332 | #define FSCACHE_COOKIE_UNAVAILABLE 2 /* T if cookie is unavailable (error, etc) */ |
331 | #define FSCACHE_COOKIE_UNAVAILABLE 3 /* T if cookie is unavailable (error, etc) */ | 333 | #define FSCACHE_COOKIE_INVALIDATING 3 /* T if cookie is being invalidated */ |
332 | #define FSCACHE_COOKIE_WAITING_ON_READS 4 /* T if cookie is waiting on reads */ | 334 | #define FSCACHE_COOKIE_RELINQUISHED 4 /* T if cookie has been relinquished */ |
333 | #define FSCACHE_COOKIE_INVALIDATING 5 /* T if cookie is being invalidated */ | 335 | #define FSCACHE_COOKIE_RETIRED 5 /* T if cookie was retired */ |
334 | }; | 336 | }; |
335 | 337 | ||
336 | extern struct fscache_cookie fscache_fsdef_index; | 338 | extern struct fscache_cookie fscache_fsdef_index; |
@@ -392,10 +394,9 @@ struct fscache_object { | |||
392 | #define FSCACHE_OBJECT_LOCK 0 /* T if object is busy being processed */ | 394 | #define FSCACHE_OBJECT_LOCK 0 /* T if object is busy being processed */ |
393 | #define FSCACHE_OBJECT_PENDING_WRITE 1 /* T if object has pending write */ | 395 | #define FSCACHE_OBJECT_PENDING_WRITE 1 /* T if object has pending write */ |
394 | #define FSCACHE_OBJECT_WAITING 2 /* T if object is waiting on its parent */ | 396 | #define FSCACHE_OBJECT_WAITING 2 /* T if object is waiting on its parent */ |
395 | #define FSCACHE_OBJECT_RETIRE 3 /* T if object should be retired */ | 397 | #define FSCACHE_OBJECT_IS_LIVE 3 /* T if object is not withdrawn or relinquished */ |
396 | #define FSCACHE_OBJECT_IS_LIVE 4 /* T if object is not withdrawn or relinquished */ | 398 | #define FSCACHE_OBJECT_IS_LOOKED_UP 4 /* T if object has been looked up */ |
397 | #define FSCACHE_OBJECT_IS_LOOKED_UP 5 /* T if object has been looked up */ | 399 | #define FSCACHE_OBJECT_IS_AVAILABLE 5 /* T if object has become active */ |
398 | #define FSCACHE_OBJECT_IS_AVAILABLE 6 /* T if object has become active */ | ||
399 | 400 | ||
400 | struct list_head cache_link; /* link in cache->object_list */ | 401 | struct list_head cache_link; /* link in cache->object_list */ |
401 | struct hlist_node cookie_link; /* link in cookie->backing_objects */ | 402 | struct hlist_node cookie_link; /* link in cookie->backing_objects */ |
@@ -415,16 +416,11 @@ struct fscache_object { | |||
415 | 416 | ||
416 | extern void fscache_object_init(struct fscache_object *, struct fscache_cookie *, | 417 | extern void fscache_object_init(struct fscache_object *, struct fscache_cookie *, |
417 | struct fscache_cache *); | 418 | struct fscache_cache *); |
419 | extern void fscache_object_destroy(struct fscache_object *); | ||
418 | 420 | ||
419 | extern void fscache_object_lookup_negative(struct fscache_object *object); | 421 | extern void fscache_object_lookup_negative(struct fscache_object *object); |
420 | extern void fscache_obtained_object(struct fscache_object *object); | 422 | extern void fscache_obtained_object(struct fscache_object *object); |
421 | 423 | ||
422 | #ifdef CONFIG_FSCACHE_OBJECT_LIST | ||
423 | extern void fscache_object_destroy(struct fscache_object *object); | ||
424 | #else | ||
425 | #define fscache_object_destroy(object) do {} while(0) | ||
426 | #endif | ||
427 | |||
428 | static inline bool fscache_object_is_live(struct fscache_object *object) | 424 | static inline bool fscache_object_is_live(struct fscache_object *object) |
429 | { | 425 | { |
430 | return test_bit(FSCACHE_OBJECT_IS_LIVE, &object->flags); | 426 | return test_bit(FSCACHE_OBJECT_IS_LIVE, &object->flags); |
@@ -512,6 +508,33 @@ static inline void fscache_end_io(struct fscache_retrieval *op, | |||
512 | op->end_io_func(page, op->context, error); | 508 | op->end_io_func(page, op->context, error); |
513 | } | 509 | } |
514 | 510 | ||
511 | /** | ||
512 | * fscache_use_cookie - Request usage of cookie attached to an object | ||
513 | * @object: Object description | ||
514 | * | ||
515 | * Request usage of the cookie attached to an object. NULL is returned if the | ||
516 | * relinquishment had reduced the cookie usage count to 0. | ||
517 | */ | ||
518 | static inline bool fscache_use_cookie(struct fscache_object *object) | ||
519 | { | ||
520 | struct fscache_cookie *cookie = object->cookie; | ||
521 | return atomic_inc_not_zero(&cookie->n_active) != 0; | ||
522 | } | ||
523 | |||
524 | /** | ||
525 | * fscache_unuse_cookie - Cease usage of cookie attached to an object | ||
526 | * @object: Object description | ||
527 | * | ||
528 | * Cease usage of the cookie attached to an object. When the users count | ||
529 | * reaches zero then the cookie relinquishment will be permitted to proceed. | ||
530 | */ | ||
531 | static inline void fscache_unuse_cookie(struct fscache_object *object) | ||
532 | { | ||
533 | struct fscache_cookie *cookie = object->cookie; | ||
534 | if (atomic_dec_and_test(&cookie->n_active)) | ||
535 | wake_up_atomic_t(&cookie->n_active); | ||
536 | } | ||
537 | |||
515 | /* | 538 | /* |
516 | * out-of-line cache backend functions | 539 | * out-of-line cache backend functions |
517 | */ | 540 | */ |