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#include <linux/module.h>
  14
  15#include "dm-path-selector.h"
  16
  17#include <linux/slab.h>
  18
  19struct ps_internal {
  20        struct path_selector_type pst;
  21        struct list_head list;
  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 && !try_module_get(psi->pst.module))
  48                psi = NULL;
  49        up_read(&_ps_lock);
  50
  51        return psi;
  52}
  53
  54struct path_selector_type *dm_get_path_selector(const char *name)
  55{
  56        struct ps_internal *psi;
  57
  58        if (!name)
  59                return NULL;
  60
  61        psi = get_path_selector(name);
  62        if (!psi) {
  63                request_module("dm-%s", name);
  64                psi = get_path_selector(name);
  65        }
  66
  67        return psi ? &psi->pst : NULL;
  68}
  69
  70void dm_put_path_selector(struct path_selector_type *pst)
  71{
  72        struct ps_internal *psi;
  73
  74        if (!pst)
  75                return;
  76
  77        down_read(&_ps_lock);
  78        psi = __find_path_selector_type(pst->name);
  79        if (!psi)
  80                goto out;
  81
  82        module_put(psi->pst.module);
  83out:
  84        up_read(&_ps_lock);
  85}
  86
  87static struct ps_internal *_alloc_path_selector(struct path_selector_type *pst)
  88{
  89        struct ps_internal *psi = kzalloc(sizeof(*psi), GFP_KERNEL);
  90
  91        if (psi)
  92                psi->pst = *pst;
  93
  94        return psi;
  95}
  96
  97int dm_register_path_selector(struct path_selector_type *pst)
  98{
  99        int r = 0;
 100        struct ps_internal *psi = _alloc_path_selector(pst);
 101
 102        if (!psi)
 103                return -ENOMEM;
 104
 105        down_write(&_ps_lock);
 106
 107        if (__find_path_selector_type(pst->name)) {
 108                kfree(psi);
 109                r = -EEXIST;
 110        } else
 111                list_add(&psi->list, &_path_selectors);
 112
 113        up_write(&_ps_lock);
 114
 115        return r;
 116}
 117
 118int dm_unregister_path_selector(struct path_selector_type *pst)
 119{
 120        struct ps_internal *psi;
 121
 122        down_write(&_ps_lock);
 123
 124        psi = __find_path_selector_type(pst->name);
 125        if (!psi) {
 126                up_write(&_ps_lock);
 127                return -EINVAL;
 128        }
 129
 130        list_del(&psi->list);
 131
 132        up_write(&_ps_lock);
 133
 134        kfree(psi);
 135
 136        return 0;
 137}
 138
 139EXPORT_SYMBOL_GPL(dm_register_path_selector);
 140EXPORT_SYMBOL_GPL(dm_unregister_path_selector);
 141