maple-iosched.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  1. /*
  2. * Maple I/O Scheduler
  3. * Based on Zen and SIO.
  4. *
  5. * Copyright (C) 2016 Joe Maples <joe@frap129.org>
  6. * (C) 2012 Brandon Berhent <bbedward@gmail.com
  7. * (C) 2012 Miguel Boton <mboton@gmail.com>
  8. *
  9. * Maple uses a first come first serve style algorithm with seperated read/write
  10. * handling to allow for read biases. By prioritizing reads, simple tasks should improve
  11. * in performance. Maple also uses hooks for the powersuspend driver to increase
  12. * expirations when power is suspended to decrease workload.
  13. */
  14. #include <linux/blkdev.h>
  15. #include <linux/elevator.h>
  16. #include <linux/bio.h>
  17. #include <linux/module.h>
  18. #include <linux/init.h>
  19. #include <linux/slab.h>
  20. #include <linux/fb.h>
  21. #define MAPLE_IOSCHED_PATCHLEVEL (8)
  22. enum { ASYNC, SYNC };
  23. /* Tunables */
  24. static const int sync_read_expire = 350; /* max time before a read sync is submitted. */
  25. static const int sync_write_expire = 550; /* max time before a write sync is submitted. */
  26. static const int async_read_expire = 250; /* ditto for read async, these limits are SOFT! */
  27. static const int async_write_expire = 450; /* ditto for write async, these limits are SOFT! */
  28. static const int fifo_batch = 16; /* # of sequential requests treated as one by the above parameters. */
  29. static const int writes_starved = 4; /* max times reads can starve a write */
  30. static const int sleep_latency_multiple = 10; /* multple for expire time when device is asleep */
  31. /* Elevator data */
  32. struct maple_data {
  33. /* Request queues */
  34. struct list_head fifo_list[2][2];
  35. /* Attributes */
  36. unsigned int batched;
  37. unsigned int starved;
  38. /* Settings */
  39. int fifo_expire[2][2];
  40. int fifo_batch;
  41. int writes_starved;
  42. int sleep_latency_multiple;
  43. /* Display state */
  44. struct notifier_block fb_notifier;
  45. bool display_on;
  46. };
  47. static inline struct maple_data *
  48. maple_get_data(struct request_queue *q) {
  49. return q->elevator->elevator_data;
  50. }
  51. static void
  52. maple_merged_requests(struct request_queue *q, struct request *rq,
  53. struct request *next)
  54. {
  55. /*
  56. * If next expires before rq, assign its expire time to rq
  57. * and move into next position (next will be deleted) in fifo.
  58. */
  59. if (!list_empty(&rq->queuelist) && !list_empty(&next->queuelist)) {
  60. if (time_before((unsigned long)next->fifo_time, (unsigned long)rq->fifo_time)) {
  61. list_move(&rq->queuelist, &next->queuelist);
  62. rq->fifo_time = next->fifo_time;
  63. }
  64. }
  65. /* Delete next request */
  66. rq_fifo_clear(next);
  67. }
  68. static void
  69. maple_add_request(struct request_queue *q, struct request *rq)
  70. {
  71. struct maple_data *mdata = maple_get_data(q);
  72. const int sync = rq_is_sync(rq);
  73. const int dir = rq_data_dir(rq);
  74. /*
  75. * Add request to the proper fifo list and set its
  76. * expire time.
  77. */
  78. /* inrease expiration when device is asleep */
  79. unsigned int fifo_expire_suspended = mdata->fifo_expire[sync][dir] * sleep_latency_multiple;
  80. if (mdata->display_on && mdata->fifo_expire[sync][dir]) {
  81. rq->fifo_time = jiffies + mdata->fifo_expire[sync][dir];
  82. list_add_tail(&rq->queuelist, &mdata->fifo_list[sync][dir]);
  83. } else if (!mdata->display_on && fifo_expire_suspended) {
  84. rq->fifo_time = jiffies + fifo_expire_suspended;
  85. list_add_tail(&rq->queuelist, &mdata->fifo_list[sync][dir]);
  86. }
  87. }
  88. static struct request *
  89. maple_expired_request(struct maple_data *mdata, int sync, int data_dir)
  90. {
  91. struct list_head *list = &mdata->fifo_list[sync][data_dir];
  92. struct request *rq;
  93. if (list_empty(list))
  94. return NULL;
  95. /* Retrieve request */
  96. rq = rq_entry_fifo(list->next);
  97. /* Request has expired */
  98. if (time_after_eq(jiffies, (unsigned long)rq->fifo_time))
  99. return rq;
  100. return NULL;
  101. }
  102. static struct request *
  103. maple_choose_expired_request(struct maple_data *mdata)
  104. {
  105. struct request *rq_sync_read = maple_expired_request(mdata, SYNC, READ);
  106. struct request *rq_sync_write = maple_expired_request(mdata, SYNC, WRITE);
  107. struct request *rq_async_read = maple_expired_request(mdata, ASYNC, READ);
  108. struct request *rq_async_write = maple_expired_request(mdata, ASYNC, WRITE);
  109. /* Reset (non-expired-)batch-counter */
  110. mdata->batched = 0;
  111. /*
  112. * Check expired requests.
  113. * Asynchronous requests have priority over synchronous.
  114. * Read requests have priority over write.
  115. */
  116. if (rq_async_read && rq_sync_read) {
  117. if (time_after((unsigned long)rq_sync_read->fifo_time, (unsigned long)rq_async_read->fifo_time))
  118. return rq_async_read;
  119. } else if (rq_async_read) {
  120. return rq_async_read;
  121. } else if (rq_sync_read) {
  122. return rq_sync_read;
  123. }
  124. if (rq_async_write && rq_sync_write) {
  125. if (time_after((unsigned long)rq_sync_write->fifo_time, (unsigned long)rq_async_write->fifo_time))
  126. return rq_async_write;
  127. } else if (rq_async_write) {
  128. return rq_async_write;
  129. } else if (rq_sync_write) {
  130. return rq_sync_write;
  131. }
  132. return NULL;
  133. }
  134. static struct request *
  135. maple_choose_request(struct maple_data *mdata, int data_dir)
  136. {
  137. struct list_head *sync = mdata->fifo_list[SYNC];
  138. struct list_head *async = mdata->fifo_list[ASYNC];
  139. /* Increase (non-expired-)batch-counter */
  140. mdata->batched++;
  141. /*
  142. * Retrieve request from available fifo list.
  143. * Asynchronous requests have priority over synchronous.
  144. * Read requests have priority over write.
  145. */
  146. if (!list_empty(&async[data_dir]))
  147. return rq_entry_fifo(async[data_dir].next);
  148. if (!list_empty(&sync[data_dir]))
  149. return rq_entry_fifo(sync[data_dir].next);
  150. if (!list_empty(&async[!data_dir]))
  151. return rq_entry_fifo(async[!data_dir].next);
  152. if (!list_empty(&sync[!data_dir]))
  153. return rq_entry_fifo(sync[!data_dir].next);
  154. return NULL;
  155. }
  156. static inline void
  157. maple_dispatch_request(struct maple_data *mdata, struct request *rq)
  158. {
  159. /*
  160. * Remove the request from the fifo list
  161. * and dispatch it.
  162. */
  163. rq_fifo_clear(rq);
  164. elv_dispatch_add_tail(rq->q, rq);
  165. if (rq_data_dir(rq)) {
  166. mdata->starved = 0;
  167. } else {
  168. if (!list_empty(&mdata->fifo_list[SYNC][WRITE]) ||
  169. !list_empty(&mdata->fifo_list[ASYNC][WRITE]))
  170. mdata->starved++;
  171. }
  172. }
  173. static int
  174. maple_dispatch_requests(struct request_queue *q, int force)
  175. {
  176. struct maple_data *mdata = maple_get_data(q);
  177. struct request *rq = NULL;
  178. int data_dir = READ;
  179. /*
  180. * Retrieve any expired request after a batch of
  181. * sequential requests.
  182. */
  183. if (mdata->batched >= mdata->fifo_batch)
  184. rq = maple_choose_expired_request(mdata);
  185. /* Retrieve request */
  186. if (!rq) {
  187. /* Treat writes fairly while suspended, otherwise allow them to be starved */
  188. if (mdata->display_on && mdata->starved >= mdata->writes_starved)
  189. data_dir = WRITE;
  190. else if (!mdata->display_on && mdata->starved >= 1)
  191. data_dir = WRITE;
  192. rq = maple_choose_request(mdata, data_dir);
  193. if (!rq)
  194. return 0;
  195. }
  196. /* Dispatch request */
  197. maple_dispatch_request(mdata, rq);
  198. return 1;
  199. }
  200. static struct request *
  201. maple_former_request(struct request_queue *q, struct request *rq)
  202. {
  203. struct maple_data *mdata = maple_get_data(q);
  204. const int sync = rq_is_sync(rq);
  205. const int data_dir = rq_data_dir(rq);
  206. if (rq->queuelist.prev == &mdata->fifo_list[sync][data_dir])
  207. return NULL;
  208. /* Return former request */
  209. return list_entry(rq->queuelist.prev, struct request, queuelist);
  210. }
  211. static struct request *
  212. maple_latter_request(struct request_queue *q, struct request *rq)
  213. {
  214. struct maple_data *mdata = maple_get_data(q);
  215. const int sync = rq_is_sync(rq);
  216. const int data_dir = rq_data_dir(rq);
  217. if (rq->queuelist.next == &mdata->fifo_list[sync][data_dir])
  218. return NULL;
  219. /* Return latter request */
  220. return list_entry(rq->queuelist.next, struct request, queuelist);
  221. }
  222. static int fb_notifier_callback(struct notifier_block *self,
  223. unsigned long event, void *data)
  224. {
  225. struct maple_data *mdata = container_of(self,
  226. struct maple_data, fb_notifier);
  227. struct fb_event *evdata = data;
  228. int *blank;
  229. if (evdata && evdata->data && event == FB_EVENT_BLANK) {
  230. blank = evdata->data;
  231. switch (*blank) {
  232. case FB_BLANK_UNBLANK:
  233. mdata->display_on = true;
  234. break;
  235. case FB_BLANK_POWERDOWN:
  236. case FB_BLANK_HSYNC_SUSPEND:
  237. case FB_BLANK_VSYNC_SUSPEND:
  238. case FB_BLANK_NORMAL:
  239. mdata->display_on = false;
  240. break;
  241. }
  242. }
  243. return 0;
  244. }
  245. static int maple_init_queue(struct request_queue *q, struct elevator_type *e)
  246. {
  247. struct maple_data *mdata;
  248. struct elevator_queue *eq;
  249. eq = elevator_alloc(q, e);
  250. if (!eq)
  251. return -ENOMEM;
  252. /* Allocate structure */
  253. mdata = kmalloc_node(sizeof(*mdata), GFP_KERNEL, q->node);
  254. if (!mdata) {
  255. kobject_put(&eq->kobj);
  256. return -ENOMEM;
  257. }
  258. eq->elevator_data = mdata;
  259. mdata->fb_notifier.notifier_call = fb_notifier_callback;
  260. fb_register_client(&mdata->fb_notifier);
  261. /* Initialize fifo lists */
  262. INIT_LIST_HEAD(&mdata->fifo_list[SYNC][READ]);
  263. INIT_LIST_HEAD(&mdata->fifo_list[SYNC][WRITE]);
  264. INIT_LIST_HEAD(&mdata->fifo_list[ASYNC][READ]);
  265. INIT_LIST_HEAD(&mdata->fifo_list[ASYNC][WRITE]);
  266. /* Initialize data */
  267. mdata->batched = 0;
  268. mdata->fifo_expire[SYNC][READ] = sync_read_expire;
  269. mdata->fifo_expire[SYNC][WRITE] = sync_write_expire;
  270. mdata->fifo_expire[ASYNC][READ] = async_read_expire;
  271. mdata->fifo_expire[ASYNC][WRITE] = async_write_expire;
  272. mdata->fifo_batch = fifo_batch;
  273. mdata->writes_starved = writes_starved;
  274. mdata->sleep_latency_multiple = sleep_latency_multiple;
  275. spin_lock_irq(q->queue_lock);
  276. q->elevator = eq;
  277. spin_unlock_irq(q->queue_lock);
  278. return 0;
  279. }
  280. static void
  281. maple_exit_queue(struct elevator_queue *e)
  282. {
  283. struct maple_data *mdata = e->elevator_data;
  284. fb_unregister_client(&mdata->fb_notifier);
  285. /* Free structure */
  286. kfree(mdata);
  287. }
  288. /*
  289. * sysfs code
  290. */
  291. static ssize_t
  292. maple_var_show(int var, char *page)
  293. {
  294. return sprintf(page, "%d\n", var);
  295. }
  296. static ssize_t
  297. maple_var_store(int *var, const char *page, size_t count)
  298. {
  299. char *p = (char *) page;
  300. *var = simple_strtol(p, &p, 10);
  301. return count;
  302. }
  303. #define SHOW_FUNCTION(__FUNC, __VAR, __CONV) \
  304. static ssize_t __FUNC(struct elevator_queue *e, char *page) \
  305. { \
  306. struct maple_data *mdata = e->elevator_data; \
  307. int __data = __VAR; \
  308. if (__CONV) \
  309. __data = jiffies_to_msecs(__data); \
  310. return maple_var_show(__data, (page)); \
  311. }
  312. SHOW_FUNCTION(maple_sync_read_expire_show, mdata->fifo_expire[SYNC][READ], 1);
  313. SHOW_FUNCTION(maple_sync_write_expire_show, mdata->fifo_expire[SYNC][WRITE], 1);
  314. SHOW_FUNCTION(maple_async_read_expire_show, mdata->fifo_expire[ASYNC][READ], 1);
  315. SHOW_FUNCTION(maple_async_write_expire_show, mdata->fifo_expire[ASYNC][WRITE], 1);
  316. SHOW_FUNCTION(maple_fifo_batch_show, mdata->fifo_batch, 0);
  317. SHOW_FUNCTION(maple_writes_starved_show, mdata->writes_starved, 0);
  318. SHOW_FUNCTION(maple_sleep_latency_multiple_show, mdata->sleep_latency_multiple, 0);
  319. #undef SHOW_FUNCTION
  320. #define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX, __CONV) \
  321. static ssize_t __FUNC(struct elevator_queue *e, const char *page, size_t count) \
  322. { \
  323. struct maple_data *mdata = e->elevator_data; \
  324. int __data; \
  325. int ret = maple_var_store(&__data, (page), count); \
  326. if (__data < (MIN)) \
  327. __data = (MIN); \
  328. else if (__data > (MAX)) \
  329. __data = (MAX); \
  330. if (__CONV) \
  331. *(__PTR) = msecs_to_jiffies(__data); \
  332. else \
  333. *(__PTR) = __data; \
  334. return ret; \
  335. }
  336. STORE_FUNCTION(maple_sync_read_expire_store, &mdata->fifo_expire[SYNC][READ], 0, INT_MAX, 1);
  337. STORE_FUNCTION(maple_sync_write_expire_store, &mdata->fifo_expire[SYNC][WRITE], 0, INT_MAX, 1);
  338. STORE_FUNCTION(maple_async_read_expire_store, &mdata->fifo_expire[ASYNC][READ], 0, INT_MAX, 1);
  339. STORE_FUNCTION(maple_async_write_expire_store, &mdata->fifo_expire[ASYNC][WRITE], 0, INT_MAX, 1);
  340. STORE_FUNCTION(maple_fifo_batch_store, &mdata->fifo_batch, 1, INT_MAX, 0);
  341. STORE_FUNCTION(maple_writes_starved_store, &mdata->writes_starved, 1, INT_MAX, 0);
  342. STORE_FUNCTION(maple_sleep_latency_multiple_store, &mdata->sleep_latency_multiple, 1, INT_MAX, 0);
  343. #undef STORE_FUNCTION
  344. #define DD_ATTR(name) \
  345. __ATTR(name, S_IRUGO|S_IWUSR, maple_##name##_show, \
  346. maple_##name##_store)
  347. static struct elv_fs_entry maple_attrs[] = {
  348. DD_ATTR(sync_read_expire),
  349. DD_ATTR(sync_write_expire),
  350. DD_ATTR(async_read_expire),
  351. DD_ATTR(async_write_expire),
  352. DD_ATTR(fifo_batch),
  353. DD_ATTR(writes_starved),
  354. DD_ATTR(sleep_latency_multiple),
  355. __ATTR_NULL
  356. };
  357. static struct elevator_type iosched_maple = {
  358. .ops.sq = {
  359. .elevator_merge_req_fn = maple_merged_requests,
  360. .elevator_dispatch_fn = maple_dispatch_requests,
  361. .elevator_add_req_fn = maple_add_request,
  362. .elevator_former_req_fn = maple_former_request,
  363. .elevator_latter_req_fn = maple_latter_request,
  364. .elevator_init_fn = maple_init_queue,
  365. .elevator_exit_fn = maple_exit_queue,
  366. },
  367. .elevator_attrs = maple_attrs,
  368. .elevator_name = "maple",
  369. .elevator_owner = THIS_MODULE,
  370. };
  371. static int __init maple_init(void)
  372. {
  373. /* Register elevator */
  374. elv_register(&iosched_maple);
  375. return 0;
  376. }
  377. static void __exit maple_exit(void)
  378. {
  379. /* Unregister elevator */
  380. elv_unregister(&iosched_maple);
  381. }
  382. module_init(maple_init);
  383. module_exit(maple_exit);
  384. MODULE_AUTHOR("Joe Maples");
  385. MODULE_LICENSE("GPL");
  386. MODULE_DESCRIPTION("Maple I/O Scheduler");
  387. MODULE_VERSION("1.0");