Changeset 58cbb0c8 in mainline


Ignore:
Timestamp:
2011-09-01T22:19:21Z (13 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
aff587f
Parents:
5f6e25e
Message:

Reference counting of device and function nodes in devman.

Location:
uspace/srv/devman
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/devman/devman.c

    r5f6e25e r58cbb0c8  
    3030 * @{
    3131 */
     32/** @file Device Manager
     33 *
     34 * Locking order:
     35 *   (1) driver_t.driver_mutex
     36 *   (2) dev_tree_t.rwlock
     37 *
     38 * Synchronization:
     39 *    - device_tree.rwlock protects:
     40 *        - tree root, complete tree topology
     41 *        - complete contents of device and function nodes
     42 *    - dev_node_t.refcnt, fun_node_t.refcnt prevent nodes from
     43 *      being deallocated
     44 *    - find_xxx() functions increase reference count of returned object
     45 *    - find_xxx_no_lock() do not increase reference count
     46 *
     47 * TODO
     48 *    - Track all steady and transient device/function states
     49 *    - Check states, wait for steady state on certain operations
     50 */
    3251
    3352#include <errno.h>
     
    4362#include "devman.h"
    4463
    45 fun_node_t *find_node_child(fun_node_t *parent, const char *name);
     64static fun_node_t *find_node_child(dev_tree_t *, fun_node_t *, const char *);
    4665
    4766/* hash table operations */
     
    406425        }
    407426       
     427        fun_add_ref(fun);
    408428        insert_fun_node(tree, fun, str_dup(""), NULL);
     429       
    409430        match_id_t *id = create_match_id();
    410431        id->id = str_dup("root");
     
    422443        }
    423444       
     445        dev_add_ref(dev);
    424446        insert_dev_node(tree, dev, fun);
    425447       
     
    467489/** Assign a driver to a device.
    468490 *
     491 * @param tree          Device tree
    469492 * @param node          The device's node in the device tree.
    470493 * @param drv           The driver.
    471494 */
    472 void attach_driver(dev_node_t *dev, driver_t *drv)
     495void attach_driver(dev_tree_t *tree, dev_node_t *dev, driver_t *drv)
    473496{
    474497        log_msg(LVL_DEBUG, "attach_driver(dev=\"%s\",drv=\"%s\")",
     
    476499       
    477500        fibril_mutex_lock(&drv->driver_mutex);
     501        fibril_rwlock_write_lock(&tree->rwlock);
    478502       
    479503        dev->drv = drv;
    480504        list_append(&dev->driver_devices, &drv->devices);
    481505       
     506        fibril_rwlock_write_unlock(&tree->rwlock);
    482507        fibril_mutex_unlock(&drv->driver_mutex);
    483508}
     
    485510/** Detach driver from device.
    486511 *
     512 * @param tree          Device tree
    487513 * @param node          The device's node in the device tree.
    488514 * @param drv           The driver.
    489515 */
    490 void detach_driver(dev_node_t *dev)
    491 {
    492         /* XXX need lock on dev */
     516void detach_driver(dev_tree_t *tree, dev_node_t *dev)
     517{
    493518        driver_t *drv = dev->drv;
    494519       
    495520        assert(drv != NULL);
     521       
    496522        log_msg(LVL_DEBUG, "detach_driver(dev=\"%s\",drv=\"%s\")",
    497523            dev->pfun->pathname, drv->name);
    498524       
    499525        fibril_mutex_lock(&drv->driver_mutex);
     526        fibril_rwlock_write_lock(&tree->rwlock);
    500527       
    501528        dev->drv = NULL;
    502529        list_remove(&dev->driver_devices);
    503530       
     531        fibril_rwlock_write_unlock(&tree->rwlock);
    504532        fibril_mutex_unlock(&drv->driver_mutex);
    505533}
     
    578606        while (link != &driver->devices.head) {
    579607                dev = list_get_instance(link, dev_node_t, driver_devices);
     608                fibril_rwlock_write_lock(&tree->rwlock);
     609               
    580610                if (dev->passed_to_driver) {
     611                        fibril_rwlock_write_unlock(&tree->rwlock);
    581612                        link = link->next;
    582613                        continue;
    583614                }
    584615
    585                 /*
    586                  * We remove the device from the list to allow safe adding
    587                  * of new devices (no one will touch our item this way).
    588                  */
    589                 list_remove(link);
     616                log_msg(LVL_DEBUG, "pass_devices_to_driver: dev->refcnt=%d\n",
     617                    (int)atomic_get(&dev->refcnt));
     618                dev_add_ref(dev);
    590619
    591620                /*
     
    594623                 */
    595624                fibril_mutex_unlock(&driver->driver_mutex);
     625                fibril_rwlock_write_unlock(&tree->rwlock);
    596626
    597627                add_device(driver, dev, tree);
     628
     629                dev_del_ref(dev);
    598630
    599631                /*
     
    602634                 */
    603635                fibril_mutex_lock(&driver->driver_mutex);
    604 
    605                 /*
    606                  * Insert the device back.
    607                  * The order is not relevant here so no harm is done
    608                  * (actually, the order would be preserved in most cases).
    609                  */
    610                 list_append(link, &driver->devices);
    611636
    612637                /*
     
    701726        char *loc_name = NULL;
    702727       
     728        assert(fibril_rwlock_is_locked(&tree->rwlock));
     729       
    703730        asprintf(&loc_name, "%s", fun->pathname);
    704731        if (loc_name == NULL)
     
    805832       
    806833        /* Attach the driver to the device. */
    807         attach_driver(dev, drv);
     834        attach_driver(tree, dev, drv);
    808835       
    809836        fibril_mutex_lock(&drv->driver_mutex);
     
    822849}
    823850
    824 int driver_dev_remove(dev_node_t *dev)
     851int driver_dev_remove(dev_tree_t *tree, dev_node_t *dev)
    825852{
    826853        async_exch_t *exch;
    827854        sysarg_t retval;
    828855        driver_t *drv;
     856        devman_handle_t handle;
    829857       
    830858        assert(dev != NULL);
     859       
    831860        log_msg(LVL_DEBUG, "driver_dev_remove(%p)", dev);
     861       
     862        fibril_rwlock_read_lock(&tree->rwlock);
    832863        drv = dev->drv;
     864        handle = dev->handle;
     865        fibril_rwlock_read_unlock(&tree->rwlock);
    833866       
    834867        exch = async_exchange_begin(drv->sess);
    835         retval = async_req_1_0(exch, DRIVER_DEV_REMOVE, dev->handle);
     868        retval = async_req_1_0(exch, DRIVER_DEV_REMOVE, handle);
    836869        async_exchange_end(exch);
    837870       
     
    840873}
    841874
    842 int driver_fun_online(fun_node_t *fun)
     875int driver_fun_online(dev_tree_t *tree, fun_node_t *fun)
    843876{
    844877        async_exch_t *exch;
    845878        sysarg_t retval;
    846879        driver_t *drv;
     880        devman_handle_t handle;
    847881       
    848882        log_msg(LVL_DEBUG, "driver_fun_online(%p)", fun);
     883
     884        fibril_rwlock_read_lock(&tree->rwlock);
     885       
    849886        if (fun->dev == NULL) {
    850887                /* XXX root function? */
     888                fibril_rwlock_read_unlock(&tree->rwlock);
    851889                return EINVAL;
    852890        }
    853891       
    854892        drv = fun->dev->drv;
     893        handle = fun->handle;
     894        fibril_rwlock_read_unlock(&tree->rwlock);
    855895       
    856896        exch = async_exchange_begin(drv->sess);
    857         retval = async_req_1_0(exch, DRIVER_FUN_ONLINE, fun->handle);
     897        retval = async_req_1_0(exch, DRIVER_FUN_ONLINE, handle);
    858898        loc_exchange_end(exch);
    859899       
     
    861901}
    862902
    863 int driver_fun_offline(fun_node_t *fun)
     903int driver_fun_offline(dev_tree_t *tree, fun_node_t *fun)
    864904{
    865905        async_exch_t *exch;
    866906        sysarg_t retval;
    867907        driver_t *drv;
     908        devman_handle_t handle;
    868909       
    869910        log_msg(LVL_DEBUG, "driver_fun_offline(%p)", fun);
     911
     912        fibril_rwlock_read_lock(&tree->rwlock);
    870913        if (fun->dev == NULL) {
    871914                /* XXX root function? */
     915                fibril_rwlock_read_unlock(&tree->rwlock);
    872916                return EINVAL;
    873917        }
    874918       
    875919        drv = fun->dev->drv;
     920        handle = fun->handle;
     921        fibril_rwlock_read_unlock(&tree->rwlock);
    876922       
    877923        exch = async_exchange_begin(drv->sess);
    878         retval = async_req_1_0(exch, DRIVER_FUN_OFFLINE, fun->handle);
     924        retval = async_req_1_0(exch, DRIVER_FUN_OFFLINE, handle);
    879925        loc_exchange_end(exch);
    880926       
     
    909955        if (!create_root_nodes(tree))
    910956                return false;
    911 
     957   
    912958        /* Find suitable driver and start it. */
    913         return assign_driver(tree->root_node->child, drivers_list, tree);
     959        dev_node_t *rdev = tree->root_node->child;
     960        dev_add_ref(rdev);
     961        int rc = assign_driver(rdev, drivers_list, tree);
     962        dev_del_ref(rdev);
     963       
     964        return rc;
    914965}
    915966
     
    922973dev_node_t *create_dev_node(void)
    923974{
    924         dev_node_t *res = malloc(sizeof(dev_node_t));
    925        
    926         if (res != NULL) {
    927                 memset(res, 0, sizeof(dev_node_t));
    928                 list_initialize(&res->functions);
    929                 link_initialize(&res->driver_devices);
    930                 link_initialize(&res->devman_dev);
    931         }
    932        
    933         return res;
     975        dev_node_t *dev;
     976       
     977        dev = calloc(1, sizeof(dev_node_t));
     978        if (dev == NULL)
     979                return NULL;
     980       
     981        atomic_set(&dev->refcnt, 0);
     982        list_initialize(&dev->functions);
     983        link_initialize(&dev->driver_devices);
     984        link_initialize(&dev->devman_dev);
     985       
     986        return dev;
    934987}
    935988
     
    9471000}
    9481001
     1002/** Increase device node reference count.
     1003 *
     1004 * @param dev   Device node
     1005 */
     1006void dev_add_ref(dev_node_t *dev)
     1007{
     1008        atomic_inc(&dev->refcnt);
     1009}
     1010
     1011/** Decrease device node reference count.
     1012 *
     1013 * When the count drops to zero the device node is freed.
     1014 *
     1015 * @param dev   Device node
     1016 */
     1017void dev_del_ref(dev_node_t *dev)
     1018{
     1019        if (atomic_predec(&dev->refcnt) == 0)
     1020                delete_dev_node(dev);
     1021}
     1022
     1023
    9491024/** Find the device node structure of the device witch has the specified handle.
    9501025 *
     
    9761051        fibril_rwlock_read_lock(&tree->rwlock);
    9771052        dev = find_dev_node_no_lock(tree, handle);
     1053        if (dev != NULL)
     1054                dev_add_ref(dev);
     1055       
    9781056        fibril_rwlock_read_unlock(&tree->rwlock);
    9791057       
     
    10031081                    list_get_instance(item, fun_node_t, dev_functions);
    10041082
    1005                 if (pos < buf_cnt)
     1083                if (pos < buf_cnt) {
    10061084                        hdl_buf[pos] = fun->handle;
     1085                }
     1086
    10071087                pos++;
    10081088        }
     
    10201100fun_node_t *create_fun_node(void)
    10211101{
    1022         fun_node_t *res = malloc(sizeof(fun_node_t));
    1023        
    1024         if (res != NULL) {
    1025                 memset(res, 0, sizeof(fun_node_t));
    1026                 link_initialize(&res->dev_functions);
    1027                 list_initialize(&res->match_ids.ids);
    1028                 link_initialize(&res->devman_fun);
    1029                 link_initialize(&res->loc_fun);
    1030         }
    1031        
    1032         return res;
     1102        fun_node_t *fun;
     1103
     1104        fun = calloc(1, sizeof(fun_node_t));
     1105        if (fun == NULL)
     1106                return NULL;
     1107       
     1108        atomic_set(&fun->refcnt, 0);
     1109        link_initialize(&fun->dev_functions);
     1110        list_initialize(&fun->match_ids.ids);
     1111        link_initialize(&fun->devman_fun);
     1112        link_initialize(&fun->loc_fun);
     1113       
     1114        return fun;
    10331115}
    10341116
     
    10481130}
    10491131
     1132/** Increase function node reference count.
     1133 *
     1134 * @param fun   Function node
     1135 */
     1136void fun_add_ref(fun_node_t *fun)
     1137{
     1138        atomic_inc(&fun->refcnt);
     1139}
     1140
     1141/** Decrease function node reference count.
     1142 *
     1143 * When the count drops to zero the function node is freed.
     1144 *
     1145 * @param fun   Function node
     1146 */
     1147void fun_del_ref(fun_node_t *fun)
     1148{
     1149        if (atomic_predec(&fun->refcnt) == 0)
     1150                delete_fun_node(fun);
     1151}
     1152
    10501153/** Find the function node with the specified handle.
    10511154 *
     
    10581161        unsigned long key = handle;
    10591162        link_t *link;
     1163        fun_node_t *fun;
    10601164       
    10611165        assert(fibril_rwlock_is_locked(&tree->rwlock));
     
    10651169                return NULL;
    10661170       
    1067         return hash_table_get_instance(link, fun_node_t, devman_fun);
     1171        fun = hash_table_get_instance(link, fun_node_t, devman_fun);
     1172       
     1173        return fun;
    10681174}
    10691175
     
    10791185       
    10801186        fibril_rwlock_read_lock(&tree->rwlock);
     1187       
    10811188        fun = find_fun_node_no_lock(tree, handle);
     1189        if (fun != NULL)
     1190                fun_add_ref(fun);
     1191       
    10821192        fibril_rwlock_read_unlock(&tree->rwlock);
    10831193       
     
    10871197/** Create and set device's full path in device tree.
    10881198 *
     1199 * @param tree          Device tree
    10891200 * @param node          The device's device node.
    10901201 * @param parent        The parent device node.
     
    10921203 *                      resources etc.).
    10931204 */
    1094 static bool set_fun_path(fun_node_t *fun, fun_node_t *parent)
    1095 {
     1205static bool set_fun_path(dev_tree_t *tree, fun_node_t *fun, fun_node_t *parent)
     1206{
     1207        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
    10961208        assert(fun->name != NULL);
    10971209       
     
    11201232 *
    11211233 * @param tree          The device tree.
    1122  * @param node          The newly added device node.
    1123  * @param dev_name      The name of the newly added device.
    1124  * @param parent        The parent device node.
     1234 * @param dev           The newly added device node.
     1235 * @param pfun          The parent function node.
    11251236 *
    11261237 * @return              True on success, false otherwise (insufficient resources
     
    11291240bool insert_dev_node(dev_tree_t *tree, dev_node_t *dev, fun_node_t *pfun)
    11301241{
    1131         assert(dev != NULL);
    1132         assert(tree != NULL);
    11331242        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
    11341243       
     
    11551264void remove_dev_node(dev_tree_t *tree, dev_node_t *dev)
    11561265{
    1157         assert(tree != NULL);
    1158         assert(dev != NULL);
    11591266        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
    11601267       
     
    11741281 *
    11751282 * @param tree          The device tree.
    1176  * @param node          The newly added function node.
    1177  * @param dev_name      The name of the newly added function.
    1178  * @param parent        Owning device node.
     1283 * @param fun           The newly added function node.
     1284 * @param fun_name      The name of the newly added function.
     1285 * @param dev           Owning device node.
    11791286 *
    11801287 * @return              True on success, false otherwise (insufficient resources
     
    11861293        fun_node_t *pfun;
    11871294       
    1188         assert(fun != NULL);
    1189         assert(tree != NULL);
    11901295        assert(fun_name != NULL);
    11911296        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
     
    11981303       
    11991304        fun->name = fun_name;
    1200         if (!set_fun_path(fun, pfun)) {
     1305        if (!set_fun_path(tree, fun, pfun)) {
    12011306                return false;
    12021307        }
     
    12221327void remove_fun_node(dev_tree_t *tree, fun_node_t *fun)
    12231328{
    1224         assert(tree != NULL);
    1225         assert(fun != NULL);
    12261329        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
    12271330       
     
    12561359       
    12571360        fun_node_t *fun = tree->root_node;
     1361        fun_add_ref(fun);
    12581362        /*
    12591363         * Relative path to the function from its parent (but with '/' at the
     
    12731377                }
    12741378               
    1275                 fun = find_node_child(fun, rel_path + 1);
     1379                fun_node_t *cfun = find_node_child(tree, fun, rel_path + 1);
     1380                fun_del_ref(fun);
     1381                fun = cfun;
    12761382               
    12771383                if (cont) {
     
    12911397 * Device tree rwlock should be held at least for reading.
    12921398 *
     1399 * @param tree Device tree
    12931400 * @param dev Device the function belongs to.
    12941401 * @param name Function name (not path).
     
    12961403 * @retval NULL No function with given name.
    12971404 */
    1298 fun_node_t *find_fun_node_in_device(dev_node_t *dev, const char *name)
    1299 {
    1300         assert(dev != NULL);
     1405fun_node_t *find_fun_node_in_device(dev_tree_t *tree, dev_node_t *dev,
     1406    const char *name)
     1407{
    13011408        assert(name != NULL);
     1409        assert(fibril_rwlock_is_locked(&tree->rwlock));
    13021410
    13031411        fun_node_t *fun;
     
    13061414                fun = list_get_instance(link, fun_node_t, dev_functions);
    13071415
    1308                 if (str_cmp(name, fun->name) == 0)
     1416                if (str_cmp(name, fun->name) == 0) {
     1417                        fun_add_ref(fun);
    13091418                        return fun;
     1419                }
    13101420        }
    13111421
     
    13171427 * Device tree rwlock should be held at least for reading.
    13181428 *
     1429 * @param tree          Device tree
    13191430 * @param parent        The parent function node.
    13201431 * @param name          The name of the child function.
    13211432 * @return              The child function node.
    13221433 */
    1323 fun_node_t *find_node_child(fun_node_t *pfun, const char *name)
    1324 {
    1325         return find_fun_node_in_device(pfun->child, name);
     1434static fun_node_t *find_node_child(dev_tree_t *tree, fun_node_t *pfun,
     1435    const char *name)
     1436{
     1437        return find_fun_node_in_device(tree, pfun->child, name);
    13261438}
    13271439
     
    13361448        fibril_rwlock_read_lock(&tree->rwlock);
    13371449        link = hash_table_find(&tree->loc_functions, &key);
    1338         if (link != NULL)
     1450        if (link != NULL) {
    13391451                fun = hash_table_get_instance(link, fun_node_t, loc_fun);
     1452                fun_add_ref(fun);
     1453        }
    13401454        fibril_rwlock_read_unlock(&tree->rwlock);
    13411455       
     
    13451459void tree_add_loc_function(dev_tree_t *tree, fun_node_t *fun)
    13461460{
     1461        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
     1462       
    13471463        unsigned long key = (unsigned long) fun->service_id;
    1348         fibril_rwlock_write_lock(&tree->rwlock);
    13491464        hash_table_insert(&tree->loc_functions, &key, &fun->loc_fun);
    1350         fibril_rwlock_write_unlock(&tree->rwlock);
    13511465}
    13521466
  • uspace/srv/devman/devman.h

    r5f6e25e r58cbb0c8  
    128128/** Device node in the device tree. */
    129129struct dev_node {
     130        /** Reference count */
     131        atomic_t refcnt;
     132       
    130133        /** The global unique identifier of the device. */
    131134        devman_handle_t handle;
     
    156159/** Function node in the device tree. */
    157160struct fun_node {
     161        /** Reference count */
     162        atomic_t refcnt;
     163       
    158164        /** The global unique identifier of the function */
    159165        devman_handle_t handle;
     
    239245
    240246extern void add_driver(driver_list_t *, driver_t *);
    241 extern void attach_driver(dev_node_t *, driver_t *);
    242 extern void detach_driver(dev_node_t *);
     247extern void attach_driver(dev_tree_t *, dev_node_t *, driver_t *);
     248extern void detach_driver(dev_tree_t *, dev_node_t *);
    243249extern void add_device(driver_t *, dev_node_t *, dev_tree_t *);
    244250extern bool start_driver(driver_t *);
    245 extern int driver_dev_remove(dev_node_t *);
    246 extern int driver_fun_online(fun_node_t *);
    247 extern int driver_fun_offline(fun_node_t *);
     251extern int driver_dev_remove(dev_tree_t *, dev_node_t *);
     252extern int driver_fun_online(dev_tree_t *, fun_node_t *);
     253extern int driver_fun_offline(dev_tree_t *, fun_node_t *);
    248254
    249255extern driver_t *find_driver(driver_list_t *, const char *);
     
    258264extern dev_node_t *create_dev_node(void);
    259265extern void delete_dev_node(dev_node_t *node);
     266extern void dev_add_ref(dev_node_t *);
     267extern void dev_del_ref(dev_node_t *);
    260268extern dev_node_t *find_dev_node_no_lock(dev_tree_t *tree,
    261269    devman_handle_t handle);
     
    267275extern fun_node_t *create_fun_node(void);
    268276extern void delete_fun_node(fun_node_t *);
     277extern void fun_add_ref(fun_node_t *);
     278extern void fun_del_ref(fun_node_t *);
    269279extern fun_node_t *find_fun_node_no_lock(dev_tree_t *tree,
    270280    devman_handle_t handle);
    271281extern fun_node_t *find_fun_node(dev_tree_t *tree, devman_handle_t handle);
    272282extern fun_node_t *find_fun_node_by_path(dev_tree_t *, char *);
    273 extern fun_node_t *find_fun_node_in_device(dev_node_t *, const char *);
     283extern fun_node_t *find_fun_node_in_device(dev_tree_t *tree, dev_node_t *,
     284    const char *);
    274285
    275286/* Device tree */
  • uspace/srv/devman/main.c

    r5f6e25e r58cbb0c8  
    242242       
    243243        fibril_rwlock_write_lock(&device_tree.rwlock);
    244        
     244
    245245        if (fun->ftype == fun_inner) {
    246246                dev = create_dev_node();
    247247                if (dev == NULL) {
    248248                        fibril_rwlock_write_unlock(&device_tree.rwlock);
    249                         delete_fun_node(fun);
    250249                        return ENOMEM;
    251250                }
    252251
    253252                insert_dev_node(&device_tree, dev, fun);
    254         }
    255        
    256         fibril_rwlock_write_unlock(&device_tree.rwlock);
     253                dev_add_ref(dev);
     254        }
    257255       
    258256        log_msg(LVL_DEBUG, "devman_add_function(fun=\"%s\")", fun->pathname);
     
    283281        }
    284282       
     283        fibril_rwlock_write_unlock(&device_tree.rwlock);
     284       
    285285        return EOK;
    286286}
     
    289289{
    290290        int rc;
     291       
     292        fibril_rwlock_write_lock(&device_tree.rwlock);
    291293       
    292294        if (fun->ftype == fun_inner) {
     
    296298                        dev_node_t *dev = fun->child;
    297299                       
    298                         rc = driver_dev_remove(dev);
     300                        dev_add_ref(dev);
     301                        fibril_rwlock_write_unlock(&device_tree.rwlock);
     302                       
     303                        rc = driver_dev_remove(&device_tree, dev);
    299304                        if (rc != EOK) {
     305                                dev_del_ref(dev);
    300306                                return ENOTSUP;
    301307                        }
    302                         detach_driver(dev);
     308                       
     309                        detach_driver(&device_tree, dev);
     310                       
    303311                        fibril_rwlock_write_lock(&device_tree.rwlock);
    304312                        remove_dev_node(&device_tree, dev);
    305                         fibril_rwlock_write_unlock(&device_tree.rwlock);
    306                         delete_dev_node(dev);
     313                       
     314                        /* Delete ref created when node was inserted */
     315                        dev_del_ref(dev);
     316                        /* Delete ref created by dev_add_ref(dev) above */
     317                        dev_del_ref(dev);
    307318                }
    308319        } else {
     
    310321                rc = loc_service_unregister(fun->service_id);
    311322                if (rc != EOK) {
     323                        fibril_rwlock_write_unlock(&device_tree.rwlock);
    312324                        log_msg(LVL_ERROR, "Failed unregistering tree service.");
    313325                        return EIO;
     
    317329        }
    318330       
     331        fibril_rwlock_write_unlock(&device_tree.rwlock);
     332       
    319333        return EOK;
    320334}
     
    331345        dev_tree_t *tree = &device_tree;
    332346       
    333         fibril_rwlock_write_lock(&tree->rwlock);
    334 
    335         dev_node_t *pdev = find_dev_node_no_lock(&device_tree, dev_handle);
    336        
     347        dev_node_t *pdev = find_dev_node(&device_tree, dev_handle);
    337348        if (pdev == NULL) {
    338                 fibril_rwlock_write_unlock(&tree->rwlock);
    339349                async_answer_0(callid, ENOENT);
    340350                return;
     
    347357                    (int) ftype);
    348358
    349                 fibril_rwlock_write_unlock(&tree->rwlock);
     359                dev_del_ref(pdev);
    350360                async_answer_0(callid, EINVAL);
    351361                return;
     
    355365        int rc = async_data_write_accept((void **)&fun_name, true, 0, 0, 0, 0);
    356366        if (rc != EOK) {
     367                dev_del_ref(pdev);
     368                async_answer_0(callid, rc);
     369                return;
     370        }
     371       
     372        fibril_rwlock_write_lock(&tree->rwlock);
     373       
     374        /* Check that function with same name is not there already. */
     375        if (find_fun_node_in_device(tree, pdev, fun_name) != NULL) {
    357376                fibril_rwlock_write_unlock(&tree->rwlock);
    358                 async_answer_0(callid, rc);
    359                 return;
    360         }
    361        
    362         /* Check that function with same name is not there already. */
    363         if (find_fun_node_in_device(pdev, fun_name) != NULL) {
    364                 fibril_rwlock_write_unlock(&tree->rwlock);
     377                dev_del_ref(pdev);
    365378                async_answer_0(callid, EEXISTS);
    366379                printf(NAME ": Warning, driver tried to register `%s' twice.\n",
     
    371384       
    372385        fun_node_t *fun = create_fun_node();
     386        fun_add_ref(fun);
    373387        fun->ftype = ftype;
    374388       
    375389        if (!insert_fun_node(&device_tree, fun, fun_name, pdev)) {
    376390                fibril_rwlock_write_unlock(&tree->rwlock);
     391                dev_del_ref(pdev);
    377392                delete_fun_node(fun);
    378393                async_answer_0(callid, ENOMEM);
     
    381396       
    382397        fibril_rwlock_write_unlock(&tree->rwlock);
     398        dev_del_ref(pdev);
    383399       
    384400        devman_receive_match_ids(match_count, &fun->match_ids);
     
    408424                async_answer_0(callid, rc);
    409425                return;
    410         }       
     426        }
    411427       
    412428        fun_node_t *fun = find_fun_node(&device_tree, handle);
     
    415431                return;
    416432        }
     433       
     434        fibril_rwlock_read_lock(&device_tree.rwlock);
    417435       
    418436        rc = loc_category_get_id(cat_name, &cat_id, IPC_FLAG_BLOCKING);
     
    427445            fun->pathname, cat_name);
    428446
     447        fibril_rwlock_read_unlock(&device_tree.rwlock);
     448        fun_del_ref(fun);
     449
    429450        async_answer_0(callid, EOK);
    430451}
     
    440461
    441462        printf("devman_drv_fun_online()\n");
    442         fibril_rwlock_write_lock(&device_tree.rwlock);
    443         fun = find_fun_node_no_lock(&device_tree, IPC_GET_ARG1(*icall));
    444         fibril_rwlock_write_unlock(&device_tree.rwlock); /* XXX FIXME */
    445        
    446         if (fun == NULL || fun->dev == NULL || fun->dev->drv != drv) {
    447                 async_answer_0(iid, ENOENT);
    448                 return;
    449         }
     463        fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
     464        if (fun == NULL) {
     465                async_answer_0(iid, ENOENT);
     466                return;
     467        }
     468       
     469        fibril_rwlock_read_lock(&device_tree.rwlock);
     470        if (fun->dev == NULL || fun->dev->drv != drv) {
     471                fibril_rwlock_read_unlock(&device_tree.rwlock);
     472                fun_del_ref(fun);
     473                async_answer_0(iid, ENOENT);
     474                return;
     475        }
     476        fibril_rwlock_read_unlock(&device_tree.rwlock);
    450477       
    451478        rc = online_function(fun);
    452479        if (rc != EOK) {
    453480                printf("devman_drv_fun_online() online_fun->ERROR\n");
     481                fun_del_ref(fun);
    454482                async_answer_0(iid, (sysarg_t) rc);
    455483                return;
    456484        }
     485       
     486        fun_del_ref(fun);
    457487        printf("devman_drv_fun_online() online_fun->OK\n");
    458488       
     
    470500        int rc;
    471501
     502        fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
     503        if (fun == NULL) {
     504                async_answer_0(iid, ENOENT);
     505                return;
     506        }
     507       
    472508        fibril_rwlock_write_lock(&device_tree.rwlock);
    473         fun = find_fun_node_no_lock(&device_tree, IPC_GET_ARG1(*icall));
    474         fibril_rwlock_write_unlock(&device_tree.rwlock); /* XXX FIXME */
    475        
    476         if (fun == NULL || fun->dev == NULL || fun->dev->drv != drv) {
    477                 async_answer_0(iid, ENOENT);
    478                 return;
    479         }
     509        if (fun->dev == NULL || fun->dev->drv != drv) {
     510                fun_del_ref(fun);
     511                async_answer_0(iid, ENOENT);
     512                return;
     513        }
     514        fibril_rwlock_write_unlock(&device_tree.rwlock);
    480515       
    481516        rc = offline_function(fun);
    482517        if (rc != EOK) {
     518                fun_del_ref(fun);
    483519                async_answer_0(iid, (sysarg_t) rc);
    484520                return;
    485521        }
    486522       
     523        fun_del_ref(fun);
    487524        async_answer_0(iid, (sysarg_t) EOK);
    488525}
     
    495532        int rc;
    496533       
     534       
     535        fun_node_t *fun = find_fun_node(&device_tree, fun_handle);
     536        if (fun == NULL) {
     537                async_answer_0(callid, ENOENT);
     538                return;
     539        }
     540       
    497541        fibril_rwlock_write_lock(&tree->rwlock);
    498        
    499         fun_node_t *fun = find_fun_node_no_lock(&device_tree, fun_handle);
    500         if (fun == NULL) {
    501                 fibril_rwlock_write_unlock(&tree->rwlock);
    502                 async_answer_0(callid, ENOENT);
    503                 return;
    504         }
    505542       
    506543        log_msg(LVL_DEBUG, "devman_remove_function(fun='%s')", fun->pathname);
     
    508545        if (fun->ftype == fun_inner) {
    509546                /* Handle possible descendants */
    510                 /* TODO */
     547                /* TODO - This is a surprise removal */
    511548                if (fun->child != NULL) {
    512549                        log_msg(LVL_WARN, "devman_remove_function(): not handling "
     
    521558                                    "service.");
    522559                                fibril_rwlock_write_unlock(&tree->rwlock);
     560                                fun_del_ref(fun);
    523561                                async_answer_0(callid, EIO);
    524562                                return;
     
    529567        remove_fun_node(&device_tree, fun);
    530568        fibril_rwlock_write_unlock(&tree->rwlock);
    531         delete_fun_node(fun);
     569       
     570        /* Delete ref added when inserting function into tree */
     571        fun_del_ref(fun);
     572        /* Delete ref added above when looking up function */
     573        fun_del_ref(fun);
    532574       
    533575        log_msg(LVL_DEBUG, "devman_remove_function() succeeded.");
     
    621663{
    622664        char *pathname;
     665        devman_handle_t handle;
    623666       
    624667        int rc = async_data_write_accept((void **) &pathname, true, 0, 0, 0, 0);
     
    637680        }
    638681
    639         async_answer_1(iid, EOK, fun->handle);
     682        fibril_rwlock_read_lock(&device_tree.rwlock);
     683        handle = fun->handle;
     684        fibril_rwlock_read_unlock(&device_tree.rwlock);
     685
     686        /* Delete reference created above by find_fun_node_by_path() */
     687        fun_del_ref(fun);
     688
     689        async_answer_1(iid, EOK, handle);
    640690}
    641691
     
    655705        if (!async_data_read_receive(&data_callid, &data_len)) {
    656706                async_answer_0(iid, EINVAL);
     707                fun_del_ref(fun);
    657708                return;
    658709        }
     
    662713                async_answer_0(data_callid, ENOMEM);
    663714                async_answer_0(iid, ENOMEM);
    664                 return;
    665         }
     715                fun_del_ref(fun);
     716                return;
     717        }
     718
     719        fibril_rwlock_read_lock(&device_tree.rwlock);
    666720
    667721        size_t sent_length = str_size(fun->name);
     
    673727        async_answer_0(iid, EOK);
    674728
     729        fibril_rwlock_read_unlock(&device_tree.rwlock);
     730        fun_del_ref(fun);
    675731        free(buffer);
    676732}
     
    692748        if (!async_data_read_receive(&data_callid, &data_len)) {
    693749                async_answer_0(iid, EINVAL);
     750                fun_del_ref(fun);
    694751                return;
    695752        }
     
    699756                async_answer_0(data_callid, ENOMEM);
    700757                async_answer_0(iid, ENOMEM);
    701                 return;
    702         }
    703 
     758                fun_del_ref(fun);
     759                return;
     760        }
     761       
     762        fibril_rwlock_read_lock(&device_tree.rwlock);
     763       
    704764        size_t sent_length = str_size(fun->pathname);
    705765        if (sent_length > data_len) {
     
    710770        async_answer_0(iid, EOK);
    711771
     772        fibril_rwlock_read_unlock(&device_tree.rwlock);
     773        fun_del_ref(fun);
    712774        free(buffer);
    713775}
     
    777839       
    778840        if (fun->child == NULL) {
     841                fun_del_ref(fun);
    779842                fibril_rwlock_read_unlock(&device_tree.rwlock);
    780843                async_answer_0(iid, ENOENT);
     
    784847        async_answer_1(iid, EOK, fun->child->handle);
    785848       
     849        fun_del_ref(fun);
    786850        fibril_rwlock_read_unlock(&device_tree.rwlock);
    787851}
     
    798862        int rc;
    799863
    800         fibril_rwlock_write_lock(&device_tree.rwlock);
    801         fun = find_fun_node_no_lock(&device_tree, IPC_GET_ARG1(*icall));
    802         fibril_rwlock_write_unlock(&device_tree.rwlock); /* XXX FIXME */
    803        
     864        fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
    804865        if (fun == NULL) {
    805866                async_answer_0(iid, ENOENT);
     
    807868        }
    808869       
    809         rc = driver_fun_online(fun);
     870        rc = driver_fun_online(&device_tree, fun);
     871        fun_del_ref(fun);
    810872       
    811873        async_answer_0(iid, (sysarg_t) rc);
     
    825887        int rc;
    826888
    827         fibril_rwlock_write_lock(&device_tree.rwlock);
    828         fun = find_fun_node_no_lock(&device_tree, IPC_GET_ARG1(*icall));
    829         fibril_rwlock_write_unlock(&device_tree.rwlock); /* XXX FIXME */
    830        
     889        fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
    831890        if (fun == NULL) {
    832891                async_answer_0(iid, ENOENT);
     
    834893        }
    835894       
    836         rc = driver_fun_offline(fun);
     895        rc = driver_fun_offline(&device_tree, fun);
     896        fun_del_ref(fun);
    837897       
    838898        async_answer_0(iid, (sysarg_t) rc);
     
    851911        }
    852912
     913        fibril_rwlock_read_lock(&device_tree.rwlock);
    853914        async_answer_1(iid, EOK, fun->handle);
     915        fibril_rwlock_read_unlock(&device_tree.rwlock);
     916        fun_del_ref(fun);
    854917}
    855918
     
    909972        if (fun == NULL)
    910973                dev = find_dev_node(&device_tree, handle);
    911         else
     974        else {
     975                fibril_rwlock_read_lock(&device_tree.rwlock);
    912976                dev = fun->dev;
     977                if (dev != NULL)
     978                        dev_add_ref(dev);
     979                fibril_rwlock_read_unlock(&device_tree.rwlock);
     980        }
    913981
    914982        /*
     
    922990                    "function with handle %" PRIun " was found.", handle);
    923991                async_answer_0(iid, ENOENT);
    924                 return;
     992                goto cleanup;
    925993        }
    926994
     
    930998                    handle);
    931999                async_answer_0(iid, ENOENT);
    932                 return;
     1000                goto cleanup;
    9331001        }
    9341002       
     
    9521020                    "the device %" PRIun " is not in usable state.", handle);
    9531021                async_answer_0(iid, ENOENT);
    954                 return;
     1022                goto cleanup;
    9551023        }
    9561024       
     
    9651033                    "Could not forward to driver `%s'.", driver->name);
    9661034                async_answer_0(iid, EINVAL);
    967                 return;
     1035                goto cleanup;
    9681036        }
    9691037
     
    9811049        async_forward_fast(iid, exch, method, fwd_h, 0, IPC_FF_NONE);
    9821050        async_exchange_end(exch);
     1051
     1052cleanup:
     1053        if (dev != NULL)
     1054                dev_del_ref(dev);
     1055        if (fun != NULL)
     1056                fun_del_ref(fun);
    9831057}
    9841058
     
    10001074        }
    10011075       
     1076        fibril_rwlock_read_lock(&device_tree.rwlock);
    10021077        dev = fun->dev;
     1078        fun_del_ref(fun);
    10031079       
    10041080        async_exch_t *exch = async_exchange_begin(dev->drv->sess);
     
    10061082            IPC_FF_NONE);
    10071083        async_exchange_end(exch);
     1084       
     1085        fibril_rwlock_read_unlock(&device_tree.rwlock);
    10081086       
    10091087        log_msg(LVL_DEBUG,
Note: See TracChangeset for help on using the changeset viewer.