History

io context sharing: preliminary support

Detach task state from ioc, instead keep track of how many processes are accessing the ioc.

Jens Axboe committed 18 years ago

Commit d38ecf91 parent fd0928d5 files · +49 −23Browse files

Unified · Split

5 files
  1. block/ll_rw_blk.c +30 −16
  2. fs/ioprio.c +0 −1
  3. include/linux/blkdev.h +1 −1
  4. include/linux/iocontext.h +18 −4
  5. kernel/fork.c +0 −1
block/ll_rw_blk.c+30−16
@@ -3854,12 +3854,13 @@ int __init blk_dev_init(void) · 3853 unmodified lines
38543854 }
38553855
38563856 /*
3857− * IO Context helper functions
3857+ * IO Context helper functions. put_io_context() returns 1 if there are no
3858+ * more users of this io context, 0 otherwise.
38583859 */
3859−void put_io_context(struct io_context *ioc)
3860+int put_io_context(struct io_context *ioc)
38603861 {
38613862 if (ioc == NULL)
3862− return;
3863+ return 1;
38633864
38643865 BUG_ON(atomic_read(&ioc->refcount) == 0);
38653866
@@ -3878,7 +3879,9 @@ void put_io_context(struct io_context *ioc) · 12 unmodified lines
38783879 rcu_read_unlock();
38793880
38803881 kmem_cache_free(iocontext_cachep, ioc);
3882+ return 1;
38813883 }
3884+ return 0;
38823885 }
38833886 EXPORT_SYMBOL(put_io_context);
38843887
@@ -3893,15 +3896,17 @@ void exit_io_context(void) · 8 unmodified lines
38933896 current->io_context = NULL;
38943897 task_unlock(current);
38953898
3896− ioc->task = NULL;
3897− if (ioc->aic && ioc->aic->exit)
3898− ioc->aic->exit(ioc->aic);
3899− if (ioc->cic_root.rb_node != NULL) {
3900− cic = rb_entry(rb_first(&ioc->cic_root), struct cfq_io_context, rb_node);
3901− cic->exit(ioc);
3902− }
3899+ if (atomic_dec_and_test(&ioc->nr_tasks)) {
3900+ if (ioc->aic && ioc->aic->exit)
3901+ ioc->aic->exit(ioc->aic);
3902+ if (ioc->cic_root.rb_node != NULL) {
3903+ cic = rb_entry(rb_first(&ioc->cic_root),
3904+ struct cfq_io_context, rb_node);
3905+ cic->exit(ioc);
3906+ }
39033907
3904− put_io_context(ioc);
3908+ put_io_context(ioc);
3909+ }
39053910 }
39063911
39073912 struct io_context *alloc_io_context(gfp_t gfp_flags, int node)
@@ -3911,7 +3916,8 @@ struct io_context *alloc_io_context(gfp_t gfp_flags, int node) · 3 unmodified lines
39113916 ret = kmem_cache_alloc_node(iocontext_cachep, gfp_flags, node);
39123917 if (ret) {
39133918 atomic_set(&ret->refcount, 1);
3914− ret->task = current;
3919+ atomic_set(&ret->nr_tasks, 1);
3920+ spin_lock_init(&ret->lock);
39153921 ret->ioprio_changed = 0;
39163922 ret->ioprio = 0;
39173923 ret->last_waited = jiffies; /* doesn't matter... */
@@ -3959,10 +3965,18 @@ static struct io_context *current_io_context(gfp_t gfp_flags, int node) · 41 unmodified lines
39593965 */
39603966 struct io_context *get_io_context(gfp_t gfp_flags, int node)
39613967 {
3962− struct io_context *ret;
3963− ret = current_io_context(gfp_flags, node);
3964− if (likely(ret))
3965− atomic_inc(&ret->refcount);
3968+ struct io_context *ret = NULL;
3969+
3970+ /*
3971+ * Check for unlikely race with exiting task. ioc ref count is
3972+ * zero when ioc is being detached.
3973+ */
3974+ do {
3975+ ret = current_io_context(gfp_flags, node);
3976+ if (unlikely(!ret))
3977+ break;
3978+ } while (!atomic_inc_not_zero(&ret->refcount));
3979+
39663980 return ret;
39673981 }
39683982 EXPORT_SYMBOL(get_io_context);
fs/ioprio.c+0−1
@@ -54,7 +54,6 @@ static int set_task_ioprio(struct task_struct *task, int ioprio) · 53 unmodified lines
5454 break;
5555 }
5656 task->io_context = ioc;
57− ioc->task = task;
5857 } while (1);
5958
6059 if (!err) {
include/linux/blkdev.h+1−1
@@ -34,7 +34,7 @@ struct sg_io_hdr; · 33 unmodified lines
3434 #define BLKDEV_MIN_RQ 4
3535 #define BLKDEV_MAX_RQ 128 /* Default maximum */
3636
37−void put_io_context(struct io_context *ioc);
37+int put_io_context(struct io_context *ioc);
3838 void exit_io_context(void);
3939 struct io_context *get_io_context(gfp_t gfp_flags, int node);
4040 struct io_context *alloc_io_context(gfp_t gfp_flags, int node);
include/linux/iocontext.h+18−4
@@ -54,13 +54,15 @@ struct cfq_io_context { · 53 unmodified lines
5454 };
5555
5656 /*
57− * This is the per-process I/O subsystem state. It is refcounted and
58− * kmalloc'ed. Currently all fields are modified in process io context
59− * (apart from the atomic refcount), so require no locking.
57+ * I/O subsystem state of the associated processes. It is refcounted
58+ * and kmalloc'ed. These could be shared between processes.
6059 */
6160 struct io_context {
6261 atomic_t refcount;
63− struct task_struct *task;
62+ atomic_t nr_tasks;
63+
64+ /* all the fields below are protected by this lock */
65+ spinlock_t lock;
6466
6567 unsigned short ioprio;
6668 unsigned short ioprio_changed;
@@ -76,4 +78,16 @@ struct io_context { · 9 unmodified lines
7678 void *ioc_data;
7779 };
7880
81+static inline struct io_context *ioc_task_link(struct io_context *ioc)
82+{
83+ /*
84+ * if ref count is zero, don't allow sharing (ioc is going away, it's
85+ * a race).
86+ */
87+ if (ioc && atomic_inc_not_zero(&ioc->refcount))
88+ return ioc;
89+
90+ return NULL;
91+}
92+
7993 #endif
kernel/fork.c+0−1
@@ -805,7 +805,6 @@ static int copy_io(struct task_struct *tsk) · 804 unmodified lines
805805 if (unlikely(!tsk->io_context))
806806 return -ENOMEM;
807807
808− tsk->io_context->task = tsk;
809808 tsk->io_context->ioprio = ioc->ioprio;
810809 }
811810 #endif