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