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/nfs4client/nfs4_dev.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 /* $FreeBSD: releng/5.2/sys/nfs4client/nfs4_dev.c 122698 2003-11-14 20:54:10Z alfred $ */
    2 /* $Id: nfs4_dev.c,v 1.10 2003/11/05 14:58:59 rees Exp $ */
    3 
    4 /*
    5  * copyright (c) 2003
    6  * the regents of the university of michigan
    7  * all rights reserved
    8  * 
    9  * permission is granted to use, copy, create derivative works and redistribute
   10  * this software and such derivative works for any purpose, so long as the name
   11  * of the university of michigan is not used in any advertising or publicity
   12  * pertaining to the use or distribution of this software without specific,
   13  * written prior authorization.  if the above copyright notice or any other
   14  * identification of the university of michigan is included in any copy of any
   15  * portion of this software, then the disclaimer below must also be included.
   16  * 
   17  * this software is provided as is, without representation from the university
   18  * of michigan as to its fitness for any purpose, and without warranty by the
   19  * university of michigan of any kind, either express or implied, including
   20  * without limitation the implied warranties of merchantability and fitness for
   21  * a particular purpose. the regents of the university of michigan shall not be
   22  * liable for any damages, including special, indirect, incidental, or
   23  * consequential damages, with respect to any claim arising out of or in
   24  * connection with the use of the software, even if it has been or is hereafter
   25  * advised of the possibility of such damages.
   26  */
   27 
   28 #include <sys/param.h>
   29 #include <sys/conf.h>
   30 #include <sys/queue.h>
   31 #include <sys/malloc.h>
   32 #include <sys/kernel.h>
   33 #include <sys/poll.h>
   34 #include <sys/mutex.h>
   35 #include <sys/stat.h>
   36 #include <sys/systm.h>
   37 #include <sys/proc.h>
   38 #include <sys/wait.h>
   39 #include <sys/signalvar.h>
   40 
   41 #include <nfs4client/nfs4_dev.h>
   42 
   43 #ifdef NFS4DEVVERBOSE
   44 #define NFS4DEV_DEBUG(X...) printf(X)
   45 #else
   46 #define NFS4DEV_DEBUG(X...)
   47 #endif
   48 
   49 #define NFS4DEV_NAME "nfs4"
   50 #define CDEV_MAJOR 29 /* XXX where are these numbers assigned!?!?  */
   51 #define CDEV_MINOR 1
   52 
   53 MALLOC_DEFINE(M_NFS4DEV, "NFS4 dev", "NFS4 device");
   54 
   55 struct nfs4dev_upcall {
   56         /* request msg */
   57         struct nfs4dev_msg up_reqmsg;
   58         size_t up_reqmsglen;
   59 
   60         /* reply (payload only) */
   61         caddr_t up_rep;
   62         size_t * up_replen;     
   63 
   64         int up_copied;          /* non-zero when reply has been copied to 
   65                                    '*up_rep' */
   66                                    
   67         int up_error;           /* non-zero if an error occured */
   68 
   69         TAILQ_ENTRY(nfs4dev_upcall) up_entry;
   70 };
   71 
   72 
   73 #define nfs4dev_upcall_get(MP) MALLOC((MP), struct nfs4dev_upcall *, sizeof(struct nfs4dev_upcall), M_NFS4DEV, M_WAITOK | M_ZERO)
   74 
   75 #define nfs4dev_upcall_put(MP) FREE((MP), M_NFS4DEV)
   76 
   77 static int nfs4dev_nopen = 0;
   78 static struct thread * nfs4dev_reader = NULL;
   79 static dev_t nfs4device = 0;
   80 static struct mtx nfs4dev_daemon_mtx;
   81 
   82 static int nfs4dev_xid = 0;
   83 /* queue of pending upcalls */
   84 TAILQ_HEAD(, nfs4dev_upcall) nfs4dev_newq;
   85 static struct mtx nfs4dev_newq_mtx;
   86 
   87 /* queue of upcalls waiting for replys */
   88 TAILQ_HEAD(, nfs4dev_upcall) nfs4dev_waitq;
   89 static struct mtx nfs4dev_waitq_mtx;
   90 
   91 /* dev hooks */
   92 static d_open_t  nfs4dev_open;
   93 static d_close_t nfs4dev_close;
   94 static d_ioctl_t nfs4dev_ioctl;
   95 static d_poll_t  nfs4dev_poll;
   96 
   97 static struct cdevsw nfs4dev_cdevsw = {
   98         .d_open =   nfs4dev_open,
   99         .d_close =  nfs4dev_close,
  100         .d_ioctl =  nfs4dev_ioctl,
  101         .d_poll =   nfs4dev_poll,
  102         .d_name =   NFS4DEV_NAME,
  103         .d_maj =    CDEV_MAJOR
  104 };
  105 
  106 static int nfs4dev_reply(caddr_t);
  107 static int nfs4dev_request(caddr_t);
  108 
  109 /* Userland requests a new operation to service */
  110 static int 
  111 nfs4dev_request(caddr_t addr)
  112 {
  113         struct nfs4dev_upcall * u;
  114         struct nfs4dev_msg * m = (struct nfs4dev_msg *) addr;
  115 
  116         mtx_lock(&nfs4dev_newq_mtx);
  117 
  118         if (TAILQ_EMPTY(&nfs4dev_newq)) {
  119                 mtx_unlock(&nfs4dev_newq_mtx);
  120                 return EAGAIN;  
  121         }
  122 
  123         u = TAILQ_FIRST(&nfs4dev_newq);
  124         TAILQ_REMOVE(&nfs4dev_newq, u, up_entry);
  125         mtx_unlock(&nfs4dev_newq_mtx);
  126 
  127         bcopy(&u->up_reqmsg, m, sizeof(struct nfs4dev_msg));
  128 
  129         mtx_lock(&nfs4dev_waitq_mtx);
  130         TAILQ_INSERT_TAIL(&nfs4dev_waitq, u, up_entry);
  131         mtx_unlock(&nfs4dev_waitq_mtx);
  132 
  133         return 0;
  134 }
  135 
  136 static int
  137 nfs4dev_reply(caddr_t addr)
  138 {
  139         struct nfs4dev_upcall * u;
  140         struct nfs4dev_msg * m = (struct nfs4dev_msg *) addr;
  141         int error;
  142 
  143         if (m->msg_vers != NFS4DEV_VERSION) {
  144                 printf("nfs4dev version mismatch\n");
  145                 return EINVAL;
  146         }
  147 
  148         if (m->msg_type > NFS4DEV_MAX_TYPE) {
  149                 NFS4DEV_DEBUG("nfs4dev: unsupported message type\n");
  150                 return EINVAL;
  151         }
  152 
  153         if (m->msg_len == 0 || m->msg_len > NFS4DEV_MSG_MAX_DATALEN) {
  154                 NFS4DEV_DEBUG("bad message length\n");
  155                 return EINVAL;
  156         }
  157                 
  158         /* match the reply with a request */
  159         mtx_lock(&nfs4dev_waitq_mtx);
  160         TAILQ_FOREACH(u, &nfs4dev_waitq, up_entry) {
  161                 if (m->msg_xid == u->up_reqmsg.msg_xid) {
  162                         if (m->msg_type == u->up_reqmsg.msg_type)
  163                                 goto found;
  164                         NFS4DEV_DEBUG("nfs4dev: op type mismatch!\n");
  165                         break;
  166                 }
  167         }
  168         mtx_unlock(&nfs4dev_waitq_mtx);
  169 
  170         NFS4DEV_DEBUG("nfs4dev msg op: %d xid: %x not found.\n",
  171             m->msg_type, m->msg_xid);
  172 
  173         error = EIO;
  174         goto bad;
  175 
  176 found:
  177         TAILQ_REMOVE(&nfs4dev_waitq, u, up_entry);
  178         mtx_unlock(&nfs4dev_waitq_mtx);
  179 
  180         if (m->msg_error) {
  181                 error = m->msg_error;
  182                 goto bad;
  183         }
  184 
  185         if (m->msg_len > *u->up_replen) {
  186                 error = EFAULT;
  187                 goto bad;
  188         }
  189 
  190         bcopy(m->msg_data, u->up_rep, m->msg_len);
  191         *u->up_replen = m->msg_len;
  192 
  193         u->up_copied = m->msg_len;
  194         wakeup(u);
  195 
  196         return 0;
  197 bad:
  198         u->up_error = error;
  199         wakeup(u);
  200         return error;
  201 }
  202 
  203 void
  204 nfs4dev_init(void)
  205 {
  206         nfs4dev_xid = arc4random();
  207         TAILQ_INIT(&nfs4dev_newq);      
  208         TAILQ_INIT(&nfs4dev_waitq);     
  209         mtx_init(&nfs4dev_newq_mtx, "nfs4dev newq", NULL, MTX_DEF);
  210         mtx_init(&nfs4dev_waitq_mtx, "nfs4dev waitq", NULL, MTX_DEF);
  211 
  212         mtx_init(&nfs4dev_daemon_mtx, "nfs4dev state", NULL, MTX_DEF);
  213 
  214         nfs4device = make_dev(&nfs4dev_cdevsw, CDEV_MINOR, (uid_t)0, (gid_t)0,
  215             S_IRUSR | S_IWUSR, "nfs4");
  216 }
  217 
  218 void
  219 nfs4dev_uninit(void)
  220 {
  221         struct proc * dead = NULL;
  222 
  223         mtx_lock(&nfs4dev_daemon_mtx);
  224         if (nfs4dev_nopen) {
  225                 if (nfs4dev_reader == NULL) {
  226                         NFS4DEV_DEBUG("nfs4dev uninit(): unregistered reader\n");
  227                 } else {
  228                         dead = nfs4dev_reader->td_proc;
  229                 }
  230         }
  231         mtx_unlock(&nfs4dev_daemon_mtx);
  232 
  233         if (dead != NULL) {
  234                 NFS4DEV_DEBUG("nfs4dev_uninit(): you forgot to kill attached daemon (pid: %u)\n",
  235                     dead->p_pid);
  236                 PROC_LOCK(dead);
  237                 psignal(dead, SIGTERM);
  238                 PROC_UNLOCK(dead);
  239         }
  240 
  241         /* XXX moot? */
  242         nfs4dev_purge();
  243 
  244         mtx_destroy(&nfs4dev_newq_mtx);
  245         mtx_destroy(&nfs4dev_waitq_mtx);
  246         mtx_destroy(&nfs4dev_daemon_mtx);
  247 
  248         destroy_dev(nfs4device);
  249 }
  250 
  251 /* device interface functions */
  252 static int
  253 nfs4dev_open(dev_t dev, int flags, int fmt, d_thread_t *td)
  254 {
  255         if (dev != nfs4device) 
  256                 return ENODEV;
  257 
  258         mtx_lock(&nfs4dev_daemon_mtx);
  259         if (nfs4dev_nopen) {
  260                 mtx_unlock(&nfs4dev_daemon_mtx);
  261                 return EBUSY;
  262         }
  263 
  264         nfs4dev_nopen++;
  265         nfs4dev_reader = curthread;
  266         mtx_unlock(&nfs4dev_daemon_mtx);
  267 
  268         return (0);
  269 }
  270 
  271 static int
  272 nfs4dev_close(dev_t dev, int flags, int fmt, d_thread_t *td)
  273 {
  274         struct nfs4dev_upcall * u;
  275 
  276         if (dev != nfs4device) 
  277                 return ENODEV;
  278 
  279         mtx_lock(&nfs4dev_daemon_mtx);
  280         if (!nfs4dev_nopen) {
  281                 mtx_unlock(&nfs4dev_daemon_mtx);
  282                 return ENOENT;
  283         }
  284 
  285         nfs4dev_nopen--; 
  286         nfs4dev_reader = NULL;
  287         mtx_unlock(&nfs4dev_daemon_mtx);
  288 
  289         mtx_lock(&nfs4dev_waitq_mtx);
  290 
  291         while (!TAILQ_EMPTY(&nfs4dev_waitq)) {
  292                 u = TAILQ_FIRST(&nfs4dev_waitq);
  293                 TAILQ_REMOVE(&nfs4dev_waitq, u, up_entry);
  294                 u->up_error = EINTR;
  295                 wakeup(u);
  296         }
  297 
  298         mtx_unlock(&nfs4dev_waitq_mtx);
  299 
  300         return 0;
  301 }
  302 
  303 static int 
  304 nfs4dev_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
  305 {
  306         int error;
  307 
  308         if (dev != nfs4device)
  309                 return ENODEV; 
  310 
  311         if (data == NULL) 
  312                 return EFAULT;
  313 
  314         if (nfs4dev_reader != curthread)
  315                 nfs4dev_reader = curthread;
  316 
  317         switch (cmd) {
  318         case NFS4DEVIOCGET:
  319                 error = nfs4dev_request(data);
  320         break;
  321         case NFS4DEVIOCPUT:
  322                 error = nfs4dev_reply(data);
  323         break;
  324         default:
  325                 NFS4DEV_DEBUG("nfs4dev_ioctl: unkown ioctl cmd %d\n", (int)cmd);
  326                 error = EOPNOTSUPP;
  327         break;
  328         }
  329 
  330         return error;
  331 }
  332 
  333 static int 
  334 nfs4dev_poll(dev_t dev, int events, struct thread *td)
  335 {
  336         int revents;
  337 
  338         if (dev != nfs4device) 
  339           return EINVAL;
  340 
  341         mtx_lock(&nfs4dev_daemon_mtx);
  342         if (nfs4dev_nopen == 0) {
  343                 mtx_unlock(&nfs4dev_daemon_mtx);
  344                 return 0;
  345         }
  346         mtx_unlock(&nfs4dev_daemon_mtx);
  347 
  348         revents = 0;
  349 
  350         /* check readable data */
  351         mtx_lock(&nfs4dev_newq_mtx);
  352           if (!TAILQ_EMPTY(&nfs4dev_newq))
  353             revents |= POLLIN;
  354         mtx_unlock(&nfs4dev_newq_mtx);
  355 
  356         mtx_lock(&nfs4dev_waitq_mtx);
  357           if (!TAILQ_EMPTY(&nfs4dev_waitq))
  358             revents |= POLLOUT;
  359         mtx_unlock(&nfs4dev_waitq_mtx);
  360 
  361         return revents;
  362 }
  363 
  364 int 
  365 nfs4dev_call(uint32_t type, caddr_t req_data, size_t req_len, caddr_t rep_data, size_t * rep_lenp)
  366 {
  367         struct nfs4dev_upcall * u;
  368         int error = 0; 
  369         unsigned int xtmp;
  370 
  371         mtx_lock(&nfs4dev_daemon_mtx);
  372         if (nfs4dev_nopen == 0) {
  373                 mtx_unlock(&nfs4dev_daemon_mtx);
  374                 return EINVAL;
  375         }
  376         mtx_unlock(&nfs4dev_daemon_mtx);
  377 
  378         if (type > NFS4DEV_MAX_TYPE)
  379           return EOPNOTSUPP;
  380 
  381         NFS4DEV_DEBUG("upcall %d/%d:%d\n", type, req_len, *rep_lenp);
  382 
  383         nfs4dev_upcall_get(u);
  384 
  385         u->up_error = 0;
  386         u->up_rep = rep_data;
  387         u->up_replen = rep_lenp;
  388         u->up_copied = 0;
  389 
  390         u->up_reqmsg.msg_vers = NFS4DEV_VERSION;
  391         /* XXX efficient copying */
  392         bcopy(req_data, u->up_reqmsg.msg_data, req_len);
  393         u->up_reqmsg.msg_len  = req_len;
  394 
  395         mtx_lock(&nfs4dev_newq_mtx);
  396 
  397         /* get new XID */
  398         while ((xtmp = arc4random() % 256) == 0);
  399         nfs4dev_xid += xtmp;
  400         u->up_reqmsg.msg_xid = nfs4dev_xid;
  401 
  402         TAILQ_INSERT_TAIL(&nfs4dev_newq, u, up_entry);
  403         mtx_unlock(&nfs4dev_newq_mtx);
  404 
  405 
  406         NFS4DEV_DEBUG("nfs4dev op: %d xid: %x sleeping\n", u->up_reqmsg.msg_type, u->up_reqmsg.msg_xid);
  407 
  408         do {
  409                 tsleep(u, PLOCK, "nfs4dev", 0);
  410         } while (u->up_copied == 0 && u->up_error == 0);
  411 
  412         /* upcall now removed from the queue */
  413 
  414         NFS4DEV_DEBUG("nfs4dev prog: %d xid: %x continues...\n", 
  415             u->up_reqmsg.msg_type, u->up_reqmsg.msg_xid);
  416 
  417         if (u->up_error) {
  418                 error = u->up_error; 
  419                 NFS4DEV_DEBUG("nfs4dev prog: %d xid: %x error: %d\n", 
  420                     u->up_reqmsg.msg_type, u->up_reqmsg.msg_xid, u->up_error);
  421                 goto out;
  422         }
  423 
  424 out:
  425         nfs4dev_upcall_put(u);
  426         return error;
  427 }
  428 
  429 void
  430 nfs4dev_purge(void)
  431 {
  432         struct nfs4dev_upcall * u;
  433 
  434         mtx_lock(&nfs4dev_newq_mtx);
  435         while (!TAILQ_EMPTY(&nfs4dev_newq)) {
  436                 u = TAILQ_FIRST(&nfs4dev_newq);
  437                 TAILQ_REMOVE(&nfs4dev_newq, u, up_entry);
  438                 u->up_error = EINTR;
  439                 wakeup(u);
  440         }
  441         mtx_unlock(&nfs4dev_newq_mtx);
  442 
  443         mtx_lock(&nfs4dev_waitq_mtx);
  444         while (!TAILQ_EMPTY(&nfs4dev_waitq)) {
  445                 u = TAILQ_FIRST(&nfs4dev_waitq);
  446                 TAILQ_REMOVE(&nfs4dev_waitq, u, up_entry);
  447                 u->up_error = EINTR;
  448                 wakeup(u);
  449         }
  450         mtx_unlock(&nfs4dev_waitq_mtx);
  451 }

Cache object: 6ae579120138d671b3fc1fa73220709e


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