brintos

brintos / linux-shallow public Read only

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