[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]

FreeBSD/Linux Kernel Cross Reference
sys/nfs4client/nfs4_dev.c

Version: -  FREEBSD  -  FREEBSD7  -  FREEBSD70  -  FREEBSD6  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  OPENSOLARIS  -  minix-3-1-1  -  TRUSTEDBSD-SEBSD  -  FREEBSD-LIBC  -  FREEBSD7-LIBC  -  FREEBSD6-LIBC  -  GLIBC27 
SearchContext: -  none  -  excerpts  -  bigexcerpts 

  1 /* $FreeBSD: src/sys/nfs4client/nfs4_dev.c,v 1.10 2008/10/23 15:53:51 des Exp $ */
  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) (MP) = malloc(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 }
457 

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.