The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_udev.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 2010 The DragonFly Project.  All rights reserved.
    3  *
    4  * This code is derived from software contributed to The DragonFly Project
    5  * by Alex Hornung <ahornung@gmail.com>
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  *
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in
   15  *    the documentation and/or other materials provided with the
   16  *    distribution.
   17  * 3. Neither the name of The DragonFly Project nor the names of its
   18  *    contributors may be used to endorse or promote products derived
   19  *    from this software without specific, prior written permission.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
   25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
   27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   32  * SUCH DAMAGE.
   33  */
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/kernel.h>
   37 #include <sys/proc.h>
   38 #include <sys/buf.h>
   39 #include <sys/conf.h>
   40 #include <sys/event.h>
   41 #include <sys/vnode.h>
   42 #include <sys/malloc.h>
   43 #include <sys/ctype.h>
   44 #include <sys/syslog.h>
   45 #include <sys/udev.h>
   46 #include <sys/devfs.h>
   47 #include <libprop/proplib.h>
   48 
   49 #include <sys/thread2.h>
   50 
   51 MALLOC_DEFINE(M_UDEV, "udev", "udev allocs");
   52 
   53 /* XXX: use UUIDs for identification; would need help from devfs */
   54 
   55 static cdev_t           udev_dev;
   56 static d_open_t         udev_dev_open;
   57 static d_close_t        udev_dev_close;
   58 static d_read_t         udev_dev_read;
   59 static d_kqfilter_t     udev_dev_kqfilter;
   60 static d_ioctl_t        udev_dev_ioctl;
   61 static d_clone_t        udev_dev_clone;
   62 
   63 struct udev_prop_ctx {
   64         prop_array_t cdevs;
   65         int error;
   66 };
   67 
   68 struct udev_event_kernel {
   69         struct udev_event ev;
   70         TAILQ_ENTRY(udev_event_kernel)  link;
   71 };
   72 
   73 struct udev_softc {
   74         TAILQ_ENTRY(udev_softc) entry;
   75         int opened;
   76         int initiated;
   77         int unit;
   78         cdev_t dev;
   79 
   80         struct udev_event_kernel marker;        /* udev_evq marker */
   81 };
   82 
   83 struct cmd_function {
   84         const char *cmd;
   85         int  (*fn)(struct udev_softc *, struct plistref *,
   86                    u_long, prop_dictionary_t);
   87 };
   88 
   89 
   90 static int _udev_dict_set_cstr(prop_dictionary_t, const char *, char *);
   91 static int _udev_dict_set_int(prop_dictionary_t, const char *, int64_t);
   92 static int _udev_dict_set_uint(prop_dictionary_t, const char *, uint64_t);
   93 static int _udev_dict_delete_key(prop_dictionary_t, const char *);
   94 static prop_dictionary_t udev_init_dict_event(cdev_t, const char *);
   95 static int udev_init_dict(cdev_t);
   96 static int udev_destroy_dict(cdev_t);
   97 static void udev_event_insert(int, prop_dictionary_t);
   98 static void udev_clean_events_locked(void);
   99 static char *udev_event_externalize(struct udev_event_kernel *);
  100 static void udev_getdevs_scan_callback(char *, cdev_t, bool, void *);
  101 static int udev_getdevs_ioctl(struct udev_softc *, struct plistref *,
  102                                         u_long, prop_dictionary_t);
  103 static void udev_dev_filter_detach(struct knote *);
  104 static int udev_dev_filter_read(struct knote *, long);
  105 
  106 static struct dev_ops udev_dev_ops = {
  107         { "udev", 0, 0 },
  108         .d_open = udev_dev_open,
  109         .d_close = udev_dev_close,
  110         .d_read = udev_dev_read,
  111         .d_kqfilter = udev_dev_kqfilter,
  112         .d_ioctl = udev_dev_ioctl
  113 };
  114 
  115 static struct cmd_function cmd_fn[] = {
  116                 { .cmd = "getdevs", .fn = udev_getdevs_ioctl},
  117                 {NULL, NULL}
  118 };
  119 
  120 DEVFS_DECLARE_CLONE_BITMAP(udev);
  121 
  122 static TAILQ_HEAD(, udev_softc) udevq;
  123 static TAILQ_HEAD(, udev_event_kernel) udev_evq;
  124 static struct kqinfo udev_kq;
  125 static struct lock udev_lk;
  126 static int udev_evqlen;
  127 static int udev_initiated_count;
  128 static int udev_open_count;
  129 static int udev_seqwait;
  130 static int udev_seq;
  131 
  132 static int
  133 _udev_dict_set_cstr(prop_dictionary_t dict, const char *key, char *str)
  134 {
  135         prop_string_t   ps;
  136 
  137         KKASSERT(dict != NULL);
  138 
  139         ps = prop_string_create_cstring(str);
  140         if (ps == NULL) {
  141                 return ENOMEM;
  142         }
  143 
  144         if (prop_dictionary_set(dict, key, ps) == false) {
  145                 prop_object_release(ps);
  146                 return ENOMEM;
  147         }
  148 
  149         prop_object_release(ps);
  150         return 0;
  151 }
  152 
  153 static int
  154 _udev_dict_set_int(prop_dictionary_t dict, const char *key, int64_t val)
  155 {
  156         prop_number_t   pn;
  157 
  158         KKASSERT(dict != NULL);
  159 
  160         pn = prop_number_create_integer(val);
  161         if (pn == NULL)
  162                 return ENOMEM;
  163 
  164         if (prop_dictionary_set(dict, key, pn) == false) {
  165                 prop_object_release(pn);
  166                 return ENOMEM;
  167         }
  168 
  169         prop_object_release(pn);
  170         return 0;
  171 }
  172 
  173 static int
  174 _udev_dict_set_uint(prop_dictionary_t dict, const char *key, uint64_t val)
  175 {
  176         prop_number_t   pn;
  177 
  178         KKASSERT(dict != NULL);
  179 
  180         pn = prop_number_create_unsigned_integer(val);
  181         if (pn == NULL)
  182                 return ENOMEM;
  183 
  184         if (prop_dictionary_set(dict, key, pn) == false) {
  185                 prop_object_release(pn);
  186                 return ENOMEM;
  187         }
  188 
  189         prop_object_release(pn);
  190         return 0;
  191 }
  192 
  193 static int
  194 _udev_dict_delete_key(prop_dictionary_t dict, const char *key)
  195 {
  196         KKASSERT(dict != NULL);
  197 
  198         prop_dictionary_remove(dict, key);
  199 
  200         return 0;
  201 }
  202 
  203 /*
  204  * Initialize an event dictionary, which contains three parameters to
  205  * identify the device referred to (name, devnum, kptr) and the affected key.
  206  */
  207 static prop_dictionary_t
  208 udev_init_dict_event(cdev_t dev, const char *key)
  209 {
  210         prop_dictionary_t       dict;
  211         uint64_t        kptr;
  212         int error;
  213 
  214         kptr = (uint64_t)(uintptr_t)dev;
  215         KKASSERT(dev != NULL);
  216 
  217         dict = prop_dictionary_create();
  218         if (dict == NULL) {
  219                 log(LOG_DEBUG, "udev_init_dict_event: prop_dictionary_create() failed\n");
  220                 return NULL;
  221         }
  222 
  223         if ((error = _udev_dict_set_cstr(dict, "name", dev->si_name)))
  224                 goto error_out;
  225         if ((error = _udev_dict_set_uint(dict, "devnum", dev->si_inode)))
  226                 goto error_out;
  227         if ((error = _udev_dict_set_uint(dict, "devtype", (dev_dflags(dev) & D_TYPEMASK))))
  228                 goto error_out;
  229         if ((error = _udev_dict_set_uint(dict, "kptr", kptr)))
  230                 goto error_out;
  231         if ((error = _udev_dict_set_cstr(dict, "key", __DECONST(char *, key))))
  232                 goto error_out;
  233 
  234         return dict;
  235 
  236 error_out:
  237         prop_object_release(dict);
  238         return NULL;
  239 }
  240 
  241 int
  242 udev_dict_set_cstr(cdev_t dev, const char *key, char *str)
  243 {
  244         prop_dictionary_t       dict;
  245         int error;
  246 
  247         KKASSERT(dev != NULL);
  248 
  249         if (dev->si_dict == NULL) {
  250                 error = udev_init_dict(dev);
  251                 if (error)
  252                         return -1;
  253         }
  254 
  255         /* Queue a key update event */
  256         dict = udev_init_dict_event(dev, key);
  257         if (dict == NULL)
  258                 return ENOMEM;
  259 
  260         if ((error = _udev_dict_set_cstr(dict, "value", str))) {
  261                 prop_object_release(dict);
  262                 return error;
  263         }
  264         udev_event_insert(UDEV_EV_KEY_UPDATE, dict);
  265         prop_object_release(dict);
  266 
  267         error = _udev_dict_set_cstr(dev->si_dict, key, str);
  268         return error;
  269 }
  270 
  271 int
  272 udev_dict_set_int(cdev_t dev, const char *key, int64_t val)
  273 {
  274         prop_dictionary_t       dict;
  275         int error;
  276 
  277         KKASSERT(dev != NULL);
  278 
  279         if (dev->si_dict == NULL) {
  280                 error = udev_init_dict(dev);
  281                 if (error)
  282                         return -1;
  283         }
  284 
  285         /* Queue a key update event */
  286         dict = udev_init_dict_event(dev, key);
  287         if (dict == NULL)
  288                 return ENOMEM;
  289         if ((error = _udev_dict_set_int(dict, "value", val))) {
  290                 prop_object_release(dict);
  291                 return error;
  292         }
  293         udev_event_insert(UDEV_EV_KEY_UPDATE, dict);
  294         prop_object_release(dict);
  295 
  296         return _udev_dict_set_int(dev->si_dict, key, val);
  297 }
  298 
  299 int
  300 udev_dict_set_uint(cdev_t dev, const char *key, uint64_t val)
  301 {
  302         prop_dictionary_t       dict;
  303         int error;
  304 
  305         KKASSERT(dev != NULL);
  306 
  307         if (dev->si_dict == NULL) {
  308                 error = udev_init_dict(dev);
  309                 if (error)
  310                         return -1;
  311         }
  312 
  313         /* Queue a key update event */
  314         dict = udev_init_dict_event(dev, key);
  315         if (dict == NULL)
  316                 return ENOMEM;
  317         if ((error = _udev_dict_set_uint(dict, "value", val))) {
  318                 prop_object_release(dict);
  319                 return error;
  320         }
  321         udev_event_insert(UDEV_EV_KEY_UPDATE, dict);
  322         prop_object_release(dict);
  323 
  324         return _udev_dict_set_uint(dev->si_dict, key, val);
  325 }
  326 
  327 int
  328 udev_dict_delete_key(cdev_t dev, const char *key)
  329 {
  330         prop_dictionary_t       dict;
  331 
  332         KKASSERT(dev != NULL);
  333 
  334         /* Queue a key removal event */
  335         dict = udev_init_dict_event(dev, key);
  336         if (dict == NULL)
  337                 return ENOMEM;
  338         udev_event_insert(UDEV_EV_KEY_REMOVE, dict);
  339         prop_object_release(dict);
  340 
  341         return _udev_dict_delete_key(dev->si_dict, key);
  342 }
  343 
  344 static int
  345 udev_init_dict(cdev_t dev)
  346 {
  347         prop_dictionary_t dict;
  348         uint64_t        kptr;
  349         int error;
  350 
  351         kptr = (uint64_t)(uintptr_t)dev;
  352 
  353         KKASSERT(dev != NULL);
  354 
  355         if (dev->si_dict != NULL) {
  356 #if 0
  357                 log(LOG_DEBUG,
  358                     "udev_init_dict: new dict for %s, but has dict already (%p)!\n",
  359                     dev->si_name, dev->si_dict);
  360 #endif
  361                 return 0;
  362         }
  363 
  364         dict = prop_dictionary_create();
  365         if (dict == NULL) {
  366                 log(LOG_DEBUG, "udev_init_dict: prop_dictionary_create() failed\n");
  367                 return ENOMEM;
  368         }
  369 
  370         if ((error = _udev_dict_set_cstr(dict, "name", dev->si_name)))
  371                 goto error_out;
  372         if ((error = _udev_dict_set_uint(dict, "devnum", dev->si_inode)))
  373                 goto error_out;
  374         if ((error = _udev_dict_set_uint(dict, "kptr", kptr)))
  375                 goto error_out;
  376         if ((error = _udev_dict_set_uint(dict, "devtype", (dev_dflags(dev) & D_TYPEMASK))))
  377                 goto error_out;
  378 
  379         /* XXX: The next 3 are marginallly useful, if at all */
  380         if ((error = _udev_dict_set_uint(dict, "uid", dev->si_uid)))
  381                 goto error_out;
  382         if ((error = _udev_dict_set_uint(dict, "gid", dev->si_gid)))
  383                 goto error_out;
  384         if ((error = _udev_dict_set_int(dict, "mode", dev->si_perms)))
  385                 goto error_out;
  386 
  387         if ((error = _udev_dict_set_int(dict, "major", dev->si_umajor)))
  388                 goto error_out;
  389         if ((error = _udev_dict_set_int(dict, "minor", dev->si_uminor)))
  390                 goto error_out;
  391         if (dev->si_ops->head.name != NULL) {
  392                 if ((error = _udev_dict_set_cstr(dict, "driver",
  393                     __DECONST(char *, dev->si_ops->head.name))))
  394                         goto error_out;
  395         }
  396 
  397         dev->si_dict = dict;
  398         return 0;
  399 
  400 error_out:
  401         dev->si_dict = NULL;
  402         prop_object_release(dict);
  403         return error;
  404 }
  405 
  406 static int
  407 udev_destroy_dict(cdev_t dev)
  408 {
  409         KKASSERT(dev != NULL);
  410 
  411         if (dev->si_dict != NULL) {
  412                 prop_object_release(dev->si_dict);
  413                 dev->si_dict = NULL;
  414         }
  415 
  416         return 0;
  417 }
  418 
  419 static void
  420 udev_event_insert(int ev_type, prop_dictionary_t dict)
  421 {
  422         struct udev_event_kernel *ev;
  423 
  424         /* Only start queing events after client has initiated properly */
  425         if (udev_initiated_count) {
  426                 /* XXX: use objcache eventually */
  427                 ev = kmalloc(sizeof(*ev), M_UDEV, M_WAITOK);
  428                 ev->ev.ev_dict = prop_dictionary_copy(dict);
  429                 if (ev->ev.ev_dict == NULL) {
  430                         kfree(ev, M_UDEV);
  431                         return;
  432                 }
  433                 ev->ev.ev_type = ev_type;
  434 
  435                 lockmgr(&udev_lk, LK_EXCLUSIVE);
  436                 TAILQ_INSERT_TAIL(&udev_evq, ev, link);
  437                 ++udev_evqlen;
  438                 ++udev_seq;
  439                 if (udev_seqwait)
  440                         wakeup(&udev_seqwait);
  441                 lockmgr(&udev_lk, LK_RELEASE);
  442                 wakeup(&udev_evq);
  443                 KNOTE(&udev_kq.ki_note, 0);
  444         } else if (udev_open_count) {
  445                 lockmgr(&udev_lk, LK_EXCLUSIVE);
  446                 ++udev_seq;
  447                 if (udev_seqwait)
  448                         wakeup(&udev_seqwait);
  449                 lockmgr(&udev_lk, LK_RELEASE);
  450                 KNOTE(&udev_kq.ki_note, 0);
  451         }
  452 }
  453 
  454 static void
  455 udev_clean_events_locked(void)
  456 {
  457         struct udev_event_kernel *ev;
  458 
  459         while ((ev = TAILQ_FIRST(&udev_evq)) &&
  460                ev->ev.ev_dict != NULL) {
  461                 TAILQ_REMOVE(&udev_evq, ev, link);
  462                 kfree(ev, M_UDEV);
  463                 --udev_evqlen;
  464         }
  465 }
  466 
  467 static char *
  468 udev_event_externalize(struct udev_event_kernel *ev)
  469 {
  470         prop_dictionary_t       dict;
  471         char *xml;
  472         int error;
  473 
  474 
  475         dict = prop_dictionary_create();
  476         if (dict == NULL) {
  477                 log(LOG_DEBUG,
  478                     "udev_event_externalize: prop_dictionary_create() failed\n");
  479                 return NULL;
  480         }
  481 
  482         if ((error = _udev_dict_set_int(dict, "evtype", ev->ev.ev_type))) {
  483                 prop_object_release(dict);
  484                 return NULL;
  485         }
  486 
  487         if (prop_dictionary_set(dict, "evdict", ev->ev.ev_dict) == false) {
  488                 prop_object_release(dict);
  489                 return NULL;
  490         }
  491 
  492         prop_object_release(ev->ev.ev_dict);
  493 
  494         xml = prop_dictionary_externalize(dict);
  495 
  496         prop_object_release(dict);
  497 
  498         return xml;
  499 }
  500 
  501 int
  502 udev_event_attach(cdev_t dev, char *name, int alias)
  503 {
  504         prop_dictionary_t       dict;
  505         int error;
  506 
  507         KKASSERT(dev != NULL);
  508 
  509         error = ENOMEM;
  510 
  511         if (alias) {
  512                 dict = prop_dictionary_copy(dev->si_dict);
  513                 if (dict == NULL)
  514                         goto error_out;
  515 
  516                 if ((error = _udev_dict_set_cstr(dict, "name", name))) {
  517                         prop_object_release(dict);
  518                         goto error_out;
  519                 }
  520 
  521                 _udev_dict_set_int(dict, "alias", 1);
  522 
  523                 udev_event_insert(UDEV_EVENT_ATTACH, dict);
  524                 prop_object_release(dict);
  525         } else {
  526                 error = udev_init_dict(dev);
  527                 if (error)
  528                         goto error_out;
  529 
  530                 _udev_dict_set_int(dev->si_dict, "alias", 0);
  531                 udev_event_insert(UDEV_EVENT_ATTACH, dev->si_dict);
  532         }
  533 
  534 error_out:
  535         return error;
  536 }
  537 
  538 int
  539 udev_event_detach(cdev_t dev, char *name, int alias)
  540 {
  541         prop_dictionary_t       dict;
  542 
  543         KKASSERT(dev != NULL);
  544 
  545         if (alias) {
  546                 dict = prop_dictionary_copy(dev->si_dict);
  547                 if (dict == NULL)
  548                         goto error_out;
  549 
  550                 if (_udev_dict_set_cstr(dict, "name", name)) {
  551                         prop_object_release(dict);
  552                         goto error_out;
  553                 }
  554 
  555                 _udev_dict_set_int(dict, "alias", 1);
  556 
  557                 udev_event_insert(UDEV_EVENT_DETACH, dict);
  558                 prop_object_release(dict);
  559         } else {
  560                 udev_event_insert(UDEV_EVENT_DETACH, dev->si_dict);
  561         }
  562 
  563 error_out:
  564         udev_destroy_dict(dev);
  565 
  566         return 0;
  567 }
  568 
  569 /*
  570  * Allow multiple opens.  Each opener gets a different device.
  571  * Messages are replicated to all devices using a marker system.
  572  */
  573 static int
  574 udev_dev_clone(struct dev_clone_args *ap)
  575 {
  576         struct udev_softc *softc;
  577         int unit;
  578 
  579         unit = devfs_clone_bitmap_get(&DEVFS_CLONE_BITMAP(udev), 1000);
  580         if (unit < 0) {
  581                 ap->a_dev = NULL;
  582                 return 1;
  583         }
  584 
  585         softc = kmalloc(sizeof(*softc), M_UDEV, M_WAITOK | M_ZERO);
  586         softc->unit = unit;
  587         lockmgr(&udev_lk, LK_EXCLUSIVE);
  588         TAILQ_INSERT_TAIL(&udevq, softc, entry);
  589         lockmgr(&udev_lk, LK_RELEASE);
  590 
  591         softc->dev = make_only_dev(&udev_dev_ops, unit, ap->a_cred->cr_ruid,
  592                                    0, 0600, "udev/%d", unit);
  593         softc->dev->si_drv1 = softc;
  594         ap->a_dev = softc->dev;
  595         return 0;
  596 }
  597 
  598 /*
  599  * dev stuff
  600  */
  601 static int
  602 udev_dev_open(struct dev_open_args *ap)
  603 {
  604         struct udev_softc *softc = ap->a_head.a_dev->si_drv1;
  605 
  606         lockmgr(&udev_lk, LK_EXCLUSIVE);
  607         if (softc == NULL || softc->opened) {
  608                 lockmgr(&udev_lk, LK_RELEASE);
  609                 return EBUSY;
  610         }
  611         softc->opened = 1;
  612         ++udev_open_count;
  613         lockmgr(&udev_lk, LK_RELEASE);
  614 
  615         return 0;
  616 }
  617 
  618 static int
  619 udev_dev_close(struct dev_close_args *ap)
  620 {
  621         struct udev_softc *softc = ap->a_head.a_dev->si_drv1;
  622 
  623         KKASSERT(softc->dev == ap->a_head.a_dev);
  624         KKASSERT(softc->opened == 1);
  625 
  626         lockmgr(&udev_lk, LK_EXCLUSIVE);
  627         TAILQ_REMOVE(&udevq, softc, entry);
  628         devfs_clone_bitmap_put(&DEVFS_CLONE_BITMAP(udev), softc->unit);
  629 
  630         if (softc->initiated) {
  631                 TAILQ_REMOVE(&udev_evq, &softc->marker, link);
  632                 softc->initiated = 0;
  633                 --udev_initiated_count;
  634                 udev_clean_events_locked();
  635         }
  636         softc->opened = 0;
  637         softc->dev = NULL;
  638         ap->a_head.a_dev->si_drv1 = NULL;
  639         --udev_open_count;
  640         lockmgr(&udev_lk, LK_RELEASE);
  641 
  642         destroy_dev(ap->a_head.a_dev);
  643         wakeup(&udev_evq);
  644 
  645         kfree(softc, M_UDEV);
  646 
  647         return 0;
  648 }
  649 
  650 static struct filterops udev_dev_read_filtops =
  651         { FILTEROP_ISFD, NULL, udev_dev_filter_detach, udev_dev_filter_read };
  652 
  653 static int
  654 udev_dev_kqfilter(struct dev_kqfilter_args *ap)
  655 {
  656         struct udev_softc *softc = ap->a_head.a_dev->si_drv1;
  657         struct knote *kn = ap->a_kn;
  658         struct klist *klist;
  659 
  660         ap->a_result = 0;
  661         lockmgr(&udev_lk, LK_EXCLUSIVE);
  662 
  663         switch (kn->kn_filter) {
  664         case EVFILT_READ:
  665                 kn->kn_fop = &udev_dev_read_filtops;
  666                 kn->kn_hook = (caddr_t)softc;
  667                 break;
  668         default:
  669                 ap->a_result = EOPNOTSUPP;
  670                 lockmgr(&udev_lk, LK_RELEASE);
  671                 return (0);
  672         }
  673 
  674         klist = &udev_kq.ki_note;
  675         knote_insert(klist, kn);
  676 
  677         lockmgr(&udev_lk, LK_RELEASE);
  678 
  679         return (0);
  680 }
  681 
  682 static void
  683 udev_dev_filter_detach(struct knote *kn)
  684 {
  685         struct klist *klist;
  686 
  687         lockmgr(&udev_lk, LK_EXCLUSIVE);
  688         klist = &udev_kq.ki_note;
  689         knote_remove(klist, kn);
  690         lockmgr(&udev_lk, LK_RELEASE);
  691 }
  692 
  693 static int
  694 udev_dev_filter_read(struct knote *kn, long hint)
  695 {
  696         struct udev_softc *softc = (void *)kn->kn_hook;
  697         struct udev_event_kernel *ev;
  698         int ready = 0;
  699 
  700         lockmgr(&udev_lk, LK_EXCLUSIVE);
  701         if (softc->initiated) {
  702                 ev = TAILQ_NEXT(&softc->marker, link);
  703                 while (ev && ev->ev.ev_dict == NULL)
  704                         ev = TAILQ_NEXT(ev, link);
  705                 if (ev)
  706                         ready = 1;
  707         }
  708         lockmgr(&udev_lk, LK_RELEASE);
  709 
  710         return (ready);
  711 }
  712 
  713 static int
  714 udev_dev_read(struct dev_read_args *ap)
  715 {
  716         struct udev_softc *softc = ap->a_head.a_dev->si_drv1;
  717         struct udev_event_kernel *ev;
  718         struct uio *uio = ap->a_uio;
  719         char    *xml;
  720         size_t  len;
  721         int     error;
  722 
  723         lockmgr(&udev_lk, LK_EXCLUSIVE);
  724 
  725         /*
  726          * Automatically enable message collection if it has not already
  727          * been enabled.
  728          */
  729         if (softc->initiated == 0) {
  730                 softc->initiated = 1;
  731                 ++udev_initiated_count;
  732                 TAILQ_INSERT_HEAD(&udev_evq, &softc->marker, link);
  733         }
  734 
  735         /*
  736          * Loop, sleep interruptably until we get an event or signal.
  737          */
  738         error = 0;
  739         for (;;) {
  740                 if (softc->initiated) {
  741                         ev = TAILQ_NEXT(&softc->marker, link);
  742                         while (ev && ev->ev.ev_dict == NULL)
  743                                 ev = TAILQ_NEXT(ev, link);
  744                         if (ev) {
  745                                 if ((xml = udev_event_externalize(ev)) == NULL) {
  746                                         error = ENOMEM;
  747                                         break;
  748                                 }
  749                                 len = strlen(xml) + 1; /* include terminator */
  750                                 if (uio->uio_resid < len)
  751                                         error = ENOMEM;
  752                                 else
  753                                         error = uiomove((caddr_t)xml, len, uio);
  754                                 kfree(xml, M_TEMP);
  755 
  756                                 /*
  757                                  * Move the marker
  758                                  */
  759                                 TAILQ_REMOVE(&udev_evq, &softc->marker, link);
  760                                 TAILQ_INSERT_AFTER(&udev_evq,
  761                                                    ev, &softc->marker, link);
  762                                 udev_clean_events_locked();
  763                                 break;
  764                         }
  765                 }
  766                 if (ap->a_ioflag & IO_NDELAY) {
  767                         error = EWOULDBLOCK;
  768                         break;
  769                 }
  770                 if ((error = lksleep(&udev_evq, &udev_lk, PCATCH, "udevq", 0)))
  771                         break;
  772         }
  773 
  774         lockmgr(&udev_lk, LK_RELEASE);
  775         return error;
  776 }
  777 
  778 static int
  779 udev_dev_ioctl(struct dev_ioctl_args *ap)
  780 {
  781         struct udev_softc *softc = ap->a_head.a_dev->si_drv1;
  782         prop_dictionary_t dict;
  783         prop_object_t   po;
  784         prop_string_t   ps;
  785         struct plistref *pref;
  786         int i, error;
  787         int seq;
  788 
  789         error = 0;
  790 
  791         switch(ap->a_cmd) {
  792         case UDEVPROP:
  793                 /* Use proplib(3) for userspace/kernel communication */
  794                 pref = (struct plistref *)ap->a_data;
  795                 error = prop_dictionary_copyin_ioctl(pref, ap->a_cmd, &dict);
  796                 if (error)
  797                         return error;
  798 
  799                 po = prop_dictionary_get(dict, "command");
  800                 if (po == NULL || prop_object_type(po) != PROP_TYPE_STRING) {
  801                         log(LOG_DEBUG, "udev: prop_dictionary_get() failed\n");
  802                         prop_object_release(dict);
  803                         return EINVAL;
  804                 }
  805 
  806                 ps = po;
  807                 /* Handle cmd */
  808                 for(i = 0; cmd_fn[i].cmd != NULL; i++) {
  809                         if (prop_string_equals_cstring(ps, cmd_fn[i].cmd))
  810                                 break;
  811                 }
  812 
  813                 if (cmd_fn[i].cmd != NULL) {
  814                         error = cmd_fn[i].fn(softc, pref, ap->a_cmd, dict);
  815                 } else {
  816                         error = EINVAL;
  817                 }
  818 
  819                 //prop_object_release(po);
  820                 prop_object_release(dict);
  821                 break;
  822         case UDEVWAIT:
  823                 /*
  824                  * Wait for events based on sequence number.  Updates
  825                  * sequence number for loop.
  826                  */
  827                 lockmgr(&udev_lk, LK_EXCLUSIVE);
  828                 seq = *(int *)ap->a_data;
  829                 ++udev_seqwait;
  830                 while (seq == udev_seq) {
  831                         error = lksleep(&udev_seqwait, &udev_lk,
  832                                         PCATCH, "udevw", 0);
  833                         if (error)
  834                                 break;
  835                 }
  836                 --udev_seqwait;
  837                 *(int *)ap->a_data = udev_seq;
  838                 lockmgr(&udev_lk, LK_RELEASE);
  839                 break;
  840         default:
  841                 error = ENOTTY; /* Inappropriate ioctl for device */
  842                 break;
  843         }
  844 
  845         return(error);
  846 }
  847 
  848 static void
  849 udev_getdevs_scan_callback(char *name, cdev_t cdev, bool is_alias, void *arg)
  850 {
  851         struct udev_prop_ctx *ctx = arg;
  852 
  853         KKASSERT(arg != NULL);
  854 
  855         if (cdev->si_dict == NULL)
  856                 return;
  857 
  858         if (prop_array_add(ctx->cdevs, cdev->si_dict) == false) {
  859                 ctx->error = EINVAL;
  860                 return;
  861         }
  862 }
  863 
  864 static int
  865 udev_getdevs_ioctl(struct udev_softc *softc, struct plistref *pref,
  866                    u_long cmd, prop_dictionary_t dict)
  867 {
  868         prop_dictionary_t odict;
  869         struct udev_prop_ctx ctx;
  870         int error;
  871 
  872         /*
  873          * Ensure event notification is enabled before doing the devfs
  874          * scan so nothing gets missed.
  875          */
  876         lockmgr(&udev_lk, LK_EXCLUSIVE);
  877         if (softc->initiated == 0) {
  878                 softc->initiated = 1;
  879                 ++udev_initiated_count;
  880                 TAILQ_INSERT_HEAD(&udev_evq, &softc->marker, link);
  881         }
  882         lockmgr(&udev_lk, LK_RELEASE);
  883 
  884         /*
  885          * Devfs scan to build full dictionary.
  886          */
  887         ctx.error = 0;
  888         ctx.cdevs = prop_array_create();
  889         if (ctx.cdevs == NULL) {
  890                 log(LOG_DEBUG,
  891                     "udev_getdevs_ioctl: prop_array_create() failed\n");
  892                 return EINVAL;
  893         }
  894 
  895         devfs_scan_callback(udev_getdevs_scan_callback, &ctx);
  896 
  897         if (ctx.error != 0) {
  898                 prop_object_release(ctx.cdevs);
  899                 return (ctx.error);
  900         }
  901 
  902         odict = prop_dictionary_create();
  903         if (odict == NULL) {
  904                 return ENOMEM;
  905         }
  906 
  907         if ((prop_dictionary_set(odict, "array", ctx.cdevs)) == 0) {
  908                 log(LOG_DEBUG,
  909                     "udev_getdevs_ioctl: prop_dictionary_set failed\n");
  910                 prop_object_release(odict);
  911                 return ENOMEM;
  912         }
  913 
  914         error = prop_dictionary_copyout_ioctl(pref, cmd, odict);
  915 
  916         prop_object_release(odict);
  917         return error;
  918 }
  919 
  920 
  921 /*
  922  * SYSINIT stuff
  923  */
  924 static void
  925 udev_init(void)
  926 {
  927         lockinit(&udev_lk, "udevlk", 0, LK_CANRECURSE);
  928         TAILQ_INIT(&udevq);
  929         TAILQ_INIT(&udev_evq);
  930 }
  931 
  932 static void
  933 udev_uninit(void)
  934 {
  935 }
  936 
  937 static void
  938 udev_dev_init(void)
  939 {
  940         udev_dev = make_autoclone_dev(&udev_dev_ops, &DEVFS_CLONE_BITMAP(udev),
  941                                       udev_dev_clone,
  942                                       UID_ROOT, GID_WHEEL, 0600, "udev");
  943 }
  944 
  945 static void
  946 udev_dev_uninit(void)
  947 {
  948         destroy_dev(udev_dev);
  949 }
  950 
  951 SYSINIT(subr_udev_register, SI_SUB_CREATE_INIT, SI_ORDER_ANY,
  952         udev_init, NULL);
  953 SYSUNINIT(subr_udev_register, SI_SUB_CREATE_INIT, SI_ORDER_ANY,
  954         udev_uninit, NULL);
  955 SYSINIT(subr_udev_dev_register, SI_SUB_DRIVERS, SI_ORDER_ANY,
  956         udev_dev_init, NULL);
  957 SYSUNINIT(subr_udev_dev_register, SI_SUB_DRIVERS, SI_ORDER_ANY,
  958         udev_dev_uninit, NULL);

Cache object: a5be13c3dcb1044ae820142b5daf6cf7


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.