2 /* $Id: nfs4_dev.c,v 1.10 2003/11/05 14:58:59 rees Exp $ */
6 * the regents of the university of michigan
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.
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.
28 #include <sys/param.h>
30 #include <sys/queue.h>
31 #include <sys/malloc.h>
32 #include <sys/kernel.h>
34 #include <sys/mutex.h>
36 #include <sys/systm.h>
39 #include <sys/signalvar.h>
41 #include <nfs4client/nfs4_dev.h>
44 #define NFS4DEV_DEBUG(X...) printf(X)
46 #define NFS4DEV_DEBUG(X...)
49 #define NFS4DEV_NAME "nfs4"
52 MALLOC_DEFINE(M_NFS4DEV, "nfs4_dev", "NFS4 device");
54 struct nfs4dev_upcall {
56 struct nfs4dev_msg up_reqmsg;
59 /* reply (payload only) */
63 int up_copied; /* non-zero when reply has been copied to
66 int up_error; /* non-zero if an error occured */
68 TAILQ_ENTRY(nfs4dev_upcall) up_entry;
72 #define nfs4dev_upcall_get(MP) MALLOC((MP), struct nfs4dev_upcall *, sizeof(struct nfs4dev_upcall), M_NFS4DEV, M_WAITOK | M_ZERO)
74 #define nfs4dev_upcall_put(MP) FREE((MP), M_NFS4DEV)
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;
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;
86 /* queue of upcalls waiting for replys */
87 TAILQ_HEAD(, nfs4dev_upcall) nfs4dev_waitq;
88 static struct mtx nfs4dev_waitq_mtx;
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;
96 static struct cdevsw nfs4dev_cdevsw = {
97 #if (__FreeBSD_version > 502102)
98 .d_version = D_VERSION,
99 .d_flags = D_NEEDGIANT,
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,
108 static int nfs4dev_reply(caddr_t);
109 static int nfs4dev_request(caddr_t);
111 /* Userland requests a new operation to service */
113 nfs4dev_request(caddr_t addr)
115 struct nfs4dev_upcall * u;
116 struct nfs4dev_msg * m = (struct nfs4dev_msg *) addr;
118 mtx_lock(&nfs4dev_newq_mtx);
120 if (TAILQ_EMPTY(&nfs4dev_newq)) {
121 mtx_unlock(&nfs4dev_newq_mtx);
125 u = TAILQ_FIRST(&nfs4dev_newq);
126 TAILQ_REMOVE(&nfs4dev_newq, u, up_entry);
127 mtx_unlock(&nfs4dev_newq_mtx);
129 bcopy(&u->up_reqmsg, m, sizeof(struct nfs4dev_msg));
131 mtx_lock(&nfs4dev_waitq_mtx);
132 TAILQ_INSERT_TAIL(&nfs4dev_waitq, u, up_entry);
133 mtx_unlock(&nfs4dev_waitq_mtx);
139 nfs4dev_reply(caddr_t addr)
141 struct nfs4dev_upcall * u;
142 struct nfs4dev_msg * m = (struct nfs4dev_msg *) addr;
145 if (m->msg_vers != NFS4DEV_VERSION) {
146 printf("nfs4dev version mismatch\n");
150 if (m->msg_type > NFS4DEV_MAX_TYPE) {
151 NFS4DEV_DEBUG("nfs4dev: unsupported message type\n");
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");
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)
167 NFS4DEV_DEBUG("nfs4dev: op type mismatch!\n");
171 mtx_unlock(&nfs4dev_waitq_mtx);
173 NFS4DEV_DEBUG("nfs4dev msg op: %d xid: %x not found.\n",
174 m->msg_type, m->msg_xid);
180 TAILQ_REMOVE(&nfs4dev_waitq, u, up_entry);
181 mtx_unlock(&nfs4dev_waitq_mtx);
184 error = m->msg_error;
188 if (m->msg_len > *u->up_replen) {
193 bcopy(m->msg_data, u->up_rep, m->msg_len);
194 *u->up_replen = m->msg_len;
196 u->up_copied = m->msg_len;
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);
217 mtx_init(&nfs4dev_daemon_mtx, "nfs4dev state", NULL, MTX_DEF);
219 nfs4device = make_dev(&nfs4dev_cdevsw, CDEV_MINOR, (uid_t)0, (gid_t)0,
220 S_IRUSR | S_IWUSR, "nfs4");
226 struct proc * dead = NULL;
228 mtx_lock(&nfs4dev_daemon_mtx);
230 if (nfs4dev_reader == NULL) {
231 NFS4DEV_DEBUG("nfs4dev uninit(): unregistered reader\n");
233 dead = nfs4dev_reader->td_proc;
236 mtx_unlock(&nfs4dev_daemon_mtx);
239 NFS4DEV_DEBUG("nfs4dev_uninit(): you forgot to kill attached daemon (pid: %u)\n",
242 psignal(dead, SIGTERM);
249 mtx_destroy(&nfs4dev_newq_mtx);
250 mtx_destroy(&nfs4dev_waitq_mtx);
251 mtx_destroy(&nfs4dev_daemon_mtx);
253 destroy_dev(nfs4device);
256 /* device interface functions */
258 nfs4dev_open(struct cdev *dev, int flags, int fmt, d_thread_t *td)
260 if (dev != nfs4device)
263 mtx_lock(&nfs4dev_daemon_mtx);
265 mtx_unlock(&nfs4dev_daemon_mtx);
270 nfs4dev_reader = curthread;
271 mtx_unlock(&nfs4dev_daemon_mtx);
277 nfs4dev_close(struct cdev *dev, int flags, int fmt, d_thread_t *td)
279 struct nfs4dev_upcall * u;
281 if (dev != nfs4device)
284 mtx_lock(&nfs4dev_daemon_mtx);
285 if (!nfs4dev_nopen) {
286 mtx_unlock(&nfs4dev_daemon_mtx);
291 nfs4dev_reader = NULL;
292 mtx_unlock(&nfs4dev_daemon_mtx);
294 mtx_lock(&nfs4dev_waitq_mtx);
296 while (!TAILQ_EMPTY(&nfs4dev_waitq)) {
297 u = TAILQ_FIRST(&nfs4dev_waitq);
298 TAILQ_REMOVE(&nfs4dev_waitq, u, up_entry);
303 mtx_unlock(&nfs4dev_waitq_mtx);
309 nfs4dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
313 if (dev != nfs4device)
319 if (nfs4dev_reader != curthread)
320 nfs4dev_reader = curthread;
324 error = nfs4dev_request(data);
327 error = nfs4dev_reply(data);
330 NFS4DEV_DEBUG("nfs4dev_ioctl: unkown ioctl cmd %d\n", (int)cmd);
339 nfs4dev_poll(struct cdev *dev, int events, struct thread *td)
343 if (dev != nfs4device)
346 mtx_lock(&nfs4dev_daemon_mtx);
347 if (nfs4dev_nopen == 0) {
348 mtx_unlock(&nfs4dev_daemon_mtx);
351 mtx_unlock(&nfs4dev_daemon_mtx);
355 /* check readable data */
356 mtx_lock(&nfs4dev_newq_mtx);
357 if (!TAILQ_EMPTY(&nfs4dev_newq))
359 mtx_unlock(&nfs4dev_newq_mtx);
361 mtx_lock(&nfs4dev_waitq_mtx);
362 if (!TAILQ_EMPTY(&nfs4dev_waitq))
364 mtx_unlock(&nfs4dev_waitq_mtx);
370 nfs4dev_call(uint32_t type, caddr_t req_data, size_t req_len, caddr_t rep_data, size_t * rep_lenp)
372 struct nfs4dev_upcall * u;
376 mtx_lock(&nfs4dev_daemon_mtx);
377 if (nfs4dev_nopen == 0) {
378 mtx_unlock(&nfs4dev_daemon_mtx);
381 mtx_unlock(&nfs4dev_daemon_mtx);
383 if (type > NFS4DEV_MAX_TYPE)
386 NFS4DEV_DEBUG("upcall %d/%d:%d\n", type, req_len, *rep_lenp);
388 nfs4dev_upcall_get(u);
391 u->up_rep = rep_data;
392 u->up_replen = rep_lenp;
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;
400 mtx_lock(&nfs4dev_newq_mtx);
403 while ((xtmp = arc4random() % 256) == 0);
405 u->up_reqmsg.msg_xid = nfs4dev_xid;
407 TAILQ_INSERT_TAIL(&nfs4dev_newq, u, up_entry);
408 mtx_unlock(&nfs4dev_newq_mtx);
411 NFS4DEV_DEBUG("nfs4dev op: %d xid: %x sleeping\n", u->up_reqmsg.msg_type, u->up_reqmsg.msg_xid);
414 tsleep(u, PLOCK, "nfs4dev", 0);
415 } while (u->up_copied == 0 && u->up_error == 0);
417 /* upcall now removed from the queue */
419 NFS4DEV_DEBUG("nfs4dev prog: %d xid: %x continues...\n",
420 u->up_reqmsg.msg_type, u->up_reqmsg.msg_xid);
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);
430 nfs4dev_upcall_put(u);
437 struct nfs4dev_upcall * u;
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);
446 mtx_unlock(&nfs4dev_newq_mtx);
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);
455 mtx_unlock(&nfs4dev_waitq_mtx);