mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
140 lines
2.4 KiB
140 lines
2.4 KiB
/* |
|
* 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; |
|
} |
|
|
|
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_register_path_selector); |
|
EXPORT_SYMBOL_GPL(dm_unregister_path_selector);
|
|
|