o So far we were assuming that a bio/rq belongs to the task who is submitting it. It did not hold good in case of async writes. This patch makes use of blkio_cgroup pataches to attribute the aysnc writes to right group instead of task submitting the bio.

o For sync requests, we continue to assume that io belongs to the task submitting it. Only in case of async requests, we make use of io tracking patches to track the owner cgroup.

o So far cfq always caches the async queue pointer. With async requests now not necessarily being tied to submitting task io context, caching the pointer will not help for async queues. This patch introduces a new config option CONFIG_TRACK_ASYNC_CONTEXT. If this option is not set, cfq retains old behavior where async queue pointer is cached in task context. If it is not set, async queue pointer is not cached and we take help of bio tracking patches to determine group bio belongs to and then map it to async queue of that group.

+config TRACK_ASYNC_CONTEXT+ bool "Determine async request context from bio"+ depends on GROUP_IOSCHED+ select CGROUP_BLKIO+ default n+ ---help---+ Normally async request is attributed to the task submitting the+ request. With group ioscheduling, for accurate accounting of+ async writes, one needs to map the request to original task/cgroup+ which originated the request and not the submitter of the request.++ Currently there are generic io tracking patches to provide facility+ to map bio to original owner. If this option is set, for async+ request, original owner of the bio is decided by using io tracking+ patches otherwise we continue to attribute the request to the+ submitting thread. endmenu

- /* ioc reference */+#ifdef CONFIG_TRACK_ASYNC_CONTEXT+ /*+ * ioc reference. If async request queue/group is determined from the+ * original task/cgroup and not from submitter task, io context can+ * not cache the pointer to async queue and everytime a request comes,+ * it will be determined by going through the async queue array.+ *+ * This comes from the fact that we might be getting async requests+ * which belong to a different cgroup altogether than the cgroup+ * iocontext belongs to. And this thread might be submitting bios+ * from various cgroups. So every time async queue will be different+ * based on the cgroup of the bio/rq. Can't cache the async cfqq+ * pointer in cic.+ */+ if (is_sync)+ elv_get_ioq(cfqq->ioq);+#else+ /*+ * async requests are being attributed to task submitting+ * it, hence cic can cache async cfqq pointer. Take the+ * queue reference even for async queue.+ */ elv_get_ioq(cfqq->ioq);+#endif return cfqq; }

/* Determine the io group and io queue of the bio submitting task */- iog = io_get_io_group(q, 0);+ iog = io_get_io_group(q, bio, 0); if (!iog) {- /* May be task belongs to a cgroup for which io group has+ /* May be bio belongs to a cgroup for which io group has * not been setup yet. */ return NULL; }@@ -2000,7 +2058,13 @@ void io_free_root_group(struct elevator_queue *e) kfree(iog); }

/*- * Get the io scheduler queue pointer for current task.+ * Get the io scheduler queue pointer for the group bio belongs to. * * If fair queuing is enabled, determine the io group of task and retrieve * the ioq pointer from that. This is used by only single queue ioschedulers * for retrieving the queue associated with the group to decide whether the * new bio can do a front merge or not. */-void *elv_get_sched_queue_current(struct request_queue *q)+void *elv_get_sched_queue_bio(struct request_queue *q, struct bio *bio) { /* Fair queuing is not enabled. There is only one queue. */ if (!elv_iosched_fair_queuing_enabled(q->elevator)) return q->elevator->sched_queue;