Commit 16f88dbd authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] generic io contexts

From: Nick Piggin <piggin@cyberone.com.au>

Generalise the AS-specific per-process IO context so that other IO schedulers
could use it.
parent 80af89ca
This diff is collapsed.
......@@ -1318,6 +1318,7 @@ get_request(request_queue_t *q, int rw, int gfp_mask, int force)
spin_lock_irq(q->queue_lock);
if (rl->count[rw] == q->nr_requests)
blk_set_queue_full(q, rw);
if (blk_queue_full(q, rw) && !force && !elv_may_queue(q, rw)) {
spin_unlock_irq(q->queue_lock);
goto out;
......@@ -2377,6 +2378,93 @@ int __init blk_dev_init(void)
return 0;
}
/*
* IO Context helper functions
*/
void put_io_context(struct io_context *ioc)
{
if (ioc == NULL)
return;
BUG_ON(atomic_read(&ioc->refcount) == 0);
if (atomic_dec_and_test(&ioc->refcount)) {
if (ioc->aic && ioc->aic->dtor)
ioc->aic->dtor(ioc->aic);
kfree(ioc);
}
}
/* Called by the exitting task */
void exit_io_context(void)
{
unsigned long flags;
struct io_context *ioc;
local_irq_save(flags);
ioc = current->io_context;
if (ioc) {
if (ioc->aic && ioc->aic->exit)
ioc->aic->exit(ioc->aic);
put_io_context(ioc);
current->io_context = NULL;
}
local_irq_restore(flags);
}
/*
* If the current task has no IO context then create one and initialise it.
* If it does have a context, take a ref on it.
*
* This is always called in the context of the task which submitted the I/O.
* But weird things happen, so we disable local interrupts to ensure exclusive
* access to *current.
*/
struct io_context *get_io_context(void)
{
struct task_struct *tsk = current;
unsigned long flags;
struct io_context *ret;
local_irq_save(flags);
ret = tsk->io_context;
if (ret == NULL) {
ret = kmalloc(sizeof(*ret), GFP_ATOMIC);
if (ret) {
atomic_set(&ret->refcount, 1);
ret->pid = tsk->pid;
ret->aic = NULL;
tsk->io_context = ret;
}
}
local_irq_restore(flags);
atomic_inc(&ret->refcount);
return ret;
}
void copy_io_context(struct io_context **pdst, struct io_context **psrc)
{
struct io_context *src = *psrc;
struct io_context *dst = *pdst;
if (src) {
BUG_ON(atomic_read(&src->refcount) == 0);
atomic_inc(&src->refcount);
put_io_context(dst);
*pdst = src;
}
}
void swap_io_context(struct io_context **ioc1, struct io_context **ioc2)
{
struct io_context *temp;
temp = *ioc1;
*ioc1 = *ioc2;
*ioc2 = temp;
}
/*
* sysfs parts below
*/
......
......@@ -24,6 +24,50 @@ struct request_pm_state;
#define BLKDEV_MIN_RQ 4
#define BLKDEV_MAX_RQ 128 /* Default maximum */
/*
* This is the per-process anticipatory I/O scheduler state.
*/
struct as_io_context {
spinlock_t lock;
void (*dtor)(struct as_io_context *aic); /* destructor */
void (*exit)(struct as_io_context *aic); /* called on task exit */
unsigned long state;
atomic_t nr_queued; /* queued reads & sync writes */
atomic_t nr_dispatched; /* number of requests gone to the drivers */
/* IO History tracking */
/* Thinktime */
unsigned long last_end_request;
unsigned long ttime_total;
unsigned long ttime_samples;
unsigned long ttime_mean;
/* Layout pattern */
long seek_samples;
sector_t last_request_pos;
sector_t seek_total;
sector_t seek_mean;
};
/*
* This is the per-process I/O subsystem state. It is refcounted and
* kmalloc'ed. Currently all fields are modified in process io context
* (apart from the atomic refcount), so require no locking.
*/
struct io_context {
atomic_t refcount;
pid_t pid;
struct as_io_context *aic;
};
void put_io_context(struct io_context *ioc);
void exit_io_context(void);
struct io_context *get_io_context(void);
void copy_io_context(struct io_context **pdst, struct io_context **psrc);
void swap_io_context(struct io_context **ioc1, struct io_context **ioc2);
struct request_list {
int count[2];
mempool_t *rq_pool;
......
......@@ -321,8 +321,8 @@ struct k_itimer {
};
struct as_io_context; /* Anticipatory scheduler */
void exit_as_io_context(void);
struct io_context; /* See blkdev.h */
void exit_io_context(void);
struct task_struct {
volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */
......@@ -452,7 +452,7 @@ struct task_struct {
struct dentry *proc_dentry;
struct backing_dev_info *backing_dev_info;
struct as_io_context *as_io_context;
struct io_context *io_context;
unsigned long ptrace_message;
siginfo_t *last_siginfo; /* For ptrace use. */
......
......@@ -682,8 +682,8 @@ NORET_TYPE void do_exit(long code)
panic("Attempted to kill the idle task!");
if (unlikely(tsk->pid == 1))
panic("Attempted to kill init!");
if (tsk->as_io_context)
exit_as_io_context();
if (tsk->io_context)
exit_io_context();
tsk->flags |= PF_EXITING;
del_timer_sync(&tsk->real_timer);
......
......@@ -864,7 +864,7 @@ struct task_struct *copy_process(unsigned long clone_flags,
p->lock_depth = -1; /* -1 = no lock */
p->start_time = get_jiffies_64();
p->security = NULL;
p->as_io_context = NULL;
p->io_context = NULL;
retval = -ENOMEM;
if ((retval = security_task_alloc(p)))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment