linux/drivers/md/dm-path-selector.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2003 Sistina Software.
   3 * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
   4 *
   5 * Module Author: Heinz Mauelshagen
   6 *
   7 * This file is released under the GPL.
   8 *
   9 * Path selector registration.
  10 */
  11
  12#include <linux/device-mapper.h>
  13
  14#include "dm-path-selector.h"
  15
  16#include <linux/slab.h>
  17
  18struct ps_internal {
  19        struct path_selector_type pst;
  20        struct list_head list;
  21};
  22
  23#define pst_to_psi(__pst) container_of((__pst), struct ps_internal, pst)
  24
  25static LIST_HEAD(_path_selectors);
  26static DECLARE_RWSEM(_ps_lock);
  27
  28static struct ps_internal *__find_path_selector_type(const char *name)
  29{
  30        struct ps_internal *psi;
  31
  32        list_for_each_entry(psi, &_path_selectors, list) {
  33                if (!strcmp(name, psi->pst.name))
  34                        return psi;
  35        }
  36
  37        return NULL;
  38}
  39
  40static struct ps_internal *get_path_selector(const char *name)
  41{
  42        struct ps_internal *psi;
  43
  44        down_read(&_ps_lock);
  45        psi = __find_path_selector_type(name);
  46        if (psi && !try_module_get(psi->pst.module))
  47                psi = NULL;
  48        up_read(&_ps_lock);
  49
  50        return psi;
  51}
  52
  53struct path_selector_type *dm_get_path_selector(const char *name)
  54{
  55        struct ps_internal *psi;
  56
  57        if (!name)
  58                return NULL;
  59
  60        psi = get_path_selector(name);
  61        if (!psi) {
  62                request_module("dm-%s", name);
  63                psi = get_path_selector(name);
  64        }
  65
  66        return psi ? &psi->pst : NULL;
  67}
  68
  69void dm_put_path_selector(struct path_selector_type *pst)
  70{
  71        struct ps_internal *psi;
  72
  73        if (!pst)
  74                return;
  75
  76        down_read(&_ps_lock);
  77        psi = __find_path_selector_type(pst->name);
  78        if (!psi)
  79                goto out;
  80
  81        module_put(psi->pst.module);
  82out:
  83        up_read(&_ps_lock);
  84}
  85
  86static struct ps_internal *_alloc_path_selector(struct path_selector_type *pst)
  87{
  88        struct ps_internal *psi = kzalloc(sizeof(*psi), GFP_KERNEL);
  89
  90        if (psi)
  91                psi->pst = *pst;
  92
  93        return psi;
  94}
  95
  96int dm_register_path_selector(struct path_selector_type *pst)
  97{
  98        int r = 0;
  99        struct ps_internal *psi = _alloc_path_selector(pst);
 100
 101        if (!psi)
 102                return -ENOMEM;
 103
 104        down_write(&_ps_lock);
 105
 106        if (__find_path_selector_type(pst->name)) {
 107                kfree(psi);
 108                r = -EEXIST;
 109        } else
 110                list_add(&psi->list, &_path_selectors);
 111
 112        up_write(&_ps_lock);
 113
 114        return r;
 115}
 116
 117int dm_unregister_path_selector(struct path_selector_type *pst)
 118{
 119        struct ps_internal *psi;
 120
 121        down_write(&_ps_lock);
 122
 123        psi = __find_path_selector_type(pst->name);
 124        if (!psi) {
 125                up_write(&_ps_lock);
 126                return -EINVAL;
 127        }
 128
 129        list_del(&psi->list);
 130
 131        up_write(&_ps_lock);
 132
 133        kfree(psi);
 134
 135        return 0;
 136}
 137
 138EXPORT_SYMBOL_GPL(dm_register_path_selector);
 139EXPORT_SYMBOL_GPL(dm_unregister_path_selector);
 140