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