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