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
  21        struct list_head list;
  22        long use;
  23};
  24
  25#define pst_to_psi(__pst) container_of((__pst), struct ps_internal, pst)
  26
  27static LIST_HEAD(_path_selectors);
  28static DECLARE_RWSEM(_ps_lock);
  29
  30static struct ps_internal *__find_path_selector_type(const char *name)
  31{
  32        struct ps_internal *psi;
  33
  34        list_for_each_entry(psi, &_path_selectors, list) {
  35                if (!strcmp(name, psi->pst.name))
  36                        return psi;
  37        }
  38
  39        return NULL;
  40}
  41
  42static struct ps_internal *get_path_selector(const char *name)
  43{
  44        struct ps_internal *psi;
  45
  46        down_read(&_ps_lock);
  47        psi = __find_path_selector_type(name);
  48        if (psi) {
  49                if ((psi->use == 0) && !try_module_get(psi->pst.module))
  50                        psi = NULL;
  51                else
  52                        psi->use++;
  53        }
  54        up_read(&_ps_lock);
  55
  56        return psi;
  57}
  58
  59struct path_selector_type *dm_get_path_selector(const char *name)
  60{
  61        struct ps_internal *psi;
  62
  63        if (!name)
  64                return NULL;
  65
  66        psi = get_path_selector(name);
  67        if (!psi) {
  68                request_module("dm-%s", name);
  69                psi = get_path_selector(name);
  70        }
  71
  72        return psi ? &psi->pst : NULL;
  73}
  74
  75void dm_put_path_selector(struct path_selector_type *pst)
  76{
  77        struct ps_internal *psi;
  78
  79        if (!pst)
  80                return;
  81
  82        down_read(&_ps_lock);
  83        psi = __find_path_selector_type(pst->name);
  84        if (!psi)
  85                goto out;
  86
  87        if (--psi->use == 0)
  88                module_put(psi->pst.module);
  89
  90        BUG_ON(psi->use < 0);
  91
  92out:
  93        up_read(&_ps_lock);
  94}
  95
  96static struct ps_internal *_alloc_path_selector(struct path_selector_type *pst)
  97{
  98        struct ps_internal *psi = kzalloc(sizeof(*psi), GFP_KERNEL);
  99
 100        if (psi)
 101                psi->pst = *pst;
 102
 103        return psi;
 104}
 105
 106int dm_register_path_selector(struct path_selector_type *pst)
 107{
 108        int r = 0;
 109        struct ps_internal *psi = _alloc_path_selector(pst);
 110
 111        if (!psi)
 112                return -ENOMEM;
 113
 114        down_write(&_ps_lock);
 115
 116        if (__find_path_selector_type(pst->name)) {
 117                kfree(psi);
 118                r = -EEXIST;
 119        } else
 120                list_add(&psi->list, &_path_selectors);
 121
 122        up_write(&_ps_lock);
 123
 124        return r;
 125}
 126
 127int dm_unregister_path_selector(struct path_selector_type *pst)
 128{
 129        struct ps_internal *psi;
 130
 131        down_write(&_ps_lock);
 132
 133        psi = __find_path_selector_type(pst->name);
 134        if (!psi) {
 135                up_write(&_ps_lock);
 136                return -EINVAL;
 137        }
 138
 139        if (psi->use) {
 140                up_write(&_ps_lock);
 141                return -ETXTBSY;
 142        }
 143
 144        list_del(&psi->list);
 145
 146        up_write(&_ps_lock);
 147
 148        kfree(psi);
 149
 150        return 0;
 151}
 152
 153EXPORT_SYMBOL_GPL(dm_register_path_selector);
 154EXPORT_SYMBOL_GPL(dm_unregister_path_selector);
 155