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 | // SPDX-License-Identifier: GPL-2.0-only /* * 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 <linux/device-mapper.h> #include <linux/module.h> #include "dm-path-selector.h" #include <linux/slab.h> struct ps_internal { struct path_selector_type pst; struct list_head list; }; #define pst_to_psi(__pst) container_of((__pst), struct ps_internal, pst) static LIST_HEAD(_path_selectors); static DECLARE_RWSEM(_ps_lock); static 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 && !try_module_get(psi->pst.module)) psi = NULL; 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; module_put(psi->pst.module); out: up_read(&_ps_lock); } static struct ps_internal *_alloc_path_selector(struct path_selector_type *pst) { struct ps_internal *psi = kzalloc(sizeof(*psi), GFP_KERNEL); if (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; } EXPORT_SYMBOL_GPL(dm_register_path_selector); 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; } list_del(&psi->list); up_write(&_ps_lock); kfree(psi); return 0; } EXPORT_SYMBOL_GPL(dm_unregister_path_selector); |