1ff56536eSAlex Hornung /* $NetBSD: dm_target.c,v 1.12 2010/01/04 00:14:41 haad Exp $ */ 2ff56536eSAlex Hornung 3ff56536eSAlex Hornung /* 4ff56536eSAlex Hornung * Copyright (c) 2008 The NetBSD Foundation, Inc. 5ff56536eSAlex Hornung * All rights reserved. 6ff56536eSAlex Hornung * 7ff56536eSAlex Hornung * This code is derived from software contributed to The NetBSD Foundation 8ff56536eSAlex Hornung * by Adam Hamsik. 9ff56536eSAlex Hornung * 10ff56536eSAlex Hornung * Redistribution and use in source and binary forms, with or without 11ff56536eSAlex Hornung * modification, are permitted provided that the following conditions 12ff56536eSAlex Hornung * are met: 13ff56536eSAlex Hornung * 1. Redistributions of source code Must retain the above copyright 14ff56536eSAlex Hornung * notice, this list of conditions and the following disclaimer. 15ff56536eSAlex Hornung * 2. Redistributions in binary form must reproduce the above copyright 16ff56536eSAlex Hornung * notice, this list of conditions and the following disclaimer in the 17ff56536eSAlex Hornung * documentation and/or other materials provided with the distribution. 18ff56536eSAlex Hornung * 19ff56536eSAlex Hornung * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20ff56536eSAlex Hornung * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21ff56536eSAlex Hornung * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22ff56536eSAlex Hornung * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23ff56536eSAlex Hornung * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24ff56536eSAlex Hornung * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25ff56536eSAlex Hornung * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26ff56536eSAlex Hornung * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27ff56536eSAlex Hornung * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28ff56536eSAlex Hornung * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29ff56536eSAlex Hornung * POSSIBILITY OF SUCH DAMAGE. 30ff56536eSAlex Hornung */ 31ff56536eSAlex Hornung 32ff56536eSAlex Hornung #include <sys/types.h> 33ff56536eSAlex Hornung #include <sys/param.h> 34ff56536eSAlex Hornung 355b279a20SAlex Hornung #include <sys/malloc.h> 36ff56536eSAlex Hornung #include <sys/module.h> 37*7115a22bSAlex Hornung #include <sys/linker.h> 38*7115a22bSAlex Hornung #include <sys/dm.h> 39ff56536eSAlex Hornung 40ff56536eSAlex Hornung #include "netbsd-dm.h" 41ff56536eSAlex Hornung 42ff56536eSAlex Hornung static dm_target_t *dm_target_lookup_name(const char *); 43ff56536eSAlex Hornung 44ff56536eSAlex Hornung TAILQ_HEAD(dm_target_head, dm_target); 45ff56536eSAlex Hornung 46ff56536eSAlex Hornung static struct dm_target_head dm_target_list = 47ff56536eSAlex Hornung TAILQ_HEAD_INITIALIZER(dm_target_list); 48ff56536eSAlex Hornung 495b279a20SAlex Hornung struct lock dm_target_mutex; 50ff56536eSAlex Hornung 51ff56536eSAlex Hornung /* 52ff56536eSAlex Hornung * Called indirectly from dm_table_load_ioctl to mark target as used. 53ff56536eSAlex Hornung */ 54ff56536eSAlex Hornung void 55ff56536eSAlex Hornung dm_target_busy(dm_target_t * target) 56ff56536eSAlex Hornung { 575b279a20SAlex Hornung atomic_add_int(&target->ref_cnt, 1); 58ff56536eSAlex Hornung } 59ff56536eSAlex Hornung /* 60ff56536eSAlex Hornung * Release reference counter on target. 61ff56536eSAlex Hornung */ 62ff56536eSAlex Hornung void 63ff56536eSAlex Hornung dm_target_unbusy(dm_target_t * target) 64ff56536eSAlex Hornung { 655b279a20SAlex Hornung KKASSERT(target->ref_cnt > 0); 665b279a20SAlex Hornung atomic_subtract_int(&target->ref_cnt, 1); 67ff56536eSAlex Hornung } 68ff56536eSAlex Hornung 69ff56536eSAlex Hornung /* 70*7115a22bSAlex Hornung * Try to autoload the module for the requested target. 71*7115a22bSAlex Hornung */ 72*7115a22bSAlex Hornung dm_target_t * 73*7115a22bSAlex Hornung dm_target_autoload(const char *dm_target_name) 74*7115a22bSAlex Hornung { 75*7115a22bSAlex Hornung char mod_name[128]; 76*7115a22bSAlex Hornung dm_target_t *dmt; 77*7115a22bSAlex Hornung linker_file_t linker_file; 78*7115a22bSAlex Hornung int error; 79*7115a22bSAlex Hornung 80*7115a22bSAlex Hornung ksnprintf(mod_name, sizeof(mod_name), "dm_target_%s", dm_target_name); 81*7115a22bSAlex Hornung error = linker_reference_module(mod_name, NULL, &linker_file); 82*7115a22bSAlex Hornung if (error != 0) { 83*7115a22bSAlex Hornung kprintf("dm: could not autoload module for target %s\n", 84*7115a22bSAlex Hornung dm_target_name); 85*7115a22bSAlex Hornung return NULL; 86*7115a22bSAlex Hornung } 87*7115a22bSAlex Hornung 88*7115a22bSAlex Hornung dmt = dm_target_lookup(dm_target_name); 89*7115a22bSAlex Hornung if (dmt == NULL) { 90*7115a22bSAlex Hornung linker_release_module(NULL, NULL, linker_file); 91*7115a22bSAlex Hornung return NULL; 92*7115a22bSAlex Hornung } 93*7115a22bSAlex Hornung 94*7115a22bSAlex Hornung /* XXX: extra-big hack to allow users to kldunload the module */ 95*7115a22bSAlex Hornung linker_file->userrefs = 1; 96*7115a22bSAlex Hornung 97*7115a22bSAlex Hornung return dmt; 98*7115a22bSAlex Hornung } 99*7115a22bSAlex Hornung 100*7115a22bSAlex Hornung /* 101ff56536eSAlex Hornung * Lookup for target in global target list. 102ff56536eSAlex Hornung */ 103ff56536eSAlex Hornung dm_target_t * 104ff56536eSAlex Hornung dm_target_lookup(const char *dm_target_name) 105ff56536eSAlex Hornung { 106ff56536eSAlex Hornung dm_target_t *dmt; 107ff56536eSAlex Hornung 108ff56536eSAlex Hornung dmt = NULL; 109ff56536eSAlex Hornung 110ff56536eSAlex Hornung if (dm_target_name == NULL) 111ff56536eSAlex Hornung return NULL; 112ff56536eSAlex Hornung 1135b279a20SAlex Hornung lockmgr(&dm_target_mutex, LK_EXCLUSIVE); 114ff56536eSAlex Hornung 115ff56536eSAlex Hornung dmt = dm_target_lookup_name(dm_target_name); 116ff56536eSAlex Hornung if (dmt != NULL) 117ff56536eSAlex Hornung dm_target_busy(dmt); 118ff56536eSAlex Hornung 1195b279a20SAlex Hornung lockmgr(&dm_target_mutex, LK_RELEASE); 120ff56536eSAlex Hornung 121ff56536eSAlex Hornung return dmt; 122ff56536eSAlex Hornung } 123ff56536eSAlex Hornung /* 124ff56536eSAlex Hornung * Search for name in TAIL and return apropriate pointer. 125ff56536eSAlex Hornung */ 126ff56536eSAlex Hornung static dm_target_t * 127ff56536eSAlex Hornung dm_target_lookup_name(const char *dm_target_name) 128ff56536eSAlex Hornung { 129ff56536eSAlex Hornung dm_target_t *dm_target; 130ff56536eSAlex Hornung 131ff56536eSAlex Hornung TAILQ_FOREACH(dm_target, &dm_target_list, dm_target_next) { 1320d42d35bSAlex Hornung if (strcmp(dm_target_name, dm_target->name) == 0) 133ff56536eSAlex Hornung return dm_target; 134ff56536eSAlex Hornung } 135ff56536eSAlex Hornung 136ff56536eSAlex Hornung return NULL; 137ff56536eSAlex Hornung } 138ff56536eSAlex Hornung /* 139ff56536eSAlex Hornung * Insert new target struct into the TAIL. 140ff56536eSAlex Hornung * dm_target 141ff56536eSAlex Hornung * contains name, version, function pointer to specifif target functions. 142ff56536eSAlex Hornung */ 143ff56536eSAlex Hornung int 144ff56536eSAlex Hornung dm_target_insert(dm_target_t * dm_target) 145ff56536eSAlex Hornung { 146ff56536eSAlex Hornung dm_target_t *dmt; 147ff56536eSAlex Hornung 1485b279a20SAlex Hornung lockmgr(&dm_target_mutex, LK_EXCLUSIVE); 149ff56536eSAlex Hornung 150ff56536eSAlex Hornung dmt = dm_target_lookup_name(dm_target->name); 151ff56536eSAlex Hornung if (dmt != NULL) { 1525b279a20SAlex Hornung kprintf("uhoh, target_insert EEXIST\n"); 1535b279a20SAlex Hornung lockmgr(&dm_target_mutex, LK_RELEASE); 154ff56536eSAlex Hornung return EEXIST; 155ff56536eSAlex Hornung } 156ff56536eSAlex Hornung TAILQ_INSERT_TAIL(&dm_target_list, dm_target, dm_target_next); 157ff56536eSAlex Hornung 1585b279a20SAlex Hornung lockmgr(&dm_target_mutex, LK_RELEASE); 159ff56536eSAlex Hornung 160ff56536eSAlex Hornung return 0; 161ff56536eSAlex Hornung } 162ff56536eSAlex Hornung 163ff56536eSAlex Hornung 164ff56536eSAlex Hornung /* 165ff56536eSAlex Hornung * Remove target from TAIL, target is selected with it's name. 166ff56536eSAlex Hornung */ 167ff56536eSAlex Hornung int 168ff56536eSAlex Hornung dm_target_rem(char *dm_target_name) 169ff56536eSAlex Hornung { 170ff56536eSAlex Hornung dm_target_t *dmt; 171ff56536eSAlex Hornung 1725b279a20SAlex Hornung KKASSERT(dm_target_name != NULL); 173ff56536eSAlex Hornung 1745b279a20SAlex Hornung lockmgr(&dm_target_mutex, LK_EXCLUSIVE); 175ff56536eSAlex Hornung 176ff56536eSAlex Hornung dmt = dm_target_lookup_name(dm_target_name); 177ff56536eSAlex Hornung if (dmt == NULL) { 1785b279a20SAlex Hornung lockmgr(&dm_target_mutex, LK_RELEASE); 179ff56536eSAlex Hornung return ENOENT; 180ff56536eSAlex Hornung } 181ff56536eSAlex Hornung if (dmt->ref_cnt > 0) { 1825b279a20SAlex Hornung lockmgr(&dm_target_mutex, LK_RELEASE); 183ff56536eSAlex Hornung return EBUSY; 184ff56536eSAlex Hornung } 185ff56536eSAlex Hornung TAILQ_REMOVE(&dm_target_list, 186ff56536eSAlex Hornung dmt, dm_target_next); 187ff56536eSAlex Hornung 1885b279a20SAlex Hornung lockmgr(&dm_target_mutex, LK_RELEASE); 189ff56536eSAlex Hornung 1905b279a20SAlex Hornung (void) kfree(dmt, M_DM); 191ff56536eSAlex Hornung 192ff56536eSAlex Hornung return 0; 193ff56536eSAlex Hornung } 194ff56536eSAlex Hornung /* 195ff56536eSAlex Hornung * Destroy all targets and remove them from queue. 196ff56536eSAlex Hornung * This routine is called from dm_detach, before module 197ff56536eSAlex Hornung * is unloaded. 198ff56536eSAlex Hornung */ 199ff56536eSAlex Hornung int 200ff56536eSAlex Hornung dm_target_destroy(void) 201ff56536eSAlex Hornung { 202ff56536eSAlex Hornung dm_target_t *dm_target; 203ff56536eSAlex Hornung 2045b279a20SAlex Hornung lockmgr(&dm_target_mutex, LK_EXCLUSIVE); 205ff56536eSAlex Hornung while (TAILQ_FIRST(&dm_target_list) != NULL) { 206ff56536eSAlex Hornung 207ff56536eSAlex Hornung dm_target = TAILQ_FIRST(&dm_target_list); 208ff56536eSAlex Hornung 209ff56536eSAlex Hornung TAILQ_REMOVE(&dm_target_list, TAILQ_FIRST(&dm_target_list), 210ff56536eSAlex Hornung dm_target_next); 211ff56536eSAlex Hornung 2125b279a20SAlex Hornung (void) kfree(dm_target, M_DM); 213ff56536eSAlex Hornung } 2145b279a20SAlex Hornung lockmgr(&dm_target_mutex, LK_RELEASE); 215ff56536eSAlex Hornung 2165b279a20SAlex Hornung lockuninit(&dm_target_mutex); 217ff56536eSAlex Hornung 218ff56536eSAlex Hornung return 0; 219ff56536eSAlex Hornung } 220ff56536eSAlex Hornung /* 221ff56536eSAlex Hornung * Allocate new target entry. 222ff56536eSAlex Hornung */ 223ff56536eSAlex Hornung dm_target_t * 224ff56536eSAlex Hornung dm_target_alloc(const char *name) 225ff56536eSAlex Hornung { 2265b279a20SAlex Hornung return kmalloc(sizeof(dm_target_t), M_DM, M_WAITOK | M_ZERO); 227ff56536eSAlex Hornung } 228ff56536eSAlex Hornung /* 229ff56536eSAlex Hornung * Return prop_array of dm_target dictionaries. 230ff56536eSAlex Hornung */ 231ff56536eSAlex Hornung prop_array_t 232ff56536eSAlex Hornung dm_target_prop_list(void) 233ff56536eSAlex Hornung { 234ff56536eSAlex Hornung prop_array_t target_array, ver; 235ff56536eSAlex Hornung prop_dictionary_t target_dict; 236ff56536eSAlex Hornung dm_target_t *dm_target; 237ff56536eSAlex Hornung 238ff56536eSAlex Hornung size_t i; 239ff56536eSAlex Hornung 240ff56536eSAlex Hornung target_array = prop_array_create(); 241ff56536eSAlex Hornung 2425b279a20SAlex Hornung lockmgr(&dm_target_mutex, LK_EXCLUSIVE); 243ff56536eSAlex Hornung 244ff56536eSAlex Hornung TAILQ_FOREACH(dm_target, &dm_target_list, dm_target_next) { 245ff56536eSAlex Hornung 246ff56536eSAlex Hornung target_dict = prop_dictionary_create(); 247ff56536eSAlex Hornung ver = prop_array_create(); 248ff56536eSAlex Hornung prop_dictionary_set_cstring(target_dict, DM_TARGETS_NAME, 249ff56536eSAlex Hornung dm_target->name); 250ff56536eSAlex Hornung 251ff56536eSAlex Hornung for (i = 0; i < 3; i++) 252ff56536eSAlex Hornung prop_array_add_uint32(ver, dm_target->version[i]); 253ff56536eSAlex Hornung 254ff56536eSAlex Hornung prop_dictionary_set(target_dict, DM_TARGETS_VERSION, ver); 255ff56536eSAlex Hornung prop_array_add(target_array, target_dict); 256ff56536eSAlex Hornung 257ff56536eSAlex Hornung prop_object_release(ver); 258ff56536eSAlex Hornung prop_object_release(target_dict); 259ff56536eSAlex Hornung } 260ff56536eSAlex Hornung 2615b279a20SAlex Hornung lockmgr(&dm_target_mutex, LK_RELEASE); 262ff56536eSAlex Hornung 263ff56536eSAlex Hornung return target_array; 264ff56536eSAlex Hornung } 2655c411e8eSAlex Hornung 266ff56536eSAlex Hornung /* Initialize dm_target subsystem. */ 267ff56536eSAlex Hornung int 268ff56536eSAlex Hornung dm_target_init(void) 269ff56536eSAlex Hornung { 2705b279a20SAlex Hornung lockinit(&dm_target_mutex, "dmtrgt", 0, LK_CANRECURSE); 271ff56536eSAlex Hornung 2725c411e8eSAlex Hornung return 0; 273ff56536eSAlex Hornung } 274