| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * 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. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-10-21 17:44:59 +01:00
										 |  |  | #include <linux/device-mapper.h>
 | 
					
						
							| 
									
										
										
										
											2011-07-03 13:58:33 -04:00
										 |  |  | #include <linux/module.h>
 | 
					
						
							| 
									
										
										
										
											2008-10-21 17:44:59 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | #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); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-05-05 16:16:09 -07:00
										 |  |  | static struct ps_internal *__find_path_selector_type(const char *name) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	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); | 
					
						
							| 
									
										
										
										
											2009-04-02 19:55:27 +01:00
										 |  |  | 	if (psi && !try_module_get(psi->pst.module)) | 
					
						
							|  |  |  | 		psi = NULL; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	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; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-02 19:55:27 +01:00
										 |  |  | 	module_put(psi->pst.module); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | out: | 
					
						
							|  |  |  | 	up_read(&_ps_lock); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct ps_internal *_alloc_path_selector(struct path_selector_type *pst) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-10-19 22:38:51 +01:00
										 |  |  | 	struct ps_internal *psi = kzalloc(sizeof(*psi), GFP_KERNEL); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-10-19 22:38:51 +01:00
										 |  |  | 	if (psi) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		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); |