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$ */
    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_MINOR 1
   51 
   52 MALLOC_DEFINE(M_NFS4DEV, "nfs4_dev", "NFS4 device");
   53 
   54 struct nfs4dev_upcall {
   55         /* request msg */
   56         struct nfs4dev_msg up_reqmsg;
   57         size_t up_reqmsglen;
   58 
   59         /* reply (payload only) */
   60         caddr_t up_rep;
   61         size_t * up_replen;     
   62 
   63         int up_copied;          /* non-zero when reply has been copied to 
   64                                    '*up_rep' */
   65                                    
   66         int up_error;           /* non-zero if an error occured */
   67 
   68         TAILQ_ENTRY(nfs4dev_upcall) up_entry;
   69 };
   70 
   71 
   72 #define nfs4dev_upcall_get(MP) MALLOC((MP), struct nfs4dev_upcall *, sizeof(struct nfs4dev_upcall), M_NFS4DEV, M_WAITOK | M_ZERO)
   73 
   74 #define nfs4dev_upcall_put(MP) FREE((MP), M_NFS4DEV)
   75 
   76 static int nfs4dev_nopen = 0;
   77 static struct thread * nfs4dev_reader = NULL;
   78 static struct cdev *nfs4device = 0;
   79 static struct mtx nfs4dev_daemon_mtx;
   80 
   81 static int nfs4dev_xid = 0;
   82 /* queue of pending upcalls */
   83 TAILQ_HEAD(, nfs4dev_upcall) nfs4dev_newq;
   84 static struct mtx nfs4dev_newq_mtx;
   85 
   86 /* queue of upcalls waiting for replys */
   87 TAILQ_HEAD(, nfs4dev_upcall) nfs4dev_waitq;
   88 static struct mtx nfs4dev_waitq_mtx;
   89 
   90 /* dev hooks */
   91 static d_open_t  nfs4dev_open;
   92 static d_close_t nfs4dev_close;
   93 static d_ioctl_t nfs4dev_ioctl;
   94 static d_poll_t  nfs4dev_poll;
   95 
   96 static struct cdevsw nfs4dev_cdevsw = {
   97 #if (__FreeBSD_version > 502102)
   98         .d_version =    D_VERSION,
   99         .d_flags =      D_NEEDGIANT,
  100 #endif
  101         .d_open =       nfs4dev_open,
  102         .d_close =      nfs4dev_close,
  103         .d_ioctl =      nfs4dev_ioctl,
  104         .d_poll =       nfs4dev_poll,
  105         .d_name =       NFS4DEV_NAME,
  106 };
  107 
  108 static int nfs4dev_reply(caddr_t);
  109 static int nfs4dev_request(caddr_t);
  110 
  111 /* Userland requests a new operation to service */
  112 static int 
  113 nfs4dev_request(caddr_t addr)
  114 {
  115         struct nfs4dev_upcall * u;
  116         struct nfs4dev_msg * m = (struct nfs4dev_msg *) addr;
  117 
  118         mtx_lock(&nfs4dev_newq_mtx);
  119 
  120         if (TAILQ_EMPTY(&nfs4dev_newq)) {
  121                 mtx_unlock(&nfs4dev_newq_mtx);
  122                 return EAGAIN;  
  123         }
  124 
  125         u = TAILQ_FIRST(&nfs4dev_newq);
  126         TAILQ_REMOVE(&nfs4dev_newq, u, up_entry);
  127         mtx_unlock(&nfs4dev_newq_mtx);
  128 
  129         bcopy(&u->up_reqmsg, m, sizeof(struct nfs4dev_msg));
  130 
  131         mtx_lock(&nfs4dev_waitq_mtx);
  132         TAILQ_INSERT_TAIL(&nfs4dev_waitq, u, up_entry);
  133         mtx_unlock(&nfs4dev_waitq_mtx);
  134 
  135         return 0;
  136 }
  137 
  138 static int
  139 nfs4dev_reply(caddr_t addr)
  140 {
  141         struct nfs4dev_upcall * u;
  142         struct nfs4dev_msg * m = (struct nfs4dev_msg *) addr;
  143         int error;
  144 
  145         if (m->msg_vers != NFS4DEV_VERSION) {
  146                 printf("nfs4dev version mismatch\n");
  147                 return EINVAL;
  148         }
  149 
  150         if (m->msg_type > NFS4DEV_MAX_TYPE) {
  151                 NFS4DEV_DEBUG("nfs4dev: unsupported message type\n");
  152                 return EINVAL;
  153         }
  154 
  155         if (m->msg_len < sizeof(*m) - NFS4DEV_MSG_MAX_DATALEN ||
  156                 m->msg_len > NFS4DEV_MSG_MAX_DATALEN) {
  157                 NFS4DEV_DEBUG("bad message length\n");
  158                 return EINVAL;
  159         }
  160 
  161         /* match the reply with a request */
  162         mtx_lock(&nfs4dev_waitq_mtx);
  163         TAILQ_FOREACH(u, &nfs4dev_waitq, up_entry) {
  164                 if (m->msg_xid == u->up_reqmsg.msg_xid) {
  165                         if (m->msg_type == u->up_reqmsg.msg_type)
  166                                 goto found;
  167                         NFS4DEV_DEBUG("nfs4dev: op type mismatch!\n");
  168                         break;
  169                 }
  170         }
  171         mtx_unlock(&nfs4dev_waitq_mtx);
  172 
  173         NFS4DEV_DEBUG("nfs4dev msg op: %d xid: %x not found.\n",
  174             m->msg_type, m->msg_xid);
  175 
  176         error = EIO;
  177         goto bad;
  178 
  179 found:
  180         TAILQ_REMOVE(&nfs4dev_waitq, u, up_entry);
  181         mtx_unlock(&nfs4dev_waitq_mtx);
  182 
  183         if (m->msg_error) {
  184                 error = m->msg_error;
  185                 goto bad;
  186         }
  187 
  188         if (m->msg_len > *u->up_replen) {
  189                 error = EFAULT;
  190                 goto bad;
  191         }
  192 
  193         bcopy(m->msg_data, u->up_rep, m->msg_len);
  194         *u->up_replen = m->msg_len;
  195 
  196         u->up_copied = m->msg_len;
  197         wakeup(u);
  198 
  199         return 0;
  200 bad:
  201         if (u) {
  202                 u->up_error = error;
  203                 wakeup(u);
  204         }
  205         return error;
  206 }
  207 
  208 void
  209 nfs4dev_init(void)
  210 {
  211         nfs4dev_xid = arc4random();
  212         TAILQ_INIT(&nfs4dev_newq);      
  213         TAILQ_INIT(&nfs4dev_waitq);     
  214         mtx_init(&nfs4dev_newq_mtx, "nfs4dev newq", NULL, MTX_DEF);
  215         mtx_init(&nfs4dev_waitq_mtx, "nfs4dev waitq", NULL, MTX_DEF);
  216 
  217         mtx_init(&nfs4dev_daemon_mtx, "nfs4dev state", NULL, MTX_DEF);
  218 
  219         nfs4device = make_dev(&nfs4dev_cdevsw, CDEV_MINOR, (uid_t)0, (gid_t)0,
  220             S_IRUSR | S_IWUSR, "nfs4");
  221 }
  222 
  223 void
  224 nfs4dev_uninit(void)
  225 {
  226         struct proc * dead = NULL;
  227 
  228         mtx_lock(&nfs4dev_daemon_mtx);
  229         if (nfs4dev_nopen) {
  230                 if (nfs4dev_reader == NULL) {
  231                         NFS4DEV_DEBUG("nfs4dev uninit(): unregistered reader\n");
  232                 } else {
  233                         dead = nfs4dev_reader->td_proc;
  234                 }
  235         }
  236         mtx_unlock(&nfs4dev_daemon_mtx);
  237 
  238         if (dead != NULL) {
  239                 NFS4DEV_DEBUG("nfs4dev_uninit(): you forgot to kill attached daemon (pid: %u)\n",
  240                     dead->p_pid);
  241                 PROC_LOCK(dead);
  242                 psignal(dead, SIGTERM);
  243                 PROC_UNLOCK(dead);
  244         }
  245 
  246         /* XXX moot? */
  247         nfs4dev_purge();
  248 
  249         mtx_destroy(&nfs4dev_newq_mtx);
  250         mtx_destroy(&nfs4dev_waitq_mtx);
  251         mtx_destroy(&nfs4dev_daemon_mtx);
  252 
  253         destroy_dev(nfs4device);
  254 }
  255 
  256 /* device interface functions */
  257 static int
  258 nfs4dev_open(struct cdev *dev, int flags, int fmt, d_thread_t *td)
  259 {
  260         if (dev != nfs4device) 
  261                 return ENODEV;
  262 
  263         mtx_lock(&nfs4dev_daemon_mtx);
  264         if (nfs4dev_nopen) {
  265                 mtx_unlock(&nfs4dev_daemon_mtx);
  266                 return EBUSY;
  267         }
  268 
  269         nfs4dev_nopen++;
  270         nfs4dev_reader = curthread;
  271         mtx_unlock(&nfs4dev_daemon_mtx);
  272 
  273         return (0);
  274 }
  275 
  276 static int
  277 nfs4dev_close(struct cdev *dev, int flags, int fmt, d_thread_t *td)
  278 {
  279         struct nfs4dev_upcall * u;
  280 
  281         if (dev != nfs4device) 
  282                 return ENODEV;
  283 
  284         mtx_lock(&nfs4dev_daemon_mtx);
  285         if (!nfs4dev_nopen) {
  286                 mtx_unlock(&nfs4dev_daemon_mtx);
  287                 return ENOENT;
  288         }
  289 
  290         nfs4dev_nopen--; 
  291         nfs4dev_reader = NULL;
  292         mtx_unlock(&nfs4dev_daemon_mtx);
  293 
  294         mtx_lock(&nfs4dev_waitq_mtx);
  295 
  296         while (!TAILQ_EMPTY(&nfs4dev_waitq)) {
  297                 u = TAILQ_FIRST(&nfs4dev_waitq);
  298                 TAILQ_REMOVE(&nfs4dev_waitq, u, up_entry);
  299                 u->up_error = EINTR;
  300                 wakeup(u);
  301         }
  302 
  303         mtx_unlock(&nfs4dev_waitq_mtx);
  304 
  305         return 0;
  306 }
  307 
  308 static int 
  309 nfs4dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
  310 {
  311         int error;
  312 
  313         if (dev != nfs4device)
  314                 return ENODEV; 
  315 
  316         if (data == NULL) 
  317                 return EFAULT;
  318 
  319         if (nfs4dev_reader != curthread)
  320                 nfs4dev_reader = curthread;
  321 
  322         switch (cmd) {
  323         case NFS4DEVIOCGET:
  324                 error = nfs4dev_request(data);
  325         break;
  326         case NFS4DEVIOCPUT:
  327                 error = nfs4dev_reply(data);
  328         break;
  329         default:
  330                 NFS4DEV_DEBUG("nfs4dev_ioctl: unkown ioctl cmd %d\n", (int)cmd);
  331                 error = EOPNOTSUPP;
  332         break;
  333         }
  334 
  335         return error;
  336 }
  337 
  338 static int 
  339 nfs4dev_poll(struct cdev *dev, int events, struct thread *td)
  340 {
  341         int revents;
  342 
  343         if (dev != nfs4device) 
  344           return EINVAL;
  345 
  346         mtx_lock(&nfs4dev_daemon_mtx);
  347         if (nfs4dev_nopen == 0) {
  348                 mtx_unlock(&nfs4dev_daemon_mtx);
  349                 return 0;
  350         }
  351         mtx_unlock(&nfs4dev_daemon_mtx);
  352 
  353         revents = 0;
  354 
  355         /* check readable data */
  356         mtx_lock(&nfs4dev_newq_mtx);
  357           if (!TAILQ_EMPTY(&nfs4dev_newq))
  358             revents |= POLLIN;
  359         mtx_unlock(&nfs4dev_newq_mtx);
  360 
  361         mtx_lock(&nfs4dev_waitq_mtx);
  362           if (!TAILQ_EMPTY(&nfs4dev_waitq))
  363             revents |= POLLOUT;
  364         mtx_unlock(&nfs4dev_waitq_mtx);
  365 
  366         return revents;
  367 }
  368 
  369 int 
  370 nfs4dev_call(uint32_t type, caddr_t req_data, size_t req_len, caddr_t rep_data, size_t * rep_lenp)
  371 {
  372         struct nfs4dev_upcall * u;
  373         int error = 0; 
  374         unsigned int xtmp;
  375 
  376         mtx_lock(&nfs4dev_daemon_mtx);
  377         if (nfs4dev_nopen == 0) {
  378                 mtx_unlock(&nfs4dev_daemon_mtx);
  379                 return EINVAL;
  380         }
  381         mtx_unlock(&nfs4dev_daemon_mtx);
  382 
  383         if (type > NFS4DEV_MAX_TYPE)
  384           return EOPNOTSUPP;
  385 
  386         NFS4DEV_DEBUG("upcall %d/%d:%d\n", type, req_len, *rep_lenp);
  387 
  388         nfs4dev_upcall_get(u);
  389 
  390         u->up_error = 0;
  391         u->up_rep = rep_data;
  392         u->up_replen = rep_lenp;
  393         u->up_copied = 0;
  394 
  395         u->up_reqmsg.msg_vers = NFS4DEV_VERSION;
  396         /* XXX efficient copying */
  397         bcopy(req_data, u->up_reqmsg.msg_data, req_len);
  398         u->up_reqmsg.msg_len  = req_len;
  399 
  400         mtx_lock(&nfs4dev_newq_mtx);
  401 
  402         /* get new XID */
  403         while ((xtmp = arc4random() % 256) == 0);
  404         nfs4dev_xid += xtmp;
  405         u->up_reqmsg.msg_xid = nfs4dev_xid;
  406 
  407         TAILQ_INSERT_TAIL(&nfs4dev_newq, u, up_entry);
  408         mtx_unlock(&nfs4dev_newq_mtx);
  409 
  410 
  411         NFS4DEV_DEBUG("nfs4dev op: %d xid: %x sleeping\n", u->up_reqmsg.msg_type, u->up_reqmsg.msg_xid);
  412 
  413         do {
  414                 tsleep(u, PLOCK, "nfs4dev", 0);
  415         } while (u->up_copied == 0 && u->up_error == 0);
  416 
  417         /* upcall now removed from the queue */
  418 
  419         NFS4DEV_DEBUG("nfs4dev prog: %d xid: %x continues...\n", 
  420             u->up_reqmsg.msg_type, u->up_reqmsg.msg_xid);
  421 
  422         if (u->up_error) {
  423                 error = u->up_error; 
  424                 NFS4DEV_DEBUG("nfs4dev prog: %d xid: %x error: %d\n", 
  425                     u->up_reqmsg.msg_type, u->up_reqmsg.msg_xid, u->up_error);
  426                 goto out;
  427         }
  428 
  429 out:
  430         nfs4dev_upcall_put(u);
  431         return error;
  432 }
  433 
  434 void
  435 nfs4dev_purge(void)
  436 {
  437         struct nfs4dev_upcall * u;
  438 
  439         mtx_lock(&nfs4dev_newq_mtx);
  440         while (!TAILQ_EMPTY(&nfs4dev_newq)) {
  441                 u = TAILQ_FIRST(&nfs4dev_newq);
  442                 TAILQ_REMOVE(&nfs4dev_newq, u, up_entry);
  443                 u->up_error = EINTR;
  444                 wakeup(u);
  445         }
  446         mtx_unlock(&nfs4dev_newq_mtx);
  447 
  448         mtx_lock(&nfs4dev_waitq_mtx);
  449         while (!TAILQ_EMPTY(&nfs4dev_waitq)) {
  450                 u = TAILQ_FIRST(&nfs4dev_waitq);
  451                 TAILQ_REMOVE(&nfs4dev_waitq, u, up_entry);
  452                 u->up_error = EINTR;
  453                 wakeup(u);
  454         }
  455         mtx_unlock(&nfs4dev_waitq_mtx);
  456 }

Cache object: 28a677cd4ff2c141bbdee7ba7bb698a1


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