linux/net/ipv4/ipvs/ip_vs_sched.c
<<
>>
Prefs
   1/*
   2 * IPVS         An implementation of the IP virtual server support for the
   3 *              LINUX operating system.  IPVS is now implemented as a module
   4 *              over the Netfilter framework. IPVS can be used to build a
   5 *              high-performance and highly available server based on a
   6 *              cluster of servers.
   7 *
   8 * Version:     $Id: ip_vs_sched.c,v 1.13 2003/05/10 03:05:23 wensong Exp $
   9 *
  10 * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
  11 *              Peter Kese <peter.kese@ijs.si>
  12 *
  13 *              This program is free software; you can redistribute it and/or
  14 *              modify it under the terms of the GNU General Public License
  15 *              as published by the Free Software Foundation; either version
  16 *              2 of the License, or (at your option) any later version.
  17 *
  18 * Changes:
  19 *
  20 */
  21
  22#include <linux/module.h>
  23#include <linux/spinlock.h>
  24#include <linux/interrupt.h>
  25#include <asm/string.h>
  26#include <linux/kmod.h>
  27#include <linux/sysctl.h>
  28
  29#include <net/ip_vs.h>
  30
  31/*
  32 *  IPVS scheduler list
  33 */
  34static LIST_HEAD(ip_vs_schedulers);
  35
  36/* lock for service table */
  37static DEFINE_RWLOCK(__ip_vs_sched_lock);
  38
  39
  40/*
  41 *  Bind a service with a scheduler
  42 */
  43int ip_vs_bind_scheduler(struct ip_vs_service *svc,
  44                         struct ip_vs_scheduler *scheduler)
  45{
  46        int ret;
  47
  48        if (svc == NULL) {
  49                IP_VS_ERR("ip_vs_bind_scheduler(): svc arg NULL\n");
  50                return -EINVAL;
  51        }
  52        if (scheduler == NULL) {
  53                IP_VS_ERR("ip_vs_bind_scheduler(): scheduler arg NULL\n");
  54                return -EINVAL;
  55        }
  56
  57        svc->scheduler = scheduler;
  58
  59        if (scheduler->init_service) {
  60                ret = scheduler->init_service(svc);
  61                if (ret) {
  62                        IP_VS_ERR("ip_vs_bind_scheduler(): init error\n");
  63                        return ret;
  64                }
  65        }
  66
  67        return 0;
  68}
  69
  70
  71/*
  72 *  Unbind a service with its scheduler
  73 */
  74int ip_vs_unbind_scheduler(struct ip_vs_service *svc)
  75{
  76        struct ip_vs_scheduler *sched;
  77
  78        if (svc == NULL) {
  79                IP_VS_ERR("ip_vs_unbind_scheduler(): svc arg NULL\n");
  80                return -EINVAL;
  81        }
  82
  83        sched = svc->scheduler;
  84        if (sched == NULL) {
  85                IP_VS_ERR("ip_vs_unbind_scheduler(): svc isn't bound\n");
  86                return -EINVAL;
  87        }
  88
  89        if (sched->done_service) {
  90                if (sched->done_service(svc) != 0) {
  91                        IP_VS_ERR("ip_vs_unbind_scheduler(): done error\n");
  92                        return -EINVAL;
  93                }
  94        }
  95
  96        svc->scheduler = NULL;
  97        return 0;
  98}
  99
 100
 101/*
 102 *  Get scheduler in the scheduler list by name
 103 */
 104static struct ip_vs_scheduler *ip_vs_sched_getbyname(const char *sched_name)
 105{
 106        struct ip_vs_scheduler *sched;
 107
 108        IP_VS_DBG(2, "ip_vs_sched_getbyname(): sched_name \"%s\"\n",
 109                  sched_name);
 110
 111        read_lock_bh(&__ip_vs_sched_lock);
 112
 113        list_for_each_entry(sched, &ip_vs_schedulers, n_list) {
 114                /*
 115                 * Test and get the modules atomically
 116                 */
 117                if (sched->module && !try_module_get(sched->module)) {
 118                        /*
 119                         * This scheduler is just deleted
 120                         */
 121                        continue;
 122                }
 123                if (strcmp(sched_name, sched->name)==0) {
 124                        /* HIT */
 125                        read_unlock_bh(&__ip_vs_sched_lock);
 126                        return sched;
 127                }
 128                if (sched->module)
 129                        module_put(sched->module);
 130        }
 131
 132        read_unlock_bh(&__ip_vs_sched_lock);
 133        return NULL;
 134}
 135
 136
 137/*
 138 *  Lookup scheduler and try to load it if it doesn't exist
 139 */
 140struct ip_vs_scheduler *ip_vs_scheduler_get(const char *sched_name)
 141{
 142        struct ip_vs_scheduler *sched;
 143
 144        /*
 145         *  Search for the scheduler by sched_name
 146         */
 147        sched = ip_vs_sched_getbyname(sched_name);
 148
 149        /*
 150         *  If scheduler not found, load the module and search again
 151         */
 152        if (sched == NULL) {
 153                request_module("ip_vs_%s", sched_name);
 154                sched = ip_vs_sched_getbyname(sched_name);
 155        }
 156
 157        return sched;
 158}
 159
 160void ip_vs_scheduler_put(struct ip_vs_scheduler *scheduler)
 161{
 162        if (scheduler->module)
 163                module_put(scheduler->module);
 164}
 165
 166
 167/*
 168 *  Register a scheduler in the scheduler list
 169 */
 170int register_ip_vs_scheduler(struct ip_vs_scheduler *scheduler)
 171{
 172        struct ip_vs_scheduler *sched;
 173
 174        if (!scheduler) {
 175                IP_VS_ERR("register_ip_vs_scheduler(): NULL arg\n");
 176                return -EINVAL;
 177        }
 178
 179        if (!scheduler->name) {
 180                IP_VS_ERR("register_ip_vs_scheduler(): NULL scheduler_name\n");
 181                return -EINVAL;
 182        }
 183
 184        /* increase the module use count */
 185        ip_vs_use_count_inc();
 186
 187        write_lock_bh(&__ip_vs_sched_lock);
 188
 189        if (scheduler->n_list.next != &scheduler->n_list) {
 190                write_unlock_bh(&__ip_vs_sched_lock);
 191                ip_vs_use_count_dec();
 192                IP_VS_ERR("register_ip_vs_scheduler(): [%s] scheduler "
 193                          "already linked\n", scheduler->name);
 194                return -EINVAL;
 195        }
 196
 197        /*
 198         *  Make sure that the scheduler with this name doesn't exist
 199         *  in the scheduler list.
 200         */
 201        list_for_each_entry(sched, &ip_vs_schedulers, n_list) {
 202                if (strcmp(scheduler->name, sched->name) == 0) {
 203                        write_unlock_bh(&__ip_vs_sched_lock);
 204                        ip_vs_use_count_dec();
 205                        IP_VS_ERR("register_ip_vs_scheduler(): [%s] scheduler "
 206                                        "already existed in the system\n",
 207                                        scheduler->name);
 208                        return -EINVAL;
 209                }
 210        }
 211        /*
 212         *      Add it into the d-linked scheduler list
 213         */
 214        list_add(&scheduler->n_list, &ip_vs_schedulers);
 215        write_unlock_bh(&__ip_vs_sched_lock);
 216
 217        IP_VS_INFO("[%s] scheduler registered.\n", scheduler->name);
 218
 219        return 0;
 220}
 221
 222
 223/*
 224 *  Unregister a scheduler from the scheduler list
 225 */
 226int unregister_ip_vs_scheduler(struct ip_vs_scheduler *scheduler)
 227{
 228        if (!scheduler) {
 229                IP_VS_ERR( "unregister_ip_vs_scheduler(): NULL arg\n");
 230                return -EINVAL;
 231        }
 232
 233        write_lock_bh(&__ip_vs_sched_lock);
 234        if (scheduler->n_list.next == &scheduler->n_list) {
 235                write_unlock_bh(&__ip_vs_sched_lock);
 236                IP_VS_ERR("unregister_ip_vs_scheduler(): [%s] scheduler "
 237                          "is not in the list. failed\n", scheduler->name);
 238                return -EINVAL;
 239        }
 240
 241        /*
 242         *      Remove it from the d-linked scheduler list
 243         */
 244        list_del(&scheduler->n_list);
 245        write_unlock_bh(&__ip_vs_sched_lock);
 246
 247        /* decrease the module use count */
 248        ip_vs_use_count_dec();
 249
 250        IP_VS_INFO("[%s] scheduler unregistered.\n", scheduler->name);
 251
 252        return 0;
 253}
 254
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.