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