Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  1 /*
  2  * Copyright (C) 2004-2005 IBM Corp.  All Rights Reserved.
  3  * Copyright (C) 2006-2009 NEC Corporation.
  4  *
  5  * dm-queue-length.c
  6  *
  7  * Module Author: Stefan Bader, IBM
  8  * Modified by: Kiyoshi Ueda, NEC
  9  *
 10  * This file is released under the GPL.
 11  *
 12  * queue-length path selector - choose a path with the least number of
 13  * in-flight I/Os.
 14  */
 15 
 16 #include "dm.h"
 17 #include "dm-path-selector.h"
 18 
 19 #include <linux/slab.h>
 20 #include <linux/ctype.h>
 21 #include <linux/errno.h>
 22 #include <linux/module.h>
 23 #include <asm/atomic.h>
 24 
 25 #define DM_MSG_PREFIX   "multipath queue-length"
 26 #define QL_MIN_IO       128
 27 #define QL_VERSION      "0.1.0"
 28 
 29 struct selector {
 30         struct list_head        valid_paths;
 31         struct list_head        failed_paths;
 32 };
 33 
 34 struct path_info {
 35         struct list_head        list;
 36         struct dm_path          *path;
 37         unsigned                repeat_count;
 38         atomic_t                qlen;   /* the number of in-flight I/Os */
 39 };
 40 
 41 static struct selector *alloc_selector(void)
 42 {
 43         struct selector *s = kmalloc(sizeof(*s), GFP_KERNEL);
 44 
 45         if (s) {
 46                 INIT_LIST_HEAD(&s->valid_paths);
 47                 INIT_LIST_HEAD(&s->failed_paths);
 48         }
 49 
 50         return s;
 51 }
 52 
 53 static int ql_create(struct path_selector *ps, unsigned argc, char **argv)
 54 {
 55         struct selector *s = alloc_selector();
 56 
 57         if (!s)
 58                 return -ENOMEM;
 59 
 60         ps->context = s;
 61         return 0;
 62 }
 63 
 64 static void ql_free_paths(struct list_head *paths)
 65 {
 66         struct path_info *pi, *next;
 67 
 68         list_for_each_entry_safe(pi, next, paths, list) {
 69                 list_del(&pi->list);
 70                 kfree(pi);
 71         }
 72 }
 73 
 74 static void ql_destroy(struct path_selector *ps)
 75 {
 76         struct selector *s = ps->context;
 77 
 78         ql_free_paths(&s->valid_paths);
 79         ql_free_paths(&s->failed_paths);
 80         kfree(s);
 81         ps->context = NULL;
 82 }
 83 
 84 static int ql_status(struct path_selector *ps, struct dm_path *path,
 85                      status_type_t type, char *result, unsigned maxlen)
 86 {
 87         unsigned sz = 0;
 88         struct path_info *pi;
 89 
 90         /* When called with NULL path, return selector status/args. */
 91         if (!path)
 92                 DMEMIT("0 ");
 93         else {
 94                 pi = path->pscontext;
 95 
 96                 switch (type) {
 97                 case STATUSTYPE_INFO:
 98                         DMEMIT("%d ", atomic_read(&pi->qlen));
 99                         break;
100                 case STATUSTYPE_TABLE:
101                         DMEMIT("%u ", pi->repeat_count);
102                         break;
103                 }
104         }
105 
106         return sz;
107 }
108 
109 static int ql_add_path(struct path_selector *ps, struct dm_path *path,
110                        int argc, char **argv, char **error)
111 {
112         struct selector *s = ps->context;
113         struct path_info *pi;
114         unsigned repeat_count = QL_MIN_IO;
115 
116         /*
117          * Arguments: [<repeat_count>]
118          *      <repeat_count>: The number of I/Os before switching path.
119          *                      If not given, default (QL_MIN_IO) is used.
120          */
121         if (argc > 1) {
122                 *error = "queue-length ps: incorrect number of arguments";
123                 return -EINVAL;
124         }
125 
126         if ((argc == 1) && (sscanf(argv[0], "%u", &repeat_count) != 1)) {
127                 *error = "queue-length ps: invalid repeat count";
128                 return -EINVAL;
129         }
130 
131         /* Allocate the path information structure */
132         pi = kmalloc(sizeof(*pi), GFP_KERNEL);
133         if (!pi) {
134                 *error = "queue-length ps: Error allocating path information";
135                 return -ENOMEM;
136         }
137 
138         pi->path = path;
139         pi->repeat_count = repeat_count;
140         atomic_set(&pi->qlen, 0);
141 
142         path->pscontext = pi;
143 
144         list_add_tail(&pi->list, &s->valid_paths);
145 
146         return 0;
147 }
148 
149 static void ql_fail_path(struct path_selector *ps, struct dm_path *path)
150 {
151         struct selector *s = ps->context;
152         struct path_info *pi = path->pscontext;
153 
154         list_move(&pi->list, &s->failed_paths);
155 }
156 
157 static int ql_reinstate_path(struct path_selector *ps, struct dm_path *path)
158 {
159         struct selector *s = ps->context;
160         struct path_info *pi = path->pscontext;
161 
162         list_move_tail(&pi->list, &s->valid_paths);
163 
164         return 0;
165 }
166 
167 /*
168  * Select a path having the minimum number of in-flight I/Os
169  */
170 static struct dm_path *ql_select_path(struct path_selector *ps,
171                                       unsigned *repeat_count, size_t nr_bytes)
172 {
173         struct selector *s = ps->context;
174         struct path_info *pi = NULL, *best = NULL;
175 
176         if (list_empty(&s->valid_paths))
177                 return NULL;
178 
179         /* Change preferred (first in list) path to evenly balance. */
180         list_move_tail(s->valid_paths.next, &s->valid_paths);
181 
182         list_for_each_entry(pi, &s->valid_paths, list) {
183                 if (!best ||
184                     (atomic_read(&pi->qlen) < atomic_read(&best->qlen)))
185                         best = pi;
186 
187                 if (!atomic_read(&best->qlen))
188                         break;
189         }
190 
191         if (!best)
192                 return NULL;
193 
194         *repeat_count = best->repeat_count;
195 
196         return best->path;
197 }
198 
199 static int ql_start_io(struct path_selector *ps, struct dm_path *path,
200                        size_t nr_bytes)
201 {
202         struct path_info *pi = path->pscontext;
203 
204         atomic_inc(&pi->qlen);
205 
206         return 0;
207 }
208 
209 static int ql_end_io(struct path_selector *ps, struct dm_path *path,
210                      size_t nr_bytes)
211 {
212         struct path_info *pi = path->pscontext;
213 
214         atomic_dec(&pi->qlen);
215 
216         return 0;
217 }
218 
219 static struct path_selector_type ql_ps = {
220         .name           = "queue-length",
221         .module         = THIS_MODULE,
222         .table_args     = 1,
223         .info_args      = 1,
224         .create         = ql_create,
225         .destroy        = ql_destroy,
226         .status         = ql_status,
227         .add_path       = ql_add_path,
228         .fail_path      = ql_fail_path,
229         .reinstate_path = ql_reinstate_path,
230         .select_path    = ql_select_path,
231         .start_io       = ql_start_io,
232         .end_io         = ql_end_io,
233 };
234 
235 static int __init dm_ql_init(void)
236 {
237         int r = dm_register_path_selector(&ql_ps);
238 
239         if (r < 0)
240                 DMERR("register failed %d", r);
241 
242         DMINFO("version " QL_VERSION " loaded");
243 
244         return r;
245 }
246 
247 static void __exit dm_ql_exit(void)
248 {
249         int r = dm_unregister_path_selector(&ql_ps);
250 
251         if (r < 0)
252                 DMERR("unregister failed %d", r);
253 }
254 
255 module_init(dm_ql_init);
256 module_exit(dm_ql_exit);
257 
258 MODULE_AUTHOR("Stefan Bader <Stefan.Bader at de.ibm.com>");
259 MODULE_DESCRIPTION(
260         "(C) Copyright IBM Corp. 2004,2005   All Rights Reserved.\n"
261         DM_NAME " path selector to balance the number of in-flight I/Os"
262 );
263 MODULE_LICENSE("GPL");
264 
  This page was automatically generated by the LXR engine.