FreeBSD/Linux Kernel Cross Reference
sys/coda/coda_psdev.c
1 /*-
2 * Coda: an Experimental Distributed File System
3 * Release 3.1
4 *
5 * Copyright (c) 1987-1998 Carnegie Mellon University
6 * All Rights Reserved
7 *
8 * Permission to use, copy, modify and distribute this software and its
9 * documentation is hereby granted, provided that both the copyright
10 * notice and this permission notice appear in all copies of the
11 * software, derivative works or modified versions, and any portions
12 * thereof, and that both notices appear in supporting documentation, and
13 * that credit is given to Carnegie Mellon University in all documents
14 * and publicity pertaining to direct or indirect use of this code or its
15 * derivatives.
16 *
17 * CODA IS AN EXPERIMENTAL SOFTWARE SYSTEM AND IS KNOWN TO HAVE BUGS,
18 * SOME OF WHICH MAY HAVE SERIOUS CONSEQUENCES. CARNEGIE MELLON ALLOWS
19 * FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION. CARNEGIE MELLON
20 * DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER
21 * RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE OR OF
22 * ANY DERIVATIVE WORK.
23 *
24 * Carnegie Mellon encourages users of this software to return any
25 * improvements or extensions that they make, and to grant Carnegie
26 * Mellon the rights to redistribute these changes without encumbrance.
27 *
28 * @(#) src/sys/coda/coda_psdev.c,v 1.1.1.1 1998/08/29 21:14:52 rvb Exp $
29 */
30 /*-
31 * Mach Operating System
32 * Copyright (c) 1989 Carnegie-Mellon University
33 * All rights reserved. The CMU software License Agreement specifies
34 * the terms and conditions for use and redistribution.
35 */
36
37 /*
38 * This code was written for the Coda filesystem at Carnegie Mellon
39 * University. Contributers include David Steere, James Kistler, and
40 * M. Satyanarayanan. */
41
42 /*
43 * These routines define the psuedo device for communication between
44 * Coda's Venus and Minicache in Mach 2.6. They used to be in cfs_subr.c,
45 * but I moved them to make it easier to port the Minicache without
46 * porting coda. -- DCS 10/12/94
47 */
48
49 /* These routines are the device entry points for Venus. */
50
51 #include <sys/cdefs.h>
52 __FBSDID("$FreeBSD: releng/6.4/sys/coda/coda_psdev.c 143624 2005-03-15 10:01:31Z phk $");
53
54
55 extern int coda_nc_initialized; /* Set if cache has been initialized */
56
57 #include <sys/param.h>
58 #include <sys/systm.h>
59 #include <sys/ioccom.h>
60 #include <sys/kernel.h>
61 #include <sys/lock.h>
62 #include <sys/malloc.h>
63 #include <sys/file.h> /* must come after sys/malloc.h */
64 #include <sys/mount.h>
65 #include <sys/mutex.h>
66 #include <sys/poll.h>
67 #include <sys/proc.h>
68
69 #include <coda/coda.h>
70 #include <coda/cnode.h>
71 #include <coda/coda_namecache.h>
72 #include <coda/coda_io.h>
73 #include <coda/coda_psdev.h>
74
75 #define CTL_C
76
77 #ifdef CTL_C
78 #include <sys/signalvar.h>
79 #endif
80
81 int coda_psdev_print_entry = 0;
82 static
83 int outstanding_upcalls = 0;
84 int coda_call_sleep = PZERO - 1;
85 #ifdef CTL_C
86 int coda_pcatch = PCATCH;
87 #else
88 #endif
89
90 #define ENTRY if(coda_psdev_print_entry) myprintf(("Entered %s\n",__func__))
91
92 void vcodaattach(int n);
93
94 struct vmsg {
95 struct queue vm_chain;
96 caddr_t vm_data;
97 u_short vm_flags;
98 u_short vm_inSize; /* Size is at most 5000 bytes */
99 u_short vm_outSize;
100 u_short vm_opcode; /* copied from data to save ptr lookup */
101 int vm_unique;
102 caddr_t vm_sleep; /* Not used by Mach. */
103 };
104
105 #define VM_READ 1
106 #define VM_WRITE 2
107 #define VM_INTR 4
108
109 /* vcodaattach: do nothing */
110 void
111 vcodaattach(n)
112 int n;
113 {
114 }
115
116 int
117 vc_nb_open(dev, flag, mode, td)
118 struct cdev *dev;
119 int flag;
120 int mode;
121 struct thread *td; /* NetBSD only */
122 {
123 struct vcomm *vcp;
124 struct coda_mntinfo *mnt;
125
126 ENTRY;
127
128 if (!coda_nc_initialized)
129 coda_nc_init();
130
131 mnt = dev2coda_mntinfo(dev);
132 vcp = &mnt->mi_vcomm;
133 if (VC_OPEN(vcp))
134 return(EBUSY);
135
136 bzero(&(vcp->vc_selproc), sizeof (struct selinfo));
137 INIT_QUEUE(vcp->vc_requests);
138 INIT_QUEUE(vcp->vc_replys);
139 MARK_VC_OPEN(vcp);
140
141 mnt->mi_vfsp = NULL;
142 mnt->mi_rootvp = NULL;
143
144 return(0);
145 }
146
147 int
148 vc_nb_close (dev, flag, mode, td)
149 struct cdev *dev;
150 int flag;
151 int mode;
152 struct thread *td;
153 {
154 register struct vcomm *vcp;
155 register struct vmsg *vmp, *nvmp = NULL;
156 struct coda_mntinfo *mi;
157 int err;
158
159 ENTRY;
160
161 mi = dev2coda_mntinfo(dev);
162 vcp = &(mi->mi_vcomm);
163
164 if (!VC_OPEN(vcp))
165 panic("vcclose: not open");
166
167 /* prevent future operations on this vfs from succeeding by auto-
168 * unmounting any vfs mounted via this device. This frees user or
169 * sysadm from having to remember where all mount points are located.
170 * Put this before WAKEUPs to avoid queuing new messages between
171 * the WAKEUP and the unmount (which can happen if we're unlucky)
172 */
173 if (!mi->mi_rootvp) {
174 /* just a simple open/close w no mount */
175 MARK_VC_CLOSED(vcp);
176 return 0;
177 }
178
179 /* Let unmount know this is for real */
180 VTOC(mi->mi_rootvp)->c_flags |= C_UNMOUNTING;
181 coda_unmounting(mi->mi_vfsp);
182
183 outstanding_upcalls = 0;
184 /* Wakeup clients so they can return. */
185 for (vmp = (struct vmsg *)GETNEXT(vcp->vc_requests);
186 !EOQ(vmp, vcp->vc_requests);
187 vmp = nvmp)
188 {
189 nvmp = (struct vmsg *)GETNEXT(vmp->vm_chain);
190 /* Free signal request messages and don't wakeup cause
191 no one is waiting. */
192 if (vmp->vm_opcode == CODA_SIGNAL) {
193 CODA_FREE((caddr_t)vmp->vm_data, (u_int)VC_IN_NO_DATA);
194 CODA_FREE((caddr_t)vmp, (u_int)sizeof(struct vmsg));
195 continue;
196 }
197 outstanding_upcalls++;
198 wakeup(&vmp->vm_sleep);
199 }
200
201 for (vmp = (struct vmsg *)GETNEXT(vcp->vc_replys);
202 !EOQ(vmp, vcp->vc_replys);
203 vmp = (struct vmsg *)GETNEXT(vmp->vm_chain))
204 {
205 outstanding_upcalls++;
206 wakeup(&vmp->vm_sleep);
207 }
208
209 MARK_VC_CLOSED(vcp);
210
211 if (outstanding_upcalls) {
212 #ifdef CODA_VERBOSE
213 printf("presleep: outstanding_upcalls = %d\n", outstanding_upcalls);
214 (void) tsleep(&outstanding_upcalls, coda_call_sleep, "coda_umount", 0);
215 printf("postsleep: outstanding_upcalls = %d\n", outstanding_upcalls);
216 #else
217 (void) tsleep(&outstanding_upcalls, coda_call_sleep, "coda_umount", 0);
218 #endif
219 }
220
221 err = dounmount(mi->mi_vfsp, flag, td);
222 if (err)
223 myprintf(("Error %d unmounting vfs in vcclose(%s)\n",
224 err, devtoname(dev)));
225 return 0;
226 }
227
228 int
229 vc_nb_read(dev, uiop, flag)
230 struct cdev *dev;
231 struct uio *uiop;
232 int flag;
233 {
234 register struct vcomm * vcp;
235 register struct vmsg *vmp;
236 int error = 0;
237
238 ENTRY;
239
240 vcp = &dev2coda_mntinfo(dev)->mi_vcomm;
241 /* Get message at head of request queue. */
242 if (EMPTY(vcp->vc_requests))
243 return(0); /* Nothing to read */
244
245 vmp = (struct vmsg *)GETNEXT(vcp->vc_requests);
246
247 /* Move the input args into userspace */
248 uiop->uio_rw = UIO_READ;
249 error = uiomove(vmp->vm_data, vmp->vm_inSize, uiop);
250 if (error) {
251 myprintf(("vcread: error (%d) on uiomove\n", error));
252 error = EINVAL;
253 }
254
255 #ifdef OLD_DIAGNOSTIC
256 if (vmp->vm_chain.forw == 0 || vmp->vm_chain.back == 0)
257 panic("vc_nb_read: bad chain");
258 #endif
259
260 REMQUE(vmp->vm_chain);
261
262 /* If request was a signal, free up the message and don't
263 enqueue it in the reply queue. */
264 if (vmp->vm_opcode == CODA_SIGNAL) {
265 if (codadebug)
266 myprintf(("vcread: signal msg (%d, %d)\n",
267 vmp->vm_opcode, vmp->vm_unique));
268 CODA_FREE((caddr_t)vmp->vm_data, (u_int)VC_IN_NO_DATA);
269 CODA_FREE((caddr_t)vmp, (u_int)sizeof(struct vmsg));
270 return(error);
271 }
272
273 vmp->vm_flags |= VM_READ;
274 INSQUE(vmp->vm_chain, vcp->vc_replys);
275
276 return(error);
277 }
278
279 int
280 vc_nb_write(dev, uiop, flag)
281 struct cdev *dev;
282 struct uio *uiop;
283 int flag;
284 {
285 register struct vcomm * vcp;
286 register struct vmsg *vmp;
287 struct coda_out_hdr *out;
288 u_long seq;
289 u_long opcode;
290 int buf[2];
291 int error = 0;
292
293 ENTRY;
294
295 vcp = &dev2coda_mntinfo(dev)->mi_vcomm;
296
297 /* Peek at the opcode, unique without transfering the data. */
298 uiop->uio_rw = UIO_WRITE;
299 error = uiomove((caddr_t)buf, sizeof(int) * 2, uiop);
300 if (error) {
301 myprintf(("vcwrite: error (%d) on uiomove\n", error));
302 return(EINVAL);
303 }
304
305 opcode = buf[0];
306 seq = buf[1];
307
308 if (codadebug)
309 myprintf(("vcwrite got a call for %ld.%ld\n", opcode, seq));
310
311 if (DOWNCALL(opcode)) {
312 union outputArgs pbuf;
313
314 /* get the rest of the data. */
315 uiop->uio_rw = UIO_WRITE;
316 error = uiomove((caddr_t)&pbuf.coda_purgeuser.oh.result, sizeof(pbuf) - (sizeof(int)*2), uiop);
317 if (error) {
318 myprintf(("vcwrite: error (%d) on uiomove (Op %ld seq %ld)\n",
319 error, opcode, seq));
320 return(EINVAL);
321 }
322
323 return handleDownCall(opcode, &pbuf);
324 }
325
326 /* Look for the message on the (waiting for) reply queue. */
327 for (vmp = (struct vmsg *)GETNEXT(vcp->vc_replys);
328 !EOQ(vmp, vcp->vc_replys);
329 vmp = (struct vmsg *)GETNEXT(vmp->vm_chain))
330 {
331 if (vmp->vm_unique == seq) break;
332 }
333
334 if (EOQ(vmp, vcp->vc_replys)) {
335 if (codadebug)
336 myprintf(("vcwrite: msg (%ld, %ld) not found\n", opcode, seq));
337
338 return(ESRCH);
339 }
340
341 /* Remove the message from the reply queue */
342 REMQUE(vmp->vm_chain);
343
344 /* move data into response buffer. */
345 out = (struct coda_out_hdr *)vmp->vm_data;
346 /* Don't need to copy opcode and uniquifier. */
347
348 /* get the rest of the data. */
349 if (vmp->vm_outSize < uiop->uio_resid) {
350 myprintf(("vcwrite: more data than asked for (%d < %d)\n",
351 vmp->vm_outSize, uiop->uio_resid));
352 wakeup(&vmp->vm_sleep); /* Notify caller of the error. */
353 return(EINVAL);
354 }
355
356 buf[0] = uiop->uio_resid; /* Save this value. */
357 uiop->uio_rw = UIO_WRITE;
358 error = uiomove((caddr_t) &out->result, vmp->vm_outSize - (sizeof(int) * 2), uiop);
359 if (error) {
360 myprintf(("vcwrite: error (%d) on uiomove (op %ld seq %ld)\n",
361 error, opcode, seq));
362 return(EINVAL);
363 }
364
365 /* I don't think these are used, but just in case. */
366 /* XXX - aren't these two already correct? -bnoble */
367 out->opcode = opcode;
368 out->unique = seq;
369 vmp->vm_outSize = buf[0]; /* Amount of data transferred? */
370 vmp->vm_flags |= VM_WRITE;
371 wakeup(&vmp->vm_sleep);
372
373 return(0);
374 }
375
376 int
377 vc_nb_ioctl(dev, cmd, addr, flag, td)
378 struct cdev *dev;
379 u_long cmd;
380 caddr_t addr;
381 int flag;
382 struct thread *td;
383 {
384 ENTRY;
385
386 switch(cmd) {
387 case CODARESIZE: {
388 struct coda_resize *data = (struct coda_resize *)addr;
389 return(coda_nc_resize(data->hashsize, data->heapsize, IS_DOWNCALL));
390 break;
391 }
392 case CODASTATS:
393 if (coda_nc_use) {
394 coda_nc_gather_stats();
395 return(0);
396 } else {
397 return(ENODEV);
398 }
399 break;
400 case CODAPRINT:
401 if (coda_nc_use) {
402 print_coda_nc();
403 return(0);
404 } else {
405 return(ENODEV);
406 }
407 break;
408 case CIOC_KERNEL_VERSION:
409 switch (*(u_int *)addr) {
410 case 0:
411 *(u_int *)addr = coda_kernel_version;
412 return 0;
413 break;
414 case 1:
415 case 2:
416 if (coda_kernel_version != *(u_int *)addr)
417 return ENOENT;
418 else
419 return 0;
420 default:
421 return ENOENT;
422 }
423 break;
424 default :
425 return(EINVAL);
426 break;
427 }
428 }
429
430 int
431 vc_nb_poll(dev, events, td)
432 struct cdev *dev;
433 int events;
434 struct thread *td;
435 {
436 register struct vcomm *vcp;
437 int event_msk = 0;
438
439 ENTRY;
440
441 vcp = &dev2coda_mntinfo(dev)->mi_vcomm;
442
443 event_msk = events & (POLLIN|POLLRDNORM);
444 if (!event_msk)
445 return(0);
446
447 if (!EMPTY(vcp->vc_requests))
448 return(events & (POLLIN|POLLRDNORM));
449
450 selrecord(td, &(vcp->vc_selproc));
451
452 return(0);
453 }
454
455 /*
456 * Statistics
457 */
458 struct coda_clstat coda_clstat;
459
460 /*
461 * Key question: whether to sleep interuptably or uninteruptably when
462 * waiting for Venus. The former seems better (cause you can ^C a
463 * job), but then GNU-EMACS completion breaks. Use tsleep with no
464 * timeout, and no longjmp happens. But, when sleeping
465 * "uninterruptibly", we don't get told if it returns abnormally
466 * (e.g. kill -9).
467 */
468
469 int
470 coda_call(mntinfo, inSize, outSize, buffer)
471 struct coda_mntinfo *mntinfo; int inSize; int *outSize; caddr_t buffer;
472 {
473 struct vcomm *vcp;
474 struct vmsg *vmp;
475 int error;
476 #ifdef CTL_C
477 struct thread *td = curthread;
478 struct proc *p = td->td_proc;
479 sigset_t psig_omask;
480 sigset_t tempset;
481 int i;
482 #endif
483 if (mntinfo == NULL) {
484 /* Unlikely, but could be a race condition with a dying warden */
485 return ENODEV;
486 }
487
488 vcp = &(mntinfo->mi_vcomm);
489
490 coda_clstat.ncalls++;
491 coda_clstat.reqs[((struct coda_in_hdr *)buffer)->opcode]++;
492
493 if (!VC_OPEN(vcp))
494 return(ENODEV);
495
496 CODA_ALLOC(vmp,struct vmsg *,sizeof(struct vmsg));
497 /* Format the request message. */
498 vmp->vm_data = buffer;
499 vmp->vm_flags = 0;
500 vmp->vm_inSize = inSize;
501 vmp->vm_outSize
502 = *outSize ? *outSize : inSize; /* |buffer| >= inSize */
503 vmp->vm_opcode = ((struct coda_in_hdr *)buffer)->opcode;
504 vmp->vm_unique = ++vcp->vc_seq;
505 if (codadebug)
506 myprintf(("Doing a call for %d.%d\n",
507 vmp->vm_opcode, vmp->vm_unique));
508
509 /* Fill in the common input args. */
510 ((struct coda_in_hdr *)buffer)->unique = vmp->vm_unique;
511
512 /* Append msg to request queue and poke Venus. */
513 INSQUE(vmp->vm_chain, vcp->vc_requests);
514 selwakeuppri(&(vcp->vc_selproc), coda_call_sleep);
515
516 /* We can be interrupted while we wait for Venus to process
517 * our request. If the interrupt occurs before Venus has read
518 * the request, we dequeue and return. If it occurs after the
519 * read but before the reply, we dequeue, send a signal
520 * message, and return. If it occurs after the reply we ignore
521 * it. In no case do we want to restart the syscall. If it
522 * was interrupted by a venus shutdown (vcclose), return
523 * ENODEV. */
524
525 /* Ignore return, We have to check anyway */
526 #ifdef CTL_C
527 /* This is work in progress. Setting coda_pcatch lets tsleep reawaken
528 on a ^c or ^z. The problem is that emacs sets certain interrupts
529 as SA_RESTART. This means that we should exit sleep handle the
530 "signal" and then go to sleep again. Mostly this is done by letting
531 the syscall complete and be restarted. We are not idempotent and
532 can not do this. A better solution is necessary.
533 */
534 i = 0;
535 PROC_LOCK(p);
536 psig_omask = td->td_sigmask;
537 do {
538 error = msleep(&vmp->vm_sleep, &p->p_mtx,
539 (coda_call_sleep|coda_pcatch), "coda_call",
540 hz*2);
541 if (error == 0)
542 break;
543 else if (error == EWOULDBLOCK) {
544 #ifdef CODA_VERBOSE
545 printf("coda_call: tsleep TIMEOUT %d sec\n", 2+2*i);
546 #endif
547 }
548 else {
549 SIGEMPTYSET(tempset);
550 SIGADDSET(tempset, SIGIO);
551 if (SIGSETEQ(td->td_siglist, tempset)) {
552 SIGADDSET(td->td_sigmask, SIGIO);
553 #ifdef CODA_VERBOSE
554 printf("coda_call: tsleep returns %d SIGIO, cnt %d\n",
555 error, i);
556 #endif
557 } else {
558 SIGDELSET(tempset, SIGIO);
559 SIGADDSET(tempset, SIGALRM);
560 if (SIGSETEQ(td->td_siglist, tempset)) {
561 SIGADDSET(td->td_sigmask, SIGALRM);
562 #ifdef CODA_VERBOSE
563 printf("coda_call: tsleep returns %d SIGALRM, cnt %d\n",
564 error, i);
565 #endif
566 }
567 else {
568 #ifdef CODA_VERBOSE
569 printf("coda_call: tsleep returns %d, cnt %d\n",
570 error, i);
571 #endif
572
573 #if notyet
574 tempset = td->td_siglist;
575 SIGSETNAND(tempset, td->td_sigmask);
576 printf("coda_call: siglist = %p, sigmask = %p, mask %p\n",
577 td->td_siglist, td->td_sigmask,
578 tempset);
579 break;
580 SIGSETOR(td->td_sigmask, td->td_siglist);
581 tempset = td->td_siglist;
582 SIGSETNAND(tempset, td->td_sigmask);
583 printf("coda_call: new mask, siglist = %p, sigmask = %p, mask %p\n",
584 td->td_siglist, td->td_sigmask,
585 tempset);
586 #endif
587 }
588 }
589 }
590 } while (error && i++ < 128 && VC_OPEN(vcp));
591 td->td_sigmask = psig_omask;
592 signotify(td);
593 PROC_UNLOCK(p);
594 #else
595 (void) tsleep(&vmp->vm_sleep, coda_call_sleep, "coda_call", 0);
596 #endif
597 if (VC_OPEN(vcp)) { /* Venus is still alive */
598 /* Op went through, interrupt or not... */
599 if (vmp->vm_flags & VM_WRITE) {
600 error = 0;
601 *outSize = vmp->vm_outSize;
602 }
603
604 else if (!(vmp->vm_flags & VM_READ)) {
605 /* Interrupted before venus read it. */
606 #ifdef CODA_VERBOSE
607 if (1)
608 #else
609 if (codadebug)
610 #endif
611 myprintf(("interrupted before read: op = %d.%d, flags = %x\n",
612 vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
613 REMQUE(vmp->vm_chain);
614 error = EINTR;
615 }
616
617 else {
618 /* (!(vmp->vm_flags & VM_WRITE)) means interrupted after
619 upcall started */
620 /* Interrupted after start of upcall, send venus a signal */
621 struct coda_in_hdr *dog;
622 struct vmsg *svmp;
623
624 #ifdef CODA_VERBOSE
625 if (1)
626 #else
627 if (codadebug)
628 #endif
629 myprintf(("Sending Venus a signal: op = %d.%d, flags = %x\n",
630 vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
631
632 REMQUE(vmp->vm_chain);
633 error = EINTR;
634
635 CODA_ALLOC(svmp, struct vmsg *, sizeof (struct vmsg));
636
637 CODA_ALLOC((svmp->vm_data), char *, sizeof (struct coda_in_hdr));
638 dog = (struct coda_in_hdr *)svmp->vm_data;
639
640 svmp->vm_flags = 0;
641 dog->opcode = svmp->vm_opcode = CODA_SIGNAL;
642 dog->unique = svmp->vm_unique = vmp->vm_unique;
643 svmp->vm_inSize = sizeof (struct coda_in_hdr);
644 /*??? rvb */ svmp->vm_outSize = sizeof (struct coda_in_hdr);
645
646 if (codadebug)
647 myprintf(("coda_call: enqueing signal msg (%d, %d)\n",
648 svmp->vm_opcode, svmp->vm_unique));
649
650 /* insert at head of queue! */
651 INSQUE(svmp->vm_chain, vcp->vc_requests);
652 selwakeuppri(&(vcp->vc_selproc), coda_call_sleep);
653 }
654 }
655
656 else { /* If venus died (!VC_OPEN(vcp)) */
657 if (codadebug)
658 myprintf(("vcclose woke op %d.%d flags %d\n",
659 vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
660
661 error = ENODEV;
662 }
663
664 CODA_FREE(vmp, sizeof(struct vmsg));
665
666 if (outstanding_upcalls > 0 && (--outstanding_upcalls == 0))
667 wakeup(&outstanding_upcalls);
668
669 if (!error)
670 error = ((struct coda_out_hdr *)buffer)->result;
671 return(error);
672 }
Cache object: f11eb13a49c82dd6eaaf88e43919fc2d
|