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/dmover/dmover_io.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: dmover_io.c,v 1.13 2003/09/13 08:32:12 jdolecek Exp $  */
    2 
    3 /*
    4  * Copyright (c) 2002, 2003 Wasabi Systems, Inc.
    5  * All rights reserved.
    6  *
    7  * Written by Jason R. Thorpe for Wasabi Systems, Inc.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  * 3. All advertising materials mentioning features or use of this software
   18  *    must display the following acknowledgement:
   19  *      This product includes software developed for the NetBSD Project by
   20  *      Wasabi Systems, Inc.
   21  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
   22  *    or promote products derived from this software without specific prior
   23  *    written permission.
   24  *
   25  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
   26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   27  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   28  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
   29  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   30  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   31  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   33  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   34  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   35  * POSSIBILITY OF SUCH DAMAGE.
   36  */
   37 
   38 /*
   39  * dmover_io.c: Support for user-space access to dmover-api
   40  *
   41  * This interface is quite simple:
   42  *
   43  *      1.  The user opens /dev/dmover, which is a cloning device.  This
   44  *          allocates internal state for the session.
   45  *
   46  *      2.  The user does a DMIO_SETFUNC to select the data movement
   47  *          function.  This actually creates the dmover session.
   48  *
   49  *      3.  The user writes request messages to its dmover handle.
   50  *
   51  *      4.  The user reads request responses from its dmover handle.
   52  *
   53  *      5.  The user closes the file descriptor and the session is
   54  *          torn down.
   55  */
   56 
   57 #include <sys/cdefs.h>
   58 __KERNEL_RCSID(0, "$NetBSD: dmover_io.c,v 1.13 2003/09/13 08:32:12 jdolecek Exp $");
   59 
   60 #include <sys/param.h>
   61 #include <sys/queue.h>
   62 #include <sys/conf.h>
   63 #include <sys/pool.h>
   64 #include <sys/proc.h>
   65 #include <sys/poll.h>
   66 #include <sys/malloc.h>
   67 #include <sys/lock.h>
   68 #include <sys/file.h>
   69 #include <sys/filedesc.h>
   70 #include <sys/filio.h>
   71 #include <sys/select.h>
   72 #include <sys/systm.h>
   73 
   74 #include <dev/dmover/dmovervar.h>
   75 #include <dev/dmover/dmover_io.h>
   76 
   77 struct dmio_usrreq_state {
   78         TAILQ_ENTRY(dmio_usrreq_state) dus_q;
   79         struct uio dus_uio_out;
   80         struct uio *dus_uio_in;
   81         struct dmover_request *dus_req;
   82         uint32_t dus_id;
   83 };
   84 
   85 struct dmio_state {
   86         struct dmover_session *ds_session;
   87         TAILQ_HEAD(, dmio_usrreq_state) ds_pending;
   88         TAILQ_HEAD(, dmio_usrreq_state) ds_complete;
   89         struct selinfo ds_selq;
   90         __volatile int ds_flags;
   91         u_int ds_nreqs;
   92         struct simplelock ds_slock;
   93 };
   94 
   95 #define DMIO_STATE_SEL          0x0001
   96 #define DMIO_STATE_DEAD         0x0002
   97 #define DMIO_STATE_LARVAL       0x0004
   98 #define DMIO_STATE_READ_WAIT    0x0008
   99 #define DMIO_STATE_WRITE_WAIT   0x0010
  100 
  101 #define DMIO_NREQS_MAX          64      /* XXX pulled out of a hat */
  102 
  103 struct pool dmio_state_pool;
  104 struct pool dmio_usrreq_state_pool;
  105 
  106 void    dmoverioattach(int);
  107 
  108 dev_type_open(dmoverioopen);
  109 
  110 const struct cdevsw dmoverio_cdevsw = {
  111         dmoverioopen, noclose, noread, nowrite, noioctl,
  112         nostop, notty, nopoll, nommap, nokqfilter,
  113 };
  114 
  115 /*
  116  * dmoverioattach:
  117  *
  118  *      Pseudo-device attach routine.
  119  */
  120 void
  121 dmoverioattach(int count)
  122 {
  123 
  124         pool_init(&dmio_state_pool, sizeof(struct dmio_state),
  125             0, 0, 0, "dmiostate", NULL);
  126         pool_init(&dmio_usrreq_state_pool, sizeof(struct dmio_usrreq_state),
  127             0, 0, 0, "dmiourstate", NULL);
  128 }
  129 
  130 /*
  131  * dmio_usrreq_init:
  132  *
  133  *      Build a request structure.
  134  */
  135 static int
  136 dmio_usrreq_init(struct file *fp, struct dmio_usrreq_state *dus,
  137     struct dmio_usrreq *req, struct dmover_request *dreq)
  138 {
  139         struct dmio_state *ds = (struct dmio_state *) fp->f_data;
  140         struct dmover_session *dses = ds->ds_session;
  141         struct uio *uio_out = &dus->dus_uio_out;
  142         struct uio *uio_in;
  143         dmio_buffer inbuf;
  144         size_t len;
  145         int i, error;
  146         u_int j;
  147 
  148         /* XXX How should malloc interact w/ FNONBLOCK? */
  149 
  150         if (req->req_outbuf.dmbuf_iovcnt != 0) {
  151                 if (req->req_outbuf.dmbuf_iovcnt > IOV_MAX)
  152                         return (EINVAL);
  153                 len = sizeof(struct iovec) * req->req_outbuf.dmbuf_iovcnt;
  154                 uio_out->uio_iov = malloc(len, M_TEMP, M_WAITOK);
  155                 error = copyin(req->req_outbuf.dmbuf_iov, uio_out->uio_iov,
  156                     len);
  157                 if (error) {
  158                         free(uio_out->uio_iov, M_TEMP);
  159                         return (error);
  160                 }
  161 
  162                 for (j = 0, len = 0; j < req->req_outbuf.dmbuf_iovcnt; j++) {
  163                         len += uio_out->uio_iov[j].iov_len;
  164                         if (len > SSIZE_MAX) {
  165                                 free(uio_out->uio_iov, M_TEMP);
  166                                 return (EINVAL);
  167                         }
  168                 }
  169 
  170                 uio_out->uio_iovcnt = req->req_outbuf.dmbuf_iovcnt;
  171                 uio_out->uio_resid = len;
  172                 uio_out->uio_rw = UIO_READ;
  173                 uio_out->uio_segflg = UIO_USERSPACE;
  174                 uio_out->uio_procp = curproc;
  175                 dreq->dreq_outbuf_type = DMOVER_BUF_UIO;
  176                 dreq->dreq_outbuf.dmbuf_uio = uio_out;
  177         } else {
  178                 uio_out->uio_iov = NULL;
  179                 uio_out = NULL;
  180                 dreq->dreq_outbuf_type = DMOVER_BUF_NONE;
  181         }
  182 
  183         memcpy(dreq->dreq_immediate, req->req_immediate,
  184             sizeof(dreq->dreq_immediate));
  185 
  186         if (dses->dses_ninputs == 0) {
  187                 /* No inputs; all done. */
  188                 return (0);
  189         }
  190 
  191         dreq->dreq_inbuf_type = DMOVER_BUF_UIO;
  192 
  193         dus->dus_uio_in = malloc(sizeof(struct uio) * dses->dses_ninputs,
  194             M_TEMP, M_WAITOK);
  195         memset(dus->dus_uio_in, 0, sizeof(struct uio) * dses->dses_ninputs);
  196 
  197         for (i = 0; i < dses->dses_ninputs; i++) {
  198                 uio_in = &dus->dus_uio_in[i];
  199 
  200                 error = copyin(&req->req_inbuf[i], &inbuf, sizeof(inbuf));
  201                 if (error)
  202                         goto bad;
  203 
  204                 if (inbuf.dmbuf_iovcnt > IOV_MAX) {
  205                         error = EINVAL;
  206                         goto bad;
  207                 }
  208                 len = sizeof(struct iovec) * inbuf.dmbuf_iovcnt;
  209                 if (len == 0) {
  210                         error = EINVAL;
  211                         goto bad;
  212                 }
  213                 uio_in->uio_iov = malloc(len, M_TEMP, M_WAITOK);
  214 
  215                 error = copyin(inbuf.dmbuf_iov, uio_in->uio_iov, len);
  216                 if (error) {
  217                         free(uio_in->uio_iov, M_TEMP);
  218                         goto bad;
  219                 }
  220 
  221                 for (j = 0, len = 0; j < inbuf.dmbuf_iovcnt; j++) {
  222                         len += uio_in->uio_iov[j].iov_len;
  223                         if (len > SSIZE_MAX) {
  224                                 free(uio_in->uio_iov, M_TEMP);
  225                                 error = EINVAL;
  226                                 goto bad;
  227                         }
  228                 }
  229 
  230                 if (uio_out != NULL && len != uio_out->uio_resid) {
  231                         free(uio_in->uio_iov, M_TEMP);
  232                         error = EINVAL;
  233                         goto bad;
  234                 }
  235 
  236                 uio_in->uio_iovcnt = inbuf.dmbuf_iovcnt;
  237                 uio_in->uio_resid = len;
  238                 uio_in->uio_rw = UIO_WRITE;
  239                 uio_in->uio_segflg = UIO_USERSPACE;
  240                 uio_in->uio_procp = curproc;
  241 
  242                 dreq->dreq_inbuf[i].dmbuf_uio = uio_in;
  243         }
  244 
  245         return (0);
  246 
  247  bad:
  248         if (i > 0) {
  249                 for (--i; i >= 0; i--) {
  250                         uio_in = &dus->dus_uio_in[i];
  251                         free(uio_in->uio_iov, M_TEMP);
  252                 }
  253         }
  254         free(dus->dus_uio_in, M_TEMP);
  255         if (uio_out != NULL)
  256                 free(uio_out->uio_iov, M_TEMP);
  257         return (error);
  258 }
  259 
  260 /*
  261  * dmio_usrreq_fini:
  262  *
  263  *      Tear down a request.  Must be called at splsoftclock().
  264  */
  265 static void
  266 dmio_usrreq_fini(struct dmio_state *ds, struct dmio_usrreq_state *dus)
  267 {
  268         struct dmover_session *dses = ds->ds_session;
  269         struct uio *uio_out = &dus->dus_uio_out;
  270         struct uio *uio_in;
  271         int i;
  272 
  273         if (uio_out->uio_iov != NULL)
  274                 free(uio_out->uio_iov, M_TEMP);
  275 
  276         if (dses->dses_ninputs == 0) {
  277                 pool_put(&dmio_usrreq_state_pool, dus);
  278                 return;
  279         }
  280 
  281         for (i = 0; i < dses->dses_ninputs; i++) {
  282                 uio_in = &dus->dus_uio_in[i];
  283                 free(uio_in->uio_iov, M_TEMP);
  284         }
  285 
  286         free(dus->dus_uio_in, M_TEMP);
  287 
  288         pool_put(&dmio_usrreq_state_pool, dus);
  289 }
  290 
  291 /*
  292  * dmio_read:
  293  *
  294  *      Read file op.
  295  */
  296 static int
  297 dmio_read(struct file *fp, off_t *offp, struct uio *uio,
  298     struct ucred *cred, int flags)
  299 {
  300         struct dmio_state *ds = (struct dmio_state *) fp->f_data;
  301         struct dmio_usrreq_state *dus;
  302         struct dmover_request *dreq;
  303         struct dmio_usrresp resp;
  304         int s, error = 0, progress = 0;
  305 
  306         if ((uio->uio_resid % sizeof(resp)) != 0)
  307                 return (EINVAL);
  308 
  309         if (ds->ds_session == NULL)
  310                 return (ENXIO);
  311 
  312         s = splsoftclock();
  313         simple_lock(&ds->ds_slock);
  314 
  315         while (uio->uio_resid != 0) {
  316 
  317                 for (;;) {
  318                         dus = TAILQ_FIRST(&ds->ds_complete);
  319                         if (dus == NULL) {
  320                                 if (fp->f_flag & FNONBLOCK) {
  321                                         error = progress ? 0 : EWOULDBLOCK;
  322                                         goto out;
  323                                 }
  324                                 ds->ds_flags |= DMIO_STATE_READ_WAIT;
  325                                 error = ltsleep(&ds->ds_complete,
  326                                     PRIBIO | PCATCH, "dmvrrd", 0,
  327                                     &ds->ds_slock);
  328                                 if (error)
  329                                         goto out;
  330                                 continue;
  331                         }
  332                         /* Have a completed request. */
  333                         TAILQ_REMOVE(&ds->ds_complete, dus, dus_q);
  334                         ds->ds_nreqs--;
  335                         if (ds->ds_flags & DMIO_STATE_WRITE_WAIT) {
  336                                 ds->ds_flags &= ~DMIO_STATE_WRITE_WAIT;
  337                                 wakeup(&ds->ds_nreqs);
  338                         }
  339                         if (ds->ds_flags & DMIO_STATE_SEL) {
  340                                 ds->ds_flags &= ~DMIO_STATE_SEL;
  341                                 selwakeup(&ds->ds_selq);
  342                         }
  343                         break;
  344                 }
  345 
  346                 simple_unlock(&ds->ds_slock);
  347 
  348                 dreq = dus->dus_req;
  349                 resp.resp_id = dus->dus_id;
  350                 if (dreq->dreq_flags & DMOVER_REQ_ERROR)
  351                         resp.resp_error = dreq->dreq_error;
  352                 else {
  353                         resp.resp_error = 0;
  354                         memcpy(resp.resp_immediate, dreq->dreq_immediate,
  355                             sizeof(resp.resp_immediate));
  356                 }
  357 
  358                 dmio_usrreq_fini(ds, dus);
  359 
  360                 splx(s);
  361 
  362                 progress = 1;
  363 
  364                 dmover_request_free(dreq);
  365 
  366                 error = uiomove(&resp, sizeof(resp), uio);
  367                 if (error)
  368                         return (error);
  369 
  370                 s = splsoftclock();
  371                 simple_lock(&ds->ds_slock);
  372         }
  373 
  374  out:
  375         simple_unlock(&ds->ds_slock);
  376         splx(s);
  377 
  378         return (error);
  379 }
  380 
  381 /*
  382  * dmio_usrreq_done:
  383  *
  384  *      Dmover completion callback.
  385  */
  386 static void
  387 dmio_usrreq_done(struct dmover_request *dreq)
  388 {
  389         struct dmio_usrreq_state *dus = dreq->dreq_cookie;
  390         struct dmio_state *ds = dreq->dreq_session->dses_cookie;
  391 
  392         /* We're already at splsoftclock(). */
  393 
  394         simple_lock(&ds->ds_slock);
  395         TAILQ_REMOVE(&ds->ds_pending, dus, dus_q);
  396         if (ds->ds_flags & DMIO_STATE_DEAD) {
  397                 ds->ds_nreqs--;
  398                 dmio_usrreq_fini(ds, dus);
  399                 dmover_request_free(dreq);
  400                 if (ds->ds_nreqs == 0) {
  401                         simple_unlock(&ds->ds_slock);
  402                         pool_put(&dmio_state_pool, ds);
  403                         return;
  404                 }
  405         } else {
  406                 TAILQ_INSERT_TAIL(&ds->ds_complete, dus, dus_q);
  407                 if (ds->ds_flags & DMIO_STATE_READ_WAIT) {
  408                         ds->ds_flags &= ~DMIO_STATE_READ_WAIT;
  409                         wakeup(&ds->ds_complete);
  410                 }
  411                 if (ds->ds_flags & DMIO_STATE_SEL) {
  412                         ds->ds_flags &= ~DMIO_STATE_SEL;
  413                         selwakeup(&ds->ds_selq);
  414                 }
  415         }
  416         simple_unlock(&ds->ds_slock);
  417 }
  418 
  419 /*
  420  * dmio_write:
  421  *
  422  *      Write file op.
  423  */
  424 static int
  425 dmio_write(struct file *fp, off_t *offp, struct uio *uio,
  426     struct ucred *cred, int flags)
  427 {
  428         struct dmio_state *ds = (struct dmio_state *) fp->f_data;
  429         struct dmio_usrreq_state *dus;
  430         struct dmover_request *dreq;
  431         struct dmio_usrreq req;
  432         int error = 0, s, progress = 0;
  433 
  434         if ((uio->uio_resid % sizeof(req)) != 0)
  435                 return (EINVAL);
  436 
  437         if (ds->ds_session == NULL)
  438                 return (ENXIO);
  439 
  440         s = splsoftclock();
  441         simple_lock(&ds->ds_slock);
  442 
  443         while (uio->uio_resid != 0) {
  444 
  445                 if (ds->ds_nreqs == DMIO_NREQS_MAX) {
  446                         if (fp->f_flag & FNONBLOCK) {
  447                                 error = progress ? 0 : EWOULDBLOCK;
  448                                 break;
  449                         }
  450                         ds->ds_flags |= DMIO_STATE_WRITE_WAIT;
  451                         error = ltsleep(&ds->ds_nreqs, PRIBIO | PCATCH,
  452                             "dmiowr", 0, &ds->ds_slock);
  453                         if (error)
  454                                 break;
  455                         continue;
  456                 }
  457 
  458                 ds->ds_nreqs++;
  459 
  460                 simple_unlock(&ds->ds_slock);
  461                 splx(s);
  462 
  463                 progress = 1;
  464 
  465                 error = uiomove(&req, sizeof(req), uio);
  466                 if (error) {
  467                         s = splsoftclock();
  468                         simple_lock(&ds->ds_slock);
  469                         ds->ds_nreqs--;
  470                         break;
  471                 }
  472 
  473                 /* XXX How should this interact with FNONBLOCK? */
  474                 dreq = dmover_request_alloc(ds->ds_session, NULL);
  475                 if (dreq == NULL) {
  476                         /* XXX */
  477                         s = splsoftclock();
  478                         simple_lock(&ds->ds_slock);
  479                         ds->ds_nreqs--;
  480                         error = ENOMEM;
  481                         break;
  482                 }
  483                 s = splsoftclock();
  484                 dus = pool_get(&dmio_usrreq_state_pool, PR_WAITOK);
  485                 splx(s);
  486 
  487                 error = dmio_usrreq_init(fp, dus, &req, dreq);
  488                 if (error) {
  489                         dmover_request_free(dreq);
  490                         s = splsoftclock();
  491                         pool_put(&dmio_usrreq_state_pool, dus);
  492                         simple_lock(&ds->ds_slock);
  493                         break;
  494                 }
  495 
  496                 dreq->dreq_callback = dmio_usrreq_done;
  497                 dreq->dreq_cookie = dus;
  498 
  499                 dus->dus_req = dreq;
  500                 dus->dus_id = req.req_id;
  501 
  502                 s = splsoftclock();
  503                 simple_lock(&ds->ds_slock);
  504 
  505                 TAILQ_INSERT_TAIL(&ds->ds_pending, dus, dus_q);
  506 
  507                 simple_unlock(&ds->ds_slock);
  508                 splx(s);
  509 
  510                 dmover_process(dreq);
  511 
  512                 s = splsoftclock();
  513                 simple_lock(&ds->ds_slock);
  514         }
  515 
  516         simple_unlock(&ds->ds_slock);
  517         splx(s);
  518 
  519         return (error);
  520 }
  521 
  522 /*
  523  * dmio_ioctl:
  524  *
  525  *      Ioctl file op.
  526  */
  527 static int
  528 dmio_ioctl(struct file *fp, u_long cmd, void *data, struct proc *p)
  529 {
  530         struct dmio_state *ds = (struct dmio_state *) fp->f_data;
  531         int error, s;
  532 
  533         switch (cmd) {
  534         case FIONBIO:
  535         case FIOASYNC:
  536                 return (0);
  537 
  538         case DMIO_SETFUNC:
  539             {
  540                 struct dmio_setfunc *dsf = data;
  541                 struct dmover_session *dses;
  542 
  543                 s = splsoftclock();
  544                 simple_lock(&ds->ds_slock);
  545 
  546                 if (ds->ds_session != NULL ||
  547                     (ds->ds_flags & DMIO_STATE_LARVAL) != 0) {
  548                         simple_unlock(&ds->ds_slock);
  549                         splx(s);
  550                         return (EBUSY);
  551                 }
  552 
  553                 ds->ds_flags |= DMIO_STATE_LARVAL;
  554 
  555                 simple_unlock(&ds->ds_slock);
  556                 splx(s);
  557 
  558                 dsf->dsf_name[DMIO_MAX_FUNCNAME - 1] = '\0';
  559                 error = dmover_session_create(dsf->dsf_name, &dses);
  560 
  561                 s = splsoftclock();
  562                 simple_lock(&ds->ds_slock);
  563 
  564                 if (error == 0) {
  565                         dses->dses_cookie = ds;
  566                         ds->ds_session = dses;
  567                 }
  568                 ds->ds_flags &= ~DMIO_STATE_LARVAL;
  569 
  570                 simple_unlock(&ds->ds_slock);
  571                 splx(s);
  572                 break;
  573             }
  574 
  575         default:
  576                 error = ENOTTY;
  577         }
  578 
  579         return (error);
  580 }
  581 
  582 /*
  583  * dmio_fcntl:
  584  *
  585  *      Fcntl file op.
  586  */
  587 static int
  588 dmio_fcntl(struct file *fp, u_int cmd, void *data, struct proc *p)
  589 {
  590 
  591         if (cmd == FNONBLOCK || cmd == FASYNC)
  592                 return (0);
  593 
  594         return (EOPNOTSUPP);
  595 }
  596 
  597 /*
  598  * dmio_poll:
  599  *
  600  *      Poll file op.
  601  */
  602 static int
  603 dmio_poll(struct file *fp, int events, struct proc *p)
  604 {
  605         struct dmio_state *ds = (struct dmio_state *) fp->f_data;
  606         int s, revents = 0;
  607 
  608         if ((events & (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM)) == 0)
  609                 return (revents);
  610 
  611         s = splsoftclock();
  612         simple_lock(&ds->ds_slock);
  613 
  614         if (ds->ds_flags & DMIO_STATE_DEAD) {
  615                 /* EOF */
  616                 revents |= events & (POLLIN | POLLRDNORM |
  617                     POLLOUT | POLLWRNORM);
  618                 goto out;
  619         }
  620 
  621         /* We can read if there are completed requests. */
  622         if (events & (POLLIN | POLLRDNORM))
  623                 if (TAILQ_EMPTY(&ds->ds_complete) == 0)
  624                         revents |= events & (POLLIN | POLLRDNORM);
  625 
  626         /*
  627          * We can write if there is there are fewer then DMIO_NREQS_MAX
  628          * are already in the queue.
  629          */
  630         if (events & (POLLOUT | POLLWRNORM))
  631                 if (ds->ds_nreqs < DMIO_NREQS_MAX)
  632                         revents |= events & (POLLOUT | POLLWRNORM);
  633 
  634         if (revents == 0) {
  635                 selrecord(p, &ds->ds_selq);
  636                 ds->ds_flags |= DMIO_STATE_SEL;
  637         }
  638 
  639  out:
  640         simple_unlock(&ds->ds_slock);
  641         splx(s);
  642 
  643         return (revents);
  644 }
  645 
  646 /*
  647  * dmio_stat:
  648  *
  649  *      Stat file op.
  650  */
  651 static int
  652 dmio_stat(struct file *fp, struct stat *sb, struct proc *p)
  653 {
  654 
  655         return (EOPNOTSUPP);
  656 }
  657 
  658 /*
  659  * dmio_close:
  660  *
  661  *      Close file op.
  662  */
  663 static int
  664 dmio_close(struct file *fp, struct proc *p)
  665 {
  666         struct dmio_state *ds = (struct dmio_state *) fp->f_data;
  667         struct dmio_usrreq_state *dus;
  668         struct dmover_session *dses;
  669         int s;
  670 
  671         s = splsoftclock();
  672         simple_lock(&ds->ds_slock);
  673 
  674         ds->ds_flags |= DMIO_STATE_DEAD;
  675 
  676         /* Garbage-collect all the responses on the queue. */
  677         while ((dus = TAILQ_FIRST(&ds->ds_complete)) != NULL) {
  678                 TAILQ_REMOVE(&ds->ds_complete, dus, dus_q);
  679                 ds->ds_nreqs--;
  680                 dmover_request_free(dus->dus_req);
  681                 dmio_usrreq_fini(ds, dus);
  682         }
  683 
  684         /*
  685          * If there are any requests pending, we have to wait for
  686          * them.  Don't free the dmio_state in this case.
  687          */
  688         if (ds->ds_nreqs == 0) {
  689                 dses = ds->ds_session;
  690                 simple_unlock(&ds->ds_slock);
  691                 pool_put(&dmio_state_pool, ds);
  692         } else {
  693                 dses = NULL;
  694                 simple_unlock(&ds->ds_slock);
  695         }
  696 
  697         splx(s);
  698 
  699         fp->f_data = NULL;
  700 
  701         if (dses != NULL)
  702                 dmover_session_destroy(dses);
  703 
  704         return (0);
  705 }
  706 
  707 static struct fileops dmio_fileops = {
  708         dmio_read,
  709         dmio_write,
  710         dmio_ioctl,
  711         dmio_fcntl,
  712         dmio_poll,
  713         dmio_stat,
  714         dmio_close,
  715 };
  716 
  717 /*
  718  * dmoverioopen:
  719  *
  720  *      Device switch open routine.
  721  */
  722 int
  723 dmoverioopen(dev_t dev, int flag, int mode, struct proc *p)
  724 {
  725         struct dmio_state *ds;
  726         struct file *fp;
  727         int error, fd, s;
  728 
  729         /* falloc() will use the descriptor for us. */
  730         if ((error = falloc(p, &fp, &fd)) != 0)
  731                 return (error);
  732 
  733         s = splsoftclock();
  734         ds = pool_get(&dmio_state_pool, PR_WAITOK);
  735         splx(s);
  736 
  737         memset(ds, 0, sizeof(*ds));
  738         TAILQ_INIT(&ds->ds_pending);
  739         TAILQ_INIT(&ds->ds_complete);
  740 
  741         fp->f_flag = FREAD | FWRITE;
  742         fp->f_type = DTYPE_MISC;
  743         fp->f_ops = &dmio_fileops;
  744         fp->f_data = (caddr_t) ds;
  745 
  746         curlwp->l_dupfd = fd;   /* XXX */
  747         FILE_SET_MATURE(fp);
  748         FILE_UNUSE(fp, p);
  749 
  750         return (ENXIO);
  751 }

Cache object: 1c8bd6650de5dba0f305b191464c79c2


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