source: mainline/uspace/srv/devmap/devmap.c@ f9c03b5

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since f9c03b5 was 4ae90f9, checked in by Vojtech Horky <vojtechhorky@…>, 14 years ago

devmap: dereference of uninitialized pointer fix

  • Property mode set to 100644
File size: 27.1 KB
RevLine 
[13125d3]1/*
2 * Copyright (c) 2007 Josef Cejka
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/**
30 * @defgroup devmap Device mapper.
[6519d6f]31 * @brief HelenOS device mapper.
[13125d3]32 * @{
[6519d6f]33 */
[13125d3]34
35/** @file
36 */
37
38#include <ipc/services.h>
39#include <ipc/ns.h>
40#include <async.h>
41#include <stdio.h>
42#include <errno.h>
[07e4a3c]43#include <bool.h>
[1e4cada]44#include <fibril_synch.h>
[798f364]45#include <stdlib.h>
[19f857a]46#include <str.h>
[21c5d41]47#include <ipc/devmap.h>
[01b87dc5]48#include <assert.h>
[13125d3]49
[7fcb74c]50#define NAME "devmap"
51#define NULL_DEVICES 256
[13125d3]52
[cb41a5e]53/** Representation of device driver.
54 *
55 * Each driver is responsible for a set of devices.
56 *
57 */
58typedef struct {
59 /** Pointers to previous and next drivers in linked list */
60 link_t drivers;
61 /** Pointer to the linked list of devices controlled by this driver */
62 link_t devices;
63 /** Phone asociated with this driver */
[96b02eb9]64 sysarg_t phone;
[cb41a5e]65 /** Device driver name */
66 char *name;
[fc02cc41]67 /** Fibril mutex for list of devices owned by this driver */
68 fibril_mutex_t devices_mutex;
[cb41a5e]69} devmap_driver_t;
70
[1313ee9]71/** Info about registered namespaces
72 *
73 */
74typedef struct {
75 /** Pointer to the previous and next device in the list of all namespaces */
76 link_t namespaces;
77 /** Unique namespace identifier */
[991f645]78 devmap_handle_t handle;
[1313ee9]79 /** Namespace name */
80 char *name;
81 /** Reference count */
82 size_t refcnt;
83} devmap_namespace_t;
84
[cb41a5e]85/** Info about registered device
86 *
87 */
88typedef struct {
89 /** Pointer to the previous and next device in the list of all devices */
90 link_t devices;
91 /** Pointer to the previous and next device in the list of devices
92 owned by one driver */
93 link_t driver_devices;
[1313ee9]94 /** Unique device identifier */
[991f645]95 devmap_handle_t handle;
[1313ee9]96 /** Device namespace */
97 devmap_namespace_t *namespace;
[cb41a5e]98 /** Device name */
99 char *name;
100 /** Device driver handling this device */
101 devmap_driver_t *driver;
[47a7174f]102 /** Use this interface when forwarding to driver. */
103 sysarg_t forward_interface;
[cb41a5e]104} devmap_device_t;
105
[798f364]106LIST_INITIALIZE(devices_list);
[1313ee9]107LIST_INITIALIZE(namespaces_list);
[798f364]108LIST_INITIALIZE(drivers_list);
[c07af37]109
[fc02cc41]110/* Locking order:
111 * drivers_list_mutex
112 * devices_list_mutex
113 * (devmap_driver_t *)->devices_mutex
114 * create_handle_mutex
115 **/
116
117static FIBRIL_MUTEX_INITIALIZE(devices_list_mutex);
[1cab2f41]118static FIBRIL_CONDVAR_INITIALIZE(devices_list_cv);
[fc02cc41]119static FIBRIL_MUTEX_INITIALIZE(drivers_list_mutex);
120static FIBRIL_MUTEX_INITIALIZE(create_handle_mutex);
[7fcb74c]121static FIBRIL_MUTEX_INITIALIZE(null_devices_mutex);
[fc02cc41]122
[991f645]123static devmap_handle_t last_handle = 0;
[7fcb74c]124static devmap_device_t *null_devices[NULL_DEVICES];
[cb41a5e]125
[63e0bdd]126/*
127 * Dummy list for null devices. This is necessary so that null devices can
128 * be used just as any other devices, e.g. in devmap_device_unregister_core().
129 */
130static LIST_INITIALIZE(dummy_null_driver_devices);
131
[991f645]132static devmap_handle_t devmap_create_handle(void)
[798f364]133{
134 /* TODO: allow reusing old handles after their unregistration
[5d0e461]135 * and implement some version of LRU algorithm, avoid overflow
[6519d6f]136 */
137
[fc02cc41]138 fibril_mutex_lock(&create_handle_mutex);
[cb41a5e]139 last_handle++;
[fc02cc41]140 fibril_mutex_unlock(&create_handle_mutex);
[6519d6f]141
[cb41a5e]142 return last_handle;
[13125d3]143}
144
[1313ee9]145/** Convert fully qualified device name to namespace and device name.
146 *
147 * A fully qualified device name can be either a plain device name
148 * (then the namespace is considered to be an empty string) or consist
149 * of two components separated by a slash. No more than one slash
150 * is allowed.
151 *
152 */
153static bool devmap_fqdn_split(const char *fqdn, char **ns_name, char **name)
154{
155 size_t cnt = 0;
156 size_t slash_offset = 0;
157 size_t slash_after = 0;
158
159 size_t offset = 0;
160 size_t offset_prev = 0;
161 wchar_t c;
162
163 while ((c = str_decode(fqdn, &offset, STR_NO_LIMIT)) != 0) {
164 if (c == '/') {
165 cnt++;
166 slash_offset = offset_prev;
167 slash_after = offset;
168 }
169 offset_prev = offset;
170 }
171
172 /* More than one slash */
173 if (cnt > 1)
174 return false;
175
176 /* No slash -> namespace is empty */
177 if (cnt == 0) {
178 *ns_name = str_dup("");
179 if (*ns_name == NULL)
180 return false;
181
182 *name = str_dup(fqdn);
[ab108be4]183 if (*name == NULL) {
184 free(*ns_name);
185 return false;
186 }
187
188 if (str_cmp(*name, "") == 0) {
189 free(*name);
[1313ee9]190 free(*ns_name);
191 return false;
192 }
193
194 return true;
195 }
196
197 /* Exactly one slash */
198 *ns_name = str_ndup(fqdn, slash_offset);
199 if (*ns_name == NULL)
200 return false;
201
202 *name = str_dup(fqdn + slash_after);
[ab108be4]203 if (*name == NULL) {
204 free(*ns_name);
205 return false;
206 }
207
208 if (str_cmp(*name, "") == 0) {
209 free(*name);
[1313ee9]210 free(*ns_name);
211 return false;
212 }
213
214 return true;
215}
216
[01b87dc5]217/** Find namespace with given name. */
[1313ee9]218static devmap_namespace_t *devmap_namespace_find_name(const char *name)
219{
[ab108be4]220 link_t *item;
[01b87dc5]221
222 assert(fibril_mutex_is_locked(&devices_list_mutex));
223
[ab108be4]224 for (item = namespaces_list.next; item != &namespaces_list; item = item->next) {
225 devmap_namespace_t *namespace =
226 list_get_instance(item, devmap_namespace_t, namespaces);
[1313ee9]227 if (str_cmp(namespace->name, name) == 0)
228 return namespace;
229 }
230
231 return NULL;
232}
233
234/** Find namespace with given handle.
235 *
236 * @todo: use hash table
237 *
238 */
[991f645]239static devmap_namespace_t *devmap_namespace_find_handle(devmap_handle_t handle)
[1313ee9]240{
[ab108be4]241 link_t *item;
[01b87dc5]242
243 assert(fibril_mutex_is_locked(&devices_list_mutex));
244
[ab108be4]245 for (item = namespaces_list.next; item != &namespaces_list; item = item->next) {
246 devmap_namespace_t *namespace =
247 list_get_instance(item, devmap_namespace_t, namespaces);
[1313ee9]248 if (namespace->handle == handle)
249 return namespace;
250 }
251
252 return NULL;
253}
254
[01b87dc5]255/** Find device with given name. */
[1313ee9]256static devmap_device_t *devmap_device_find_name(const char *ns_name,
257 const char *name)
[07e4a3c]258{
[ab108be4]259 link_t *item;
[01b87dc5]260
261 assert(fibril_mutex_is_locked(&devices_list_mutex));
262
[ab108be4]263 for (item = devices_list.next; item != &devices_list; item = item->next) {
264 devmap_device_t *device =
265 list_get_instance(item, devmap_device_t, devices);
266 if ((str_cmp(device->namespace->name, ns_name) == 0)
267 && (str_cmp(device->name, name) == 0))
[1313ee9]268 return device;
[798f364]269 }
[6519d6f]270
[1313ee9]271 return NULL;
[798f364]272}
273
274/** Find device with given handle.
[6519d6f]275 *
[798f364]276 * @todo: use hash table
[6519d6f]277 *
[798f364]278 */
[991f645]279static devmap_device_t *devmap_device_find_handle(devmap_handle_t handle)
[798f364]280{
[ab108be4]281 link_t *item;
[01b87dc5]282
283 assert(fibril_mutex_is_locked(&devices_list_mutex));
284
[ab108be4]285 for (item = devices_list.next; item != &devices_list; item = item->next) {
286 devmap_device_t *device =
287 list_get_instance(item, devmap_device_t, devices);
[6519d6f]288 if (device->handle == handle)
[1313ee9]289 return device;
[798f364]290 }
[6519d6f]291
[1313ee9]292 return NULL;
293}
294
[01b87dc5]295/** Create a namespace (if not already present). */
[1313ee9]296static devmap_namespace_t *devmap_namespace_create(const char *ns_name)
297{
[01b87dc5]298 devmap_namespace_t *namespace;
299
300 assert(fibril_mutex_is_locked(&devices_list_mutex));
301
302 namespace = devmap_namespace_find_name(ns_name);
[1313ee9]303 if (namespace != NULL)
304 return namespace;
305
306 namespace = (devmap_namespace_t *) malloc(sizeof(devmap_namespace_t));
307 if (namespace == NULL)
308 return NULL;
309
310 namespace->name = str_dup(ns_name);
311 if (namespace->name == NULL) {
312 free(namespace);
[798f364]313 return NULL;
[fc02cc41]314 }
[6519d6f]315
[1313ee9]316 namespace->handle = devmap_create_handle();
317 namespace->refcnt = 0;
[798f364]318
[1313ee9]319 /*
320 * Insert new namespace into list of registered namespaces
321 */
322 list_append(&(namespace->namespaces), &namespaces_list);
[fc02cc41]323
[1313ee9]324 return namespace;
[798f364]325}
326
[01b87dc5]327/** Destroy a namespace (if it is no longer needed). */
[1313ee9]328static void devmap_namespace_destroy(devmap_namespace_t *namespace)
329{
[01b87dc5]330 assert(fibril_mutex_is_locked(&devices_list_mutex));
331
[1313ee9]332 if (namespace->refcnt == 0) {
333 list_remove(&(namespace->namespaces));
334
335 free(namespace->name);
336 free(namespace);
337 }
338}
339
[01b87dc5]340/** Increase namespace reference count by including device. */
[1313ee9]341static void devmap_namespace_addref(devmap_namespace_t *namespace,
342 devmap_device_t *device)
343{
[01b87dc5]344 assert(fibril_mutex_is_locked(&devices_list_mutex));
345
[1313ee9]346 device->namespace = namespace;
347 namespace->refcnt++;
348}
349
[01b87dc5]350/** Decrease namespace reference count. */
[1313ee9]351static void devmap_namespace_delref(devmap_namespace_t *namespace)
352{
[01b87dc5]353 assert(fibril_mutex_is_locked(&devices_list_mutex));
354
[1313ee9]355 namespace->refcnt--;
356 devmap_namespace_destroy(namespace);
357}
358
[01b87dc5]359/** Unregister device and free it. */
[1313ee9]360static void devmap_device_unregister_core(devmap_device_t *device)
[798f364]361{
[01b87dc5]362 assert(fibril_mutex_is_locked(&devices_list_mutex));
363
[1313ee9]364 devmap_namespace_delref(device->namespace);
[798f364]365 list_remove(&(device->devices));
366 list_remove(&(device->driver_devices));
[6519d6f]367
368 free(device->name);
[798f364]369 free(device);
370}
371
[7f3e3e7]372/**
373 * Read info about new driver and add it into linked list of registered
374 * drivers.
[798f364]375 */
[1313ee9]376static devmap_driver_t *devmap_driver_register(void)
[798f364]377{
[6519d6f]378 ipc_call_t icall;
379 ipc_callid_t iid = async_get_call(&icall);
380
[228e490]381 if (IPC_GET_IMETHOD(icall) != DEVMAP_DRIVER_REGISTER) {
[ffa2c8ef]382 async_answer_0(iid, EREFUSED);
[1313ee9]383 return NULL;
[6519d6f]384 }
385
[ab108be4]386 devmap_driver_t *driver =
387 (devmap_driver_t *) malloc(sizeof(devmap_driver_t));
[6519d6f]388 if (driver == NULL) {
[ffa2c8ef]389 async_answer_0(iid, ENOMEM);
[1313ee9]390 return NULL;
[07e4a3c]391 }
[6519d6f]392
393 /*
[798f364]394 * Get driver name
395 */
[4cac2d69]396 int rc = async_data_write_accept((void **) &driver->name, true, 0,
[eda925a]397 DEVMAP_NAME_MAXLEN, 0, NULL);
[1313ee9]398 if (rc != EOK) {
[798f364]399 free(driver);
[ffa2c8ef]400 async_answer_0(iid, rc);
[1313ee9]401 return NULL;
[798f364]402 }
[6519d6f]403
404 /*
[5d0e461]405 * Create connection to the driver
[798f364]406 */
[6519d6f]407 ipc_call_t call;
[1313ee9]408 ipc_callid_t callid = async_get_call(&call);
[6519d6f]409
[228e490]410 if (IPC_GET_IMETHOD(call) != IPC_M_CONNECT_TO_ME) {
[798f364]411 free(driver->name);
412 free(driver);
[ffa2c8ef]413 async_answer_0(callid, ENOTSUP);
414 async_answer_0(iid, ENOTSUP);
[1313ee9]415 return NULL;
[798f364]416 }
[6519d6f]417
[38c706cc]418 driver->phone = IPC_GET_ARG5(call);
[ffa2c8ef]419 async_answer_0(callid, EOK);
[798f364]420
[ab108be4]421 /*
422 * Initialize mutex for list of devices
423 * owned by this driver
424 */
425 fibril_mutex_initialize(&driver->devices_mutex);
426
427 /*
428 * Initialize list of asociated devices
429 */
430 list_initialize(&driver->devices);
[ca2a18e]431
432 link_initialize(&driver->drivers);
[6519d6f]433
[fc02cc41]434 fibril_mutex_lock(&drivers_list_mutex);
435
[7f3e3e7]436 /* TODO:
[ab108be4]437 * Check that no driver with name equal to
438 * driver->name is registered
[7f3e3e7]439 */
[6519d6f]440
441 /*
[798f364]442 * Insert new driver into list of registered drivers
443 */
444 list_append(&(driver->drivers), &drivers_list);
[fc02cc41]445 fibril_mutex_unlock(&drivers_list_mutex);
[798f364]446
[ffa2c8ef]447 async_answer_0(iid, EOK);
[6519d6f]448
[1313ee9]449 return driver;
[07e4a3c]450}
451
[6519d6f]452/**
453 * Unregister device driver, unregister all its devices and free driver
[b74959bd]454 * structure.
[6519d6f]455 *
[798f364]456 */
457static int devmap_driver_unregister(devmap_driver_t *driver)
[07e4a3c]458{
[6519d6f]459 if (driver == NULL)
[798f364]460 return EEXISTS;
[21c5d41]461
[fc02cc41]462 fibril_mutex_lock(&drivers_list_mutex);
463
[cb41a5e]464 if (driver->phone != 0)
[ffa2c8ef]465 async_hangup(driver->phone);
[798f364]466
[cb41a5e]467 /* Remove it from list of drivers */
[798f364]468 list_remove(&(driver->drivers));
[6519d6f]469
[fc02cc41]470 /* Unregister all its devices */
471 fibril_mutex_lock(&devices_list_mutex);
472 fibril_mutex_lock(&driver->devices_mutex);
473
[798f364]474 while (!list_empty(&(driver->devices))) {
[6519d6f]475 devmap_device_t *device = list_get_instance(driver->devices.next,
[7f3e3e7]476 devmap_device_t, driver_devices);
[798f364]477 devmap_device_unregister_core(device);
478 }
479
[fc02cc41]480 fibril_mutex_unlock(&driver->devices_mutex);
481 fibril_mutex_unlock(&devices_list_mutex);
482 fibril_mutex_unlock(&drivers_list_mutex);
483
[ab108be4]484 /* Free name and driver */
[cb41a5e]485 if (driver->name != NULL)
[798f364]486 free(driver->name);
[6519d6f]487
[798f364]488 free(driver);
[6519d6f]489
[07e4a3c]490 return EOK;
491}
492
[798f364]493/** Register instance of device
494 *
495 */
496static void devmap_device_register(ipc_callid_t iid, ipc_call_t *icall,
[b74959bd]497 devmap_driver_t *driver)
[07e4a3c]498{
[6519d6f]499 if (driver == NULL) {
[ffa2c8ef]500 async_answer_0(iid, EREFUSED);
[798f364]501 return;
502 }
503
504 /* Create new device entry */
[ab108be4]505 devmap_device_t *device =
506 (devmap_device_t *) malloc(sizeof(devmap_device_t));
[6519d6f]507 if (device == NULL) {
[ffa2c8ef]508 async_answer_0(iid, ENOMEM);
[798f364]509 return;
510 }
511
[47a7174f]512 /* Set the interface, if any. */
513 device->forward_interface = IPC_GET_ARG1(*icall);
514
[1313ee9]515 /* Get fqdn */
516 char *fqdn;
[4cac2d69]517 int rc = async_data_write_accept((void **) &fqdn, true, 0,
[eda925a]518 DEVMAP_NAME_MAXLEN, 0, NULL);
[1313ee9]519 if (rc != EOK) {
[798f364]520 free(device);
[ffa2c8ef]521 async_answer_0(iid, rc);
[798f364]522 return;
523 }
[6519d6f]524
[1313ee9]525 char *ns_name;
526 if (!devmap_fqdn_split(fqdn, &ns_name, &device->name)) {
527 free(fqdn);
[798f364]528 free(device);
[ffa2c8ef]529 async_answer_0(iid, EINVAL);
[798f364]530 return;
531 }
[21c5d41]532
[1313ee9]533 free(fqdn);
534
535 fibril_mutex_lock(&devices_list_mutex);
[6519d6f]536
[1313ee9]537 devmap_namespace_t *namespace = devmap_namespace_create(ns_name);
538 free(ns_name);
[ab108be4]539 if (namespace == NULL) {
[1313ee9]540 fibril_mutex_unlock(&devices_list_mutex);
[ab108be4]541 free(device->name);
[798f364]542 free(device);
[ffa2c8ef]543 async_answer_0(iid, ENOMEM);
[798f364]544 return;
[07e4a3c]545 }
[798f364]546
[ca2a18e]547 link_initialize(&device->devices);
548 link_initialize(&device->driver_devices);
[6519d6f]549
[1313ee9]550 /* Check that device is not already registered */
551 if (devmap_device_find_name(namespace->name, device->name) != NULL) {
[ab108be4]552 printf("%s: Device '%s/%s' already registered\n", NAME,
[4ae90f9]553 namespace->name, device->name);
[1313ee9]554 devmap_namespace_destroy(namespace);
[fc02cc41]555 fibril_mutex_unlock(&devices_list_mutex);
[798f364]556 free(device->name);
557 free(device);
[ffa2c8ef]558 async_answer_0(iid, EEXISTS);
[798f364]559 return;
[07e4a3c]560 }
[6519d6f]561
[798f364]562 /* Get unique device handle */
[6519d6f]563 device->handle = devmap_create_handle();
[47a7174f]564
[1313ee9]565 devmap_namespace_addref(namespace, device);
[798f364]566 device->driver = driver;
[07e4a3c]567
[798f364]568 /* Insert device into list of all devices */
[b74959bd]569 list_append(&device->devices, &devices_list);
[6519d6f]570
[fc02cc41]571 /* Insert device into list of devices that belog to one driver */
572 fibril_mutex_lock(&device->driver->devices_mutex);
573
[b74959bd]574 list_append(&device->driver_devices, &device->driver->devices);
[798f364]575
[fc02cc41]576 fibril_mutex_unlock(&device->driver->devices_mutex);
[1cab2f41]577 fibril_condvar_broadcast(&devices_list_cv);
[fc02cc41]578 fibril_mutex_unlock(&devices_list_mutex);
579
[ffa2c8ef]580 async_answer_1(iid, EOK, device->handle);
[07e4a3c]581}
582
[798f364]583/**
584 *
585 */
586static int devmap_device_unregister(ipc_callid_t iid, ipc_call_t *icall,
[b74959bd]587 devmap_driver_t *driver)
[07e4a3c]588{
[798f364]589 /* TODO */
[07e4a3c]590 return EOK;
591}
[13125d3]592
[798f364]593/** Connect client to the device.
[6519d6f]594 *
[798f364]595 * Find device driver owning requested device and forward
596 * the message to it.
[6519d6f]597 *
[798f364]598 */
599static void devmap_forward(ipc_callid_t callid, ipc_call_t *call)
600{
[1313ee9]601 fibril_mutex_lock(&devices_list_mutex);
602
[798f364]603 /*
604 * Get handle from request
605 */
[991f645]606 devmap_handle_t handle = IPC_GET_ARG2(*call);
[6519d6f]607 devmap_device_t *dev = devmap_device_find_handle(handle);
608
[cb41a5e]609 if ((dev == NULL) || (dev->driver == NULL) || (dev->driver->phone == 0)) {
[ab108be4]610 fibril_mutex_unlock(&devices_list_mutex);
[ffa2c8ef]611 async_answer_0(callid, ENOENT);
[798f364]612 return;
[6519d6f]613 }
614
[47a7174f]615 if (dev->forward_interface == 0) {
[ffa2c8ef]616 async_forward_fast(callid, dev->driver->phone,
[47a7174f]617 dev->handle, 0, 0,
618 IPC_FF_NONE);
619 } else {
[ffa2c8ef]620 async_forward_fast(callid, dev->driver->phone,
[47a7174f]621 dev->forward_interface, dev->handle, 0,
622 IPC_FF_NONE);
623 }
[1313ee9]624
625 fibril_mutex_unlock(&devices_list_mutex);
[798f364]626}
627
628/** Find handle for device instance identified by name.
[6519d6f]629 *
[798f364]630 * In answer will be send EOK and device handle in arg1 or a error
[6519d6f]631 * code from errno.h.
632 *
[798f364]633 */
[1313ee9]634static void devmap_device_get_handle(ipc_callid_t iid, ipc_call_t *icall)
[798f364]635{
[1313ee9]636 char *fqdn;
[6519d6f]637
[1313ee9]638 /* Get fqdn */
[4cac2d69]639 int rc = async_data_write_accept((void **) &fqdn, true, 0,
[eda925a]640 DEVMAP_NAME_MAXLEN, 0, NULL);
[1313ee9]641 if (rc != EOK) {
[ffa2c8ef]642 async_answer_0(iid, rc);
[798f364]643 return;
644 }
[6519d6f]645
[1313ee9]646 char *ns_name;
647 char *name;
648 if (!devmap_fqdn_split(fqdn, &ns_name, &name)) {
649 free(fqdn);
[ffa2c8ef]650 async_answer_0(iid, EINVAL);
[798f364]651 return;
[6519d6f]652 }
653
[1313ee9]654 free(fqdn);
[6519d6f]655
[c07af37]656 fibril_mutex_lock(&devices_list_mutex);
[1cab2f41]657 const devmap_device_t *dev;
[1313ee9]658
[1cab2f41]659recheck:
[1313ee9]660
[798f364]661 /*
[1cab2f41]662 * Find device name in the list of known devices.
[798f364]663 */
[1313ee9]664 dev = devmap_device_find_name(ns_name, name);
[6519d6f]665
[798f364]666 /*
667 * Device was not found.
668 */
[6519d6f]669 if (dev == NULL) {
670 if (IPC_GET_ARG1(*icall) & IPC_FLAG_BLOCKING) {
[1cab2f41]671 /* Blocking lookup */
672 fibril_condvar_wait(&devices_list_cv,
673 &devices_list_mutex);
674 goto recheck;
[6519d6f]675 }
676
[ffa2c8ef]677 async_answer_0(iid, ENOENT);
[1313ee9]678 free(ns_name);
[6519d6f]679 free(name);
[c07af37]680 fibril_mutex_unlock(&devices_list_mutex);
[798f364]681 return;
682 }
[6519d6f]683
[ffa2c8ef]684 async_answer_1(iid, EOK, dev->handle);
[ab108be4]685
686 fibril_mutex_unlock(&devices_list_mutex);
[1313ee9]687 free(ns_name);
[6519d6f]688 free(name);
[798f364]689}
690
[1313ee9]691/** Find handle for namespace identified by name.
692 *
693 * In answer will be send EOK and device handle in arg1 or a error
694 * code from errno.h.
[798f364]695 *
696 */
[1313ee9]697static void devmap_namespace_get_handle(ipc_callid_t iid, ipc_call_t *icall)
[798f364]698{
[1313ee9]699 char *name;
700
701 /* Get device name */
[4cac2d69]702 int rc = async_data_write_accept((void **) &name, true, 0,
[eda925a]703 DEVMAP_NAME_MAXLEN, 0, NULL);
[1313ee9]704 if (rc != EOK) {
[ffa2c8ef]705 async_answer_0(iid, rc);
[1313ee9]706 return;
707 }
708
709 fibril_mutex_lock(&devices_list_mutex);
710 const devmap_namespace_t *namespace;
711
712recheck:
[6519d6f]713
[798f364]714 /*
[1313ee9]715 * Find namespace name in the list of known namespaces.
[798f364]716 */
[1313ee9]717 namespace = devmap_namespace_find_name(name);
718
719 /*
720 * Namespace was not found.
721 */
722 if (namespace == NULL) {
723 if (IPC_GET_ARG1(*icall) & IPC_FLAG_BLOCKING) {
724 /* Blocking lookup */
725 fibril_condvar_wait(&devices_list_cv,
726 &devices_list_mutex);
727 goto recheck;
728 }
729
[ffa2c8ef]730 async_answer_0(iid, ENOENT);
[1313ee9]731 free(name);
732 fibril_mutex_unlock(&devices_list_mutex);
[798f364]733 return;
734 }
[6519d6f]735
[ffa2c8ef]736 async_answer_1(iid, EOK, namespace->handle);
[ab108be4]737
738 fibril_mutex_unlock(&devices_list_mutex);
[1313ee9]739 free(name);
740}
741
742static void devmap_handle_probe(ipc_callid_t iid, ipc_call_t *icall)
743{
744 fibril_mutex_lock(&devices_list_mutex);
[6519d6f]745
[ab108be4]746 devmap_namespace_t *namespace =
747 devmap_namespace_find_handle(IPC_GET_ARG1(*icall));
[1313ee9]748 if (namespace == NULL) {
[ab108be4]749 devmap_device_t *dev =
750 devmap_device_find_handle(IPC_GET_ARG1(*icall));
[1313ee9]751 if (dev == NULL)
[ffa2c8ef]752 async_answer_1(iid, EOK, DEV_HANDLE_NONE);
[1313ee9]753 else
[ffa2c8ef]754 async_answer_1(iid, EOK, DEV_HANDLE_DEVICE);
[1313ee9]755 } else
[ffa2c8ef]756 async_answer_1(iid, EOK, DEV_HANDLE_NAMESPACE);
[6519d6f]757
[1313ee9]758 fibril_mutex_unlock(&devices_list_mutex);
[798f364]759}
760
[1313ee9]761static void devmap_get_namespace_count(ipc_callid_t iid, ipc_call_t *icall)
[cb41a5e]762{
[fc02cc41]763 fibril_mutex_lock(&devices_list_mutex);
[ffa2c8ef]764 async_answer_1(iid, EOK, list_count(&namespaces_list));
[fc02cc41]765 fibril_mutex_unlock(&devices_list_mutex);
[cb41a5e]766}
767
[1313ee9]768static void devmap_get_device_count(ipc_callid_t iid, ipc_call_t *icall)
[cb41a5e]769{
[fc02cc41]770 fibril_mutex_lock(&devices_list_mutex);
771
[ab108be4]772 devmap_namespace_t *namespace =
773 devmap_namespace_find_handle(IPC_GET_ARG1(*icall));
[1313ee9]774 if (namespace == NULL)
[ffa2c8ef]775 async_answer_0(iid, EEXISTS);
[1313ee9]776 else
[ffa2c8ef]777 async_answer_1(iid, EOK, namespace->refcnt);
[1313ee9]778
779 fibril_mutex_unlock(&devices_list_mutex);
780}
781
782static void devmap_get_namespaces(ipc_callid_t iid, ipc_call_t *icall)
783{
[cb41a5e]784 ipc_callid_t callid;
785 size_t size;
[0da4e41]786 if (!async_data_read_receive(&callid, &size)) {
[ffa2c8ef]787 async_answer_0(callid, EREFUSED);
788 async_answer_0(iid, EREFUSED);
[cb41a5e]789 return;
790 }
791
792 if ((size % sizeof(dev_desc_t)) != 0) {
[ffa2c8ef]793 async_answer_0(callid, EINVAL);
794 async_answer_0(iid, EINVAL);
[cb41a5e]795 return;
796 }
797
[1313ee9]798 fibril_mutex_lock(&devices_list_mutex);
799
[5d0e461]800 size_t count = size / sizeof(dev_desc_t);
[1313ee9]801 if (count != list_count(&namespaces_list)) {
[ab108be4]802 fibril_mutex_unlock(&devices_list_mutex);
[ffa2c8ef]803 async_answer_0(callid, EOVERFLOW);
804 async_answer_0(iid, EOVERFLOW);
[1313ee9]805 return;
806 }
807
[cb41a5e]808 dev_desc_t *desc = (dev_desc_t *) malloc(size);
809 if (desc == NULL) {
[ab108be4]810 fibril_mutex_unlock(&devices_list_mutex);
[ffa2c8ef]811 async_answer_0(callid, ENOMEM);
812 async_answer_0(iid, ENOMEM);
[cb41a5e]813 return;
814 }
815
[ab108be4]816 link_t *item;
[5d0e461]817 size_t pos = 0;
[ab108be4]818 for (item = namespaces_list.next; item != &namespaces_list;
819 item = item->next) {
820 devmap_namespace_t *namespace =
821 list_get_instance(item, devmap_namespace_t, namespaces);
[cb41a5e]822
[1313ee9]823 desc[pos].handle = namespace->handle;
824 str_cpy(desc[pos].name, DEVMAP_NAME_MAXLEN, namespace->name);
[cb41a5e]825 pos++;
826 }
827
[96b02eb9]828 sysarg_t retval = async_data_read_finalize(callid, desc, size);
[1313ee9]829
830 free(desc);
831 fibril_mutex_unlock(&devices_list_mutex);
832
[ffa2c8ef]833 async_answer_0(iid, retval);
[1313ee9]834}
835
836static void devmap_get_devices(ipc_callid_t iid, ipc_call_t *icall)
837{
838 /* FIXME: Use faster algorithm which can make better use
839 of namespaces */
840
841 ipc_callid_t callid;
842 size_t size;
843 if (!async_data_read_receive(&callid, &size)) {
[ffa2c8ef]844 async_answer_0(callid, EREFUSED);
845 async_answer_0(iid, EREFUSED);
[cb41a5e]846 return;
847 }
848
[1313ee9]849 if ((size % sizeof(dev_desc_t)) != 0) {
[ffa2c8ef]850 async_answer_0(callid, EINVAL);
851 async_answer_0(iid, EINVAL);
[1313ee9]852 return;
853 }
854
855 fibril_mutex_lock(&devices_list_mutex);
856
[ab108be4]857 devmap_namespace_t *namespace =
858 devmap_namespace_find_handle(IPC_GET_ARG1(*icall));
[1313ee9]859 if (namespace == NULL) {
860 fibril_mutex_unlock(&devices_list_mutex);
[ffa2c8ef]861 async_answer_0(callid, ENOENT);
862 async_answer_0(iid, ENOENT);
[1313ee9]863 return;
864 }
865
866 size_t count = size / sizeof(dev_desc_t);
867 if (count != namespace->refcnt) {
[ab108be4]868 fibril_mutex_unlock(&devices_list_mutex);
[ffa2c8ef]869 async_answer_0(callid, EOVERFLOW);
870 async_answer_0(iid, EOVERFLOW);
[1313ee9]871 return;
872 }
873
874 dev_desc_t *desc = (dev_desc_t *) malloc(size);
875 if (desc == NULL) {
[ab108be4]876 fibril_mutex_unlock(&devices_list_mutex);
[ffa2c8ef]877 async_answer_0(callid, ENOMEM);
878 async_answer_0(iid, EREFUSED);
[1313ee9]879 return;
880 }
[cb41a5e]881
[ab108be4]882 link_t *item;
[1313ee9]883 size_t pos = 0;
[ab108be4]884 for (item = devices_list.next; item != &devices_list; item = item->next) {
885 devmap_device_t *device =
886 list_get_instance(item, devmap_device_t, devices);
[1313ee9]887
888 if (device->namespace == namespace) {
889 desc[pos].handle = device->handle;
890 str_cpy(desc[pos].name, DEVMAP_NAME_MAXLEN, device->name);
891 pos++;
892 }
893 }
894
[96b02eb9]895 sysarg_t retval = async_data_read_finalize(callid, desc, size);
[1313ee9]896
897 free(desc);
[fc02cc41]898 fibril_mutex_unlock(&devices_list_mutex);
899
[ffa2c8ef]900 async_answer_0(iid, retval);
[cb41a5e]901}
902
[7fcb74c]903static void devmap_null_create(ipc_callid_t iid, ipc_call_t *icall)
[cb41a5e]904{
[7fcb74c]905 fibril_mutex_lock(&null_devices_mutex);
906
907 unsigned int i;
908 bool fnd = false;
909
910 for (i = 0; i < NULL_DEVICES; i++) {
911 if (null_devices[i] == NULL) {
912 fnd = true;
913 break;
914 }
915 }
916
917 if (!fnd) {
918 fibril_mutex_unlock(&null_devices_mutex);
[ffa2c8ef]919 async_answer_0(iid, ENOMEM);
[7fcb74c]920 return;
921 }
922
[1313ee9]923 char null[DEVMAP_NAME_MAXLEN];
924 snprintf(null, DEVMAP_NAME_MAXLEN, "%u", i);
925
926 char *dev_name = str_dup(null);
927 if (dev_name == NULL) {
928 fibril_mutex_unlock(&null_devices_mutex);
[ffa2c8ef]929 async_answer_0(iid, ENOMEM);
[1313ee9]930 return;
931 }
932
[ab108be4]933 devmap_device_t *device =
934 (devmap_device_t *) malloc(sizeof(devmap_device_t));
[7fcb74c]935 if (device == NULL) {
936 fibril_mutex_unlock(&null_devices_mutex);
[ffa2c8ef]937 async_answer_0(iid, ENOMEM);
[7fcb74c]938 return;
939 }
[cb41a5e]940
[1313ee9]941 fibril_mutex_lock(&devices_list_mutex);
[7fcb74c]942
[1313ee9]943 devmap_namespace_t *namespace = devmap_namespace_create("null");
[ab108be4]944 if (namespace == NULL) {
[1313ee9]945 fibril_mutex_lock(&devices_list_mutex);
[7fcb74c]946 fibril_mutex_unlock(&null_devices_mutex);
[ffa2c8ef]947 async_answer_0(iid, ENOMEM);
[7fcb74c]948 return;
[cb41a5e]949 }
950
[ca2a18e]951 link_initialize(&device->devices);
952 link_initialize(&device->driver_devices);
[cb41a5e]953
954 /* Get unique device handle */
955 device->handle = devmap_create_handle();
956 device->driver = NULL;
957
[1313ee9]958 devmap_namespace_addref(namespace, device);
959 device->name = dev_name;
960
[63e0bdd]961 /*
962 * Insert device into list of all devices and into null devices array.
963 * Insert device into a dummy list of null driver's devices so that it
964 * can be safely removed later.
965 */
[cb41a5e]966 list_append(&device->devices, &devices_list);
[63e0bdd]967 list_append(&device->driver_devices, &dummy_null_driver_devices);
[7fcb74c]968 null_devices[i] = device;
[cb41a5e]969
[fc02cc41]970 fibril_mutex_unlock(&devices_list_mutex);
[7fcb74c]971 fibril_mutex_unlock(&null_devices_mutex);
972
[ffa2c8ef]973 async_answer_1(iid, EOK, (sysarg_t) i);
[7fcb74c]974}
975
976static void devmap_null_destroy(ipc_callid_t iid, ipc_call_t *icall)
977{
[96b02eb9]978 sysarg_t i = IPC_GET_ARG1(*icall);
[ab108be4]979 if (i >= NULL_DEVICES) {
[ffa2c8ef]980 async_answer_0(iid, ELIMIT);
[ab108be4]981 return;
982 }
983
984 fibril_mutex_lock(&null_devices_mutex);
[7fcb74c]985
986 if (null_devices[i] == NULL) {
[ab108be4]987 fibril_mutex_unlock(&null_devices_mutex);
[ffa2c8ef]988 async_answer_0(iid, ENOENT);
[7fcb74c]989 return;
990 }
991
[1313ee9]992 fibril_mutex_lock(&devices_list_mutex);
[7fcb74c]993 devmap_device_unregister_core(null_devices[i]);
[1313ee9]994 fibril_mutex_unlock(&devices_list_mutex);
995
[7fcb74c]996 null_devices[i] = NULL;
997
998 fibril_mutex_unlock(&null_devices_mutex);
[ffa2c8ef]999 async_answer_0(iid, EOK);
[7fcb74c]1000}
1001
1002/** Initialize device mapper.
1003 *
1004 *
1005 */
1006static bool devmap_init(void)
1007{
1008 fibril_mutex_lock(&null_devices_mutex);
1009
1010 unsigned int i;
1011 for (i = 0; i < NULL_DEVICES; i++)
1012 null_devices[i] = NULL;
1013
1014 fibril_mutex_unlock(&null_devices_mutex);
[fc02cc41]1015
[cb41a5e]1016 return true;
1017}
1018
[798f364]1019/** Handle connection with device driver.
[13125d3]1020 *
1021 */
[21c5d41]1022static void devmap_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
[13125d3]1023{
[6519d6f]1024 /* Accept connection */
[ffa2c8ef]1025 async_answer_0(iid, EOK);
[6519d6f]1026
[1313ee9]1027 devmap_driver_t *driver = devmap_driver_register();
1028 if (driver == NULL)
[798f364]1029 return;
1030
[6519d6f]1031 bool cont = true;
[07e4a3c]1032 while (cont) {
[6519d6f]1033 ipc_call_t call;
1034 ipc_callid_t callid = async_get_call(&call);
1035
[228e490]1036 switch (IPC_GET_IMETHOD(call)) {
[13125d3]1037 case IPC_M_PHONE_HUNGUP:
[07e4a3c]1038 cont = false;
[6519d6f]1039 continue;
[798f364]1040 case DEVMAP_DRIVER_UNREGISTER:
[6519d6f]1041 if (NULL == driver)
[ffa2c8ef]1042 async_answer_0(callid, ENOENT);
[6519d6f]1043 else
[ffa2c8ef]1044 async_answer_0(callid, EOK);
[07e4a3c]1045 break;
[798f364]1046 case DEVMAP_DEVICE_REGISTER:
1047 /* Register one instance of device */
1048 devmap_device_register(callid, &call, driver);
[07e4a3c]1049 break;
[798f364]1050 case DEVMAP_DEVICE_UNREGISTER:
1051 /* Remove instance of device identified by handler */
1052 devmap_device_unregister(callid, &call, driver);
1053 break;
1054 case DEVMAP_DEVICE_GET_HANDLE:
[1313ee9]1055 devmap_device_get_handle(callid, &call);
[798f364]1056 break;
[1313ee9]1057 case DEVMAP_NAMESPACE_GET_HANDLE:
1058 devmap_namespace_get_handle(callid, &call);
[798f364]1059 break;
1060 default:
[ffa2c8ef]1061 async_answer_0(callid, ENOENT);
[798f364]1062 }
1063 }
1064
[7fcb74c]1065 if (driver != NULL) {
[6519d6f]1066 /*
[b74959bd]1067 * Unregister the device driver and all its devices.
1068 */
[798f364]1069 devmap_driver_unregister(driver);
1070 driver = NULL;
1071 }
1072}
1073
1074/** Handle connection with device client.
1075 *
1076 */
[21c5d41]1077static void devmap_connection_client(ipc_callid_t iid, ipc_call_t *icall)
[798f364]1078{
[6519d6f]1079 /* Accept connection */
[ffa2c8ef]1080 async_answer_0(iid, EOK);
[6519d6f]1081
[798f364]1082 bool cont = true;
1083 while (cont) {
[6519d6f]1084 ipc_call_t call;
1085 ipc_callid_t callid = async_get_call(&call);
1086
[228e490]1087 switch (IPC_GET_IMETHOD(call)) {
[798f364]1088 case IPC_M_PHONE_HUNGUP:
[07e4a3c]1089 cont = false;
[6519d6f]1090 continue;
[798f364]1091 case DEVMAP_DEVICE_GET_HANDLE:
[1313ee9]1092 devmap_device_get_handle(callid, &call);
1093 break;
1094 case DEVMAP_NAMESPACE_GET_HANDLE:
1095 devmap_namespace_get_handle(callid, &call);
[07e4a3c]1096 break;
[1313ee9]1097 case DEVMAP_HANDLE_PROBE:
1098 devmap_handle_probe(callid, &call);
[13125d3]1099 break;
[1313ee9]1100 case DEVMAP_NULL_CREATE:
[7fcb74c]1101 devmap_null_create(callid, &call);
1102 break;
[1313ee9]1103 case DEVMAP_NULL_DESTROY:
[7fcb74c]1104 devmap_null_destroy(callid, &call);
1105 break;
[1313ee9]1106 case DEVMAP_GET_NAMESPACE_COUNT:
1107 devmap_get_namespace_count(callid, &call);
1108 break;
1109 case DEVMAP_GET_DEVICE_COUNT:
1110 devmap_get_device_count(callid, &call);
1111 break;
1112 case DEVMAP_GET_NAMESPACES:
1113 devmap_get_namespaces(callid, &call);
[cb41a5e]1114 break;
[1313ee9]1115 case DEVMAP_GET_DEVICES:
[cb41a5e]1116 devmap_get_devices(callid, &call);
1117 break;
[13125d3]1118 default:
[ffa2c8ef]1119 async_answer_0(callid, ENOENT);
[13125d3]1120 }
1121 }
1122}
1123
[6519d6f]1124/** Function for handling connections to devmap
[798f364]1125 *
1126 */
[21c5d41]1127static void devmap_connection(ipc_callid_t iid, ipc_call_t *icall)
[798f364]1128{
[21c5d41]1129 /* Select interface */
[96b02eb9]1130 switch ((sysarg_t) (IPC_GET_ARG1(*icall))) {
[7f3e3e7]1131 case DEVMAP_DRIVER:
1132 devmap_connection_driver(iid, icall);
1133 break;
1134 case DEVMAP_CLIENT:
1135 devmap_connection_client(iid, icall);
1136 break;
[b61d47d]1137 case DEVMAP_CONNECT_TO_DEVICE:
[21c5d41]1138 /* Connect client to selected device */
[b61d47d]1139 devmap_forward(iid, icall);
1140 break;
[7f3e3e7]1141 default:
[6519d6f]1142 /* No such interface */
[ffa2c8ef]1143 async_answer_0(iid, ENOENT);
[798f364]1144 }
1145}
[13125d3]1146
[798f364]1147/**
1148 *
1149 */
[13125d3]1150int main(int argc, char *argv[])
1151{
[ab108be4]1152 printf("%s: HelenOS Device Mapper\n", NAME);
[21c5d41]1153
[cb41a5e]1154 if (!devmap_init()) {
[ab108be4]1155 printf("%s: Error while initializing service\n", NAME);
[13125d3]1156 return -1;
1157 }
[21c5d41]1158
[c07af37]1159 /* Set a handler of incomming connections */
[798f364]1160 async_set_client_connection(devmap_connection);
[7fcb74c]1161
[7f3e3e7]1162 /* Register device mapper at naming service */
[007e6efa]1163 if (service_register(SERVICE_DEVMAP) != EOK)
[13125d3]1164 return -1;
1165
[ab108be4]1166 printf("%s: Accepting connections\n", NAME);
[13125d3]1167 async_manager();
[6519d6f]1168
[13125d3]1169 /* Never reached */
1170 return 0;
1171}
1172
[fb623e2]1173/**
[13125d3]1174 * @}
1175 */
Note: See TracBrowser for help on using the repository browser.