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/dev/misc/putter/putter.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 /*      $NetBSD: putter.c,v 1.31 2011/02/06 14:29:25 haad Exp $ */
    2 
    3 /*
    4  * Copyright (c) 2006, 2007  Antti Kantee.  All Rights Reserved.
    5  *
    6  * Development of this software was supported by the
    7  * Ulla Tuominen Foundation and the Finnish Cultural Foundation and the
    8  * Research Foundation of Helsinki University of Technology
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
   20  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   22  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   25  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   29  * SUCH DAMAGE.
   30  */
   31 
   32 /*
   33  * Pass-to-Userspace TransporTER: generic kernel-user request-response
   34  * transport interface.
   35  */
   36 
   37 #include <sys/param.h>
   38 #include <sys/systm.h>
   39 #include <sys/conf.h>
   40 #include <sys/device.h>
   41 #include <sys/devfs.h>
   42 #include <sys/fcntl.h>
   43 #include <sys/filio.h>
   44 #include <sys/kernel.h>
   45 #include <sys/malloc.h>
   46 #include <sys/module.h>
   47 #include <sys/spinlock.h>
   48 #include <sys/spinlock2.h>
   49 #include <sys/uio.h>
   50 #include <sys/vnode.h>
   51 
   52 #include <dev/misc/putter/putter_sys.h>
   53 
   54 static MALLOC_DEFINE(M_PUTTER, "putter", "Putter device data");
   55 
   56 /*
   57  * Device routines.  These are for when /dev/putter is initially
   58  * opened before it has been cloned.
   59  */
   60 
   61 static d_open_t puttercdopen;
   62 static d_read_t putter_fop_read;
   63 static d_write_t putter_fop_write;
   64 static d_ioctl_t putter_fop_ioctl;
   65 static d_close_t putter_fop_close;
   66 static d_kqfilter_t putter_fop_kqfilter;
   67 
   68 DEVFS_DECLARE_CLONE_BITMAP(putter);
   69 
   70 /* dev */
   71 static struct dev_ops putter_ops = {
   72         { "putter", 0, 0 },
   73         .d_open =       puttercdopen,
   74         .d_close =      putter_fop_close,
   75         .d_read =       putter_fop_read,
   76         .d_write =      putter_fop_write,
   77         .d_ioctl =      putter_fop_ioctl,
   78         .d_kqfilter =   putter_fop_kqfilter,
   79 };
   80 
   81 #if 0
   82 /*
   83  * Configuration data.
   84  *
   85  * This is static-size for now.  Will be redone for devfs.
   86  */
   87 
   88 #define PUTTER_CONFSIZE 16
   89 
   90 static struct putter_config {
   91         int     pc_minor;
   92         int     (*pc_config)(int, int, int);
   93 } putterconf[PUTTER_CONFSIZE];
   94 
   95 static int
   96 putter_configure(dev_t dev, int flags, int fmt, int fd)
   97 {
   98         struct putter_config *pc;
   99 
  100         /* are we the catch-all node? */
  101         if (minor(dev) == PUTTER_MINOR_WILDCARD
  102             || minor(dev) == PUTTER_MINOR_COMPAT)
  103                 return 0;
  104 
  105         /* nopes?  try to configure us */
  106         for (pc = putterconf; pc->pc_config; pc++)
  107                 if (minor(dev) == pc->pc_minor)
  108                         return pc->pc_config(fd, flags, fmt);
  109         return ENXIO;
  110 }
  111 
  112 int
  113 putter_register(putter_config_fn pcfn, int minor)
  114 {
  115         int i;
  116 
  117         for (i = 0; i < PUTTER_CONFSIZE; i++)
  118                 if (putterconf[i].pc_config == NULL)
  119                         break;
  120         if (i == PUTTER_CONFSIZE)
  121                 return EBUSY;
  122 
  123         putterconf[i].pc_minor = minor;
  124         putterconf[i].pc_config = pcfn;
  125         return 0;
  126 }
  127 #endif
  128 
  129 /*
  130  * putter instance structures.  these are always allocated and freed
  131  * from the context of the transport user.
  132  */
  133 struct putter_instance {
  134         pid_t                   pi_pid;
  135         int                     pi_idx;
  136         struct kqinfo           pi_kq;
  137 
  138         void                    *pi_private;
  139         struct putter_ops       *pi_pop;
  140 
  141         uint8_t                 *pi_curput;
  142         size_t                  pi_curres;
  143         void                    *pi_curopaq;
  144 
  145         TAILQ_ENTRY(putter_instance) pi_entries;
  146 };
  147 #define PUTTER_EMBRYO ((void *)-1)      /* before attach        */
  148 #define PUTTER_DEAD ((void *)-2)        /* after detach         */
  149 
  150 static TAILQ_HEAD(, putter_instance) putter_ilist
  151     = TAILQ_HEAD_INITIALIZER(putter_ilist);
  152 
  153 #ifdef DEBUG
  154 #ifndef PUTTERDEBUG
  155 #define PUTTERDEBUG
  156 #endif
  157 #endif
  158 
  159 #ifdef PUTTERDEBUG
  160 int putterdebug = 0;
  161 #define DPRINTF(x) if (putterdebug > 0) kprintf x
  162 #define DPRINTF_VERBOSE(x) if (putterdebug > 1) kprintf x
  163 #else
  164 #define DPRINTF(x)
  165 #define DPRINTF_VERBOSE(x)
  166 #endif
  167 
  168 /*
  169  * public init / deinit
  170  */
  171 
  172 /* protects both the list and the contents of the list elements */
  173 static struct spinlock pi_mtx = SPINLOCK_INITIALIZER(&pi_mtx);
  174 
  175 /*
  176  * fd routines, for cloner
  177  */
  178 
  179 static int
  180 putter_fop_read(struct dev_read_args *ap)
  181 {
  182         cdev_t dev = ap->a_head.a_dev;
  183         struct putter_instance *pi = dev->si_drv1;
  184         struct uio *uio = ap->a_uio;
  185         size_t origres, moved;
  186         int error;
  187 
  188         if (pi->pi_private == PUTTER_EMBRYO || pi->pi_private == PUTTER_DEAD) {
  189                 kprintf("putter_fop_read: private %d not inited\n", pi->pi_idx);
  190                 return ENOENT;
  191         }
  192 
  193         if (pi->pi_curput == NULL) {
  194                 error = pi->pi_pop->pop_getout(pi->pi_private, uio->uio_resid,
  195                     ap->a_ioflag & IO_NDELAY, &pi->pi_curput,
  196                     &pi->pi_curres, &pi->pi_curopaq);
  197                 if (error) {
  198                         return error;
  199                 }
  200         }
  201 
  202         origres = uio->uio_resid;
  203         error = uiomove(pi->pi_curput, pi->pi_curres, uio);
  204         moved = origres - uio->uio_resid;
  205         DPRINTF(("putter_fop_read (%p): moved %zu bytes from %p, error %d\n",
  206             pi, moved, pi->pi_curput, error));
  207 
  208         KKASSERT(pi->pi_curres >= moved);
  209         pi->pi_curres -= moved;
  210         pi->pi_curput += moved;
  211 
  212         if (pi->pi_curres == 0) {
  213                 pi->pi_pop->pop_releaseout(pi->pi_private,
  214                     pi->pi_curopaq, error);
  215                 pi->pi_curput = NULL;
  216         }
  217 
  218         return error;
  219 }
  220 
  221 static int
  222 putter_fop_write(struct dev_write_args *ap)
  223 {
  224         cdev_t dev = ap->a_head.a_dev;
  225         struct putter_instance *pi = dev->si_drv1;
  226         struct uio *uio = ap->a_uio;
  227         struct putter_hdr pth;
  228         uint8_t *buf;
  229         size_t frsize;
  230         int error;
  231 
  232         DPRINTF(("putter_fop_write (%p): writing response, resid %zu\n",
  233             pi->pi_private, uio->uio_resid));
  234 
  235         if (pi->pi_private == PUTTER_EMBRYO || pi->pi_private == PUTTER_DEAD) {
  236                 kprintf("putter_fop_write: putter %d not inited\n", pi->pi_idx);
  237                 return ENOENT;
  238         }
  239 
  240         error = uiomove((char *)&pth, sizeof(struct putter_hdr), uio);
  241         if (error) {
  242                 return error;
  243         }
  244 
  245         /* Sorry mate, the kernel doesn't buffer. */
  246         frsize = pth.pth_framelen - sizeof(struct putter_hdr);
  247         if (uio->uio_resid < frsize) {
  248                 return EINVAL;
  249         }
  250 
  251         buf = kmalloc(frsize + sizeof(struct putter_hdr), M_PUTTER, M_WAITOK);
  252         memcpy(buf, &pth, sizeof(pth));
  253         error = uiomove(buf+sizeof(struct putter_hdr), frsize, uio);
  254         if (error == 0) {
  255                 pi->pi_pop->pop_dispatch(pi->pi_private,
  256                     (struct putter_hdr *)buf);
  257         }
  258         kfree(buf, M_PUTTER);
  259 
  260         return error;
  261 }
  262 
  263 /*
  264  * device close = forced unmount.
  265  *
  266  * unmounting is a frightfully complex operation to avoid races
  267  */
  268 static int
  269 putter_fop_close(struct dev_close_args *ap)
  270 {
  271         cdev_t dev = ap->a_head.a_dev;
  272         struct putter_instance *pi = dev->si_drv1;
  273         int rv;
  274 
  275         DPRINTF(("putter_fop_close: device closed\n"));
  276 
  277  restart:
  278         spin_lock(&pi_mtx);
  279         /*
  280          * First check if the driver was never born.  In that case
  281          * remove the instance from the list.  If mount is attempted later,
  282          * it will simply fail.
  283          */
  284         if (pi->pi_private == PUTTER_EMBRYO) {
  285                 TAILQ_REMOVE(&putter_ilist, pi, pi_entries);
  286                 spin_unlock(&pi_mtx);
  287 
  288                 DPRINTF(("putter_fop_close: data associated with dev %i was "
  289                     "embryonic\n", dev->si_uminor));
  290 
  291                 goto out;
  292         }
  293 
  294         /*
  295          * Next, analyze if unmount was called and the instance is dead.
  296          * In this case we can just free the structure and go home, it
  297          * was removed from the list by putter_rmprivate().
  298          */
  299         if (pi->pi_private == PUTTER_DEAD) {
  300                 spin_unlock(&pi_mtx);
  301 
  302                 DPRINTF(("putter_fop_close: putter associated with dev %d "
  303                     "dead, freeing\n", pi->pi_idx));
  304 
  305                 goto out;
  306         }
  307 
  308         /*
  309          * So we have a reference.  Proceed to unravel the
  310          * underlying driver.
  311          */
  312         spin_unlock(&pi_mtx);
  313 
  314         /* hmm?  suspicious locking? */
  315         while ((rv = pi->pi_pop->pop_close(pi->pi_private)) == ERESTART)
  316                 goto restart;
  317 
  318  out:
  319         /*
  320          * Finally, release the instance information.  It was already
  321          * removed from the list by putter_rmprivate() and we know it's
  322          * dead, so no need to lock.
  323          */
  324         kfree(pi, M_PUTTER);
  325 
  326         return 0;
  327 }
  328 
  329 static int
  330 putter_fop_ioctl(struct dev_ioctl_args *ap)
  331 {
  332 
  333         /*
  334          * work already done in sys_ioctl().  skip sanity checks to enable
  335          * setting non-blocking fd on an embryotic driver.
  336          */
  337         if (ap->a_cmd == FIONBIO)
  338                 return 0;
  339 
  340         return EINVAL;
  341 }
  342 
  343 /* kqueue stuff */
  344 
  345 static void
  346 filt_putterdetach(struct knote *kn)
  347 {
  348         struct putter_instance *pi = (void *)kn->kn_hook;
  349         struct klist *klist;
  350 
  351         klist = &pi->pi_kq.ki_note;
  352         knote_remove(klist, kn);
  353 }
  354 
  355 static int
  356 filt_putter_rd(struct knote *kn, long hint)
  357 {
  358         struct putter_instance *pi = (void *)kn->kn_hook;
  359         int error, rv;
  360 
  361         error = 0;
  362         spin_lock(&pi_mtx);
  363         if (pi->pi_private == PUTTER_EMBRYO || pi->pi_private == PUTTER_DEAD)
  364                 error = 1;
  365         spin_unlock(&pi_mtx);
  366         if (error) {
  367                 return 0;
  368         }
  369 
  370         kn->kn_data = pi->pi_pop->pop_waitcount(pi->pi_private);
  371         rv = kn->kn_data != 0;
  372         return rv;
  373 }
  374 
  375 static int
  376 filt_putter_wr(struct knote *kn, long hint)
  377 {
  378         /* Writing is always OK */
  379         kn->kn_data = 0;
  380         return 1;
  381 }
  382 
  383 static struct filterops putter_filtops_rd =
  384         { FILTEROP_ISFD, NULL, filt_putterdetach, filt_putter_rd };
  385 static struct filterops putter_filtops_wr =
  386         { FILTEROP_ISFD, NULL, filt_putterdetach, filt_putter_wr };
  387 
  388 static int
  389 putter_fop_kqfilter(struct dev_kqfilter_args *ap)
  390 {
  391         cdev_t dev = ap->a_head.a_dev;
  392         struct putter_instance *pi = dev->si_drv1;
  393         struct knote *kn = ap->a_kn;
  394         struct klist *klist;
  395 
  396         switch (kn->kn_filter) {
  397         case EVFILT_READ:
  398                 kn->kn_fop = &putter_filtops_rd;
  399                 kn->kn_hook = (char *)pi;
  400                 break;
  401         case EVFILT_WRITE:
  402                 kn->kn_fop = &putter_filtops_wr;
  403                 kn->kn_hook = (char *)pi;
  404                 break;
  405         default:
  406                 ap->a_result = EOPNOTSUPP;
  407                 return 0;
  408         }
  409 
  410         klist = &pi->pi_kq.ki_note;
  411         knote_insert(klist, kn);
  412 
  413         return 0;
  414 }
  415 
  416 int
  417 puttercdopen(struct dev_open_args *ap)
  418 {
  419         cdev_t dev = ap->a_head.a_dev;
  420         struct putter_instance *pi;
  421 
  422         pi = kmalloc(sizeof(struct putter_instance), M_PUTTER,
  423             M_WAITOK | M_ZERO);
  424         dev->si_drv1 = pi;
  425 
  426         pi->pi_pid = curproc->p_pid;
  427         pi->pi_idx = dev->si_uminor;
  428         pi->pi_curput = NULL;
  429         pi->pi_curres = 0;
  430         pi->pi_curopaq = NULL;
  431         pi->pi_private = PUTTER_EMBRYO;
  432 
  433         spin_lock(&pi_mtx);
  434         TAILQ_INSERT_TAIL(&putter_ilist, pi, pi_entries);
  435         spin_unlock(&pi_mtx);
  436 
  437         DPRINTF(("puttercdopen: registered embryonic pmp for pid: %d\n",
  438             pi->pi_pid));
  439         return 0;
  440 }
  441 
  442 
  443 /*
  444  * Set the private structure for the file descriptor.  This is
  445  * typically done immediately when the counterpart has knowledge
  446  * about the private structure's address and the file descriptor
  447  * (e.g. vfs mount routine).
  448  *
  449  * We only want to make sure that the caller had the right to open the
  450  * device, we don't so much care about which context it gets in case
  451  * the same process opened multiple (since they are equal at this point).
  452  */
  453 struct putter_instance *
  454 putter_attach(pid_t pid, int minor, void *ppriv, struct putter_ops *pop)
  455 {
  456         struct putter_instance *pi = NULL;
  457 
  458         spin_lock(&pi_mtx);
  459         TAILQ_FOREACH(pi, &putter_ilist, pi_entries) {
  460                 if (pi->pi_pid == pid && pi->pi_idx == minor &&
  461                     pi->pi_private == PUTTER_EMBRYO) {
  462                         pi->pi_private = ppriv;
  463                         pi->pi_pop = pop;
  464                         break;
  465                     }
  466         }
  467         spin_unlock(&pi_mtx);
  468 
  469         DPRINTF(("putter_setprivate: pi at %p (%d/%d)\n", pi,
  470             pi ? pi->pi_pid : 0, pi ? pi->pi_idx : 0));
  471 
  472         return pi;
  473 }
  474 
  475 /*
  476  * Remove fp <-> private mapping.
  477  */
  478 void
  479 putter_detach(struct putter_instance *pi)
  480 {
  481 
  482         spin_lock(&pi_mtx);
  483         TAILQ_REMOVE(&putter_ilist, pi, pi_entries);
  484         pi->pi_private = PUTTER_DEAD;
  485         spin_unlock(&pi_mtx);
  486 
  487         DPRINTF(("putter_nukebypmp: nuked %p\n", pi));
  488 }
  489 
  490 void
  491 putter_notify(struct putter_instance *pi)
  492 {
  493 
  494         KNOTE(&pi->pi_kq.ki_note, 0);
  495 }
  496 
  497 static int
  498 putter_clone(struct dev_clone_args *ap)
  499 {
  500         int minor;
  501 
  502         minor = devfs_clone_bitmap_get(&DEVFS_CLONE_BITMAP(putter), 0);
  503         ap->a_dev = make_only_dev(&putter_ops, minor, UID_ROOT, GID_WHEEL, 0600,
  504             "putter%d", minor);
  505         return 0;
  506 }
  507 
  508 static int
  509 putter_modevent(module_t mod, int type, void *data)
  510 {
  511         switch (type) {
  512         case MOD_LOAD:
  513                 make_autoclone_dev(&putter_ops, &DEVFS_CLONE_BITMAP(putter),
  514                         putter_clone, UID_ROOT, GID_WHEEL, 0600, "putter");
  515                 break;
  516         case MOD_UNLOAD:
  517                 devfs_clone_handler_del("putter");
  518                 dev_ops_remove_all(&putter_ops);
  519                 devfs_clone_bitmap_uninit(&DEVFS_CLONE_BITMAP(putter));
  520                 break;
  521         default:
  522                 break;
  523         }
  524         return (0);
  525 }
  526 
  527 static moduledata_t putter_mod = {
  528         "putter",
  529         putter_modevent,
  530         NULL
  531 };
  532 DECLARE_MODULE(putter, putter_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
  533 MODULE_VERSION(putter, 1);

Cache object: a5f7e88b30ca67d23b9c3ad6d0e9e71b


[ 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.