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-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /* $FreeBSD: releng/5.4/sys/nfs4client/nfs4_dev.c 141090 2005-01-31 23:27:04Z imp $ */
    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 == 0 || m->msg_len > NFS4DEV_MSG_MAX_DATALEN) {
  156                 NFS4DEV_DEBUG("bad message length\n");
  157                 return EINVAL;
  158         }
  159                 
  160         /* match the reply with a request */
  161         mtx_lock(&nfs4dev_waitq_mtx);
  162         TAILQ_FOREACH(u, &nfs4dev_waitq, up_entry) {
  163                 if (m->msg_xid == u->up_reqmsg.msg_xid) {
  164                         if (m->msg_type == u->up_reqmsg.msg_type)
  165                                 goto found;
  166                         NFS4DEV_DEBUG("nfs4dev: op type mismatch!\n");
  167                         break;
  168                 }
  169         }
  170         mtx_unlock(&nfs4dev_waitq_mtx);
  171 
  172         NFS4DEV_DEBUG("nfs4dev msg op: %d xid: %x not found.\n",
  173             m->msg_type, m->msg_xid);
  174 
  175         error = EIO;
  176         goto bad;
  177 
  178 found:
  179         TAILQ_REMOVE(&nfs4dev_waitq, u, up_entry);
  180         mtx_unlock(&nfs4dev_waitq_mtx);
  181 
  182         if (m->msg_error) {
  183                 error = m->msg_error;
  184                 goto bad;
  185         }
  186 
  187         if (m->msg_len > *u->up_replen) {
  188                 error = EFAULT;
  189                 goto bad;
  190         }
  191 
  192         bcopy(m->msg_data, u->up_rep, m->msg_len);
  193         *u->up_replen = m->msg_len;
  194 
  195         u->up_copied = m->msg_len;
  196         wakeup(u);
  197 
  198         return 0;
  199 bad:
  200         u->up_error = error;
  201         wakeup(u);
  202         return error;
  203 }
  204 
  205 void
  206 nfs4dev_init(void)
  207 {
  208         nfs4dev_xid = arc4random();
  209         TAILQ_INIT(&nfs4dev_newq);      
  210         TAILQ_INIT(&nfs4dev_waitq);     
  211         mtx_init(&nfs4dev_newq_mtx, "nfs4dev newq", NULL, MTX_DEF);
  212         mtx_init(&nfs4dev_waitq_mtx, "nfs4dev waitq", NULL, MTX_DEF);
  213 
  214         mtx_init(&nfs4dev_daemon_mtx, "nfs4dev state", NULL, MTX_DEF);
  215 
  216         nfs4device = make_dev(&nfs4dev_cdevsw, CDEV_MINOR, (uid_t)0, (gid_t)0,
  217             S_IRUSR | S_IWUSR, "nfs4");
  218 }
  219 
  220 void
  221 nfs4dev_uninit(void)
  222 {
  223         struct proc * dead = NULL;
  224 
  225         mtx_lock(&nfs4dev_daemon_mtx);
  226         if (nfs4dev_nopen) {
  227                 if (nfs4dev_reader == NULL) {
  228                         NFS4DEV_DEBUG("nfs4dev uninit(): unregistered reader\n");
  229                 } else {
  230                         dead = nfs4dev_reader->td_proc;
  231                 }
  232         }
  233         mtx_unlock(&nfs4dev_daemon_mtx);
  234 
  235         if (dead != NULL) {
  236                 NFS4DEV_DEBUG("nfs4dev_uninit(): you forgot to kill attached daemon (pid: %u)\n",
  237                     dead->p_pid);
  238                 PROC_LOCK(dead);
  239                 psignal(dead, SIGTERM);
  240                 PROC_UNLOCK(dead);
  241         }
  242 
  243         /* XXX moot? */
  244         nfs4dev_purge();
  245 
  246         mtx_destroy(&nfs4dev_newq_mtx);
  247         mtx_destroy(&nfs4dev_waitq_mtx);
  248         mtx_destroy(&nfs4dev_daemon_mtx);
  249 
  250         destroy_dev(nfs4device);
  251 }
  252 
  253 /* device interface functions */
  254 static int
  255 nfs4dev_open(struct cdev *dev, int flags, int fmt, d_thread_t *td)
  256 {
  257         if (dev != nfs4device) 
  258                 return ENODEV;
  259 
  260         mtx_lock(&nfs4dev_daemon_mtx);
  261         if (nfs4dev_nopen) {
  262                 mtx_unlock(&nfs4dev_daemon_mtx);
  263                 return EBUSY;
  264         }
  265 
  266         nfs4dev_nopen++;
  267         nfs4dev_reader = curthread;
  268         mtx_unlock(&nfs4dev_daemon_mtx);
  269 
  270         return (0);
  271 }
  272 
  273 static int
  274 nfs4dev_close(struct cdev *dev, int flags, int fmt, d_thread_t *td)
  275 {
  276         struct nfs4dev_upcall * u;
  277 
  278         if (dev != nfs4device) 
  279                 return ENODEV;
  280 
  281         mtx_lock(&nfs4dev_daemon_mtx);
  282         if (!nfs4dev_nopen) {
  283                 mtx_unlock(&nfs4dev_daemon_mtx);
  284                 return ENOENT;
  285         }
  286 
  287         nfs4dev_nopen--; 
  288         nfs4dev_reader = NULL;
  289         mtx_unlock(&nfs4dev_daemon_mtx);
  290 
  291         mtx_lock(&nfs4dev_waitq_mtx);
  292 
  293         while (!TAILQ_EMPTY(&nfs4dev_waitq)) {
  294                 u = TAILQ_FIRST(&nfs4dev_waitq);
  295                 TAILQ_REMOVE(&nfs4dev_waitq, u, up_entry);
  296                 u->up_error = EINTR;
  297                 wakeup(u);
  298         }
  299 
  300         mtx_unlock(&nfs4dev_waitq_mtx);
  301 
  302         return 0;
  303 }
  304 
  305 static int 
  306 nfs4dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
  307 {
  308         int error;
  309 
  310         if (dev != nfs4device)
  311                 return ENODEV; 
  312 
  313         if (data == NULL) 
  314                 return EFAULT;
  315 
  316         if (nfs4dev_reader != curthread)
  317                 nfs4dev_reader = curthread;
  318 
  319         switch (cmd) {
  320         case NFS4DEVIOCGET:
  321                 error = nfs4dev_request(data);
  322         break;
  323         case NFS4DEVIOCPUT:
  324                 error = nfs4dev_reply(data);
  325         break;
  326         default:
  327                 NFS4DEV_DEBUG("nfs4dev_ioctl: unkown ioctl cmd %d\n", (int)cmd);
  328                 error = EOPNOTSUPP;
  329         break;
  330         }
  331 
  332         return error;
  333 }
  334 
  335 static int 
  336 nfs4dev_poll(struct cdev *dev, int events, struct thread *td)
  337 {
  338         int revents;
  339 
  340         if (dev != nfs4device) 
  341           return EINVAL;
  342 
  343         mtx_lock(&nfs4dev_daemon_mtx);
  344         if (nfs4dev_nopen == 0) {
  345                 mtx_unlock(&nfs4dev_daemon_mtx);
  346                 return 0;
  347         }
  348         mtx_unlock(&nfs4dev_daemon_mtx);
  349 
  350         revents = 0;
  351 
  352         /* check readable data */
  353         mtx_lock(&nfs4dev_newq_mtx);
  354           if (!TAILQ_EMPTY(&nfs4dev_newq))
  355             revents |= POLLIN;
  356         mtx_unlock(&nfs4dev_newq_mtx);
  357 
  358         mtx_lock(&nfs4dev_waitq_mtx);
  359           if (!TAILQ_EMPTY(&nfs4dev_waitq))
  360             revents |= POLLOUT;
  361         mtx_unlock(&nfs4dev_waitq_mtx);
  362 
  363         return revents;
  364 }
  365 
  366 int 
  367 nfs4dev_call(uint32_t type, caddr_t req_data, size_t req_len, caddr_t rep_data, size_t * rep_lenp)
  368 {
  369         struct nfs4dev_upcall * u;
  370         int error = 0; 
  371         unsigned int xtmp;
  372 
  373         mtx_lock(&nfs4dev_daemon_mtx);
  374         if (nfs4dev_nopen == 0) {
  375                 mtx_unlock(&nfs4dev_daemon_mtx);
  376                 return EINVAL;
  377         }
  378         mtx_unlock(&nfs4dev_daemon_mtx);
  379 
  380         if (type > NFS4DEV_MAX_TYPE)
  381           return EOPNOTSUPP;
  382 
  383         NFS4DEV_DEBUG("upcall %d/%d:%d\n", type, req_len, *rep_lenp);
  384 
  385         nfs4dev_upcall_get(u);
  386 
  387         u->up_error = 0;
  388         u->up_rep = rep_data;
  389         u->up_replen = rep_lenp;
  390         u->up_copied = 0;
  391 
  392         u->up_reqmsg.msg_vers = NFS4DEV_VERSION;
  393         /* XXX efficient copying */
  394         bcopy(req_data, u->up_reqmsg.msg_data, req_len);
  395         u->up_reqmsg.msg_len  = req_len;
  396 
  397         mtx_lock(&nfs4dev_newq_mtx);
  398 
  399         /* get new XID */
  400         while ((xtmp = arc4random() % 256) == 0);
  401         nfs4dev_xid += xtmp;
  402         u->up_reqmsg.msg_xid = nfs4dev_xid;
  403 
  404         TAILQ_INSERT_TAIL(&nfs4dev_newq, u, up_entry);
  405         mtx_unlock(&nfs4dev_newq_mtx);
  406 
  407 
  408         NFS4DEV_DEBUG("nfs4dev op: %d xid: %x sleeping\n", u->up_reqmsg.msg_type, u->up_reqmsg.msg_xid);
  409 
  410         do {
  411                 tsleep(u, PLOCK, "nfs4dev", 0);
  412         } while (u->up_copied == 0 && u->up_error == 0);
  413 
  414         /* upcall now removed from the queue */
  415 
  416         NFS4DEV_DEBUG("nfs4dev prog: %d xid: %x continues...\n", 
  417             u->up_reqmsg.msg_type, u->up_reqmsg.msg_xid);
  418 
  419         if (u->up_error) {
  420                 error = u->up_error; 
  421                 NFS4DEV_DEBUG("nfs4dev prog: %d xid: %x error: %d\n", 
  422                     u->up_reqmsg.msg_type, u->up_reqmsg.msg_xid, u->up_error);
  423                 goto out;
  424         }
  425 
  426 out:
  427         nfs4dev_upcall_put(u);
  428         return error;
  429 }
  430 
  431 void
  432 nfs4dev_purge(void)
  433 {
  434         struct nfs4dev_upcall * u;
  435 
  436         mtx_lock(&nfs4dev_newq_mtx);
  437         while (!TAILQ_EMPTY(&nfs4dev_newq)) {
  438                 u = TAILQ_FIRST(&nfs4dev_newq);
  439                 TAILQ_REMOVE(&nfs4dev_newq, u, up_entry);
  440                 u->up_error = EINTR;
  441                 wakeup(u);
  442         }
  443         mtx_unlock(&nfs4dev_newq_mtx);
  444 
  445         mtx_lock(&nfs4dev_waitq_mtx);
  446         while (!TAILQ_EMPTY(&nfs4dev_waitq)) {
  447                 u = TAILQ_FIRST(&nfs4dev_waitq);
  448                 TAILQ_REMOVE(&nfs4dev_waitq, u, up_entry);
  449                 u->up_error = EINTR;
  450                 wakeup(u);
  451         }
  452         mtx_unlock(&nfs4dev_waitq_mtx);
  453 }

Cache object: e0ff534c69fe29c14bc337c6b1a73569


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