Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (C) 2003 Sistina Software.
0003  * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
0004  *
0005  * Module Author: Heinz Mauelshagen
0006  *
0007  * This file is released under the GPL.
0008  *
0009  * Round-robin path selector.
0010  */
0011 
0012 #include <linux/device-mapper.h>
0013 
0014 #include "dm-path-selector.h"
0015 
0016 #include <linux/slab.h>
0017 #include <linux/module.h>
0018 
0019 #define DM_MSG_PREFIX "multipath round-robin"
0020 #define RR_MIN_IO     1
0021 #define RR_VERSION    "1.2.0"
0022 
0023 /*-----------------------------------------------------------------
0024  * Path-handling code, paths are held in lists
0025  *---------------------------------------------------------------*/
0026 struct path_info {
0027     struct list_head list;
0028     struct dm_path *path;
0029     unsigned repeat_count;
0030 };
0031 
0032 static void free_paths(struct list_head *paths)
0033 {
0034     struct path_info *pi, *next;
0035 
0036     list_for_each_entry_safe(pi, next, paths, list) {
0037         list_del(&pi->list);
0038         kfree(pi);
0039     }
0040 }
0041 
0042 /*-----------------------------------------------------------------
0043  * Round-robin selector
0044  *---------------------------------------------------------------*/
0045 
0046 struct selector {
0047     struct list_head valid_paths;
0048     struct list_head invalid_paths;
0049     spinlock_t lock;
0050 };
0051 
0052 static struct selector *alloc_selector(void)
0053 {
0054     struct selector *s = kmalloc(sizeof(*s), GFP_KERNEL);
0055 
0056     if (s) {
0057         INIT_LIST_HEAD(&s->valid_paths);
0058         INIT_LIST_HEAD(&s->invalid_paths);
0059         spin_lock_init(&s->lock);
0060     }
0061 
0062     return s;
0063 }
0064 
0065 static int rr_create(struct path_selector *ps, unsigned argc, char **argv)
0066 {
0067     struct selector *s;
0068 
0069     s = alloc_selector();
0070     if (!s)
0071         return -ENOMEM;
0072 
0073     ps->context = s;
0074     return 0;
0075 }
0076 
0077 static void rr_destroy(struct path_selector *ps)
0078 {
0079     struct selector *s = ps->context;
0080 
0081     free_paths(&s->valid_paths);
0082     free_paths(&s->invalid_paths);
0083     kfree(s);
0084     ps->context = NULL;
0085 }
0086 
0087 static int rr_status(struct path_selector *ps, struct dm_path *path,
0088              status_type_t type, char *result, unsigned int maxlen)
0089 {
0090     struct path_info *pi;
0091     int sz = 0;
0092 
0093     if (!path)
0094         DMEMIT("0 ");
0095     else {
0096         switch(type) {
0097         case STATUSTYPE_INFO:
0098             break;
0099         case STATUSTYPE_TABLE:
0100             pi = path->pscontext;
0101             DMEMIT("%u ", pi->repeat_count);
0102             break;
0103 
0104         case STATUSTYPE_IMA:
0105             *result = '\0';
0106             break;
0107         }
0108     }
0109 
0110     return sz;
0111 }
0112 
0113 /*
0114  * Called during initialisation to register each path with an
0115  * optional repeat_count.
0116  */
0117 static int rr_add_path(struct path_selector *ps, struct dm_path *path,
0118                int argc, char **argv, char **error)
0119 {
0120     struct selector *s = ps->context;
0121     struct path_info *pi;
0122     unsigned repeat_count = RR_MIN_IO;
0123     char dummy;
0124     unsigned long flags;
0125 
0126     if (argc > 1) {
0127         *error = "round-robin ps: incorrect number of arguments";
0128         return -EINVAL;
0129     }
0130 
0131     /* First path argument is number of I/Os before switching path */
0132     if ((argc == 1) && (sscanf(argv[0], "%u%c", &repeat_count, &dummy) != 1)) {
0133         *error = "round-robin ps: invalid repeat count";
0134         return -EINVAL;
0135     }
0136 
0137     if (repeat_count > 1) {
0138         DMWARN_LIMIT("repeat_count > 1 is deprecated, using 1 instead");
0139         repeat_count = 1;
0140     }
0141 
0142     /* allocate the path */
0143     pi = kmalloc(sizeof(*pi), GFP_KERNEL);
0144     if (!pi) {
0145         *error = "round-robin ps: Error allocating path context";
0146         return -ENOMEM;
0147     }
0148 
0149     pi->path = path;
0150     pi->repeat_count = repeat_count;
0151 
0152     path->pscontext = pi;
0153 
0154     spin_lock_irqsave(&s->lock, flags);
0155     list_add_tail(&pi->list, &s->valid_paths);
0156     spin_unlock_irqrestore(&s->lock, flags);
0157 
0158     return 0;
0159 }
0160 
0161 static void rr_fail_path(struct path_selector *ps, struct dm_path *p)
0162 {
0163     unsigned long flags;
0164     struct selector *s = ps->context;
0165     struct path_info *pi = p->pscontext;
0166 
0167     spin_lock_irqsave(&s->lock, flags);
0168     list_move(&pi->list, &s->invalid_paths);
0169     spin_unlock_irqrestore(&s->lock, flags);
0170 }
0171 
0172 static int rr_reinstate_path(struct path_selector *ps, struct dm_path *p)
0173 {
0174     unsigned long flags;
0175     struct selector *s = ps->context;
0176     struct path_info *pi = p->pscontext;
0177 
0178     spin_lock_irqsave(&s->lock, flags);
0179     list_move(&pi->list, &s->valid_paths);
0180     spin_unlock_irqrestore(&s->lock, flags);
0181 
0182     return 0;
0183 }
0184 
0185 static struct dm_path *rr_select_path(struct path_selector *ps, size_t nr_bytes)
0186 {
0187     unsigned long flags;
0188     struct selector *s = ps->context;
0189     struct path_info *pi = NULL;
0190 
0191     spin_lock_irqsave(&s->lock, flags);
0192     if (!list_empty(&s->valid_paths)) {
0193         pi = list_entry(s->valid_paths.next, struct path_info, list);
0194         list_move_tail(&pi->list, &s->valid_paths);
0195     }
0196     spin_unlock_irqrestore(&s->lock, flags);
0197 
0198     return pi ? pi->path : NULL;
0199 }
0200 
0201 static struct path_selector_type rr_ps = {
0202     .name = "round-robin",
0203     .module = THIS_MODULE,
0204     .table_args = 1,
0205     .info_args = 0,
0206     .create = rr_create,
0207     .destroy = rr_destroy,
0208     .status = rr_status,
0209     .add_path = rr_add_path,
0210     .fail_path = rr_fail_path,
0211     .reinstate_path = rr_reinstate_path,
0212     .select_path = rr_select_path,
0213 };
0214 
0215 static int __init dm_rr_init(void)
0216 {
0217     int r = dm_register_path_selector(&rr_ps);
0218 
0219     if (r < 0)
0220         DMERR("register failed %d", r);
0221 
0222     DMINFO("version " RR_VERSION " loaded");
0223 
0224     return r;
0225 }
0226 
0227 static void __exit dm_rr_exit(void)
0228 {
0229     int r = dm_unregister_path_selector(&rr_ps);
0230 
0231     if (r < 0)
0232         DMERR("unregister failed %d", r);
0233 }
0234 
0235 module_init(dm_rr_init);
0236 module_exit(dm_rr_exit);
0237 
0238 MODULE_DESCRIPTION(DM_NAME " round-robin multipath path selector");
0239 MODULE_AUTHOR("Sistina Software <dm-devel@redhat.com>");
0240 MODULE_LICENSE("GPL");