141 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2003 Sistina Software.4 * Copyright (C) 2004 Red Hat, Inc. All rights reserved.5 *6 * Module Author: Heinz Mauelshagen7 *8 * This file is released under the GPL.9 *10 * Path selector registration.11 */12 13#include <linux/device-mapper.h>14#include <linux/module.h>15 16#include "dm-path-selector.h"17 18#include <linux/slab.h>19 20struct ps_internal {21 struct path_selector_type pst;22 struct list_head list;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 && !try_module_get(psi->pst.module))49 psi = NULL;50 up_read(&_ps_lock);51 52 return psi;53}54 55struct path_selector_type *dm_get_path_selector(const char *name)56{57 struct ps_internal *psi;58 59 if (!name)60 return NULL;61 62 psi = get_path_selector(name);63 if (!psi) {64 request_module("dm-%s", name);65 psi = get_path_selector(name);66 }67 68 return psi ? &psi->pst : NULL;69}70 71void dm_put_path_selector(struct path_selector_type *pst)72{73 struct ps_internal *psi;74 75 if (!pst)76 return;77 78 down_read(&_ps_lock);79 psi = __find_path_selector_type(pst->name);80 if (!psi)81 goto out;82 83 module_put(psi->pst.module);84out:85 up_read(&_ps_lock);86}87 88static struct ps_internal *_alloc_path_selector(struct path_selector_type *pst)89{90 struct ps_internal *psi = kzalloc(sizeof(*psi), GFP_KERNEL);91 92 if (psi)93 psi->pst = *pst;94 95 return psi;96}97 98int dm_register_path_selector(struct path_selector_type *pst)99{100 int r = 0;101 struct ps_internal *psi = _alloc_path_selector(pst);102 103 if (!psi)104 return -ENOMEM;105 106 down_write(&_ps_lock);107 108 if (__find_path_selector_type(pst->name)) {109 kfree(psi);110 r = -EEXIST;111 } else112 list_add(&psi->list, &_path_selectors);113 114 up_write(&_ps_lock);115 116 return r;117}118EXPORT_SYMBOL_GPL(dm_register_path_selector);119 120int dm_unregister_path_selector(struct path_selector_type *pst)121{122 struct ps_internal *psi;123 124 down_write(&_ps_lock);125 126 psi = __find_path_selector_type(pst->name);127 if (!psi) {128 up_write(&_ps_lock);129 return -EINVAL;130 }131 132 list_del(&psi->list);133 134 up_write(&_ps_lock);135 136 kfree(psi);137 138 return 0;139}140EXPORT_SYMBOL_GPL(dm_unregister_path_selector);141