dm-round-robin.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. /*
  2. * Copyright (C) 2003 Sistina Software.
  3. * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
  4. *
  5. * Module Author: Heinz Mauelshagen
  6. *
  7. * This file is released under the GPL.
  8. *
  9. * Round-robin path selector.
  10. */
  11. #include <linux/device-mapper.h>
  12. #include "dm-path-selector.h"
  13. #include <linux/slab.h>
  14. #define DM_MSG_PREFIX "multipath round-robin"
  15. /*-----------------------------------------------------------------
  16. * Path-handling code, paths are held in lists
  17. *---------------------------------------------------------------*/
  18. struct path_info {
  19. struct list_head list;
  20. struct dm_path *path;
  21. unsigned repeat_count;
  22. };
  23. static void free_paths(struct list_head *paths)
  24. {
  25. struct path_info *pi, *next;
  26. list_for_each_entry_safe(pi, next, paths, list) {
  27. list_del(&pi->list);
  28. kfree(pi);
  29. }
  30. }
  31. /*-----------------------------------------------------------------
  32. * Round-robin selector
  33. *---------------------------------------------------------------*/
  34. #define RR_MIN_IO 1000
  35. struct selector {
  36. struct list_head valid_paths;
  37. struct list_head invalid_paths;
  38. };
  39. static struct selector *alloc_selector(void)
  40. {
  41. struct selector *s = kmalloc(sizeof(*s), GFP_KERNEL);
  42. if (s) {
  43. INIT_LIST_HEAD(&s->valid_paths);
  44. INIT_LIST_HEAD(&s->invalid_paths);
  45. }
  46. return s;
  47. }
  48. static int rr_create(struct path_selector *ps, unsigned argc, char **argv)
  49. {
  50. struct selector *s;
  51. s = alloc_selector();
  52. if (!s)
  53. return -ENOMEM;
  54. ps->context = s;
  55. return 0;
  56. }
  57. static void rr_destroy(struct path_selector *ps)
  58. {
  59. struct selector *s = (struct selector *) ps->context;
  60. free_paths(&s->valid_paths);
  61. free_paths(&s->invalid_paths);
  62. kfree(s);
  63. ps->context = NULL;
  64. }
  65. static int rr_status(struct path_selector *ps, struct dm_path *path,
  66. status_type_t type, char *result, unsigned int maxlen)
  67. {
  68. struct path_info *pi;
  69. int sz = 0;
  70. if (!path)
  71. DMEMIT("0 ");
  72. else {
  73. switch(type) {
  74. case STATUSTYPE_INFO:
  75. break;
  76. case STATUSTYPE_TABLE:
  77. pi = path->pscontext;
  78. DMEMIT("%u ", pi->repeat_count);
  79. break;
  80. }
  81. }
  82. return sz;
  83. }
  84. /*
  85. * Called during initialisation to register each path with an
  86. * optional repeat_count.
  87. */
  88. static int rr_add_path(struct path_selector *ps, struct dm_path *path,
  89. int argc, char **argv, char **error)
  90. {
  91. struct selector *s = (struct selector *) ps->context;
  92. struct path_info *pi;
  93. unsigned repeat_count = RR_MIN_IO;
  94. if (argc > 1) {
  95. *error = "round-robin ps: incorrect number of arguments";
  96. return -EINVAL;
  97. }
  98. /* First path argument is number of I/Os before switching path */
  99. if ((argc == 1) && (sscanf(argv[0], "%u", &repeat_count) != 1)) {
  100. *error = "round-robin ps: invalid repeat count";
  101. return -EINVAL;
  102. }
  103. /* allocate the path */
  104. pi = kmalloc(sizeof(*pi), GFP_KERNEL);
  105. if (!pi) {
  106. *error = "round-robin ps: Error allocating path context";
  107. return -ENOMEM;
  108. }
  109. pi->path = path;
  110. pi->repeat_count = repeat_count;
  111. path->pscontext = pi;
  112. list_add_tail(&pi->list, &s->valid_paths);
  113. return 0;
  114. }
  115. static void rr_fail_path(struct path_selector *ps, struct dm_path *p)
  116. {
  117. struct selector *s = (struct selector *) ps->context;
  118. struct path_info *pi = p->pscontext;
  119. list_move(&pi->list, &s->invalid_paths);
  120. }
  121. static int rr_reinstate_path(struct path_selector *ps, struct dm_path *p)
  122. {
  123. struct selector *s = (struct selector *) ps->context;
  124. struct path_info *pi = p->pscontext;
  125. list_move(&pi->list, &s->valid_paths);
  126. return 0;
  127. }
  128. static struct dm_path *rr_select_path(struct path_selector *ps,
  129. unsigned *repeat_count, size_t nr_bytes)
  130. {
  131. struct selector *s = (struct selector *) ps->context;
  132. struct path_info *pi = NULL;
  133. if (!list_empty(&s->valid_paths)) {
  134. pi = list_entry(s->valid_paths.next, struct path_info, list);
  135. list_move_tail(&pi->list, &s->valid_paths);
  136. *repeat_count = pi->repeat_count;
  137. }
  138. return pi ? pi->path : NULL;
  139. }
  140. static struct path_selector_type rr_ps = {
  141. .name = "round-robin",
  142. .module = THIS_MODULE,
  143. .table_args = 1,
  144. .info_args = 0,
  145. .create = rr_create,
  146. .destroy = rr_destroy,
  147. .status = rr_status,
  148. .add_path = rr_add_path,
  149. .fail_path = rr_fail_path,
  150. .reinstate_path = rr_reinstate_path,
  151. .select_path = rr_select_path,
  152. };
  153. static int __init dm_rr_init(void)
  154. {
  155. int r = dm_register_path_selector(&rr_ps);
  156. if (r < 0)
  157. DMERR("register failed %d", r);
  158. DMINFO("version 1.0.0 loaded");
  159. return r;
  160. }
  161. static void __exit dm_rr_exit(void)
  162. {
  163. int r = dm_unregister_path_selector(&rr_ps);
  164. if (r < 0)
  165. DMERR("unregister failed %d", r);
  166. }
  167. module_init(dm_rr_init);
  168. module_exit(dm_rr_exit);
  169. MODULE_DESCRIPTION(DM_NAME " round-robin multipath path selector");
  170. MODULE_AUTHOR("Sistina Software <dm-devel@redhat.com>");
  171. MODULE_LICENSE("GPL");