2009-04-03 15:42:35 +00:00
|
|
|
/* Worker thread pool for slow items, such as filesystem lookups or mkdirs
|
|
|
|
*
|
|
|
|
* Copyright (C) 2008 Red Hat, Inc. All Rights Reserved.
|
|
|
|
* Written by David Howells (dhowells@redhat.com)
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public Licence
|
|
|
|
* as published by the Free Software Foundation; either version
|
|
|
|
* 2 of the Licence, or (at your option) any later version.
|
2009-04-03 15:42:35 +00:00
|
|
|
*
|
|
|
|
* See Documentation/slow-work.txt
|
2009-04-03 15:42:35 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _LINUX_SLOW_WORK_H
|
|
|
|
#define _LINUX_SLOW_WORK_H
|
|
|
|
|
|
|
|
#ifdef CONFIG_SLOW_WORK
|
|
|
|
|
2009-04-03 15:42:35 +00:00
|
|
|
#include <linux/sysctl.h>
|
2009-11-19 18:10:47 +00:00
|
|
|
#include <linux/timer.h>
|
2009-04-03 15:42:35 +00:00
|
|
|
|
2009-04-03 15:42:35 +00:00
|
|
|
struct slow_work;
|
2009-12-01 15:36:11 +00:00
|
|
|
#ifdef CONFIG_SLOW_WORK_DEBUG
|
2009-11-19 18:10:51 +00:00
|
|
|
struct seq_file;
|
|
|
|
#endif
|
2009-04-03 15:42:35 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* The operations used to support slow work items
|
|
|
|
*/
|
|
|
|
struct slow_work_ops {
|
2009-11-19 18:10:23 +00:00
|
|
|
/* owner */
|
|
|
|
struct module *owner;
|
|
|
|
|
2009-04-03 15:42:35 +00:00
|
|
|
/* get a ref on a work item
|
|
|
|
* - return 0 if successful, -ve if not
|
|
|
|
*/
|
|
|
|
int (*get_ref)(struct slow_work *work);
|
|
|
|
|
|
|
|
/* discard a ref to a work item */
|
|
|
|
void (*put_ref)(struct slow_work *work);
|
|
|
|
|
|
|
|
/* execute a work item */
|
|
|
|
void (*execute)(struct slow_work *work);
|
2009-11-19 18:10:51 +00:00
|
|
|
|
2009-12-01 15:36:11 +00:00
|
|
|
#ifdef CONFIG_SLOW_WORK_DEBUG
|
|
|
|
/* describe a work item for debugfs */
|
2009-11-19 18:10:51 +00:00
|
|
|
void (*desc)(struct slow_work *work, struct seq_file *m);
|
|
|
|
#endif
|
2009-04-03 15:42:35 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* A slow work item
|
|
|
|
* - A reference is held on the parent object by the thread pool when it is
|
|
|
|
* queued
|
|
|
|
*/
|
|
|
|
struct slow_work {
|
2009-11-19 18:10:23 +00:00
|
|
|
struct module *owner; /* the owning module */
|
2009-04-03 15:42:35 +00:00
|
|
|
unsigned long flags;
|
|
|
|
#define SLOW_WORK_PENDING 0 /* item pending (further) execution */
|
|
|
|
#define SLOW_WORK_EXECUTING 1 /* item currently executing */
|
|
|
|
#define SLOW_WORK_ENQ_DEFERRED 2 /* item enqueue deferred */
|
|
|
|
#define SLOW_WORK_VERY_SLOW 3 /* item is very slow */
|
2009-11-19 18:10:43 +00:00
|
|
|
#define SLOW_WORK_CANCELLING 4 /* item is being cancelled, don't enqueue */
|
2009-11-19 18:10:47 +00:00
|
|
|
#define SLOW_WORK_DELAYED 5 /* item is struct delayed_slow_work with active timer */
|
2009-04-03 15:42:35 +00:00
|
|
|
const struct slow_work_ops *ops; /* operations table for this item */
|
|
|
|
struct list_head link; /* link in queue */
|
2009-12-01 15:36:11 +00:00
|
|
|
#ifdef CONFIG_SLOW_WORK_DEBUG
|
2009-11-19 18:10:51 +00:00
|
|
|
struct timespec mark; /* jiffies at which queued or exec begun */
|
|
|
|
#endif
|
2009-04-03 15:42:35 +00:00
|
|
|
};
|
|
|
|
|
2009-11-19 18:10:47 +00:00
|
|
|
struct delayed_slow_work {
|
|
|
|
struct slow_work work;
|
|
|
|
struct timer_list timer;
|
|
|
|
};
|
|
|
|
|
2009-04-03 15:42:35 +00:00
|
|
|
/**
|
|
|
|
* slow_work_init - Initialise a slow work item
|
|
|
|
* @work: The work item to initialise
|
|
|
|
* @ops: The operations to use to handle the slow work item
|
|
|
|
*
|
|
|
|
* Initialise a slow work item.
|
|
|
|
*/
|
|
|
|
static inline void slow_work_init(struct slow_work *work,
|
|
|
|
const struct slow_work_ops *ops)
|
|
|
|
{
|
|
|
|
work->flags = 0;
|
|
|
|
work->ops = ops;
|
|
|
|
INIT_LIST_HEAD(&work->link);
|
|
|
|
}
|
|
|
|
|
2009-11-19 18:10:47 +00:00
|
|
|
/**
|
|
|
|
* slow_work_init - Initialise a delayed slow work item
|
|
|
|
* @work: The work item to initialise
|
|
|
|
* @ops: The operations to use to handle the slow work item
|
|
|
|
*
|
|
|
|
* Initialise a delayed slow work item.
|
|
|
|
*/
|
|
|
|
static inline void delayed_slow_work_init(struct delayed_slow_work *dwork,
|
|
|
|
const struct slow_work_ops *ops)
|
|
|
|
{
|
|
|
|
init_timer(&dwork->timer);
|
|
|
|
slow_work_init(&dwork->work, ops);
|
|
|
|
}
|
|
|
|
|
2009-04-03 15:42:35 +00:00
|
|
|
/**
|
2009-04-21 22:30:32 +00:00
|
|
|
* vslow_work_init - Initialise a very slow work item
|
2009-04-03 15:42:35 +00:00
|
|
|
* @work: The work item to initialise
|
|
|
|
* @ops: The operations to use to handle the slow work item
|
|
|
|
*
|
|
|
|
* Initialise a very slow work item. This item will be restricted such that
|
|
|
|
* only a certain number of the pool threads will be able to execute items of
|
|
|
|
* this type.
|
|
|
|
*/
|
|
|
|
static inline void vslow_work_init(struct slow_work *work,
|
|
|
|
const struct slow_work_ops *ops)
|
|
|
|
{
|
|
|
|
work->flags = 1 << SLOW_WORK_VERY_SLOW;
|
|
|
|
work->ops = ops;
|
|
|
|
INIT_LIST_HEAD(&work->link);
|
|
|
|
}
|
|
|
|
|
2009-11-19 18:10:53 +00:00
|
|
|
/**
|
|
|
|
* slow_work_is_queued - Determine if a slow work item is on the work queue
|
|
|
|
* work: The work item to test
|
|
|
|
*
|
|
|
|
* Determine if the specified slow-work item is on the work queue. This
|
|
|
|
* returns true if it is actually on the queue.
|
|
|
|
*
|
|
|
|
* If the item is executing and has been marked for requeue when execution
|
|
|
|
* finishes, then false will be returned.
|
|
|
|
*
|
|
|
|
* Anyone wishing to wait for completion of execution can wait on the
|
|
|
|
* SLOW_WORK_EXECUTING bit.
|
|
|
|
*/
|
|
|
|
static inline bool slow_work_is_queued(struct slow_work *work)
|
|
|
|
{
|
|
|
|
unsigned long flags = work->flags;
|
|
|
|
return flags & SLOW_WORK_PENDING && !(flags & SLOW_WORK_EXECUTING);
|
|
|
|
}
|
|
|
|
|
2009-04-03 15:42:35 +00:00
|
|
|
extern int slow_work_enqueue(struct slow_work *work);
|
2009-11-19 18:10:43 +00:00
|
|
|
extern void slow_work_cancel(struct slow_work *work);
|
2009-11-19 18:10:23 +00:00
|
|
|
extern int slow_work_register_user(struct module *owner);
|
|
|
|
extern void slow_work_unregister_user(struct module *owner);
|
2009-04-03 15:42:35 +00:00
|
|
|
|
2009-11-19 18:10:47 +00:00
|
|
|
extern int delayed_slow_work_enqueue(struct delayed_slow_work *dwork,
|
|
|
|
unsigned long delay);
|
|
|
|
|
|
|
|
static inline void delayed_slow_work_cancel(struct delayed_slow_work *dwork)
|
|
|
|
{
|
|
|
|
slow_work_cancel(&dwork->work);
|
|
|
|
}
|
|
|
|
|
SLOW_WORK: Allow a requeueable work item to sleep till the thread is needed
Add a function to allow a requeueable work item to sleep till the thread
processing it is needed by the slow-work facility to perform other work.
Sometimes a work item can't progress immediately, but must wait for the
completion of another work item that's currently being processed by another
slow-work thread.
In some circumstances, the waiting item could instead - theoretically - put
itself back on the queue and yield its thread back to the slow-work facility,
thus waiting till it gets processing time again before attempting to progress.
This would allow other work items processing time on that thread.
However, this only works if there is something on the queue for it to queue
behind - otherwise it will just get a thread again immediately, and will end
up cycling between the queue and the thread, eating up valuable CPU time.
So, slow_work_sleep_till_thread_needed() is provided such that an item can put
itself on a wait queue that will wake it up when the event it is actually
interested in occurs, then call this function in lieu of calling schedule().
This function will then sleep until either the item's event occurs or another
work item appears on the queue. If another work item is queued, but the
item's event hasn't occurred, then the work item should requeue itself and
yield the thread back to the slow-work facility by returning.
This can be used by CacheFiles for an object that is being created on one
thread to wait for an object being deleted on another thread where there is
nothing on the queue for the creation to go and wait behind. As soon as an
item appears on the queue that could be given thread time instead, CacheFiles
can stick the creating object back on the queue and return to the slow-work
facility - assuming the object deletion didn't also complete.
Signed-off-by: David Howells <dhowells@redhat.com>
2009-11-19 18:10:57 +00:00
|
|
|
extern bool slow_work_sleep_till_thread_needed(struct slow_work *work,
|
|
|
|
signed long *_timeout);
|
|
|
|
|
2009-04-03 15:42:35 +00:00
|
|
|
#ifdef CONFIG_SYSCTL
|
|
|
|
extern ctl_table slow_work_sysctls[];
|
|
|
|
#endif
|
2009-04-03 15:42:35 +00:00
|
|
|
|
|
|
|
#endif /* CONFIG_SLOW_WORK */
|
|
|
|
#endif /* _LINUX_SLOW_WORK_H */
|