5003_BFQ-3-block-add-Early-Queue-Merge-EQM-v7r5-for-3.16.0.patch 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189
  1. From 5b290be286aa74051b4b77a216032b771ceadd23 Mon Sep 17 00:00:00 2001
  2. From: Mauro Andreolini <mauro.andreolini@unimore.it>
  3. Date: Wed, 18 Jun 2014 17:38:07 +0200
  4. Subject: [PATCH 3/3] block, bfq: add Early Queue Merge (EQM) to BFQ-v7r5 for
  5. 3.16.0
  6. A set of processes may happen to perform interleaved reads, i.e.,requests
  7. whose union would give rise to a sequential read pattern. There are two
  8. typical cases: in the first case, processes read fixed-size chunks of
  9. data at a fixed distance from each other, while in the second case processes
  10. may read variable-size chunks at variable distances. The latter case occurs
  11. for example with QEMU, which splits the I/O generated by the guest into
  12. multiple chunks, and lets these chunks be served by a pool of cooperating
  13. processes, iteratively assigning the next chunk of I/O to the first
  14. available process. CFQ uses actual queue merging for the first type of
  15. rocesses, whereas it uses preemption to get a sequential read pattern out
  16. of the read requests performed by the second type of processes. In the end
  17. it uses two different mechanisms to achieve the same goal: boosting the
  18. throughput with interleaved I/O.
  19. This patch introduces Early Queue Merge (EQM), a unified mechanism to get a
  20. sequential read pattern with both types of processes. The main idea is
  21. checking newly arrived requests against the next request of the active queue
  22. both in case of actual request insert and in case of request merge. By doing
  23. so, both the types of processes can be handled by just merging their queues.
  24. EQM is then simpler and more compact than the pair of mechanisms used in
  25. CFQ.
  26. Finally, EQM also preserves the typical low-latency properties of BFQ, by
  27. properly restoring the weight-raising state of a queue when it gets back to
  28. a non-merged state.
  29. Signed-off-by: Mauro Andreolini <mauro.andreolini@unimore.it>
  30. Signed-off-by: Arianna Avanzini <avanzini.arianna@gmail.com>
  31. Signed-off-by: Paolo Valente <paolo.valente@unimore.it>
  32. ---
  33. block/bfq-iosched.c | 736 ++++++++++++++++++++++++++++++++++++----------------
  34. block/bfq-sched.c | 28 --
  35. block/bfq.h | 46 +++-
  36. 3 files changed, 556 insertions(+), 254 deletions(-)
  37. diff --git a/block/bfq-iosched.c b/block/bfq-iosched.c
  38. index 0a0891b..d1d8e67 100644
  39. --- a/block/bfq-iosched.c
  40. +++ b/block/bfq-iosched.c
  41. @@ -571,6 +571,57 @@ static inline unsigned int bfq_wr_duration(struct bfq_data *bfqd)
  42. return dur;
  43. }
  44. +static inline unsigned
  45. +bfq_bfqq_cooperations(struct bfq_queue *bfqq)
  46. +{
  47. + return bfqq->bic ? bfqq->bic->cooperations : 0;
  48. +}
  49. +
  50. +static inline void
  51. +bfq_bfqq_resume_state(struct bfq_queue *bfqq, struct bfq_io_cq *bic)
  52. +{
  53. + if (bic->saved_idle_window)
  54. + bfq_mark_bfqq_idle_window(bfqq);
  55. + else
  56. + bfq_clear_bfqq_idle_window(bfqq);
  57. + if (bic->saved_IO_bound)
  58. + bfq_mark_bfqq_IO_bound(bfqq);
  59. + else
  60. + bfq_clear_bfqq_IO_bound(bfqq);
  61. + if (bic->wr_time_left && bfqq->bfqd->low_latency &&
  62. + bic->cooperations < bfqq->bfqd->bfq_coop_thresh) {
  63. + /*
  64. + * Start a weight raising period with the duration given by
  65. + * the raising_time_left snapshot.
  66. + */
  67. + if (bfq_bfqq_busy(bfqq))
  68. + bfqq->bfqd->wr_busy_queues++;
  69. + bfqq->wr_coeff = bfqq->bfqd->bfq_wr_coeff;
  70. + bfqq->wr_cur_max_time = bic->wr_time_left;
  71. + bfqq->last_wr_start_finish = jiffies;
  72. + bfqq->entity.ioprio_changed = 1;
  73. + }
  74. + /*
  75. + * Clear wr_time_left to prevent bfq_bfqq_save_state() from
  76. + * getting confused about the queue's need of a weight-raising
  77. + * period.
  78. + */
  79. + bic->wr_time_left = 0;
  80. +}
  81. +
  82. +/*
  83. + * Must be called with the queue_lock held.
  84. + */
  85. +static int bfqq_process_refs(struct bfq_queue *bfqq)
  86. +{
  87. + int process_refs, io_refs;
  88. +
  89. + io_refs = bfqq->allocated[READ] + bfqq->allocated[WRITE];
  90. + process_refs = atomic_read(&bfqq->ref) - io_refs - bfqq->entity.on_st;
  91. + BUG_ON(process_refs < 0);
  92. + return process_refs;
  93. +}
  94. +
  95. static void bfq_add_request(struct request *rq)
  96. {
  97. struct bfq_queue *bfqq = RQ_BFQQ(rq);
  98. @@ -602,8 +653,11 @@ static void bfq_add_request(struct request *rq)
  99. if (!bfq_bfqq_busy(bfqq)) {
  100. int soft_rt = bfqd->bfq_wr_max_softrt_rate > 0 &&
  101. + bfq_bfqq_cooperations(bfqq) < bfqd->bfq_coop_thresh &&
  102. time_is_before_jiffies(bfqq->soft_rt_next_start);
  103. - idle_for_long_time = time_is_before_jiffies(
  104. + idle_for_long_time = bfq_bfqq_cooperations(bfqq) <
  105. + bfqd->bfq_coop_thresh &&
  106. + time_is_before_jiffies(
  107. bfqq->budget_timeout +
  108. bfqd->bfq_wr_min_idle_time);
  109. entity->budget = max_t(unsigned long, bfqq->max_budget,
  110. @@ -624,11 +678,20 @@ static void bfq_add_request(struct request *rq)
  111. if (!bfqd->low_latency)
  112. goto add_bfqq_busy;
  113. + if (bfq_bfqq_just_split(bfqq))
  114. + goto set_ioprio_changed;
  115. +
  116. /*
  117. - * If the queue is not being boosted and has been idle
  118. - * for enough time, start a weight-raising period
  119. + * If the queue:
  120. + * - is not being boosted,
  121. + * - has been idle for enough time,
  122. + * - is not a sync queue or is linked to a bfq_io_cq (it is
  123. + * shared "for its nature" or it is not shared and its
  124. + * requests have not been redirected to a shared queue)
  125. + * start a weight-raising period.
  126. */
  127. - if (old_wr_coeff == 1 && (idle_for_long_time || soft_rt)) {
  128. + if (old_wr_coeff == 1 && (idle_for_long_time || soft_rt) &&
  129. + (!bfq_bfqq_sync(bfqq) || bfqq->bic != NULL)) {
  130. bfqq->wr_coeff = bfqd->bfq_wr_coeff;
  131. if (idle_for_long_time)
  132. bfqq->wr_cur_max_time = bfq_wr_duration(bfqd);
  133. @@ -642,9 +705,11 @@ static void bfq_add_request(struct request *rq)
  134. } else if (old_wr_coeff > 1) {
  135. if (idle_for_long_time)
  136. bfqq->wr_cur_max_time = bfq_wr_duration(bfqd);
  137. - else if (bfqq->wr_cur_max_time ==
  138. - bfqd->bfq_wr_rt_max_time &&
  139. - !soft_rt) {
  140. + else if (bfq_bfqq_cooperations(bfqq) >=
  141. + bfqd->bfq_coop_thresh ||
  142. + (bfqq->wr_cur_max_time ==
  143. + bfqd->bfq_wr_rt_max_time &&
  144. + !soft_rt)) {
  145. bfqq->wr_coeff = 1;
  146. bfq_log_bfqq(bfqd, bfqq,
  147. "wrais ending at %lu, rais_max_time %u",
  148. @@ -660,18 +725,18 @@ static void bfq_add_request(struct request *rq)
  149. /*
  150. *
  151. * The remaining weight-raising time is lower
  152. - * than bfqd->bfq_wr_rt_max_time, which
  153. - * means that the application is enjoying
  154. - * weight raising either because deemed soft-
  155. - * rt in the near past, or because deemed
  156. - * interactive a long ago. In both cases,
  157. - * resetting now the current remaining weight-
  158. - * raising time for the application to the
  159. - * weight-raising duration for soft rt
  160. - * applications would not cause any latency
  161. - * increase for the application (as the new
  162. - * duration would be higher than the remaining
  163. - * time).
  164. + * than bfqd->bfq_wr_rt_max_time, which means
  165. + * that the application is enjoying weight
  166. + * raising either because deemed soft-rt in
  167. + * the near past, or because deemed interactive
  168. + * a long ago.
  169. + * In both cases, resetting now the current
  170. + * remaining weight-raising time for the
  171. + * application to the weight-raising duration
  172. + * for soft rt applications would not cause any
  173. + * latency increase for the application (as the
  174. + * new duration would be higher than the
  175. + * remaining time).
  176. *
  177. * In addition, the application is now meeting
  178. * the requirements for being deemed soft rt.
  179. @@ -706,6 +771,7 @@ static void bfq_add_request(struct request *rq)
  180. bfqd->bfq_wr_rt_max_time;
  181. }
  182. }
  183. +set_ioprio_changed:
  184. if (old_wr_coeff != bfqq->wr_coeff)
  185. entity->ioprio_changed = 1;
  186. add_bfqq_busy:
  187. @@ -918,90 +984,35 @@ static void bfq_end_wr(struct bfq_data *bfqd)
  188. spin_unlock_irq(bfqd->queue->queue_lock);
  189. }
  190. -static int bfq_allow_merge(struct request_queue *q, struct request *rq,
  191. - struct bio *bio)
  192. +static inline sector_t bfq_io_struct_pos(void *io_struct, bool request)
  193. {
  194. - struct bfq_data *bfqd = q->elevator->elevator_data;
  195. - struct bfq_io_cq *bic;
  196. - struct bfq_queue *bfqq;
  197. -
  198. - /*
  199. - * Disallow merge of a sync bio into an async request.
  200. - */
  201. - if (bfq_bio_sync(bio) && !rq_is_sync(rq))
  202. - return 0;
  203. -
  204. - /*
  205. - * Lookup the bfqq that this bio will be queued with. Allow
  206. - * merge only if rq is queued there.
  207. - * Queue lock is held here.
  208. - */
  209. - bic = bfq_bic_lookup(bfqd, current->io_context);
  210. - if (bic == NULL)
  211. - return 0;
  212. -
  213. - bfqq = bic_to_bfqq(bic, bfq_bio_sync(bio));
  214. - return bfqq == RQ_BFQQ(rq);
  215. -}
  216. -
  217. -static void __bfq_set_in_service_queue(struct bfq_data *bfqd,
  218. - struct bfq_queue *bfqq)
  219. -{
  220. - if (bfqq != NULL) {
  221. - bfq_mark_bfqq_must_alloc(bfqq);
  222. - bfq_mark_bfqq_budget_new(bfqq);
  223. - bfq_clear_bfqq_fifo_expire(bfqq);
  224. -
  225. - bfqd->budgets_assigned = (bfqd->budgets_assigned*7 + 256) / 8;
  226. -
  227. - bfq_log_bfqq(bfqd, bfqq,
  228. - "set_in_service_queue, cur-budget = %lu",
  229. - bfqq->entity.budget);
  230. - }
  231. -
  232. - bfqd->in_service_queue = bfqq;
  233. -}
  234. -
  235. -/*
  236. - * Get and set a new queue for service.
  237. - */
  238. -static struct bfq_queue *bfq_set_in_service_queue(struct bfq_data *bfqd,
  239. - struct bfq_queue *bfqq)
  240. -{
  241. - if (!bfqq)
  242. - bfqq = bfq_get_next_queue(bfqd);
  243. + if (request)
  244. + return blk_rq_pos(io_struct);
  245. else
  246. - bfq_get_next_queue_forced(bfqd, bfqq);
  247. -
  248. - __bfq_set_in_service_queue(bfqd, bfqq);
  249. - return bfqq;
  250. + return ((struct bio *)io_struct)->bi_iter.bi_sector;
  251. }
  252. -static inline sector_t bfq_dist_from_last(struct bfq_data *bfqd,
  253. - struct request *rq)
  254. +static inline sector_t bfq_dist_from(sector_t pos1,
  255. + sector_t pos2)
  256. {
  257. - if (blk_rq_pos(rq) >= bfqd->last_position)
  258. - return blk_rq_pos(rq) - bfqd->last_position;
  259. + if (pos1 >= pos2)
  260. + return pos1 - pos2;
  261. else
  262. - return bfqd->last_position - blk_rq_pos(rq);
  263. + return pos2 - pos1;
  264. }
  265. -/*
  266. - * Return true if bfqq has no request pending and rq is close enough to
  267. - * bfqd->last_position, or if rq is closer to bfqd->last_position than
  268. - * bfqq->next_rq
  269. - */
  270. -static inline int bfq_rq_close(struct bfq_data *bfqd, struct request *rq)
  271. +static inline int bfq_rq_close_to_sector(void *io_struct, bool request,
  272. + sector_t sector)
  273. {
  274. - return bfq_dist_from_last(bfqd, rq) <= BFQQ_SEEK_THR;
  275. + return bfq_dist_from(bfq_io_struct_pos(io_struct, request), sector) <=
  276. + BFQQ_SEEK_THR;
  277. }
  278. -static struct bfq_queue *bfqq_close(struct bfq_data *bfqd)
  279. +static struct bfq_queue *bfqq_close(struct bfq_data *bfqd, sector_t sector)
  280. {
  281. struct rb_root *root = &bfqd->rq_pos_tree;
  282. struct rb_node *parent, *node;
  283. struct bfq_queue *__bfqq;
  284. - sector_t sector = bfqd->last_position;
  285. if (RB_EMPTY_ROOT(root))
  286. return NULL;
  287. @@ -1020,7 +1031,7 @@ static struct bfq_queue *bfqq_close(struct bfq_data *bfqd)
  288. * next_request position).
  289. */
  290. __bfqq = rb_entry(parent, struct bfq_queue, pos_node);
  291. - if (bfq_rq_close(bfqd, __bfqq->next_rq))
  292. + if (bfq_rq_close_to_sector(__bfqq->next_rq, true, sector))
  293. return __bfqq;
  294. if (blk_rq_pos(__bfqq->next_rq) < sector)
  295. @@ -1031,7 +1042,7 @@ static struct bfq_queue *bfqq_close(struct bfq_data *bfqd)
  296. return NULL;
  297. __bfqq = rb_entry(node, struct bfq_queue, pos_node);
  298. - if (bfq_rq_close(bfqd, __bfqq->next_rq))
  299. + if (bfq_rq_close_to_sector(__bfqq->next_rq, true, sector))
  300. return __bfqq;
  301. return NULL;
  302. @@ -1040,14 +1051,12 @@ static struct bfq_queue *bfqq_close(struct bfq_data *bfqd)
  303. /*
  304. * bfqd - obvious
  305. * cur_bfqq - passed in so that we don't decide that the current queue
  306. - * is closely cooperating with itself.
  307. - *
  308. - * We are assuming that cur_bfqq has dispatched at least one request,
  309. - * and that bfqd->last_position reflects a position on the disk associated
  310. - * with the I/O issued by cur_bfqq.
  311. + * is closely cooperating with itself
  312. + * sector - used as a reference point to search for a close queue
  313. */
  314. static struct bfq_queue *bfq_close_cooperator(struct bfq_data *bfqd,
  315. - struct bfq_queue *cur_bfqq)
  316. + struct bfq_queue *cur_bfqq,
  317. + sector_t sector)
  318. {
  319. struct bfq_queue *bfqq;
  320. @@ -1067,7 +1076,7 @@ static struct bfq_queue *bfq_close_cooperator(struct bfq_data *bfqd,
  321. * working closely on the same area of the disk. In that case,
  322. * we can group them together and don't waste time idling.
  323. */
  324. - bfqq = bfqq_close(bfqd);
  325. + bfqq = bfqq_close(bfqd, sector);
  326. if (bfqq == NULL || bfqq == cur_bfqq)
  327. return NULL;
  328. @@ -1094,6 +1103,305 @@ static struct bfq_queue *bfq_close_cooperator(struct bfq_data *bfqd,
  329. return bfqq;
  330. }
  331. +static struct bfq_queue *
  332. +bfq_setup_merge(struct bfq_queue *bfqq, struct bfq_queue *new_bfqq)
  333. +{
  334. + int process_refs, new_process_refs;
  335. + struct bfq_queue *__bfqq;
  336. +
  337. + /*
  338. + * If there are no process references on the new_bfqq, then it is
  339. + * unsafe to follow the ->new_bfqq chain as other bfqq's in the chain
  340. + * may have dropped their last reference (not just their last process
  341. + * reference).
  342. + */
  343. + if (!bfqq_process_refs(new_bfqq))
  344. + return NULL;
  345. +
  346. + /* Avoid a circular list and skip interim queue merges. */
  347. + while ((__bfqq = new_bfqq->new_bfqq)) {
  348. + if (__bfqq == bfqq)
  349. + return NULL;
  350. + new_bfqq = __bfqq;
  351. + }
  352. +
  353. + process_refs = bfqq_process_refs(bfqq);
  354. + new_process_refs = bfqq_process_refs(new_bfqq);
  355. + /*
  356. + * If the process for the bfqq has gone away, there is no
  357. + * sense in merging the queues.
  358. + */
  359. + if (process_refs == 0 || new_process_refs == 0)
  360. + return NULL;
  361. +
  362. + bfq_log_bfqq(bfqq->bfqd, bfqq, "scheduling merge with queue %d",
  363. + new_bfqq->pid);
  364. +
  365. + /*
  366. + * Merging is just a redirection: the requests of the process
  367. + * owning one of the two queues are redirected to the other queue.
  368. + * The latter queue, in its turn, is set as shared if this is the
  369. + * first time that the requests of some process are redirected to
  370. + * it.
  371. + *
  372. + * We redirect bfqq to new_bfqq and not the opposite, because we
  373. + * are in the context of the process owning bfqq, hence we have
  374. + * the io_cq of this process. So we can immediately configure this
  375. + * io_cq to redirect the requests of the process to new_bfqq.
  376. + *
  377. + * NOTE, even if new_bfqq coincides with the in-service queue, the
  378. + * io_cq of new_bfqq is not available, because, if the in-service
  379. + * queue is shared, bfqd->in_service_bic may not point to the
  380. + * io_cq of the in-service queue.
  381. + * Redirecting the requests of the process owning bfqq to the
  382. + * currently in-service queue is in any case the best option, as
  383. + * we feed the in-service queue with new requests close to the
  384. + * last request served and, by doing so, hopefully increase the
  385. + * throughput.
  386. + */
  387. + bfqq->new_bfqq = new_bfqq;
  388. + atomic_add(process_refs, &new_bfqq->ref);
  389. + return new_bfqq;
  390. +}
  391. +
  392. +/*
  393. + * Attempt to schedule a merge of bfqq with the currently in-service queue
  394. + * or with a close queue among the scheduled queues.
  395. + * Return NULL if no merge was scheduled, a pointer to the shared bfq_queue
  396. + * structure otherwise.
  397. + */
  398. +static struct bfq_queue *
  399. +bfq_setup_cooperator(struct bfq_data *bfqd, struct bfq_queue *bfqq,
  400. + void *io_struct, bool request)
  401. +{
  402. + struct bfq_queue *in_service_bfqq, *new_bfqq;
  403. +
  404. + if (bfqq->new_bfqq)
  405. + return bfqq->new_bfqq;
  406. +
  407. + if (!io_struct)
  408. + return NULL;
  409. +
  410. + in_service_bfqq = bfqd->in_service_queue;
  411. +
  412. + if (in_service_bfqq == NULL || in_service_bfqq == bfqq ||
  413. + !bfqd->in_service_bic)
  414. + goto check_scheduled;
  415. +
  416. + if (bfq_class_idle(in_service_bfqq) || bfq_class_idle(bfqq))
  417. + goto check_scheduled;
  418. +
  419. + if (bfq_class_rt(in_service_bfqq) != bfq_class_rt(bfqq))
  420. + goto check_scheduled;
  421. +
  422. + if (in_service_bfqq->entity.parent != bfqq->entity.parent)
  423. + goto check_scheduled;
  424. +
  425. + if (bfq_rq_close_to_sector(io_struct, request, bfqd->last_position) &&
  426. + bfq_bfqq_sync(in_service_bfqq) && bfq_bfqq_sync(bfqq)) {
  427. + new_bfqq = bfq_setup_merge(bfqq, in_service_bfqq);
  428. + if (new_bfqq != NULL)
  429. + return new_bfqq; /* Merge with in-service queue */
  430. + }
  431. +
  432. + /*
  433. + * Check whether there is a cooperator among currently scheduled
  434. + * queues. The only thing we need is that the bio/request is not
  435. + * NULL, as we need it to establish whether a cooperator exists.
  436. + */
  437. +check_scheduled:
  438. + new_bfqq = bfq_close_cooperator(bfqd, bfqq,
  439. + bfq_io_struct_pos(io_struct, request));
  440. + if (new_bfqq)
  441. + return bfq_setup_merge(bfqq, new_bfqq);
  442. +
  443. + return NULL;
  444. +}
  445. +
  446. +static inline void
  447. +bfq_bfqq_save_state(struct bfq_queue *bfqq)
  448. +{
  449. + /*
  450. + * If bfqq->bic == NULL, the queue is already shared or its requests
  451. + * have already been redirected to a shared queue; both idle window
  452. + * and weight raising state have already been saved. Do nothing.
  453. + */
  454. + if (bfqq->bic == NULL)
  455. + return;
  456. + if (bfqq->bic->wr_time_left)
  457. + /*
  458. + * This is the queue of a just-started process, and would
  459. + * deserve weight raising: we set wr_time_left to the full
  460. + * weight-raising duration to trigger weight-raising when
  461. + * and if the queue is split and the first request of the
  462. + * queue is enqueued.
  463. + */
  464. + bfqq->bic->wr_time_left = bfq_wr_duration(bfqq->bfqd);
  465. + else if (bfqq->wr_coeff > 1) {
  466. + unsigned long wr_duration =
  467. + jiffies - bfqq->last_wr_start_finish;
  468. + /*
  469. + * It may happen that a queue's weight raising period lasts
  470. + * longer than its wr_cur_max_time, as weight raising is
  471. + * handled only when a request is enqueued or dispatched (it
  472. + * does not use any timer). If the weight raising period is
  473. + * about to end, don't save it.
  474. + */
  475. + if (bfqq->wr_cur_max_time <= wr_duration)
  476. + bfqq->bic->wr_time_left = 0;
  477. + else
  478. + bfqq->bic->wr_time_left =
  479. + bfqq->wr_cur_max_time - wr_duration;
  480. + /*
  481. + * The bfq_queue is becoming shared or the requests of the
  482. + * process owning the queue are being redirected to a shared
  483. + * queue. Stop the weight raising period of the queue, as in
  484. + * both cases it should not be owned by an interactive or
  485. + * soft real-time application.
  486. + */
  487. + bfq_bfqq_end_wr(bfqq);
  488. + } else
  489. + bfqq->bic->wr_time_left = 0;
  490. + bfqq->bic->saved_idle_window = bfq_bfqq_idle_window(bfqq);
  491. + bfqq->bic->saved_IO_bound = bfq_bfqq_IO_bound(bfqq);
  492. + bfqq->bic->cooperations++;
  493. + bfqq->bic->failed_cooperations = 0;
  494. +}
  495. +
  496. +static inline void
  497. +bfq_get_bic_reference(struct bfq_queue *bfqq)
  498. +{
  499. + /*
  500. + * If bfqq->bic has a non-NULL value, the bic to which it belongs
  501. + * is about to begin using a shared bfq_queue.
  502. + */
  503. + if (bfqq->bic)
  504. + atomic_long_inc(&bfqq->bic->icq.ioc->refcount);
  505. +}
  506. +
  507. +static void
  508. +bfq_merge_bfqqs(struct bfq_data *bfqd, struct bfq_io_cq *bic,
  509. + struct bfq_queue *bfqq, struct bfq_queue *new_bfqq)
  510. +{
  511. + bfq_log_bfqq(bfqd, bfqq, "merging with queue %lu",
  512. + (long unsigned)new_bfqq->pid);
  513. + /* Save weight raising and idle window of the merged queues */
  514. + bfq_bfqq_save_state(bfqq);
  515. + bfq_bfqq_save_state(new_bfqq);
  516. + if (bfq_bfqq_IO_bound(bfqq))
  517. + bfq_mark_bfqq_IO_bound(new_bfqq);
  518. + bfq_clear_bfqq_IO_bound(bfqq);
  519. + /*
  520. + * Grab a reference to the bic, to prevent it from being destroyed
  521. + * before being possibly touched by a bfq_split_bfqq().
  522. + */
  523. + bfq_get_bic_reference(bfqq);
  524. + bfq_get_bic_reference(new_bfqq);
  525. + /*
  526. + * Merge queues (that is, let bic redirect its requests to new_bfqq)
  527. + */
  528. + bic_set_bfqq(bic, new_bfqq, 1);
  529. + bfq_mark_bfqq_coop(new_bfqq);
  530. + /*
  531. + * new_bfqq now belongs to at least two bics (it is a shared queue):
  532. + * set new_bfqq->bic to NULL. bfqq either:
  533. + * - does not belong to any bic any more, and hence bfqq->bic must
  534. + * be set to NULL, or
  535. + * - is a queue whose owning bics have already been redirected to a
  536. + * different queue, hence the queue is destined to not belong to
  537. + * any bic soon and bfqq->bic is already NULL (therefore the next
  538. + * assignment causes no harm).
  539. + */
  540. + new_bfqq->bic = NULL;
  541. + bfqq->bic = NULL;
  542. + bfq_put_queue(bfqq);
  543. +}
  544. +
  545. +static inline void bfq_bfqq_increase_failed_cooperations(struct bfq_queue *bfqq)
  546. +{
  547. + struct bfq_io_cq *bic = bfqq->bic;
  548. + struct bfq_data *bfqd = bfqq->bfqd;
  549. +
  550. + if (bic && bfq_bfqq_cooperations(bfqq) >= bfqd->bfq_coop_thresh) {
  551. + bic->failed_cooperations++;
  552. + if (bic->failed_cooperations >= bfqd->bfq_failed_cooperations)
  553. + bic->cooperations = 0;
  554. + }
  555. +}
  556. +
  557. +static int bfq_allow_merge(struct request_queue *q, struct request *rq,
  558. + struct bio *bio)
  559. +{
  560. + struct bfq_data *bfqd = q->elevator->elevator_data;
  561. + struct bfq_io_cq *bic;
  562. + struct bfq_queue *bfqq, *new_bfqq;
  563. +
  564. + /*
  565. + * Disallow merge of a sync bio into an async request.
  566. + */
  567. + if (bfq_bio_sync(bio) && !rq_is_sync(rq))
  568. + return 0;
  569. +
  570. + /*
  571. + * Lookup the bfqq that this bio will be queued with. Allow
  572. + * merge only if rq is queued there.
  573. + * Queue lock is held here.
  574. + */
  575. + bic = bfq_bic_lookup(bfqd, current->io_context);
  576. + if (bic == NULL)
  577. + return 0;
  578. +
  579. + bfqq = bic_to_bfqq(bic, bfq_bio_sync(bio));
  580. + /*
  581. + * We take advantage of this function to perform an early merge
  582. + * of the queues of possible cooperating processes.
  583. + */
  584. + if (bfqq != NULL) {
  585. + new_bfqq = bfq_setup_cooperator(bfqd, bfqq, bio, false);
  586. + if (new_bfqq != NULL) {
  587. + bfq_merge_bfqqs(bfqd, bic, bfqq, new_bfqq);
  588. + /*
  589. + * If we get here, the bio will be queued in the
  590. + * shared queue, i.e., new_bfqq, so use new_bfqq
  591. + * to decide whether bio and rq can be merged.
  592. + */
  593. + bfqq = new_bfqq;
  594. + } else
  595. + bfq_bfqq_increase_failed_cooperations(bfqq);
  596. + }
  597. +
  598. + return bfqq == RQ_BFQQ(rq);
  599. +}
  600. +
  601. +static void __bfq_set_in_service_queue(struct bfq_data *bfqd,
  602. + struct bfq_queue *bfqq)
  603. +{
  604. + if (bfqq != NULL) {
  605. + bfq_mark_bfqq_must_alloc(bfqq);
  606. + bfq_mark_bfqq_budget_new(bfqq);
  607. + bfq_clear_bfqq_fifo_expire(bfqq);
  608. +
  609. + bfqd->budgets_assigned = (bfqd->budgets_assigned*7 + 256) / 8;
  610. +
  611. + bfq_log_bfqq(bfqd, bfqq,
  612. + "set_in_service_queue, cur-budget = %lu",
  613. + bfqq->entity.budget);
  614. + }
  615. +
  616. + bfqd->in_service_queue = bfqq;
  617. +}
  618. +
  619. +/*
  620. + * Get and set a new queue for service.
  621. + */
  622. +static struct bfq_queue *bfq_set_in_service_queue(struct bfq_data *bfqd)
  623. +{
  624. + struct bfq_queue *bfqq = bfq_get_next_queue(bfqd);
  625. +
  626. + __bfq_set_in_service_queue(bfqd, bfqq);
  627. + return bfqq;
  628. +}
  629. +
  630. /*
  631. * If enough samples have been computed, return the current max budget
  632. * stored in bfqd, which is dynamically updated according to the
  633. @@ -1237,63 +1545,6 @@ static struct request *bfq_check_fifo(struct bfq_queue *bfqq)
  634. return rq;
  635. }
  636. -/*
  637. - * Must be called with the queue_lock held.
  638. - */
  639. -static int bfqq_process_refs(struct bfq_queue *bfqq)
  640. -{
  641. - int process_refs, io_refs;
  642. -
  643. - io_refs = bfqq->allocated[READ] + bfqq->allocated[WRITE];
  644. - process_refs = atomic_read(&bfqq->ref) - io_refs - bfqq->entity.on_st;
  645. - BUG_ON(process_refs < 0);
  646. - return process_refs;
  647. -}
  648. -
  649. -static void bfq_setup_merge(struct bfq_queue *bfqq, struct bfq_queue *new_bfqq)
  650. -{
  651. - int process_refs, new_process_refs;
  652. - struct bfq_queue *__bfqq;
  653. -
  654. - /*
  655. - * If there are no process references on the new_bfqq, then it is
  656. - * unsafe to follow the ->new_bfqq chain as other bfqq's in the chain
  657. - * may have dropped their last reference (not just their last process
  658. - * reference).
  659. - */
  660. - if (!bfqq_process_refs(new_bfqq))
  661. - return;
  662. -
  663. - /* Avoid a circular list and skip interim queue merges. */
  664. - while ((__bfqq = new_bfqq->new_bfqq)) {
  665. - if (__bfqq == bfqq)
  666. - return;
  667. - new_bfqq = __bfqq;
  668. - }
  669. -
  670. - process_refs = bfqq_process_refs(bfqq);
  671. - new_process_refs = bfqq_process_refs(new_bfqq);
  672. - /*
  673. - * If the process for the bfqq has gone away, there is no
  674. - * sense in merging the queues.
  675. - */
  676. - if (process_refs == 0 || new_process_refs == 0)
  677. - return;
  678. -
  679. - /*
  680. - * Merge in the direction of the lesser amount of work.
  681. - */
  682. - if (new_process_refs >= process_refs) {
  683. - bfqq->new_bfqq = new_bfqq;
  684. - atomic_add(process_refs, &new_bfqq->ref);
  685. - } else {
  686. - new_bfqq->new_bfqq = bfqq;
  687. - atomic_add(new_process_refs, &bfqq->ref);
  688. - }
  689. - bfq_log_bfqq(bfqq->bfqd, bfqq, "scheduling merge with queue %d",
  690. - new_bfqq->pid);
  691. -}
  692. -
  693. static inline unsigned long bfq_bfqq_budget_left(struct bfq_queue *bfqq)
  694. {
  695. struct bfq_entity *entity = &bfqq->entity;
  696. @@ -2011,7 +2262,7 @@ static inline bool bfq_bfqq_must_idle(struct bfq_queue *bfqq)
  697. */
  698. static struct bfq_queue *bfq_select_queue(struct bfq_data *bfqd)
  699. {
  700. - struct bfq_queue *bfqq, *new_bfqq = NULL;
  701. + struct bfq_queue *bfqq;
  702. struct request *next_rq;
  703. enum bfqq_expiration reason = BFQ_BFQQ_BUDGET_TIMEOUT;
  704. @@ -2021,17 +2272,6 @@ static struct bfq_queue *bfq_select_queue(struct bfq_data *bfqd)
  705. bfq_log_bfqq(bfqd, bfqq, "select_queue: already in-service queue");
  706. - /*
  707. - * If another queue has a request waiting within our mean seek
  708. - * distance, let it run. The expire code will check for close
  709. - * cooperators and put the close queue at the front of the
  710. - * service tree. If possible, merge the expiring queue with the
  711. - * new bfqq.
  712. - */
  713. - new_bfqq = bfq_close_cooperator(bfqd, bfqq);
  714. - if (new_bfqq != NULL && bfqq->new_bfqq == NULL)
  715. - bfq_setup_merge(bfqq, new_bfqq);
  716. -
  717. if (bfq_may_expire_for_budg_timeout(bfqq) &&
  718. !timer_pending(&bfqd->idle_slice_timer) &&
  719. !bfq_bfqq_must_idle(bfqq))
  720. @@ -2070,10 +2310,7 @@ static struct bfq_queue *bfq_select_queue(struct bfq_data *bfqd)
  721. bfq_clear_bfqq_wait_request(bfqq);
  722. del_timer(&bfqd->idle_slice_timer);
  723. }
  724. - if (new_bfqq == NULL)
  725. - goto keep_queue;
  726. - else
  727. - goto expire;
  728. + goto keep_queue;
  729. }
  730. }
  731. @@ -2082,40 +2319,30 @@ static struct bfq_queue *bfq_select_queue(struct bfq_data *bfqd)
  732. * in flight (possibly waiting for a completion) or is idling for a
  733. * new request, then keep it.
  734. */
  735. - if (new_bfqq == NULL && (timer_pending(&bfqd->idle_slice_timer) ||
  736. - (bfqq->dispatched != 0 && bfq_bfqq_must_not_expire(bfqq)))) {
  737. + if (timer_pending(&bfqd->idle_slice_timer) ||
  738. + (bfqq->dispatched != 0 && bfq_bfqq_must_not_expire(bfqq))) {
  739. bfqq = NULL;
  740. goto keep_queue;
  741. - } else if (new_bfqq != NULL && timer_pending(&bfqd->idle_slice_timer)) {
  742. - /*
  743. - * Expiring the queue because there is a close cooperator,
  744. - * cancel timer.
  745. - */
  746. - bfq_clear_bfqq_wait_request(bfqq);
  747. - del_timer(&bfqd->idle_slice_timer);
  748. }
  749. reason = BFQ_BFQQ_NO_MORE_REQUESTS;
  750. expire:
  751. bfq_bfqq_expire(bfqd, bfqq, 0, reason);
  752. new_queue:
  753. - bfqq = bfq_set_in_service_queue(bfqd, new_bfqq);
  754. + bfqq = bfq_set_in_service_queue(bfqd);
  755. bfq_log(bfqd, "select_queue: new queue %d returned",
  756. bfqq != NULL ? bfqq->pid : 0);
  757. keep_queue:
  758. return bfqq;
  759. }
  760. -static void bfq_update_wr_data(struct bfq_data *bfqd,
  761. - struct bfq_queue *bfqq)
  762. +static void bfq_update_wr_data(struct bfq_data *bfqd, struct bfq_queue *bfqq)
  763. {
  764. - if (bfqq->wr_coeff > 1) { /* queue is being boosted */
  765. - struct bfq_entity *entity = &bfqq->entity;
  766. -
  767. + struct bfq_entity *entity = &bfqq->entity;
  768. + if (bfqq->wr_coeff > 1) { /* queue is being weight-raised */
  769. bfq_log_bfqq(bfqd, bfqq,
  770. "raising period dur %u/%u msec, old coeff %u, w %d(%d)",
  771. - jiffies_to_msecs(jiffies -
  772. - bfqq->last_wr_start_finish),
  773. + jiffies_to_msecs(jiffies - bfqq->last_wr_start_finish),
  774. jiffies_to_msecs(bfqq->wr_cur_max_time),
  775. bfqq->wr_coeff,
  776. bfqq->entity.weight, bfqq->entity.orig_weight);
  777. @@ -2124,11 +2351,15 @@ static void bfq_update_wr_data(struct bfq_data *bfqd,
  778. entity->orig_weight * bfqq->wr_coeff);
  779. if (entity->ioprio_changed)
  780. bfq_log_bfqq(bfqd, bfqq, "WARN: pending prio change");
  781. +
  782. /*
  783. * If too much time has elapsed from the beginning
  784. - * of this weight-raising, stop it.
  785. + * of this weight-raising period, or the queue has
  786. + * exceeded the acceptable number of cooperations,
  787. + * stop it.
  788. */
  789. - if (time_is_before_jiffies(bfqq->last_wr_start_finish +
  790. + if (bfq_bfqq_cooperations(bfqq) >= bfqd->bfq_coop_thresh ||
  791. + time_is_before_jiffies(bfqq->last_wr_start_finish +
  792. bfqq->wr_cur_max_time)) {
  793. bfqq->last_wr_start_finish = jiffies;
  794. bfq_log_bfqq(bfqd, bfqq,
  795. @@ -2136,11 +2367,13 @@ static void bfq_update_wr_data(struct bfq_data *bfqd,
  796. bfqq->last_wr_start_finish,
  797. jiffies_to_msecs(bfqq->wr_cur_max_time));
  798. bfq_bfqq_end_wr(bfqq);
  799. - __bfq_entity_update_weight_prio(
  800. - bfq_entity_service_tree(entity),
  801. - entity);
  802. }
  803. }
  804. + /* Update weight both if it must be raised and if it must be lowered */
  805. + if ((entity->weight > entity->orig_weight) != (bfqq->wr_coeff > 1))
  806. + __bfq_entity_update_weight_prio(
  807. + bfq_entity_service_tree(entity),
  808. + entity);
  809. }
  810. /*
  811. @@ -2377,6 +2610,25 @@ static inline void bfq_init_icq(struct io_cq *icq)
  812. struct bfq_io_cq *bic = icq_to_bic(icq);
  813. bic->ttime.last_end_request = jiffies;
  814. + /*
  815. + * A newly created bic indicates that the process has just
  816. + * started doing I/O, and is probably mapping into memory its
  817. + * executable and libraries: it definitely needs weight raising.
  818. + * There is however the possibility that the process performs,
  819. + * for a while, I/O close to some other process. EQM intercepts
  820. + * this behavior and may merge the queue corresponding to the
  821. + * process with some other queue, BEFORE the weight of the queue
  822. + * is raised. Merged queues are not weight-raised (they are assumed
  823. + * to belong to processes that benefit only from high throughput).
  824. + * If the merge is basically the consequence of an accident, then
  825. + * the queue will be split soon and will get back its old weight.
  826. + * It is then important to write down somewhere that this queue
  827. + * does need weight raising, even if it did not make it to get its
  828. + * weight raised before being merged. To this purpose, we overload
  829. + * the field raising_time_left and assign 1 to it, to mark the queue
  830. + * as needing weight raising.
  831. + */
  832. + bic->wr_time_left = 1;
  833. }
  834. static void bfq_exit_icq(struct io_cq *icq)
  835. @@ -2390,6 +2642,13 @@ static void bfq_exit_icq(struct io_cq *icq)
  836. }
  837. if (bic->bfqq[BLK_RW_SYNC]) {
  838. + /*
  839. + * If the bic is using a shared queue, put the reference
  840. + * taken on the io_context when the bic started using a
  841. + * shared bfq_queue.
  842. + */
  843. + if (bfq_bfqq_coop(bic->bfqq[BLK_RW_SYNC]))
  844. + put_io_context(icq->ioc);
  845. bfq_exit_bfqq(bfqd, bic->bfqq[BLK_RW_SYNC]);
  846. bic->bfqq[BLK_RW_SYNC] = NULL;
  847. }
  848. @@ -2678,6 +2937,10 @@ static void bfq_update_idle_window(struct bfq_data *bfqd,
  849. if (!bfq_bfqq_sync(bfqq) || bfq_class_idle(bfqq))
  850. return;
  851. + /* Idle window just restored, statistics are meaningless. */
  852. + if (bfq_bfqq_just_split(bfqq))
  853. + return;
  854. +
  855. enable_idle = bfq_bfqq_idle_window(bfqq);
  856. if (atomic_read(&bic->icq.ioc->active_ref) == 0 ||
  857. @@ -2725,6 +2988,7 @@ static void bfq_rq_enqueued(struct bfq_data *bfqd, struct bfq_queue *bfqq,
  858. if (bfqq->entity.service > bfq_max_budget(bfqd) / 8 ||
  859. !BFQQ_SEEKY(bfqq))
  860. bfq_update_idle_window(bfqd, bfqq, bic);
  861. + bfq_clear_bfqq_just_split(bfqq);
  862. bfq_log_bfqq(bfqd, bfqq,
  863. "rq_enqueued: idle_window=%d (seeky %d, mean %llu)",
  864. @@ -2785,13 +3049,49 @@ static void bfq_rq_enqueued(struct bfq_data *bfqd, struct bfq_queue *bfqq,
  865. static void bfq_insert_request(struct request_queue *q, struct request *rq)
  866. {
  867. struct bfq_data *bfqd = q->elevator->elevator_data;
  868. - struct bfq_queue *bfqq = RQ_BFQQ(rq);
  869. + struct bfq_queue *bfqq = RQ_BFQQ(rq), *new_bfqq;
  870. assert_spin_locked(bfqd->queue->queue_lock);
  871. +
  872. + /*
  873. + * An unplug may trigger a requeue of a request from the device
  874. + * driver: make sure we are in process context while trying to
  875. + * merge two bfq_queues.
  876. + */
  877. + if (!in_interrupt()) {
  878. + new_bfqq = bfq_setup_cooperator(bfqd, bfqq, rq, true);
  879. + if (new_bfqq != NULL) {
  880. + if (bic_to_bfqq(RQ_BIC(rq), 1) != bfqq)
  881. + new_bfqq = bic_to_bfqq(RQ_BIC(rq), 1);
  882. + /*
  883. + * Release the request's reference to the old bfqq
  884. + * and make sure one is taken to the shared queue.
  885. + */
  886. + new_bfqq->allocated[rq_data_dir(rq)]++;
  887. + bfqq->allocated[rq_data_dir(rq)]--;
  888. + atomic_inc(&new_bfqq->ref);
  889. + bfq_put_queue(bfqq);
  890. + if (bic_to_bfqq(RQ_BIC(rq), 1) == bfqq)
  891. + bfq_merge_bfqqs(bfqd, RQ_BIC(rq),
  892. + bfqq, new_bfqq);
  893. + rq->elv.priv[1] = new_bfqq;
  894. + bfqq = new_bfqq;
  895. + } else
  896. + bfq_bfqq_increase_failed_cooperations(bfqq);
  897. + }
  898. +
  899. bfq_init_prio_data(bfqq, RQ_BIC(rq));
  900. bfq_add_request(rq);
  901. + /*
  902. + * Here a newly-created bfq_queue has already started a weight-raising
  903. + * period: clear raising_time_left to prevent bfq_bfqq_save_state()
  904. + * from assigning it a full weight-raising period. See the detailed
  905. + * comments about this field in bfq_init_icq().
  906. + */
  907. + if (bfqq->bic != NULL)
  908. + bfqq->bic->wr_time_left = 0;
  909. rq->fifo_time = jiffies + bfqd->bfq_fifo_expire[rq_is_sync(rq)];
  910. list_add_tail(&rq->queuelist, &bfqq->fifo);
  911. @@ -2956,18 +3256,6 @@ static void bfq_put_request(struct request *rq)
  912. }
  913. }
  914. -static struct bfq_queue *
  915. -bfq_merge_bfqqs(struct bfq_data *bfqd, struct bfq_io_cq *bic,
  916. - struct bfq_queue *bfqq)
  917. -{
  918. - bfq_log_bfqq(bfqd, bfqq, "merging with queue %lu",
  919. - (long unsigned)bfqq->new_bfqq->pid);
  920. - bic_set_bfqq(bic, bfqq->new_bfqq, 1);
  921. - bfq_mark_bfqq_coop(bfqq->new_bfqq);
  922. - bfq_put_queue(bfqq);
  923. - return bic_to_bfqq(bic, 1);
  924. -}
  925. -
  926. /*
  927. * Returns NULL if a new bfqq should be allocated, or the old bfqq if this
  928. * was the last process referring to said bfqq.
  929. @@ -2976,6 +3264,9 @@ static struct bfq_queue *
  930. bfq_split_bfqq(struct bfq_io_cq *bic, struct bfq_queue *bfqq)
  931. {
  932. bfq_log_bfqq(bfqq->bfqd, bfqq, "splitting queue");
  933. +
  934. + put_io_context(bic->icq.ioc);
  935. +
  936. if (bfqq_process_refs(bfqq) == 1) {
  937. bfqq->pid = current->pid;
  938. bfq_clear_bfqq_coop(bfqq);
  939. @@ -3004,6 +3295,7 @@ static int bfq_set_request(struct request_queue *q, struct request *rq,
  940. struct bfq_queue *bfqq;
  941. struct bfq_group *bfqg;
  942. unsigned long flags;
  943. + bool split = false;
  944. might_sleep_if(gfp_mask & __GFP_WAIT);
  945. @@ -3022,24 +3314,14 @@ new_queue:
  946. bfqq = bfq_get_queue(bfqd, bfqg, is_sync, bic, gfp_mask);
  947. bic_set_bfqq(bic, bfqq, is_sync);
  948. } else {
  949. - /*
  950. - * If the queue was seeky for too long, break it apart.
  951. - */
  952. + /* If the queue was seeky for too long, break it apart. */
  953. if (bfq_bfqq_coop(bfqq) && bfq_bfqq_split_coop(bfqq)) {
  954. bfq_log_bfqq(bfqd, bfqq, "breaking apart bfqq");
  955. bfqq = bfq_split_bfqq(bic, bfqq);
  956. + split = true;
  957. if (!bfqq)
  958. goto new_queue;
  959. }
  960. -
  961. - /*
  962. - * Check to see if this queue is scheduled to merge with
  963. - * another closely cooperating queue. The merging of queues
  964. - * happens here as it must be done in process context.
  965. - * The reference on new_bfqq was taken in merge_bfqqs.
  966. - */
  967. - if (bfqq->new_bfqq != NULL)
  968. - bfqq = bfq_merge_bfqqs(bfqd, bic, bfqq);
  969. }
  970. bfqq->allocated[rw]++;
  971. @@ -3050,6 +3332,26 @@ new_queue:
  972. rq->elv.priv[0] = bic;
  973. rq->elv.priv[1] = bfqq;
  974. + /*
  975. + * If a bfq_queue has only one process reference, it is owned
  976. + * by only one bfq_io_cq: we can set the bic field of the
  977. + * bfq_queue to the address of that structure. Also, if the
  978. + * queue has just been split, mark a flag so that the
  979. + * information is available to the other scheduler hooks.
  980. + */
  981. + if (bfqq_process_refs(bfqq) == 1) {
  982. + bfqq->bic = bic;
  983. + if (split) {
  984. + bfq_mark_bfqq_just_split(bfqq);
  985. + /*
  986. + * If the queue has just been split from a shared
  987. + * queue, restore the idle window and the possible
  988. + * weight raising period.
  989. + */
  990. + bfq_bfqq_resume_state(bfqq, bic);
  991. + }
  992. + }
  993. +
  994. spin_unlock_irqrestore(q->queue_lock, flags);
  995. return 0;
  996. diff --git a/block/bfq-sched.c b/block/bfq-sched.c
  997. index c4831b7..546a254 100644
  998. --- a/block/bfq-sched.c
  999. +++ b/block/bfq-sched.c
  1000. @@ -1084,34 +1084,6 @@ static struct bfq_queue *bfq_get_next_queue(struct bfq_data *bfqd)
  1001. return bfqq;
  1002. }
  1003. -/*
  1004. - * Forced extraction of the given queue.
  1005. - */
  1006. -static void bfq_get_next_queue_forced(struct bfq_data *bfqd,
  1007. - struct bfq_queue *bfqq)
  1008. -{
  1009. - struct bfq_entity *entity;
  1010. - struct bfq_sched_data *sd;
  1011. -
  1012. - BUG_ON(bfqd->in_service_queue != NULL);
  1013. -
  1014. - entity = &bfqq->entity;
  1015. - /*
  1016. - * Bubble up extraction/update from the leaf to the root.
  1017. - */
  1018. - for_each_entity(entity) {
  1019. - sd = entity->sched_data;
  1020. - bfq_update_budget(entity);
  1021. - bfq_update_vtime(bfq_entity_service_tree(entity));
  1022. - bfq_active_extract(bfq_entity_service_tree(entity), entity);
  1023. - sd->in_service_entity = entity;
  1024. - sd->next_in_service = NULL;
  1025. - entity->service = 0;
  1026. - }
  1027. -
  1028. - return;
  1029. -}
  1030. -
  1031. static void __bfq_bfqd_reset_in_service(struct bfq_data *bfqd)
  1032. {
  1033. if (bfqd->in_service_bic != NULL) {
  1034. diff --git a/block/bfq.h b/block/bfq.h
  1035. index a83e69d..ebbd040 100644
  1036. --- a/block/bfq.h
  1037. +++ b/block/bfq.h
  1038. @@ -215,18 +215,21 @@ struct bfq_group;
  1039. * idle @bfq_queue with no outstanding requests, then
  1040. * the task associated with the queue it is deemed as
  1041. * soft real-time (see the comments to the function
  1042. - * bfq_bfqq_softrt_next_start()).
  1043. + * bfq_bfqq_softrt_next_start())
  1044. * @last_idle_bklogged: time of the last transition of the @bfq_queue from
  1045. * idle to backlogged
  1046. * @service_from_backlogged: cumulative service received from the @bfq_queue
  1047. * since the last transition from idle to
  1048. * backlogged
  1049. + * @bic: pointer to the bfq_io_cq owning the bfq_queue, set to %NULL if the
  1050. + * queue is shared
  1051. *
  1052. - * A bfq_queue is a leaf request queue; it can be associated with an io_context
  1053. - * or more, if it is async or shared between cooperating processes. @cgroup
  1054. - * holds a reference to the cgroup, to be sure that it does not disappear while
  1055. - * a bfqq still references it (mostly to avoid races between request issuing and
  1056. - * task migration followed by cgroup destruction).
  1057. + * A bfq_queue is a leaf request queue; it can be associated with an
  1058. + * io_context or more, if it is async or shared between cooperating
  1059. + * processes. @cgroup holds a reference to the cgroup, to be sure that it
  1060. + * does not disappear while a bfqq still references it (mostly to avoid
  1061. + * races between request issuing and task migration followed by cgroup
  1062. + * destruction).
  1063. * All the fields are protected by the queue lock of the containing bfqd.
  1064. */
  1065. struct bfq_queue {
  1066. @@ -264,6 +267,7 @@ struct bfq_queue {
  1067. unsigned int requests_within_timer;
  1068. pid_t pid;
  1069. + struct bfq_io_cq *bic;
  1070. /* weight-raising fields */
  1071. unsigned long wr_cur_max_time;
  1072. @@ -293,12 +297,34 @@ struct bfq_ttime {
  1073. * @icq: associated io_cq structure
  1074. * @bfqq: array of two process queues, the sync and the async
  1075. * @ttime: associated @bfq_ttime struct
  1076. + * @wr_time_left: snapshot of the time left before weight raising ends
  1077. + * for the sync queue associated to this process; this
  1078. + * snapshot is taken to remember this value while the weight
  1079. + * raising is suspended because the queue is merged with a
  1080. + * shared queue, and is used to set @raising_cur_max_time
  1081. + * when the queue is split from the shared queue and its
  1082. + * weight is raised again
  1083. + * @saved_idle_window: same purpose as the previous field for the idle
  1084. + * window
  1085. + * @saved_IO_bound: same purpose as the previous two fields for the I/O
  1086. + * bound classification of a queue
  1087. + * @cooperations: counter of consecutive successful queue merges underwent
  1088. + * by any of the process' @bfq_queues
  1089. + * @failed_cooperations: counter of consecutive failed queue merges of any
  1090. + * of the process' @bfq_queues
  1091. */
  1092. struct bfq_io_cq {
  1093. struct io_cq icq; /* must be the first member */
  1094. struct bfq_queue *bfqq[2];
  1095. struct bfq_ttime ttime;
  1096. int ioprio;
  1097. +
  1098. + unsigned int wr_time_left;
  1099. + unsigned int saved_idle_window;
  1100. + unsigned int saved_IO_bound;
  1101. +
  1102. + unsigned int cooperations;
  1103. + unsigned int failed_cooperations;
  1104. };
  1105. enum bfq_device_speed {
  1106. @@ -511,7 +537,7 @@ enum bfqq_state_flags {
  1107. BFQ_BFQQ_FLAG_prio_changed, /* task priority has changed */
  1108. BFQ_BFQQ_FLAG_sync, /* synchronous queue */
  1109. BFQ_BFQQ_FLAG_budget_new, /* no completion with this budget */
  1110. - BFQ_BFQQ_FLAG_IO_bound, /*
  1111. + BFQ_BFQQ_FLAG_IO_bound, /*
  1112. * bfqq has timed-out at least once
  1113. * having consumed at most 2/10 of
  1114. * its budget
  1115. @@ -520,12 +546,13 @@ enum bfqq_state_flags {
  1116. * bfqq has proved to be slow and
  1117. * seeky until budget timeout
  1118. */
  1119. - BFQ_BFQQ_FLAG_softrt_update, /*
  1120. + BFQ_BFQQ_FLAG_softrt_update, /*
  1121. * may need softrt-next-start
  1122. * update
  1123. */
  1124. BFQ_BFQQ_FLAG_coop, /* bfqq is shared */
  1125. - BFQ_BFQQ_FLAG_split_coop, /* shared bfqq will be splitted */
  1126. + BFQ_BFQQ_FLAG_split_coop, /* shared bfqq will be split */
  1127. + BFQ_BFQQ_FLAG_just_split, /* queue has just been split */
  1128. };
  1129. #define BFQ_BFQQ_FNS(name) \
  1130. @@ -554,6 +581,7 @@ BFQ_BFQQ_FNS(IO_bound);
  1131. BFQ_BFQQ_FNS(constantly_seeky);
  1132. BFQ_BFQQ_FNS(coop);
  1133. BFQ_BFQQ_FNS(split_coop);
  1134. +BFQ_BFQQ_FNS(just_split);
  1135. BFQ_BFQQ_FNS(softrt_update);
  1136. #undef BFQ_BFQQ_FNS
  1137. --
  1138. 2.0.3