cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dm-ps-round-robin.c (5209B)


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