1ff56536eSAlex Hornung /* $NetBSD: dm_target.c,v 1.12 2010/01/04 00:14:41 haad Exp $ */ 2ff56536eSAlex Hornung 3ff56536eSAlex Hornung /* 4ba2ce341SAlex Hornung * Copyright (c) 2010-2011 Alex Hornung <alex@alexhornung.com> 5ff56536eSAlex Hornung * Copyright (c) 2008 The NetBSD Foundation, Inc. 6ff56536eSAlex Hornung * All rights reserved. 7ff56536eSAlex Hornung * 8ff56536eSAlex Hornung * This code is derived from software contributed to The NetBSD Foundation 9ff56536eSAlex Hornung * by Adam Hamsik. 10ff56536eSAlex Hornung * 11ff56536eSAlex Hornung * Redistribution and use in source and binary forms, with or without 12ff56536eSAlex Hornung * modification, are permitted provided that the following conditions 13ff56536eSAlex Hornung * are met: 14ff56536eSAlex Hornung * 1. Redistributions of source code Must retain the above copyright 15ff56536eSAlex Hornung * notice, this list of conditions and the following disclaimer. 16ff56536eSAlex Hornung * 2. Redistributions in binary form must reproduce the above copyright 17ff56536eSAlex Hornung * notice, this list of conditions and the following disclaimer in the 18ff56536eSAlex Hornung * documentation and/or other materials provided with the distribution. 19ff56536eSAlex Hornung * 20ff56536eSAlex Hornung * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21ff56536eSAlex Hornung * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22ff56536eSAlex Hornung * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23ff56536eSAlex Hornung * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24ff56536eSAlex Hornung * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25ff56536eSAlex Hornung * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26ff56536eSAlex Hornung * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27ff56536eSAlex Hornung * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28ff56536eSAlex Hornung * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29ff56536eSAlex Hornung * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30ff56536eSAlex Hornung * POSSIBILITY OF SUCH DAMAGE. 31ff56536eSAlex Hornung */ 32ff56536eSAlex Hornung 33ff56536eSAlex Hornung #include <sys/types.h> 34ff56536eSAlex Hornung #include <sys/param.h> 35ff56536eSAlex Hornung 365b279a20SAlex Hornung #include <sys/malloc.h> 37ff56536eSAlex Hornung #include <sys/module.h> 387115a22bSAlex Hornung #include <sys/linker.h> 39a84e173eSAlex Hornung #include <dev/disk/dm/dm.h> 40ff56536eSAlex Hornung 41ff56536eSAlex Hornung #include "netbsd-dm.h" 42ff56536eSAlex Hornung 43ff56536eSAlex Hornung static dm_target_t *dm_target_lookup_name(const char *); 44ff56536eSAlex Hornung 45ff56536eSAlex Hornung TAILQ_HEAD(dm_target_head, dm_target); 46ff56536eSAlex Hornung 47ff56536eSAlex Hornung static struct dm_target_head dm_target_list = 48ff56536eSAlex Hornung TAILQ_HEAD_INITIALIZER(dm_target_list); 49ff56536eSAlex Hornung 50*637b454aSTomohiro Kusumi static struct lock dm_target_mutex; 51ff56536eSAlex Hornung 52ff56536eSAlex Hornung /* 53ff56536eSAlex Hornung * Called indirectly from dm_table_load_ioctl to mark target as used. 54ff56536eSAlex Hornung */ 55ff56536eSAlex Hornung void 56ff56536eSAlex Hornung dm_target_busy(dm_target_t * target) 57ff56536eSAlex Hornung { 585b279a20SAlex Hornung atomic_add_int(&target->ref_cnt, 1); 59ff56536eSAlex Hornung } 60ff56536eSAlex Hornung /* 61ff56536eSAlex Hornung * Release reference counter on target. 62ff56536eSAlex Hornung */ 63ff56536eSAlex Hornung void 64ff56536eSAlex Hornung dm_target_unbusy(dm_target_t * target) 65ff56536eSAlex Hornung { 665b279a20SAlex Hornung KKASSERT(target->ref_cnt > 0); 675b279a20SAlex Hornung atomic_subtract_int(&target->ref_cnt, 1); 68ff56536eSAlex Hornung } 69ff56536eSAlex Hornung 70ff56536eSAlex Hornung /* 717115a22bSAlex Hornung * Try to autoload the module for the requested target. 727115a22bSAlex Hornung */ 737115a22bSAlex Hornung dm_target_t * 747115a22bSAlex Hornung dm_target_autoload(const char *dm_target_name) 757115a22bSAlex Hornung { 767115a22bSAlex Hornung char mod_name[128]; 777115a22bSAlex Hornung dm_target_t *dmt; 787115a22bSAlex Hornung linker_file_t linker_file; 797115a22bSAlex Hornung int error; 807115a22bSAlex Hornung 817115a22bSAlex Hornung ksnprintf(mod_name, sizeof(mod_name), "dm_target_%s", dm_target_name); 827115a22bSAlex Hornung error = linker_reference_module(mod_name, NULL, &linker_file); 837115a22bSAlex Hornung if (error != 0) { 847115a22bSAlex Hornung kprintf("dm: could not autoload module for target %s\n", 857115a22bSAlex Hornung dm_target_name); 867115a22bSAlex Hornung return NULL; 877115a22bSAlex Hornung } 887115a22bSAlex Hornung 897115a22bSAlex Hornung dmt = dm_target_lookup(dm_target_name); 907115a22bSAlex Hornung if (dmt == NULL) { 917115a22bSAlex Hornung linker_release_module(NULL, NULL, linker_file); 927115a22bSAlex Hornung return NULL; 937115a22bSAlex Hornung } 947115a22bSAlex Hornung 957115a22bSAlex Hornung /* XXX: extra-big hack to allow users to kldunload the module */ 967115a22bSAlex Hornung linker_file->userrefs = 1; 977115a22bSAlex Hornung 987115a22bSAlex Hornung return dmt; 997115a22bSAlex Hornung } 1007115a22bSAlex Hornung 1017115a22bSAlex Hornung /* 102ff56536eSAlex Hornung * Lookup for target in global target list. 103ff56536eSAlex Hornung */ 104ff56536eSAlex Hornung dm_target_t * 105ff56536eSAlex Hornung dm_target_lookup(const char *dm_target_name) 106ff56536eSAlex Hornung { 107ff56536eSAlex Hornung dm_target_t *dmt; 108ff56536eSAlex Hornung 109ff56536eSAlex Hornung dmt = NULL; 110ff56536eSAlex Hornung 111ff56536eSAlex Hornung if (dm_target_name == NULL) 112ff56536eSAlex Hornung return NULL; 113ff56536eSAlex Hornung 1145b279a20SAlex Hornung lockmgr(&dm_target_mutex, LK_EXCLUSIVE); 115ff56536eSAlex Hornung 116ff56536eSAlex Hornung dmt = dm_target_lookup_name(dm_target_name); 117ff56536eSAlex Hornung if (dmt != NULL) 118ff56536eSAlex Hornung dm_target_busy(dmt); 119ff56536eSAlex Hornung 1205b279a20SAlex Hornung lockmgr(&dm_target_mutex, LK_RELEASE); 121ff56536eSAlex Hornung 122ff56536eSAlex Hornung return dmt; 123ff56536eSAlex Hornung } 124ff56536eSAlex Hornung /* 125ff56536eSAlex Hornung * Search for name in TAIL and return apropriate pointer. 126ff56536eSAlex Hornung */ 127ff56536eSAlex Hornung static dm_target_t * 128ff56536eSAlex Hornung dm_target_lookup_name(const char *dm_target_name) 129ff56536eSAlex Hornung { 130ff56536eSAlex Hornung dm_target_t *dm_target; 131ff56536eSAlex Hornung 132ff56536eSAlex Hornung TAILQ_FOREACH(dm_target, &dm_target_list, dm_target_next) { 1330d42d35bSAlex Hornung if (strcmp(dm_target_name, dm_target->name) == 0) 134ff56536eSAlex Hornung return dm_target; 135ff56536eSAlex Hornung } 136ff56536eSAlex Hornung 137ff56536eSAlex Hornung return NULL; 138ff56536eSAlex Hornung } 139ff56536eSAlex Hornung /* 140ff56536eSAlex Hornung * Insert new target struct into the TAIL. 141ff56536eSAlex Hornung * dm_target 142ff56536eSAlex Hornung * contains name, version, function pointer to specifif target functions. 143ff56536eSAlex Hornung */ 144ff56536eSAlex Hornung int 145ff56536eSAlex Hornung dm_target_insert(dm_target_t * dm_target) 146ff56536eSAlex Hornung { 147ff56536eSAlex Hornung dm_target_t *dmt; 148ff56536eSAlex Hornung 1495b279a20SAlex Hornung lockmgr(&dm_target_mutex, LK_EXCLUSIVE); 150ff56536eSAlex Hornung 151ff56536eSAlex Hornung dmt = dm_target_lookup_name(dm_target->name); 152ff56536eSAlex Hornung if (dmt != NULL) { 1535b279a20SAlex Hornung kprintf("uhoh, target_insert EEXIST\n"); 1545b279a20SAlex Hornung lockmgr(&dm_target_mutex, LK_RELEASE); 155ff56536eSAlex Hornung return EEXIST; 156ff56536eSAlex Hornung } 157ff56536eSAlex Hornung TAILQ_INSERT_TAIL(&dm_target_list, dm_target, dm_target_next); 158ff56536eSAlex Hornung 1595b279a20SAlex Hornung lockmgr(&dm_target_mutex, LK_RELEASE); 160ff56536eSAlex Hornung 161ff56536eSAlex Hornung return 0; 162ff56536eSAlex Hornung } 163ff56536eSAlex Hornung 164ff56536eSAlex Hornung 165ff56536eSAlex Hornung /* 166ff56536eSAlex Hornung * Remove target from TAIL, target is selected with it's name. 167ff56536eSAlex Hornung */ 168ff56536eSAlex Hornung int 169ff56536eSAlex Hornung dm_target_rem(char *dm_target_name) 170ff56536eSAlex Hornung { 171ff56536eSAlex Hornung dm_target_t *dmt; 172ff56536eSAlex Hornung 1735b279a20SAlex Hornung KKASSERT(dm_target_name != NULL); 174ff56536eSAlex Hornung 1755b279a20SAlex Hornung lockmgr(&dm_target_mutex, LK_EXCLUSIVE); 176ff56536eSAlex Hornung 177ff56536eSAlex Hornung dmt = dm_target_lookup_name(dm_target_name); 178ff56536eSAlex Hornung if (dmt == NULL) { 1795b279a20SAlex Hornung lockmgr(&dm_target_mutex, LK_RELEASE); 180ff56536eSAlex Hornung return ENOENT; 181ff56536eSAlex Hornung } 182ff56536eSAlex Hornung if (dmt->ref_cnt > 0) { 1835b279a20SAlex Hornung lockmgr(&dm_target_mutex, LK_RELEASE); 184ff56536eSAlex Hornung return EBUSY; 185ff56536eSAlex Hornung } 186ff56536eSAlex Hornung TAILQ_REMOVE(&dm_target_list, 187ff56536eSAlex Hornung dmt, dm_target_next); 188ff56536eSAlex Hornung 1895b279a20SAlex Hornung lockmgr(&dm_target_mutex, LK_RELEASE); 190ff56536eSAlex Hornung 1915b279a20SAlex Hornung (void) kfree(dmt, M_DM); 192ff56536eSAlex Hornung 193ff56536eSAlex Hornung return 0; 194ff56536eSAlex Hornung } 195ff56536eSAlex Hornung 196ff56536eSAlex Hornung /* 197ff56536eSAlex Hornung * Allocate new target entry. 198ff56536eSAlex Hornung */ 199ff56536eSAlex Hornung dm_target_t * 200ff56536eSAlex Hornung dm_target_alloc(const char *name) 201ff56536eSAlex Hornung { 2025b279a20SAlex Hornung return kmalloc(sizeof(dm_target_t), M_DM, M_WAITOK | M_ZERO); 203ff56536eSAlex Hornung } 204ff56536eSAlex Hornung /* 205ff56536eSAlex Hornung * Return prop_array of dm_target dictionaries. 206ff56536eSAlex Hornung */ 207ff56536eSAlex Hornung prop_array_t 208ff56536eSAlex Hornung dm_target_prop_list(void) 209ff56536eSAlex Hornung { 210ff56536eSAlex Hornung prop_array_t target_array, ver; 211ff56536eSAlex Hornung prop_dictionary_t target_dict; 212ff56536eSAlex Hornung dm_target_t *dm_target; 213ff56536eSAlex Hornung 214ff56536eSAlex Hornung size_t i; 215ff56536eSAlex Hornung 216ff56536eSAlex Hornung target_array = prop_array_create(); 217ff56536eSAlex Hornung 2185b279a20SAlex Hornung lockmgr(&dm_target_mutex, LK_EXCLUSIVE); 219ff56536eSAlex Hornung 220ff56536eSAlex Hornung TAILQ_FOREACH(dm_target, &dm_target_list, dm_target_next) { 221ff56536eSAlex Hornung 222ff56536eSAlex Hornung target_dict = prop_dictionary_create(); 223ff56536eSAlex Hornung ver = prop_array_create(); 224ff56536eSAlex Hornung prop_dictionary_set_cstring(target_dict, DM_TARGETS_NAME, 225ff56536eSAlex Hornung dm_target->name); 226ff56536eSAlex Hornung 227ff56536eSAlex Hornung for (i = 0; i < 3; i++) 228ff56536eSAlex Hornung prop_array_add_uint32(ver, dm_target->version[i]); 229ff56536eSAlex Hornung 230ff56536eSAlex Hornung prop_dictionary_set(target_dict, DM_TARGETS_VERSION, ver); 231ff56536eSAlex Hornung prop_array_add(target_array, target_dict); 232ff56536eSAlex Hornung 233ff56536eSAlex Hornung prop_object_release(ver); 234ff56536eSAlex Hornung prop_object_release(target_dict); 235ff56536eSAlex Hornung } 236ff56536eSAlex Hornung 2375b279a20SAlex Hornung lockmgr(&dm_target_mutex, LK_RELEASE); 238ff56536eSAlex Hornung 239ff56536eSAlex Hornung return target_array; 240ff56536eSAlex Hornung } 2415c411e8eSAlex Hornung 242ff56536eSAlex Hornung /* Initialize dm_target subsystem. */ 243ff56536eSAlex Hornung int 244ff56536eSAlex Hornung dm_target_init(void) 245ff56536eSAlex Hornung { 2465b279a20SAlex Hornung lockinit(&dm_target_mutex, "dmtrgt", 0, LK_CANRECURSE); 247ff56536eSAlex Hornung 2485c411e8eSAlex Hornung return 0; 249ff56536eSAlex Hornung } 2509fada28aSAlex Hornung 2519fada28aSAlex Hornung /* 2529fada28aSAlex Hornung * Destroy all targets and remove them from queue. 2539fada28aSAlex Hornung * This routine is called from dm_detach, before module 2549fada28aSAlex Hornung * is unloaded. 2559fada28aSAlex Hornung */ 2569fada28aSAlex Hornung int 2579fada28aSAlex Hornung dm_target_uninit(void) 2589fada28aSAlex Hornung { 2599fada28aSAlex Hornung dm_target_t *dm_target; 2609fada28aSAlex Hornung 2619fada28aSAlex Hornung lockmgr(&dm_target_mutex, LK_EXCLUSIVE); 2629fada28aSAlex Hornung while (TAILQ_FIRST(&dm_target_list) != NULL) { 2639fada28aSAlex Hornung 2649fada28aSAlex Hornung dm_target = TAILQ_FIRST(&dm_target_list); 2659fada28aSAlex Hornung 2669fada28aSAlex Hornung TAILQ_REMOVE(&dm_target_list, TAILQ_FIRST(&dm_target_list), 2679fada28aSAlex Hornung dm_target_next); 2689fada28aSAlex Hornung 2699fada28aSAlex Hornung (void) kfree(dm_target, M_DM); 2709fada28aSAlex Hornung } 2719fada28aSAlex Hornung lockmgr(&dm_target_mutex, LK_RELEASE); 2729fada28aSAlex Hornung 2739fada28aSAlex Hornung lockuninit(&dm_target_mutex); 2749fada28aSAlex Hornung 2759fada28aSAlex Hornung return 0; 2769fada28aSAlex Hornung } 277