|
@@ -14,7 +14,6 @@
|
|
|
|
|
|
#define FSCACHE_DEBUG_LEVEL COOKIE
|
|
|
#include <linux/module.h>
|
|
|
-#include <linux/seq_file.h>
|
|
|
#include "internal.h"
|
|
|
|
|
|
const char *fscache_object_states[FSCACHE_OBJECT__NSTATES] = {
|
|
@@ -50,12 +49,8 @@ const char fscache_object_states_short[FSCACHE_OBJECT__NSTATES][5] = {
|
|
|
[FSCACHE_OBJECT_DEAD] = "DEAD",
|
|
|
};
|
|
|
|
|
|
-static void fscache_object_slow_work_put_ref(struct slow_work *);
|
|
|
-static int fscache_object_slow_work_get_ref(struct slow_work *);
|
|
|
-static void fscache_object_slow_work_execute(struct slow_work *);
|
|
|
-#ifdef CONFIG_SLOW_WORK_DEBUG
|
|
|
-static void fscache_object_slow_work_desc(struct slow_work *, struct seq_file *);
|
|
|
-#endif
|
|
|
+static int fscache_get_object(struct fscache_object *);
|
|
|
+static void fscache_put_object(struct fscache_object *);
|
|
|
static void fscache_initialise_object(struct fscache_object *);
|
|
|
static void fscache_lookup_object(struct fscache_object *);
|
|
|
static void fscache_object_available(struct fscache_object *);
|
|
@@ -64,17 +59,6 @@ static void fscache_withdraw_object(struct fscache_object *);
|
|
|
static void fscache_enqueue_dependents(struct fscache_object *);
|
|
|
static void fscache_dequeue_object(struct fscache_object *);
|
|
|
|
|
|
-const struct slow_work_ops fscache_object_slow_work_ops = {
|
|
|
- .owner = THIS_MODULE,
|
|
|
- .get_ref = fscache_object_slow_work_get_ref,
|
|
|
- .put_ref = fscache_object_slow_work_put_ref,
|
|
|
- .execute = fscache_object_slow_work_execute,
|
|
|
-#ifdef CONFIG_SLOW_WORK_DEBUG
|
|
|
- .desc = fscache_object_slow_work_desc,
|
|
|
-#endif
|
|
|
-};
|
|
|
-EXPORT_SYMBOL(fscache_object_slow_work_ops);
|
|
|
-
|
|
|
/*
|
|
|
* we need to notify the parent when an op completes that we had outstanding
|
|
|
* upon it
|
|
@@ -345,7 +329,7 @@ unsupported_event:
|
|
|
/*
|
|
|
* execute an object
|
|
|
*/
|
|
|
-static void fscache_object_slow_work_execute(struct slow_work *work)
|
|
|
+void fscache_object_work_func(struct work_struct *work)
|
|
|
{
|
|
|
struct fscache_object *object =
|
|
|
container_of(work, struct fscache_object, work);
|
|
@@ -359,23 +343,9 @@ static void fscache_object_slow_work_execute(struct slow_work *work)
|
|
|
if (object->events & object->event_mask)
|
|
|
fscache_enqueue_object(object);
|
|
|
clear_bit(FSCACHE_OBJECT_EV_REQUEUE, &object->events);
|
|
|
+ fscache_put_object(object);
|
|
|
}
|
|
|
-
|
|
|
-/*
|
|
|
- * describe an object for slow-work debugging
|
|
|
- */
|
|
|
-#ifdef CONFIG_SLOW_WORK_DEBUG
|
|
|
-static void fscache_object_slow_work_desc(struct slow_work *work,
|
|
|
- struct seq_file *m)
|
|
|
-{
|
|
|
- struct fscache_object *object =
|
|
|
- container_of(work, struct fscache_object, work);
|
|
|
-
|
|
|
- seq_printf(m, "FSC: OBJ%x: %s",
|
|
|
- object->debug_id,
|
|
|
- fscache_object_states_short[object->state]);
|
|
|
-}
|
|
|
-#endif
|
|
|
+EXPORT_SYMBOL(fscache_object_work_func);
|
|
|
|
|
|
/*
|
|
|
* initialise an object
|
|
@@ -393,7 +363,6 @@ static void fscache_initialise_object(struct fscache_object *object)
|
|
|
_enter("");
|
|
|
ASSERT(object->cookie != NULL);
|
|
|
ASSERT(object->cookie->parent != NULL);
|
|
|
- ASSERT(list_empty(&object->work.link));
|
|
|
|
|
|
if (object->events & ((1 << FSCACHE_OBJECT_EV_ERROR) |
|
|
|
(1 << FSCACHE_OBJECT_EV_RELEASE) |
|
|
@@ -671,10 +640,8 @@ static void fscache_drop_object(struct fscache_object *object)
|
|
|
object->parent = NULL;
|
|
|
}
|
|
|
|
|
|
- /* this just shifts the object release to the slow work processor */
|
|
|
- fscache_stat(&fscache_n_cop_put_object);
|
|
|
- object->cache->ops->put_object(object);
|
|
|
- fscache_stat_d(&fscache_n_cop_put_object);
|
|
|
+ /* this just shifts the object release to the work processor */
|
|
|
+ fscache_put_object(object);
|
|
|
|
|
|
_leave("");
|
|
|
}
|
|
@@ -758,12 +725,10 @@ void fscache_withdrawing_object(struct fscache_cache *cache,
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * allow the slow work item processor to get a ref on an object
|
|
|
+ * get a ref on an object
|
|
|
*/
|
|
|
-static int fscache_object_slow_work_get_ref(struct slow_work *work)
|
|
|
+static int fscache_get_object(struct fscache_object *object)
|
|
|
{
|
|
|
- struct fscache_object *object =
|
|
|
- container_of(work, struct fscache_object, work);
|
|
|
int ret;
|
|
|
|
|
|
fscache_stat(&fscache_n_cop_grab_object);
|
|
@@ -773,13 +738,10 @@ static int fscache_object_slow_work_get_ref(struct slow_work *work)
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * allow the slow work item processor to discard a ref on a work item
|
|
|
+ * discard a ref on a work item
|
|
|
*/
|
|
|
-static void fscache_object_slow_work_put_ref(struct slow_work *work)
|
|
|
+static void fscache_put_object(struct fscache_object *object)
|
|
|
{
|
|
|
- struct fscache_object *object =
|
|
|
- container_of(work, struct fscache_object, work);
|
|
|
-
|
|
|
fscache_stat(&fscache_n_cop_put_object);
|
|
|
object->cache->ops->put_object(object);
|
|
|
fscache_stat_d(&fscache_n_cop_put_object);
|
|
@@ -792,8 +754,48 @@ void fscache_enqueue_object(struct fscache_object *object)
|
|
|
{
|
|
|
_enter("{OBJ%x}", object->debug_id);
|
|
|
|
|
|
- slow_work_enqueue(&object->work);
|
|
|
+ if (fscache_get_object(object) >= 0) {
|
|
|
+ wait_queue_head_t *cong_wq =
|
|
|
+ &get_cpu_var(fscache_object_cong_wait);
|
|
|
+
|
|
|
+ if (queue_work(fscache_object_wq, &object->work)) {
|
|
|
+ if (fscache_object_congested())
|
|
|
+ wake_up(cong_wq);
|
|
|
+ } else
|
|
|
+ fscache_put_object(object);
|
|
|
+
|
|
|
+ put_cpu_var(fscache_object_cong_wait);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * fscache_object_sleep_till_congested - Sleep until object wq is congested
|
|
|
+ * @timoutp: Scheduler sleep timeout
|
|
|
+ *
|
|
|
+ * Allow an object handler to sleep until the object workqueue is congested.
|
|
|
+ *
|
|
|
+ * The caller must set up a wake up event before calling this and must have set
|
|
|
+ * the appropriate sleep mode (such as TASK_UNINTERRUPTIBLE) and tested its own
|
|
|
+ * condition before calling this function as no test is made here.
|
|
|
+ *
|
|
|
+ * %true is returned if the object wq is congested, %false otherwise.
|
|
|
+ */
|
|
|
+bool fscache_object_sleep_till_congested(signed long *timeoutp)
|
|
|
+{
|
|
|
+ wait_queue_head_t *cong_wq = &__get_cpu_var(fscache_object_cong_wait);
|
|
|
+ DEFINE_WAIT(wait);
|
|
|
+
|
|
|
+ if (fscache_object_congested())
|
|
|
+ return true;
|
|
|
+
|
|
|
+ add_wait_queue_exclusive(cong_wq, &wait);
|
|
|
+ if (!fscache_object_congested())
|
|
|
+ *timeoutp = schedule_timeout(*timeoutp);
|
|
|
+ finish_wait(cong_wq, &wait);
|
|
|
+
|
|
|
+ return fscache_object_congested();
|
|
|
}
|
|
|
+EXPORT_SYMBOL_GPL(fscache_object_sleep_till_congested);
|
|
|
|
|
|
/*
|
|
|
* enqueue the dependents of an object for metadata-type processing
|
|
@@ -819,9 +821,7 @@ static void fscache_enqueue_dependents(struct fscache_object *object)
|
|
|
|
|
|
/* sort onto appropriate lists */
|
|
|
fscache_enqueue_object(dep);
|
|
|
- fscache_stat(&fscache_n_cop_put_object);
|
|
|
- dep->cache->ops->put_object(dep);
|
|
|
- fscache_stat_d(&fscache_n_cop_put_object);
|
|
|
+ fscache_put_object(dep);
|
|
|
|
|
|
if (!list_empty(&object->dependents))
|
|
|
cond_resched_lock(&object->lock);
|