linux/drivers/md/dm-round-robin.c
<<
>>
Prefs
   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
  12#include <linux/device-mapper.h>
  13
  14#include "dm-path-selector.h"
  15
  16#include <linux/slab.h>
  17
  18#define DM_MSG_PREFIX "multipath round-robin"
  19
  20/*-----------------------------------------------------------------
  21 * Path-handling code, paths are held in lists
  22 *---------------------------------------------------------------*/
  23struct path_info {
  24        struct list_head list;
  25        struct dm_path *path;
  26        unsigned repeat_count;
  27};
  28
  29static void free_paths(struct list_head *paths)
  30{
  31        struct path_info *pi, *next;
  32
  33        list_for_each_entry_safe(pi, next, paths, list) {
  34                list_del(&pi->list);
  35                kfree(pi);
  36        }
  37}
  38
  39/*-----------------------------------------------------------------
  40 * Round-robin selector
  41 *---------------------------------------------------------------*/
  42
  43#define RR_MIN_IO               1000
  44
  45struct selector {
  46        struct list_head valid_paths;
  47        struct list_head invalid_paths;
  48};
  49
  50static struct selector *alloc_selector(void)
  51{
  52        struct selector *s = kmalloc(sizeof(*s), GFP_KERNEL);
  53
  54        if (s) {
  55                INIT_LIST_HEAD(&s->valid_paths);
  56                INIT_LIST_HEAD(&s->invalid_paths);
  57        }
  58
  59        return s;
  60}
  61
  62static int rr_create(struct path_selector *ps, unsigned argc, char **argv)
  63{
  64        struct selector *s;
  65
  66        s = alloc_selector();
  67        if (!s)
  68                return -ENOMEM;
  69
  70        ps->context = s;
  71        return 0;
  72}
  73
  74static void rr_destroy(struct path_selector *ps)
  75{
  76        struct selector *s = (struct selector *) ps->context;
  77
  78        free_paths(&s->valid_paths);
  79        free_paths(&s->invalid_paths);
  80        kfree(s);
  81        ps->context = NULL;
  82}
  83
  84static int rr_status(struct path_selector *ps, struct dm_path *path,
  85                     status_type_t type, char *result, unsigned int maxlen)
  86{
  87        struct path_info *pi;
  88        int sz = 0;
  89
  90        if (!path)
  91                DMEMIT("0 ");
  92        else {
  93                switch(type) {
  94                case STATUSTYPE_INFO:
  95                        break;
  96                case STATUSTYPE_TABLE:
  97                        pi = path->pscontext;
  98                        DMEMIT("%u ", pi->repeat_count);
  99                        break;
 100                }
 101        }
 102
 103        return sz;
 104}
 105
 106/*
 107 * Called during initialisation to register each path with an
 108 * optional repeat_count.
 109 */
 110static int rr_add_path(struct path_selector *ps, struct dm_path *path,
 111                       int argc, char **argv, char **error)
 112{
 113        struct selector *s = (struct selector *) ps->context;
 114        struct path_info *pi;
 115        unsigned repeat_count = RR_MIN_IO;
 116
 117        if (argc > 1) {
 118                *error = "round-robin ps: incorrect number of arguments";
 119                return -EINVAL;
 120        }
 121
 122        /* First path argument is number of I/Os before switching path */
 123        if ((argc == 1) && (sscanf(argv[0], "%u", &repeat_count) != 1)) {
 124                *error = "round-robin ps: invalid repeat count";
 125                return -EINVAL;
 126        }
 127
 128        /* allocate the path */
 129        pi = kmalloc(sizeof(*pi), GFP_KERNEL);
 130        if (!pi) {
 131                *error = "round-robin ps: Error allocating path context";
 132                return -ENOMEM;
 133        }
 134
 135        pi->path = path;
 136        pi->repeat_count = repeat_count;
 137
 138        path->pscontext = pi;
 139
 140        list_add_tail(&pi->list, &s->valid_paths);
 141
 142        return 0;
 143}
 144
 145static void rr_fail_path(struct path_selector *ps, struct dm_path *p)
 146{
 147        struct selector *s = (struct selector *) ps->context;
 148        struct path_info *pi = p->pscontext;
 149
 150        list_move(&pi->list, &s->invalid_paths);
 151}
 152
 153static int rr_reinstate_path(struct path_selector *ps, struct dm_path *p)
 154{
 155        struct selector *s = (struct selector *) ps->context;
 156        struct path_info *pi = p->pscontext;
 157
 158        list_move(&pi->list, &s->valid_paths);
 159
 160        return 0;
 161}
 162
 163static struct dm_path *rr_select_path(struct path_selector *ps,
 164                                      unsigned *repeat_count, size_t nr_bytes)
 165{
 166        struct selector *s = (struct selector *) ps->context;
 167        struct path_info *pi = NULL;
 168
 169        if (!list_empty(&s->valid_paths)) {
 170                pi = list_entry(s->valid_paths.next, struct path_info, list);
 171                list_move_tail(&pi->list, &s->valid_paths);
 172                *repeat_count = pi->repeat_count;
 173        }
 174
 175        return pi ? pi->path : NULL;
 176}
 177
 178static struct path_selector_type rr_ps = {
 179        .name = "round-robin",
 180        .module = THIS_MODULE,
 181        .table_args = 1,
 182        .info_args = 0,
 183        .create = rr_create,
 184        .destroy = rr_destroy,
 185        .status = rr_status,
 186        .add_path = rr_add_path,
 187        .fail_path = rr_fail_path,
 188        .reinstate_path = rr_reinstate_path,
 189        .select_path = rr_select_path,
 190};
 191
 192static int __init dm_rr_init(void)
 193{
 194        int r = dm_register_path_selector(&rr_ps);
 195
 196        if (r < 0)
 197                DMERR("register failed %d", r);
 198
 199        DMINFO("version 1.0.0 loaded");
 200
 201        return r;
 202}
 203
 204static void __exit dm_rr_exit(void)
 205{
 206        int r = dm_unregister_path_selector(&rr_ps);
 207
 208        if (r < 0)
 209                DMERR("unregister failed %d", r);
 210}
 211
 212module_init(dm_rr_init);
 213module_exit(dm_rr_exit);
 214
 215MODULE_DESCRIPTION(DM_NAME " round-robin multipath path selector");
 216MODULE_AUTHOR("Sistina Software <dm-devel@redhat.com>");
 217MODULE_LICENSE("GPL");
 218
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.