~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to drivers/md/dm-queue-length.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 <linux/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");