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 Coda's
44 * Venus and Minicache in Mach 2.6. They used to be in cfs_subr.c, but I
45 * moved them to make it easier to port the Minicache without porting coda.
46 * -- DCS 10/12/94
47 */
48
49 /*
50 * These routines are the device entry points for Venus.
51 */
52
53 #include <sys/cdefs.h>
54 __FBSDID("$FreeBSD: releng/8.4/sys/fs/coda/coda_psdev.c 194990 2009-06-25 18:46:30Z kib $");
55
56 #include <sys/param.h>
57 #include <sys/systm.h>
58 #include <sys/conf.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 #include <sys/filedesc.h>
69
70 #include <fs/coda/coda.h>
71 #include <fs/coda/cnode.h>
72 #include <fs/coda/coda_io.h>
73 #include <fs/coda/coda_psdev.h>
74
75 /*
76 * Variables to determine how Coda sleeps and whether or not it is
77 * interruptible when it does sleep waiting for Venus.
78 */
79 /* #define CTL_C */
80
81 #ifdef CTL_C
82 #include <sys/signalvar.h>
83 #endif
84
85 int coda_psdev_print_entry = 0;
86 static int outstanding_upcalls = 0;
87 int coda_call_sleep = PZERO - 1;
88 #ifdef CTL_C
89 int coda_pcatch = PCATCH;
90 #else
91 #endif
92
93 #define ENTRY do { \
94 if (coda_psdev_print_entry) \
95 myprintf(("Entered %s\n", __func__)); \
96 } while (0)
97
98 struct vmsg {
99 TAILQ_ENTRY(vmsg) vm_chain;
100 caddr_t vm_data;
101 u_short vm_flags;
102 u_short vm_inSize; /* Size is at most 5000 bytes */
103 u_short vm_outSize;
104 u_short vm_opcode; /* Copied from data to save ptr deref */
105 int vm_unique;
106 caddr_t vm_sleep; /* Not used by Mach. */
107 };
108
109 #define VM_READ 1
110 #define VM_WRITE 2
111 #define VM_INTR 4 /* Unused. */
112
113 int
114 vc_open(struct cdev *dev, int flag, int mode, struct thread *td)
115 {
116 struct vcomm *vcp;
117 struct coda_mntinfo *mnt;
118
119 ENTRY;
120 mnt = dev2coda_mntinfo(dev);
121 KASSERT(mnt, ("Coda: tried to open uninitialized cfs device"));
122 vcp = &mnt->mi_vcomm;
123 if (VC_OPEN(vcp))
124 return (EBUSY);
125 bzero(&(vcp->vc_selproc), sizeof (struct selinfo));
126 TAILQ_INIT(&vcp->vc_requests);
127 TAILQ_INIT(&vcp->vc_replies);
128 MARK_VC_OPEN(vcp);
129 mnt->mi_vfsp = NULL;
130 mnt->mi_rootvp = NULL;
131 return (0);
132 }
133
134 int
135 vc_close(struct cdev *dev, int flag, int mode, struct thread *td)
136 {
137 struct vcomm *vcp;
138 struct vmsg *vmp, *nvmp = NULL;
139 struct coda_mntinfo *mi;
140 int err;
141
142 ENTRY;
143 mi = dev2coda_mntinfo(dev);
144 KASSERT(mi, ("Coda: closing unknown cfs device"));
145 vcp = &mi->mi_vcomm;
146 KASSERT(VC_OPEN(vcp), ("Coda: closing unopened cfs device"));
147
148 /*
149 * Prevent future operations on this vfs from succeeding by
150 * auto-unmounting any vfs mounted via this device. This frees user
151 * or sysadm from having to remember where all mount points are
152 * located. Put this before WAKEUPs to avoid queuing new messages
153 * between the WAKEUP and the unmount (which can happen if we're
154 * unlucky).
155 */
156 if (mi->mi_rootvp == NULL) {
157 /*
158 * Just a simple open/close with no mount.
159 */
160 MARK_VC_CLOSED(vcp);
161 return (0);
162 }
163
164 /*
165 * Let unmount know this is for real.
166 */
167 VTOC(mi->mi_rootvp)->c_flags |= C_UNMOUNTING;
168 coda_unmounting(mi->mi_vfsp);
169
170 /*
171 * Wakeup clients so they can return.
172 */
173 outstanding_upcalls = 0;
174 TAILQ_FOREACH_SAFE(vmp, &vcp->vc_requests, vm_chain, nvmp) {
175 /*
176 * Free signal request messages and don't wakeup cause no one
177 * is waiting.
178 */
179 if (vmp->vm_opcode == CODA_SIGNAL) {
180 CODA_FREE((caddr_t)vmp->vm_data,
181 (u_int)VC_IN_NO_DATA);
182 CODA_FREE((caddr_t)vmp, (u_int)sizeof(struct vmsg));
183 continue;
184 }
185 outstanding_upcalls++;
186 wakeup(&vmp->vm_sleep);
187 }
188 TAILQ_FOREACH(vmp, &vcp->vc_replies, vm_chain) {
189 outstanding_upcalls++;
190 wakeup(&vmp->vm_sleep);
191 }
192 MARK_VC_CLOSED(vcp);
193 if (outstanding_upcalls) {
194 #ifdef CODA_VERBOSE
195 printf("presleep: outstanding_upcalls = %d\n",
196 outstanding_upcalls);
197 #endif
198 (void) tsleep(&outstanding_upcalls, coda_call_sleep,
199 "coda_umount", 0);
200 #ifdef CODA_VERBOSE
201 printf("postsleep: outstanding_upcalls = %d\n",
202 outstanding_upcalls);
203 #endif
204 }
205 err = dounmount(mi->mi_vfsp, flag, td);
206 if (err)
207 myprintf(("Error %d unmounting vfs in vcclose(%s)\n", err,
208 devtoname(dev)));
209 return (0);
210 }
211
212 int
213 vc_read(struct cdev *dev, struct uio *uiop, int flag)
214 {
215 struct vcomm *vcp;
216 struct vmsg *vmp;
217 int error = 0;
218
219 ENTRY;
220 vcp = &dev2coda_mntinfo(dev)->mi_vcomm;
221
222 /*
223 * Get message at head of request queue.
224 */
225 vmp = TAILQ_FIRST(&vcp->vc_requests);
226 if (vmp == NULL)
227 return (0); /* Nothing to read */
228
229 /*
230 * Move the input args into userspace.
231 *
232 * XXXRW: This is not safe in the presence of >1 reader, as vmp is
233 * still on the head of the list.
234 */
235 uiop->uio_rw = UIO_READ;
236 error = uiomove(vmp->vm_data, vmp->vm_inSize, uiop);
237 if (error) {
238 myprintf(("vcread: error (%d) on uiomove\n", error));
239 error = EINVAL;
240 }
241 TAILQ_REMOVE(&vcp->vc_requests, vmp, vm_chain);
242
243 /*
244 * If request was a signal, free up the message and don't enqueue it
245 * in the reply queue.
246 */
247 if (vmp->vm_opcode == CODA_SIGNAL) {
248 if (codadebug)
249 myprintf(("vcread: signal msg (%d, %d)\n",
250 vmp->vm_opcode, vmp->vm_unique));
251 CODA_FREE((caddr_t)vmp->vm_data, (u_int)VC_IN_NO_DATA);
252 CODA_FREE((caddr_t)vmp, (u_int)sizeof(struct vmsg));
253 return (error);
254 }
255 vmp->vm_flags |= VM_READ;
256 TAILQ_INSERT_TAIL(&vcp->vc_replies, vmp, vm_chain);
257 return (error);
258 }
259
260 int
261 vc_write(struct cdev *dev, struct uio *uiop, int flag)
262 {
263 struct vcomm *vcp;
264 struct vmsg *vmp;
265 struct coda_out_hdr *out;
266 u_long seq;
267 u_long opcode;
268 int buf[2];
269 int error = 0;
270
271 ENTRY;
272 vcp = &dev2coda_mntinfo(dev)->mi_vcomm;
273
274 /*
275 * Peek at the opcode, unique without transfering the data.
276 */
277 uiop->uio_rw = UIO_WRITE;
278 error = uiomove((caddr_t)buf, sizeof(int) * 2, uiop);
279 if (error) {
280 myprintf(("vcwrite: error (%d) on uiomove\n", error));
281 return (EINVAL);
282 }
283 opcode = buf[0];
284 seq = buf[1];
285 if (codadebug)
286 myprintf(("vcwrite got a call for %ld.%ld\n", opcode, seq));
287 if (DOWNCALL(opcode)) {
288 union outputArgs pbuf;
289
290 /*
291 * Get the rest of the data.
292 */
293 uiop->uio_rw = UIO_WRITE;
294 error = uiomove((caddr_t)&pbuf.coda_purgeuser.oh.result,
295 sizeof(pbuf) - (sizeof(int)*2), uiop);
296 if (error) {
297 myprintf(("vcwrite: error (%d) on uiomove (Op %ld "
298 "seq %ld)\n", error, opcode, seq));
299 return (EINVAL);
300 }
301 return (handleDownCall(dev2coda_mntinfo(dev), opcode, &pbuf));
302 }
303
304 /*
305 * Look for the message on the (waiting for) reply queue.
306 */
307 TAILQ_FOREACH(vmp, &vcp->vc_replies, vm_chain) {
308 if (vmp->vm_unique == seq)
309 break;
310 }
311 if (vmp == NULL) {
312 if (codadebug)
313 myprintf(("vcwrite: msg (%ld, %ld) not found\n",
314 opcode, seq));
315 return (ESRCH);
316 }
317
318 /*
319 * Remove the message from the reply queue.
320 */
321 TAILQ_REMOVE(&vcp->vc_replies, vmp, vm_chain);
322
323 /*
324 * Move data into response buffer.
325 */
326 out = (struct coda_out_hdr *)vmp->vm_data;
327
328 /*
329 * Don't need to copy opcode and uniquifier.
330 *
331 * Get the rest of the data.
332 */
333 if (vmp->vm_outSize < uiop->uio_resid) {
334 myprintf(("vcwrite: more data than asked for (%d < %zd)\n",
335 vmp->vm_outSize, uiop->uio_resid));
336
337 /*
338 * Notify caller of the error.
339 */
340 wakeup(&vmp->vm_sleep);
341 return (EINVAL);
342 }
343
344 /*
345 * Save the value.
346 */
347 buf[0] = uiop->uio_resid;
348 uiop->uio_rw = UIO_WRITE;
349 error = uiomove((caddr_t) &out->result, vmp->vm_outSize -
350 (sizeof(int) * 2), uiop);
351 if (error) {
352 myprintf(("vcwrite: error (%d) on uiomove (op %ld seq %ld)\n",
353 error, opcode, seq));
354 return (EINVAL);
355 }
356
357 /*
358 * I don't think these are used, but just in case.
359 *
360 * XXX - aren't these two already correct? -bnoble
361 */
362 out->opcode = opcode;
363 out->unique = seq;
364 vmp->vm_outSize = buf[0]; /* Amount of data transferred? */
365 vmp->vm_flags |= VM_WRITE;
366 error = 0;
367 if (opcode == CODA_OPEN_BY_FD) {
368 struct coda_open_by_fd_out *tmp =
369 (struct coda_open_by_fd_out *)out;
370 struct file *fp;
371 struct vnode *vp = NULL;
372
373 if (tmp->oh.result == 0) {
374 error = getvnode(uiop->uio_td->td_proc->p_fd,
375 tmp->fd, &fp);
376 if (!error) {
377 /*
378 * XXX: Since the whole driver runs with
379 * Giant, don't actually need to acquire it
380 * explicitly here yet.
381 */
382 mtx_lock(&Giant);
383 vp = fp->f_vnode;
384 VREF(vp);
385 fdrop(fp, uiop->uio_td);
386 mtx_unlock(&Giant);
387 }
388 }
389 tmp->vp = vp;
390 }
391 wakeup(&vmp->vm_sleep);
392 return (error);
393 }
394
395 int
396 vc_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
397 struct thread *t)
398 {
399
400 ENTRY;
401 switch(cmd) {
402 case CODARESIZE:
403 return (ENODEV);
404
405 case CODASTATS:
406 return (ENODEV);
407
408 case CODAPRINT:
409 return (ENODEV);
410
411 case CIOC_KERNEL_VERSION:
412 switch (*(u_int *)addr) {
413 case 0:
414 *(u_int *)addr = coda_kernel_version;
415 return (0);
416
417 case 1:
418 case 2:
419 if (coda_kernel_version != *(u_int *)addr)
420 return (ENOENT);
421 else
422 return (0);
423
424 default:
425 return (ENOENT);
426 }
427
428 default:
429 return (EINVAL);
430 }
431 }
432
433 int
434 vc_poll(struct cdev *dev, int events, struct thread *td)
435 {
436 struct vcomm *vcp;
437 int event_msk = 0;
438
439 ENTRY;
440 vcp = &dev2coda_mntinfo(dev)->mi_vcomm;
441 event_msk = events & (POLLIN|POLLRDNORM);
442 if (!event_msk)
443 return (0);
444 if (!TAILQ_EMPTY(&vcp->vc_requests))
445 return (events & (POLLIN|POLLRDNORM));
446 selrecord(td, &(vcp->vc_selproc));
447 return (0);
448 }
449
450 /*
451 * Statistics.
452 */
453 struct coda_clstat coda_clstat;
454
455 /*
456 * Key question: whether to sleep interuptably or uninteruptably when waiting
457 * for Venus. The former seems better (cause you can ^C a job), but then
458 * GNU-EMACS completion breaks. Use tsleep with no timeout, and no longjmp
459 * happens. But, when sleeping "uninterruptibly", we don't get told if it
460 * returns abnormally (e.g. kill -9).
461 */
462 int
463 coda_call(struct coda_mntinfo *mntinfo, int inSize, int *outSize,
464 caddr_t buffer)
465 {
466 struct vcomm *vcp;
467 struct vmsg *vmp;
468 int error;
469 #ifdef CTL_C
470 struct thread *td = curthread;
471 struct proc *p = td->td_proc;
472 sigset_t psig_omask;
473 sigset_t tempset;
474 int i;
475 #endif
476
477 /*
478 * Unlikely, but could be a race condition with a dying warden.
479 */
480 if (mntinfo == NULL)
481 return ENODEV;
482 vcp = &(mntinfo->mi_vcomm);
483 coda_clstat.ncalls++;
484 coda_clstat.reqs[((struct coda_in_hdr *)buffer)->opcode]++;
485 if (!VC_OPEN(vcp))
486 return (ENODEV);
487 CODA_ALLOC(vmp,struct vmsg *,sizeof(struct vmsg));
488
489 /*
490 * Format the request message.
491 */
492 vmp->vm_data = buffer;
493 vmp->vm_flags = 0;
494 vmp->vm_inSize = inSize;
495 vmp->vm_outSize
496 = *outSize ? *outSize : inSize; /* |buffer| >= inSize */
497 vmp->vm_opcode = ((struct coda_in_hdr *)buffer)->opcode;
498 vmp->vm_unique = ++vcp->vc_seq;
499 if (codadebug)
500 myprintf(("Doing a call for %d.%d\n", vmp->vm_opcode,
501 vmp->vm_unique));
502
503 /*
504 * Fill in the common input args.
505 */
506 ((struct coda_in_hdr *)buffer)->unique = vmp->vm_unique;
507
508 /*
509 * Append msg to request queue and poke Venus.
510 */
511 TAILQ_INSERT_TAIL(&vcp->vc_requests, vmp, vm_chain);
512 selwakeuppri(&(vcp->vc_selproc), coda_call_sleep);
513
514 /*
515 * We can be interrupted while we wait for Venus to process our
516 * request. If the interrupt occurs before Venus has read the
517 * request, we dequeue and return. If it occurs after the read but
518 * before the reply, we dequeue, send a signal message, and return.
519 * If it occurs after the reply we ignore it. In no case do we want
520 * to restart the syscall. If it was interrupted by a venus shutdown
521 * (vcclose), return ENODEV.
522 *
523 * Ignore return, we have to check anyway.
524 */
525 #ifdef CTL_C
526 /*
527 * This is work in progress. Setting coda_pcatch lets tsleep
528 * reawaken on a ^c or ^z. The problem is that emacs sets certain
529 * interrupts as SA_RESTART. This means that we should exit sleep
530 * handle the "signal" and then go to sleep again. Mostly this is
531 * done by letting the syscall complete and be restarted. We are not
532 * idempotent and 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", hz*2);
540 if (error == 0)
541 break;
542 else if (error == EWOULDBLOCK) {
543 #ifdef CODA_VERBOSE
544 printf("coda_call: tsleep TIMEOUT %d sec\n", 2+2*i);
545 #endif
546 }
547 else {
548 SIGEMPTYSET(tempset);
549 SIGADDSET(tempset, SIGIO);
550 if (SIGSETEQ(td->td_siglist, tempset)) {
551 SIGADDSET(td->td_sigmask, SIGIO);
552 #ifdef CODA_VERBOSE
553 printf("coda_call: tsleep returns %d SIGIO, "
554 "cnt %d\n", error, i);
555 #endif
556 } else {
557 SIGDELSET(tempset, SIGIO);
558 SIGADDSET(tempset, SIGALRM);
559 if (SIGSETEQ(td->td_siglist, tempset)) {
560 SIGADDSET(td->td_sigmask, SIGALRM);
561 #ifdef CODA_VERBOSE
562 printf("coda_call: tsleep returns "
563 "%d SIGALRM, cnt %d\n", error, i);
564 #endif
565 } else {
566 #ifdef CODA_VERBOSE
567 printf("coda_call: tsleep returns "
568 "%d, cnt %d\n", error, i);
569 #endif
570
571 #ifdef notyet
572 tempset = td->td_siglist;
573 SIGSETNAND(tempset, td->td_sigmask);
574 printf("coda_call: siglist = %p, "
575 "sigmask = %p, mask %p\n",
576 td->td_siglist, td->td_sigmask,
577 tempset);
578 break;
579 SIGSETOR(td->td_sigmask, td->td_siglist);
580 tempset = td->td_siglist;
581 SIGSETNAND(tempset, td->td_sigmask);
582 printf("coda_call: new mask, "
583 "siglist = %p, sigmask = %p, "
584 "mask %p\n", td->td_siglist,
585 td->td_sigmask, 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)) {
598 /*
599 * Venus is still alive.
600 *
601 * Op went through, interrupt or not...
602 */
603 if (vmp->vm_flags & VM_WRITE) {
604 error = 0;
605 *outSize = vmp->vm_outSize;
606 } else if (!(vmp->vm_flags & VM_READ)) {
607 /* Interrupted before venus read it. */
608 #ifdef CODA_VERBOSE
609 if (1)
610 #else
611 if (codadebug)
612 #endif
613 myprintf(("interrupted before read: op = "
614 "%d.%d, flags = %x\n", vmp->vm_opcode,
615 vmp->vm_unique, vmp->vm_flags));
616 TAILQ_REMOVE(&vcp->vc_requests, vmp, vm_chain);
617 error = EINTR;
618 } else {
619 /*
620 * (!(vmp->vm_flags & VM_WRITE)) means interrupted
621 * after upcall started.
622 *
623 * Interrupted after start of upcall, send venus a
624 * signal.
625 */
626 struct coda_in_hdr *dog;
627 struct vmsg *svmp;
628
629 #ifdef CODA_VERBOSE
630 if (1)
631 #else
632 if (codadebug)
633 #endif
634 myprintf(("Sending Venus a signal: op = "
635 "%d.%d, flags = %x\n", vmp->vm_opcode,
636 vmp->vm_unique, vmp->vm_flags));
637 TAILQ_REMOVE(&vcp->vc_requests, vmp, vm_chain);
638 error = EINTR;
639 CODA_ALLOC(svmp, struct vmsg *, sizeof(struct vmsg));
640 CODA_ALLOC((svmp->vm_data), char *,
641 sizeof(struct coda_in_hdr));
642 dog = (struct coda_in_hdr *)svmp->vm_data;
643 svmp->vm_flags = 0;
644 dog->opcode = svmp->vm_opcode = CODA_SIGNAL;
645 dog->unique = svmp->vm_unique = vmp->vm_unique;
646 svmp->vm_inSize = sizeof (struct coda_in_hdr);
647 /*??? rvb */ svmp->vm_outSize = sizeof (struct coda_in_hdr);
648 if (codadebug)
649 myprintf(("coda_call: enqueing signal msg "
650 "(%d, %d)\n", svmp->vm_opcode,
651 svmp->vm_unique));
652
653 /*
654 * Insert at head of queue!
655 *
656 * XXXRW: Actually, the tail.
657 */
658 TAILQ_INSERT_TAIL(&vcp->vc_requests, svmp, vm_chain);
659 selwakeuppri(&(vcp->vc_selproc), coda_call_sleep);
660 }
661 } else {
662 /* If venus died (!VC_OPEN(vcp)) */
663 if (codadebug)
664 myprintf(("vcclose woke op %d.%d flags %d\n",
665 vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
666 error = ENODEV;
667 }
668 CODA_FREE(vmp, sizeof(struct vmsg));
669 if (outstanding_upcalls > 0 && (--outstanding_upcalls == 0))
670 wakeup(&outstanding_upcalls);
671 if (!error)
672 error = ((struct coda_out_hdr *)buffer)->result;
673 return (error);
674 }
Cache object: ff098e1479d1fd7e2b12fec203a8a666
|