diff options
author | Tejun Heo <tj@kernel.org> | 2010-07-20 16:09:01 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2010-07-22 16:58:34 -0400 |
commit | 8b8edefa2fffbff97f9eec8b70e78ae23abad1a0 (patch) | |
tree | 7f0efac8adb9c9ed7be8af63e51510954f1c51dc /fs | |
parent | e120153ddf8620fd0a194d301e9c5a8b28483bb5 (diff) |
fscache: convert object to use workqueue instead of slow-work
Make fscache object state transition callbacks use workqueue instead
of slow-work. New dedicated unbound CPU workqueue fscache_object_wq
is created. get/put callbacks are renamed and modified to take
@object and called directly from the enqueue wrapper and the work
function. While at it, make all open coded instances of get/put to
use fscache_get/put_object().
* Unbound workqueue is used.
* work_busy() output is printed instead of slow-work flags in object
debugging outputs. They mean basically the same thing bit-for-bit.
* sysctl fscache.object_max_active added to control concurrency. The
default value is nr_cpus clamped between 4 and
WQ_UNBOUND_MAX_ACTIVE.
* slow_work_sleep_till_thread_needed() is replaced with fscache
private implementation fscache_object_sleep_till_congested() which
waits on fscache_object_wq congestion.
* debugfs support is dropped for now. Tracing API based debug
facility is planned to be added.
Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/cachefiles/namei.c | 13 | ||||
-rw-r--r-- | fs/fscache/internal.h | 7 | ||||
-rw-r--r-- | fs/fscache/main.c | 76 | ||||
-rw-r--r-- | fs/fscache/object-list.c | 11 | ||||
-rw-r--r-- | fs/fscache/object.c | 106 |
5 files changed, 147 insertions, 66 deletions
diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c index f4a7840bf42c..42c7fafc8bfe 100644 --- a/fs/cachefiles/namei.c +++ b/fs/cachefiles/namei.c | |||
@@ -37,9 +37,9 @@ void __cachefiles_printk_object(struct cachefiles_object *object, | |||
37 | 37 | ||
38 | printk(KERN_ERR "%sobject: OBJ%x\n", | 38 | printk(KERN_ERR "%sobject: OBJ%x\n", |
39 | prefix, object->fscache.debug_id); | 39 | prefix, object->fscache.debug_id); |
40 | printk(KERN_ERR "%sobjstate=%s fl=%lx swfl=%lx ev=%lx[%lx]\n", | 40 | printk(KERN_ERR "%sobjstate=%s fl=%lx wbusy=%x ev=%lx[%lx]\n", |
41 | prefix, fscache_object_states[object->fscache.state], | 41 | prefix, fscache_object_states[object->fscache.state], |
42 | object->fscache.flags, object->fscache.work.flags, | 42 | object->fscache.flags, work_busy(&object->fscache.work), |
43 | object->fscache.events, | 43 | object->fscache.events, |
44 | object->fscache.event_mask & FSCACHE_OBJECT_EVENTS_MASK); | 44 | object->fscache.event_mask & FSCACHE_OBJECT_EVENTS_MASK); |
45 | printk(KERN_ERR "%sops=%u inp=%u exc=%u\n", | 45 | printk(KERN_ERR "%sops=%u inp=%u exc=%u\n", |
@@ -212,7 +212,7 @@ wait_for_old_object: | |||
212 | 212 | ||
213 | /* if the object we're waiting for is queued for processing, | 213 | /* if the object we're waiting for is queued for processing, |
214 | * then just put ourselves on the queue behind it */ | 214 | * then just put ourselves on the queue behind it */ |
215 | if (slow_work_is_queued(&xobject->fscache.work)) { | 215 | if (work_pending(&xobject->fscache.work)) { |
216 | _debug("queue OBJ%x behind OBJ%x immediately", | 216 | _debug("queue OBJ%x behind OBJ%x immediately", |
217 | object->fscache.debug_id, | 217 | object->fscache.debug_id, |
218 | xobject->fscache.debug_id); | 218 | xobject->fscache.debug_id); |
@@ -220,8 +220,7 @@ wait_for_old_object: | |||
220 | } | 220 | } |
221 | 221 | ||
222 | /* otherwise we sleep until either the object we're waiting for | 222 | /* otherwise we sleep until either the object we're waiting for |
223 | * is done, or the slow-work facility wants the thread back to | 223 | * is done, or the fscache_object is congested */ |
224 | * do other work */ | ||
225 | wq = bit_waitqueue(&xobject->flags, CACHEFILES_OBJECT_ACTIVE); | 224 | wq = bit_waitqueue(&xobject->flags, CACHEFILES_OBJECT_ACTIVE); |
226 | init_wait(&wait); | 225 | init_wait(&wait); |
227 | requeue = false; | 226 | requeue = false; |
@@ -229,8 +228,8 @@ wait_for_old_object: | |||
229 | prepare_to_wait(wq, &wait, TASK_UNINTERRUPTIBLE); | 228 | prepare_to_wait(wq, &wait, TASK_UNINTERRUPTIBLE); |
230 | if (!test_bit(CACHEFILES_OBJECT_ACTIVE, &xobject->flags)) | 229 | if (!test_bit(CACHEFILES_OBJECT_ACTIVE, &xobject->flags)) |
231 | break; | 230 | break; |
232 | requeue = slow_work_sleep_till_thread_needed( | 231 | |
233 | &object->fscache.work, &timeout); | 232 | requeue = fscache_object_sleep_till_congested(&timeout); |
234 | } while (timeout > 0 && !requeue); | 233 | } while (timeout > 0 && !requeue); |
235 | finish_wait(wq, &wait); | 234 | finish_wait(wq, &wait); |
236 | 235 | ||
diff --git a/fs/fscache/internal.h b/fs/fscache/internal.h index edd7434ab6e5..6e0b5fb25231 100644 --- a/fs/fscache/internal.h +++ b/fs/fscache/internal.h | |||
@@ -82,6 +82,13 @@ extern unsigned fscache_defer_lookup; | |||
82 | extern unsigned fscache_defer_create; | 82 | extern unsigned fscache_defer_create; |
83 | extern unsigned fscache_debug; | 83 | extern unsigned fscache_debug; |
84 | extern struct kobject *fscache_root; | 84 | extern struct kobject *fscache_root; |
85 | extern struct workqueue_struct *fscache_object_wq; | ||
86 | DECLARE_PER_CPU(wait_queue_head_t, fscache_object_cong_wait); | ||
87 | |||
88 | static inline bool fscache_object_congested(void) | ||
89 | { | ||
90 | return workqueue_congested(WORK_CPU_UNBOUND, fscache_object_wq); | ||
91 | } | ||
85 | 92 | ||
86 | extern int fscache_wait_bit(void *); | 93 | extern int fscache_wait_bit(void *); |
87 | extern int fscache_wait_bit_interruptible(void *); | 94 | extern int fscache_wait_bit_interruptible(void *); |
diff --git a/fs/fscache/main.c b/fs/fscache/main.c index add6bdb53f04..bb8d4c35c7a2 100644 --- a/fs/fscache/main.c +++ b/fs/fscache/main.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/sched.h> | 15 | #include <linux/sched.h> |
16 | #include <linux/completion.h> | 16 | #include <linux/completion.h> |
17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
18 | #include <linux/seq_file.h> | ||
18 | #include "internal.h" | 19 | #include "internal.h" |
19 | 20 | ||
20 | MODULE_DESCRIPTION("FS Cache Manager"); | 21 | MODULE_DESCRIPTION("FS Cache Manager"); |
@@ -40,22 +41,89 @@ MODULE_PARM_DESC(fscache_debug, | |||
40 | "FS-Cache debugging mask"); | 41 | "FS-Cache debugging mask"); |
41 | 42 | ||
42 | struct kobject *fscache_root; | 43 | struct kobject *fscache_root; |
44 | struct workqueue_struct *fscache_object_wq; | ||
45 | |||
46 | DEFINE_PER_CPU(wait_queue_head_t, fscache_object_cong_wait); | ||
47 | |||
48 | /* these values serve as lower bounds, will be adjusted in fscache_init() */ | ||
49 | static unsigned fscache_object_max_active = 4; | ||
50 | |||
51 | #ifdef CONFIG_SYSCTL | ||
52 | static struct ctl_table_header *fscache_sysctl_header; | ||
53 | |||
54 | static int fscache_max_active_sysctl(struct ctl_table *table, int write, | ||
55 | void __user *buffer, | ||
56 | size_t *lenp, loff_t *ppos) | ||
57 | { | ||
58 | struct workqueue_struct **wqp = table->extra1; | ||
59 | unsigned int *datap = table->data; | ||
60 | int ret; | ||
61 | |||
62 | ret = proc_dointvec(table, write, buffer, lenp, ppos); | ||
63 | if (ret == 0) | ||
64 | workqueue_set_max_active(*wqp, *datap); | ||
65 | return ret; | ||
66 | } | ||
67 | |||
68 | ctl_table fscache_sysctls[] = { | ||
69 | { | ||
70 | .procname = "object_max_active", | ||
71 | .data = &fscache_object_max_active, | ||
72 | .maxlen = sizeof(unsigned), | ||
73 | .mode = 0644, | ||
74 | .proc_handler = fscache_max_active_sysctl, | ||
75 | .extra1 = &fscache_object_wq, | ||
76 | }, | ||
77 | {} | ||
78 | }; | ||
79 | |||
80 | ctl_table fscache_sysctls_root[] = { | ||
81 | { | ||
82 | .procname = "fscache", | ||
83 | .mode = 0555, | ||
84 | .child = fscache_sysctls, | ||
85 | }, | ||
86 | {} | ||
87 | }; | ||
88 | #endif | ||
43 | 89 | ||
44 | /* | 90 | /* |
45 | * initialise the fs caching module | 91 | * initialise the fs caching module |
46 | */ | 92 | */ |
47 | static int __init fscache_init(void) | 93 | static int __init fscache_init(void) |
48 | { | 94 | { |
95 | unsigned int nr_cpus = num_possible_cpus(); | ||
96 | unsigned int cpu; | ||
49 | int ret; | 97 | int ret; |
50 | 98 | ||
51 | ret = slow_work_register_user(THIS_MODULE); | 99 | ret = slow_work_register_user(THIS_MODULE); |
52 | if (ret < 0) | 100 | if (ret < 0) |
53 | goto error_slow_work; | 101 | goto error_slow_work; |
54 | 102 | ||
103 | fscache_object_max_active = | ||
104 | clamp_val(nr_cpus, | ||
105 | fscache_object_max_active, WQ_UNBOUND_MAX_ACTIVE); | ||
106 | |||
107 | ret = -ENOMEM; | ||
108 | fscache_object_wq = alloc_workqueue("fscache_object", WQ_UNBOUND, | ||
109 | fscache_object_max_active); | ||
110 | if (!fscache_object_wq) | ||
111 | goto error_object_wq; | ||
112 | |||
113 | for_each_possible_cpu(cpu) | ||
114 | init_waitqueue_head(&per_cpu(fscache_object_cong_wait, cpu)); | ||
115 | |||
55 | ret = fscache_proc_init(); | 116 | ret = fscache_proc_init(); |
56 | if (ret < 0) | 117 | if (ret < 0) |
57 | goto error_proc; | 118 | goto error_proc; |
58 | 119 | ||
120 | #ifdef CONFIG_SYSCTL | ||
121 | ret = -ENOMEM; | ||
122 | fscache_sysctl_header = register_sysctl_table(fscache_sysctls_root); | ||
123 | if (!fscache_sysctl_header) | ||
124 | goto error_sysctl; | ||
125 | #endif | ||
126 | |||
59 | fscache_cookie_jar = kmem_cache_create("fscache_cookie_jar", | 127 | fscache_cookie_jar = kmem_cache_create("fscache_cookie_jar", |
60 | sizeof(struct fscache_cookie), | 128 | sizeof(struct fscache_cookie), |
61 | 0, | 129 | 0, |
@@ -78,8 +146,14 @@ static int __init fscache_init(void) | |||
78 | error_kobj: | 146 | error_kobj: |
79 | kmem_cache_destroy(fscache_cookie_jar); | 147 | kmem_cache_destroy(fscache_cookie_jar); |
80 | error_cookie_jar: | 148 | error_cookie_jar: |
149 | #ifdef CONFIG_SYSCTL | ||
150 | unregister_sysctl_table(fscache_sysctl_header); | ||
151 | error_sysctl: | ||
152 | #endif | ||
81 | fscache_proc_cleanup(); | 153 | fscache_proc_cleanup(); |
82 | error_proc: | 154 | error_proc: |
155 | destroy_workqueue(fscache_object_wq); | ||
156 | error_object_wq: | ||
83 | slow_work_unregister_user(THIS_MODULE); | 157 | slow_work_unregister_user(THIS_MODULE); |
84 | error_slow_work: | 158 | error_slow_work: |
85 | return ret; | 159 | return ret; |
@@ -96,7 +170,9 @@ static void __exit fscache_exit(void) | |||
96 | 170 | ||
97 | kobject_put(fscache_root); | 171 | kobject_put(fscache_root); |
98 | kmem_cache_destroy(fscache_cookie_jar); | 172 | kmem_cache_destroy(fscache_cookie_jar); |
173 | unregister_sysctl_table(fscache_sysctl_header); | ||
99 | fscache_proc_cleanup(); | 174 | fscache_proc_cleanup(); |
175 | destroy_workqueue(fscache_object_wq); | ||
100 | slow_work_unregister_user(THIS_MODULE); | 176 | slow_work_unregister_user(THIS_MODULE); |
101 | printk(KERN_NOTICE "FS-Cache: Unloaded\n"); | 177 | printk(KERN_NOTICE "FS-Cache: Unloaded\n"); |
102 | } | 178 | } |
diff --git a/fs/fscache/object-list.c b/fs/fscache/object-list.c index 4a8eb31c5338..ebe29c581380 100644 --- a/fs/fscache/object-list.c +++ b/fs/fscache/object-list.c | |||
@@ -34,8 +34,8 @@ struct fscache_objlist_data { | |||
34 | #define FSCACHE_OBJLIST_CONFIG_NOREADS 0x00000200 /* show objects without active reads */ | 34 | #define FSCACHE_OBJLIST_CONFIG_NOREADS 0x00000200 /* show objects without active reads */ |
35 | #define FSCACHE_OBJLIST_CONFIG_EVENTS 0x00000400 /* show objects with events */ | 35 | #define FSCACHE_OBJLIST_CONFIG_EVENTS 0x00000400 /* show objects with events */ |
36 | #define FSCACHE_OBJLIST_CONFIG_NOEVENTS 0x00000800 /* show objects without no events */ | 36 | #define FSCACHE_OBJLIST_CONFIG_NOEVENTS 0x00000800 /* show objects without no events */ |
37 | #define FSCACHE_OBJLIST_CONFIG_WORK 0x00001000 /* show objects with slow work */ | 37 | #define FSCACHE_OBJLIST_CONFIG_WORK 0x00001000 /* show objects with work */ |
38 | #define FSCACHE_OBJLIST_CONFIG_NOWORK 0x00002000 /* show objects without slow work */ | 38 | #define FSCACHE_OBJLIST_CONFIG_NOWORK 0x00002000 /* show objects without work */ |
39 | 39 | ||
40 | u8 buf[512]; /* key and aux data buffer */ | 40 | u8 buf[512]; /* key and aux data buffer */ |
41 | }; | 41 | }; |
@@ -231,12 +231,11 @@ static int fscache_objlist_show(struct seq_file *m, void *v) | |||
231 | READS, NOREADS); | 231 | READS, NOREADS); |
232 | FILTER(obj->events & obj->event_mask, | 232 | FILTER(obj->events & obj->event_mask, |
233 | EVENTS, NOEVENTS); | 233 | EVENTS, NOEVENTS); |
234 | FILTER(obj->work.flags & ~(1UL << SLOW_WORK_VERY_SLOW), | 234 | FILTER(work_busy(&obj->work), WORK, NOWORK); |
235 | WORK, NOWORK); | ||
236 | } | 235 | } |
237 | 236 | ||
238 | seq_printf(m, | 237 | seq_printf(m, |
239 | "%8x %8x %s %5u %3u %3u %3u %2u %5u %2lx %2lx %1lx %1lx | ", | 238 | "%8x %8x %s %5u %3u %3u %3u %2u %5u %2lx %2lx %1lx %1x | ", |
240 | obj->debug_id, | 239 | obj->debug_id, |
241 | obj->parent ? obj->parent->debug_id : -1, | 240 | obj->parent ? obj->parent->debug_id : -1, |
242 | fscache_object_states_short[obj->state], | 241 | fscache_object_states_short[obj->state], |
@@ -249,7 +248,7 @@ static int fscache_objlist_show(struct seq_file *m, void *v) | |||
249 | obj->event_mask & FSCACHE_OBJECT_EVENTS_MASK, | 248 | obj->event_mask & FSCACHE_OBJECT_EVENTS_MASK, |
250 | obj->events, | 249 | obj->events, |
251 | obj->flags, | 250 | obj->flags, |
252 | obj->work.flags); | 251 | work_busy(&obj->work)); |
253 | 252 | ||
254 | no_cookie = true; | 253 | no_cookie = true; |
255 | keylen = auxlen = 0; | 254 | keylen = auxlen = 0; |
diff --git a/fs/fscache/object.c b/fs/fscache/object.c index 0b589a9b4ffc..b6b897c550ac 100644 --- a/fs/fscache/object.c +++ b/fs/fscache/object.c | |||
@@ -14,7 +14,6 @@ | |||
14 | 14 | ||
15 | #define FSCACHE_DEBUG_LEVEL COOKIE | 15 | #define FSCACHE_DEBUG_LEVEL COOKIE |
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/seq_file.h> | ||
18 | #include "internal.h" | 17 | #include "internal.h" |
19 | 18 | ||
20 | const char *fscache_object_states[FSCACHE_OBJECT__NSTATES] = { | 19 | const char *fscache_object_states[FSCACHE_OBJECT__NSTATES] = { |
@@ -50,12 +49,8 @@ const char fscache_object_states_short[FSCACHE_OBJECT__NSTATES][5] = { | |||
50 | [FSCACHE_OBJECT_DEAD] = "DEAD", | 49 | [FSCACHE_OBJECT_DEAD] = "DEAD", |
51 | }; | 50 | }; |
52 | 51 | ||
53 | static void fscache_object_slow_work_put_ref(struct slow_work *); | 52 | static int fscache_get_object(struct fscache_object *); |
54 | static int fscache_object_slow_work_get_ref(struct slow_work *); | 53 | static void fscache_put_object(struct fscache_object *); |
55 | static void fscache_object_slow_work_execute(struct slow_work *); | ||
56 | #ifdef CONFIG_SLOW_WORK_DEBUG | ||
57 | static void fscache_object_slow_work_desc(struct slow_work *, struct seq_file *); | ||
58 | #endif | ||
59 | static void fscache_initialise_object(struct fscache_object *); | 54 | static void fscache_initialise_object(struct fscache_object *); |
60 | static void fscache_lookup_object(struct fscache_object *); | 55 | static void fscache_lookup_object(struct fscache_object *); |
61 | static void fscache_object_available(struct fscache_object *); | 56 | static void fscache_object_available(struct fscache_object *); |
@@ -64,17 +59,6 @@ static void fscache_withdraw_object(struct fscache_object *); | |||
64 | static void fscache_enqueue_dependents(struct fscache_object *); | 59 | static void fscache_enqueue_dependents(struct fscache_object *); |
65 | static void fscache_dequeue_object(struct fscache_object *); | 60 | static void fscache_dequeue_object(struct fscache_object *); |
66 | 61 | ||
67 | const struct slow_work_ops fscache_object_slow_work_ops = { | ||
68 | .owner = THIS_MODULE, | ||
69 | .get_ref = fscache_object_slow_work_get_ref, | ||
70 | .put_ref = fscache_object_slow_work_put_ref, | ||
71 | .execute = fscache_object_slow_work_execute, | ||
72 | #ifdef CONFIG_SLOW_WORK_DEBUG | ||
73 | .desc = fscache_object_slow_work_desc, | ||
74 | #endif | ||
75 | }; | ||
76 | EXPORT_SYMBOL(fscache_object_slow_work_ops); | ||
77 | |||
78 | /* | 62 | /* |
79 | * we need to notify the parent when an op completes that we had outstanding | 63 | * we need to notify the parent when an op completes that we had outstanding |
80 | * upon it | 64 | * upon it |
@@ -345,7 +329,7 @@ unsupported_event: | |||
345 | /* | 329 | /* |
346 | * execute an object | 330 | * execute an object |
347 | */ | 331 | */ |
348 | static void fscache_object_slow_work_execute(struct slow_work *work) | 332 | void fscache_object_work_func(struct work_struct *work) |
349 | { | 333 | { |
350 | struct fscache_object *object = | 334 | struct fscache_object *object = |
351 | container_of(work, struct fscache_object, work); | 335 | container_of(work, struct fscache_object, work); |
@@ -359,23 +343,9 @@ static void fscache_object_slow_work_execute(struct slow_work *work) | |||
359 | if (object->events & object->event_mask) | 343 | if (object->events & object->event_mask) |
360 | fscache_enqueue_object(object); | 344 | fscache_enqueue_object(object); |
361 | clear_bit(FSCACHE_OBJECT_EV_REQUEUE, &object->events); | 345 | clear_bit(FSCACHE_OBJECT_EV_REQUEUE, &object->events); |
346 | fscache_put_object(object); | ||
362 | } | 347 | } |
363 | 348 | EXPORT_SYMBOL(fscache_object_work_func); | |
364 | /* | ||
365 | * describe an object for slow-work debugging | ||
366 | */ | ||
367 | #ifdef CONFIG_SLOW_WORK_DEBUG | ||
368 | static void fscache_object_slow_work_desc(struct slow_work *work, | ||
369 | struct seq_file *m) | ||
370 | { | ||
371 | struct fscache_object *object = | ||
372 | container_of(work, struct fscache_object, work); | ||
373 | |||
374 | seq_printf(m, "FSC: OBJ%x: %s", | ||
375 | object->debug_id, | ||
376 | fscache_object_states_short[object->state]); | ||
377 | } | ||
378 | #endif | ||
379 | 349 | ||
380 | /* | 350 | /* |
381 | * initialise an object | 351 | * initialise an object |
@@ -393,7 +363,6 @@ static void fscache_initialise_object(struct fscache_object *object) | |||
393 | _enter(""); | 363 | _enter(""); |
394 | ASSERT(object->cookie != NULL); | 364 | ASSERT(object->cookie != NULL); |
395 | ASSERT(object->cookie->parent != NULL); | 365 | ASSERT(object->cookie->parent != NULL); |
396 | ASSERT(list_empty(&object->work.link)); | ||
397 | 366 | ||
398 | if (object->events & ((1 << FSCACHE_OBJECT_EV_ERROR) | | 367 | if (object->events & ((1 << FSCACHE_OBJECT_EV_ERROR) | |
399 | (1 << FSCACHE_OBJECT_EV_RELEASE) | | 368 | (1 << FSCACHE_OBJECT_EV_RELEASE) | |
@@ -671,10 +640,8 @@ static void fscache_drop_object(struct fscache_object *object) | |||
671 | object->parent = NULL; | 640 | object->parent = NULL; |
672 | } | 641 | } |
673 | 642 | ||
674 | /* this just shifts the object release to the slow work processor */ | 643 | /* this just shifts the object release to the work processor */ |
675 | fscache_stat(&fscache_n_cop_put_object); | 644 | fscache_put_object(object); |
676 | object->cache->ops->put_object(object); | ||
677 | fscache_stat_d(&fscache_n_cop_put_object); | ||
678 | 645 | ||
679 | _leave(""); | 646 | _leave(""); |
680 | } | 647 | } |
@@ -758,12 +725,10 @@ void fscache_withdrawing_object(struct fscache_cache *cache, | |||
758 | } | 725 | } |
759 | 726 | ||
760 | /* | 727 | /* |
761 | * allow the slow work item processor to get a ref on an object | 728 | * get a ref on an object |
762 | */ | 729 | */ |
763 | static int fscache_object_slow_work_get_ref(struct slow_work *work) | 730 | static int fscache_get_object(struct fscache_object *object) |
764 | { | 731 | { |
765 | struct fscache_object *object = | ||
766 | container_of(work, struct fscache_object, work); | ||
767 | int ret; | 732 | int ret; |
768 | 733 | ||
769 | fscache_stat(&fscache_n_cop_grab_object); | 734 | fscache_stat(&fscache_n_cop_grab_object); |
@@ -773,13 +738,10 @@ static int fscache_object_slow_work_get_ref(struct slow_work *work) | |||
773 | } | 738 | } |
774 | 739 | ||
775 | /* | 740 | /* |
776 | * allow the slow work item processor to discard a ref on a work item | 741 | * discard a ref on a work item |
777 | */ | 742 | */ |
778 | static void fscache_object_slow_work_put_ref(struct slow_work *work) | 743 | static void fscache_put_object(struct fscache_object *object) |
779 | { | 744 | { |
780 | struct fscache_object *object = | ||
781 | container_of(work, struct fscache_object, work); | ||
782 | |||
783 | fscache_stat(&fscache_n_cop_put_object); | 745 | fscache_stat(&fscache_n_cop_put_object); |
784 | object->cache->ops->put_object(object); | 746 | object->cache->ops->put_object(object); |
785 | fscache_stat_d(&fscache_n_cop_put_object); | 747 | fscache_stat_d(&fscache_n_cop_put_object); |
@@ -792,8 +754,48 @@ void fscache_enqueue_object(struct fscache_object *object) | |||
792 | { | 754 | { |
793 | _enter("{OBJ%x}", object->debug_id); | 755 | _enter("{OBJ%x}", object->debug_id); |
794 | 756 | ||
795 | slow_work_enqueue(&object->work); | 757 | if (fscache_get_object(object) >= 0) { |
758 | wait_queue_head_t *cong_wq = | ||
759 | &get_cpu_var(fscache_object_cong_wait); | ||
760 | |||
761 | if (queue_work(fscache_object_wq, &object->work)) { | ||
762 | if (fscache_object_congested()) | ||
763 | wake_up(cong_wq); | ||
764 | } else | ||
765 | fscache_put_object(object); | ||
766 | |||
767 | put_cpu_var(fscache_object_cong_wait); | ||
768 | } | ||
769 | } | ||
770 | |||
771 | /** | ||
772 | * fscache_object_sleep_till_congested - Sleep until object wq is congested | ||
773 | * @timoutp: Scheduler sleep timeout | ||
774 | * | ||
775 | * Allow an object handler to sleep until the object workqueue is congested. | ||
776 | * | ||
777 | * The caller must set up a wake up event before calling this and must have set | ||
778 | * the appropriate sleep mode (such as TASK_UNINTERRUPTIBLE) and tested its own | ||
779 | * condition before calling this function as no test is made here. | ||
780 | * | ||
781 | * %true is returned if the object wq is congested, %false otherwise. | ||
782 | */ | ||
783 | bool fscache_object_sleep_till_congested(signed long *timeoutp) | ||
784 | { | ||
785 | wait_queue_head_t *cong_wq = &__get_cpu_var(fscache_object_cong_wait); | ||
786 | DEFINE_WAIT(wait); | ||
787 | |||
788 | if (fscache_object_congested()) | ||
789 | return true; | ||
790 | |||
791 | add_wait_queue_exclusive(cong_wq, &wait); | ||
792 | if (!fscache_object_congested()) | ||
793 | *timeoutp = schedule_timeout(*timeoutp); | ||
794 | finish_wait(cong_wq, &wait); | ||
795 | |||
796 | return fscache_object_congested(); | ||
796 | } | 797 | } |
798 | EXPORT_SYMBOL_GPL(fscache_object_sleep_till_congested); | ||
797 | 799 | ||
798 | /* | 800 | /* |
799 | * enqueue the dependents of an object for metadata-type processing | 801 | * enqueue the dependents of an object for metadata-type processing |
@@ -819,9 +821,7 @@ static void fscache_enqueue_dependents(struct fscache_object *object) | |||
819 | 821 | ||
820 | /* sort onto appropriate lists */ | 822 | /* sort onto appropriate lists */ |
821 | fscache_enqueue_object(dep); | 823 | fscache_enqueue_object(dep); |
822 | fscache_stat(&fscache_n_cop_put_object); | 824 | fscache_put_object(dep); |
823 | dep->cache->ops->put_object(dep); | ||
824 | fscache_stat_d(&fscache_n_cop_put_object); | ||
825 | 825 | ||
826 | if (!list_empty(&object->dependents)) | 826 | if (!list_empty(&object->dependents)) |
827 | cond_resched_lock(&object->lock); | 827 | cond_resched_lock(&object->lock); |