xref: /openbmc/linux/fs/coda/upcall.c (revision d5cb9783536a41df9f9cba5b0a1d78047ed787f7)
1 /*
2  * Mostly platform independent upcall operations to Venus:
3  *  -- upcalls
4  *  -- upcall routines
5  *
6  * Linux 2.0 version
7  * Copyright (C) 1996 Peter J. Braam <braam@maths.ox.ac.uk>,
8  * Michael Callahan <callahan@maths.ox.ac.uk>
9  *
10  * Redone for Linux 2.1
11  * Copyright (C) 1997 Carnegie Mellon University
12  *
13  * Carnegie Mellon University encourages users of this code to contribute
14  * improvements to the Coda project. Contact Peter Braam <coda@cs.cmu.edu>.
15  */
16 
17 #include <asm/system.h>
18 #include <linux/signal.h>
19 
20 #include <linux/types.h>
21 #include <linux/kernel.h>
22 #include <linux/mm.h>
23 #include <linux/time.h>
24 #include <linux/fs.h>
25 #include <linux/file.h>
26 #include <linux/stat.h>
27 #include <linux/errno.h>
28 #include <linux/string.h>
29 #include <asm/uaccess.h>
30 #include <linux/vmalloc.h>
31 #include <linux/vfs.h>
32 
33 #include <linux/coda.h>
34 #include <linux/coda_linux.h>
35 #include <linux/coda_psdev.h>
36 #include <linux/coda_fs_i.h>
37 #include <linux/coda_cache.h>
38 #include <linux/coda_proc.h>
39 
40 #define upc_alloc() kmalloc(sizeof(struct upc_req), GFP_KERNEL)
41 #define upc_free(r) kfree(r)
42 
43 static int coda_upcall(struct coda_sb_info *mntinfo, int inSize, int *outSize,
44 		       union inputArgs *buffer);
45 
46 static void *alloc_upcall(int opcode, int size)
47 {
48 	union inputArgs *inp;
49 
50 	CODA_ALLOC(inp, union inputArgs *, size);
51         if (!inp)
52 		return ERR_PTR(-ENOMEM);
53 
54         inp->ih.opcode = opcode;
55 	inp->ih.pid = current->pid;
56 	inp->ih.pgid = process_group(current);
57 #ifdef CONFIG_CODA_FS_OLD_API
58 	memset(&inp->ih.cred, 0, sizeof(struct coda_cred));
59 	inp->ih.cred.cr_fsuid = current->fsuid;
60 #else
61 	inp->ih.uid = current->fsuid;
62 #endif
63 	return (void*)inp;
64 }
65 
66 #define UPARG(op)\
67 do {\
68 	inp = (union inputArgs *)alloc_upcall(op, insize); \
69         if (IS_ERR(inp)) { return PTR_ERR(inp); }\
70         outp = (union outputArgs *)(inp); \
71         outsize = insize; \
72 } while (0)
73 
74 #define INSIZE(tag) sizeof(struct coda_ ## tag ## _in)
75 #define OUTSIZE(tag) sizeof(struct coda_ ## tag ## _out)
76 #define SIZE(tag)  max_t(unsigned int, INSIZE(tag), OUTSIZE(tag))
77 
78 
79 /* the upcalls */
80 int venus_rootfid(struct super_block *sb, struct CodaFid *fidp)
81 {
82         union inputArgs *inp;
83         union outputArgs *outp;
84         int insize, outsize, error;
85 
86         insize = SIZE(root);
87         UPARG(CODA_ROOT);
88 
89 	error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
90 
91 	if (error) {
92 	        printk("coda_get_rootfid: error %d\n", error);
93 	} else {
94 		*fidp = outp->coda_root.VFid;
95 	}
96 
97 	CODA_FREE(inp, insize);
98 	return error;
99 }
100 
101 int venus_getattr(struct super_block *sb, struct CodaFid *fid,
102 		     struct coda_vattr *attr)
103 {
104         union inputArgs *inp;
105         union outputArgs *outp;
106         int insize, outsize, error;
107 
108         insize = SIZE(getattr);
109 	UPARG(CODA_GETATTR);
110         inp->coda_getattr.VFid = *fid;
111 
112         error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
113 
114 	*attr = outp->coda_getattr.attr;
115 
116 	CODA_FREE(inp, insize);
117         return error;
118 }
119 
120 int venus_setattr(struct super_block *sb, struct CodaFid *fid,
121 		  struct coda_vattr *vattr)
122 {
123         union inputArgs *inp;
124         union outputArgs *outp;
125         int insize, outsize, error;
126 
127 	insize = SIZE(setattr);
128 	UPARG(CODA_SETATTR);
129 
130         inp->coda_setattr.VFid = *fid;
131 	inp->coda_setattr.attr = *vattr;
132 
133         error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
134 
135         CODA_FREE(inp, insize);
136         return error;
137 }
138 
139 int venus_lookup(struct super_block *sb, struct CodaFid *fid,
140 		    const char *name, int length, int * type,
141 		    struct CodaFid *resfid)
142 {
143         union inputArgs *inp;
144         union outputArgs *outp;
145         int insize, outsize, error;
146 	int offset;
147 
148 	offset = INSIZE(lookup);
149         insize = max_t(unsigned int, offset + length +1, OUTSIZE(lookup));
150 	UPARG(CODA_LOOKUP);
151 
152         inp->coda_lookup.VFid = *fid;
153 	inp->coda_lookup.name = offset;
154 	inp->coda_lookup.flags = CLU_CASE_SENSITIVE;
155         /* send Venus a null terminated string */
156         memcpy((char *)(inp) + offset, name, length);
157         *((char *)inp + offset + length) = '\0';
158 
159         error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
160 
161 	*resfid = outp->coda_lookup.VFid;
162 	*type = outp->coda_lookup.vtype;
163 
164 	CODA_FREE(inp, insize);
165 	return error;
166 }
167 
168 int venus_store(struct super_block *sb, struct CodaFid *fid, int flags,
169                 vuid_t uid)
170 {
171         union inputArgs *inp;
172         union outputArgs *outp;
173         int insize, outsize, error;
174 #ifdef CONFIG_CODA_FS_OLD_API
175 	struct coda_cred cred = { 0, };
176 	cred.cr_fsuid = uid;
177 #endif
178 
179 	insize = SIZE(store);
180 	UPARG(CODA_STORE);
181 
182 #ifdef CONFIG_CODA_FS_OLD_API
183 	memcpy(&(inp->ih.cred), &cred, sizeof(cred));
184 #else
185 	inp->ih.uid = uid;
186 #endif
187 
188         inp->coda_store.VFid = *fid;
189         inp->coda_store.flags = flags;
190 
191         error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
192 
193 	CODA_FREE(inp, insize);
194         return error;
195 }
196 
197 int venus_release(struct super_block *sb, struct CodaFid *fid, int flags)
198 {
199         union inputArgs *inp;
200         union outputArgs *outp;
201         int insize, outsize, error;
202 
203 	insize = SIZE(release);
204 	UPARG(CODA_RELEASE);
205 
206 	inp->coda_release.VFid = *fid;
207 	inp->coda_release.flags = flags;
208 
209 	error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
210 
211 	CODA_FREE(inp, insize);
212 	return error;
213 }
214 
215 int venus_close(struct super_block *sb, struct CodaFid *fid, int flags,
216                 vuid_t uid)
217 {
218 	union inputArgs *inp;
219 	union outputArgs *outp;
220 	int insize, outsize, error;
221 #ifdef CONFIG_CODA_FS_OLD_API
222 	struct coda_cred cred = { 0, };
223 	cred.cr_fsuid = uid;
224 #endif
225 
226 	insize = SIZE(release);
227 	UPARG(CODA_CLOSE);
228 
229 #ifdef CONFIG_CODA_FS_OLD_API
230 	memcpy(&(inp->ih.cred), &cred, sizeof(cred));
231 #else
232 	inp->ih.uid = uid;
233 #endif
234 
235         inp->coda_close.VFid = *fid;
236         inp->coda_close.flags = flags;
237 
238         error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
239 
240 	CODA_FREE(inp, insize);
241         return error;
242 }
243 
244 int venus_open(struct super_block *sb, struct CodaFid *fid,
245 		  int flags, struct file **fh)
246 {
247         union inputArgs *inp;
248         union outputArgs *outp;
249         int insize, outsize, error;
250 
251 	insize = SIZE(open_by_fd);
252 	UPARG(CODA_OPEN_BY_FD);
253 
254         inp->coda_open.VFid = *fid;
255         inp->coda_open.flags = flags;
256 
257         error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
258 
259 	*fh = outp->coda_open_by_fd.fh;
260 
261 	CODA_FREE(inp, insize);
262 	return error;
263 }
264 
265 int venus_mkdir(struct super_block *sb, struct CodaFid *dirfid,
266 		   const char *name, int length,
267 		   struct CodaFid *newfid, struct coda_vattr *attrs)
268 {
269         union inputArgs *inp;
270         union outputArgs *outp;
271         int insize, outsize, error;
272         int offset;
273 
274 	offset = INSIZE(mkdir);
275 	insize = max_t(unsigned int, offset + length + 1, OUTSIZE(mkdir));
276 	UPARG(CODA_MKDIR);
277 
278         inp->coda_mkdir.VFid = *dirfid;
279         inp->coda_mkdir.attr = *attrs;
280 	inp->coda_mkdir.name = offset;
281         /* Venus must get null terminated string */
282         memcpy((char *)(inp) + offset, name, length);
283         *((char *)inp + offset + length) = '\0';
284 
285         error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
286 
287 	*attrs = outp->coda_mkdir.attr;
288 	*newfid = outp->coda_mkdir.VFid;
289 
290 	CODA_FREE(inp, insize);
291 	return error;
292 }
293 
294 
295 int venus_rename(struct super_block *sb, struct CodaFid *old_fid,
296 		 struct CodaFid *new_fid, size_t old_length,
297 		 size_t new_length, const char *old_name,
298 		 const char *new_name)
299 {
300 	union inputArgs *inp;
301         union outputArgs *outp;
302         int insize, outsize, error;
303 	int offset, s;
304 
305 	offset = INSIZE(rename);
306 	insize = max_t(unsigned int, offset + new_length + old_length + 8,
307 		     OUTSIZE(rename));
308  	UPARG(CODA_RENAME);
309 
310         inp->coda_rename.sourceFid = *old_fid;
311         inp->coda_rename.destFid =  *new_fid;
312         inp->coda_rename.srcname = offset;
313 
314         /* Venus must receive an null terminated string */
315         s = ( old_length & ~0x3) +4; /* round up to word boundary */
316         memcpy((char *)(inp) + offset, old_name, old_length);
317         *((char *)inp + offset + old_length) = '\0';
318 
319         /* another null terminated string for Venus */
320         offset += s;
321         inp->coda_rename.destname = offset;
322         s = ( new_length & ~0x3) +4; /* round up to word boundary */
323         memcpy((char *)(inp) + offset, new_name, new_length);
324         *((char *)inp + offset + new_length) = '\0';
325 
326         error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
327 
328 	CODA_FREE(inp, insize);
329 	return error;
330 }
331 
332 int venus_create(struct super_block *sb, struct CodaFid *dirfid,
333 		 const char *name, int length, int excl, int mode,
334 		 struct CodaFid *newfid, struct coda_vattr *attrs)
335 {
336         union inputArgs *inp;
337         union outputArgs *outp;
338         int insize, outsize, error;
339         int offset;
340 
341         offset = INSIZE(create);
342 	insize = max_t(unsigned int, offset + length + 1, OUTSIZE(create));
343 	UPARG(CODA_CREATE);
344 
345         inp->coda_create.VFid = *dirfid;
346         inp->coda_create.attr.va_mode = mode;
347 	inp->coda_create.excl = excl;
348         inp->coda_create.mode = mode;
349         inp->coda_create.name = offset;
350 
351         /* Venus must get null terminated string */
352         memcpy((char *)(inp) + offset, name, length);
353         *((char *)inp + offset + length) = '\0';
354 
355         error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
356 
357 	*attrs = outp->coda_create.attr;
358 	*newfid = outp->coda_create.VFid;
359 
360 	CODA_FREE(inp, insize);
361 	return error;
362 }
363 
364 int venus_rmdir(struct super_block *sb, struct CodaFid *dirfid,
365 		    const char *name, int length)
366 {
367         union inputArgs *inp;
368         union outputArgs *outp;
369         int insize, outsize, error;
370         int offset;
371 
372         offset = INSIZE(rmdir);
373 	insize = max_t(unsigned int, offset + length + 1, OUTSIZE(rmdir));
374 	UPARG(CODA_RMDIR);
375 
376         inp->coda_rmdir.VFid = *dirfid;
377         inp->coda_rmdir.name = offset;
378         memcpy((char *)(inp) + offset, name, length);
379 	*((char *)inp + offset + length) = '\0';
380 
381         error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
382 
383 	CODA_FREE(inp, insize);
384 	return error;
385 }
386 
387 int venus_remove(struct super_block *sb, struct CodaFid *dirfid,
388 		    const char *name, int length)
389 {
390         union inputArgs *inp;
391         union outputArgs *outp;
392         int error=0, insize, outsize, offset;
393 
394         offset = INSIZE(remove);
395 	insize = max_t(unsigned int, offset + length + 1, OUTSIZE(remove));
396 	UPARG(CODA_REMOVE);
397 
398         inp->coda_remove.VFid = *dirfid;
399         inp->coda_remove.name = offset;
400         memcpy((char *)(inp) + offset, name, length);
401 	*((char *)inp + offset + length) = '\0';
402 
403         error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
404 
405 	CODA_FREE(inp, insize);
406 	return error;
407 }
408 
409 int venus_readlink(struct super_block *sb, struct CodaFid *fid,
410 		      char *buffer, int *length)
411 {
412         union inputArgs *inp;
413         union outputArgs *outp;
414         int insize, outsize, error;
415         int retlen;
416         char *result;
417 
418 	insize = max_t(unsigned int,
419 		     INSIZE(readlink), OUTSIZE(readlink)+ *length + 1);
420 	UPARG(CODA_READLINK);
421 
422         inp->coda_readlink.VFid = *fid;
423 
424         error =  coda_upcall(coda_sbp(sb), insize, &outsize, inp);
425 
426 	if (! error) {
427                 retlen = outp->coda_readlink.count;
428 		if ( retlen > *length )
429 		        retlen = *length;
430 		*length = retlen;
431 		result =  (char *)outp + (long)outp->coda_readlink.data;
432 		memcpy(buffer, result, retlen);
433 		*(buffer + retlen) = '\0';
434 	}
435 
436         CODA_FREE(inp, insize);
437         return error;
438 }
439 
440 
441 
442 int venus_link(struct super_block *sb, struct CodaFid *fid,
443 		  struct CodaFid *dirfid, const char *name, int len )
444 {
445         union inputArgs *inp;
446         union outputArgs *outp;
447         int insize, outsize, error;
448         int offset;
449 
450 	offset = INSIZE(link);
451 	insize = max_t(unsigned int, offset  + len + 1, OUTSIZE(link));
452         UPARG(CODA_LINK);
453 
454         inp->coda_link.sourceFid = *fid;
455         inp->coda_link.destFid = *dirfid;
456         inp->coda_link.tname = offset;
457 
458         /* make sure strings are null terminated */
459         memcpy((char *)(inp) + offset, name, len);
460         *((char *)inp + offset + len) = '\0';
461 
462         error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
463 
464 	CODA_FREE(inp, insize);
465         return error;
466 }
467 
468 int venus_symlink(struct super_block *sb, struct CodaFid *fid,
469 		     const char *name, int len,
470 		     const char *symname, int symlen)
471 {
472         union inputArgs *inp;
473         union outputArgs *outp;
474         int insize, outsize, error;
475         int offset, s;
476 
477         offset = INSIZE(symlink);
478 	insize = max_t(unsigned int, offset + len + symlen + 8, OUTSIZE(symlink));
479 	UPARG(CODA_SYMLINK);
480 
481         /*        inp->coda_symlink.attr = *tva; XXXXXX */
482         inp->coda_symlink.VFid = *fid;
483 
484 	/* Round up to word boundary and null terminate */
485         inp->coda_symlink.srcname = offset;
486         s = ( symlen  & ~0x3 ) + 4;
487         memcpy((char *)(inp) + offset, symname, symlen);
488         *((char *)inp + offset + symlen) = '\0';
489 
490 	/* Round up to word boundary and null terminate */
491         offset += s;
492         inp->coda_symlink.tname = offset;
493         s = (len & ~0x3) + 4;
494         memcpy((char *)(inp) + offset, name, len);
495         *((char *)inp + offset + len) = '\0';
496 
497 	error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
498 
499 	CODA_FREE(inp, insize);
500         return error;
501 }
502 
503 int venus_fsync(struct super_block *sb, struct CodaFid *fid)
504 {
505         union inputArgs *inp;
506         union outputArgs *outp;
507 	int insize, outsize, error;
508 
509 	insize=SIZE(fsync);
510 	UPARG(CODA_FSYNC);
511 
512         inp->coda_fsync.VFid = *fid;
513         error = coda_upcall(coda_sbp(sb), sizeof(union inputArgs),
514                             &outsize, inp);
515 
516 	CODA_FREE(inp, insize);
517 	return error;
518 }
519 
520 int venus_access(struct super_block *sb, struct CodaFid *fid, int mask)
521 {
522         union inputArgs *inp;
523         union outputArgs *outp;
524 	int insize, outsize, error;
525 
526 	insize = SIZE(access);
527 	UPARG(CODA_ACCESS);
528 
529         inp->coda_access.VFid = *fid;
530         inp->coda_access.flags = mask;
531 
532 	error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
533 
534 	CODA_FREE(inp, insize);
535 	return error;
536 }
537 
538 
539 int venus_pioctl(struct super_block *sb, struct CodaFid *fid,
540 		 unsigned int cmd, struct PioctlData *data)
541 {
542         union inputArgs *inp;
543         union outputArgs *outp;
544 	int insize, outsize, error;
545 	int iocsize;
546 
547 	insize = VC_MAXMSGSIZE;
548 	UPARG(CODA_IOCTL);
549 
550         /* build packet for Venus */
551         if (data->vi.in_size > VC_MAXDATASIZE) {
552 		error = -EINVAL;
553 		goto exit;
554         }
555 
556         if (data->vi.out_size > VC_MAXDATASIZE) {
557 		error = -EINVAL;
558 		goto exit;
559 	}
560 
561         inp->coda_ioctl.VFid = *fid;
562 
563         /* the cmd field was mutated by increasing its size field to
564          * reflect the path and follow args. We need to subtract that
565          * out before sending the command to Venus.  */
566         inp->coda_ioctl.cmd = (cmd & ~(PIOCPARM_MASK << 16));
567         iocsize = ((cmd >> 16) & PIOCPARM_MASK) - sizeof(char *) - sizeof(int);
568         inp->coda_ioctl.cmd |= (iocsize & PIOCPARM_MASK) <<	16;
569 
570         /* in->coda_ioctl.rwflag = flag; */
571         inp->coda_ioctl.len = data->vi.in_size;
572         inp->coda_ioctl.data = (char *)(INSIZE(ioctl));
573 
574         /* get the data out of user space */
575         if ( copy_from_user((char*)inp + (long)inp->coda_ioctl.data,
576 			    data->vi.in, data->vi.in_size) ) {
577 		error = -EINVAL;
578 	        goto exit;
579 	}
580 
581         error = coda_upcall(coda_sbp(sb), SIZE(ioctl) + data->vi.in_size,
582                             &outsize, inp);
583 
584         if (error) {
585 	        printk("coda_pioctl: Venus returns: %d for %s\n",
586 		       error, coda_f2s(fid));
587 		goto exit;
588 	}
589 
590 	if (outsize < (long)outp->coda_ioctl.data + outp->coda_ioctl.len) {
591 		error = -EINVAL;
592 		goto exit;
593 	}
594 
595 	/* Copy out the OUT buffer. */
596         if (outp->coda_ioctl.len > data->vi.out_size) {
597 		error = -EINVAL;
598 		goto exit;
599         }
600 
601 	/* Copy out the OUT buffer. */
602 	if (copy_to_user(data->vi.out,
603 			 (char *)outp + (long)outp->coda_ioctl.data,
604 			 outp->coda_ioctl.len)) {
605 		error = -EFAULT;
606 		goto exit;
607 	}
608 
609  exit:
610 	CODA_FREE(inp, insize);
611 	return error;
612 }
613 
614 int venus_statfs(struct super_block *sb, struct kstatfs *sfs)
615 {
616         union inputArgs *inp;
617         union outputArgs *outp;
618         int insize, outsize, error;
619 
620 	insize = max_t(unsigned int, INSIZE(statfs), OUTSIZE(statfs));
621 	UPARG(CODA_STATFS);
622 
623         error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
624 
625         if (!error) {
626 		sfs->f_blocks = outp->coda_statfs.stat.f_blocks;
627 		sfs->f_bfree  = outp->coda_statfs.stat.f_bfree;
628 		sfs->f_bavail = outp->coda_statfs.stat.f_bavail;
629 		sfs->f_files  = outp->coda_statfs.stat.f_files;
630 		sfs->f_ffree  = outp->coda_statfs.stat.f_ffree;
631 	} else {
632 		printk("coda_statfs: Venus returns: %d\n", error);
633 	}
634 
635         CODA_FREE(inp, insize);
636         return error;
637 }
638 
639 /*
640  * coda_upcall and coda_downcall routines.
641  *
642  */
643 
644 static inline void coda_waitfor_upcall(struct upc_req *vmp,
645 				       struct venus_comm *vcommp)
646 {
647 	DECLARE_WAITQUEUE(wait, current);
648 
649 	vmp->uc_posttime = jiffies;
650 
651 	add_wait_queue(&vmp->uc_sleep, &wait);
652 	for (;;) {
653 		if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE )
654 			set_current_state(TASK_INTERRUPTIBLE);
655 		else
656 			set_current_state(TASK_UNINTERRUPTIBLE);
657 
658                 /* venus died */
659                 if ( !vcommp->vc_inuse )
660                         break;
661 
662 		/* got a reply */
663 		if ( vmp->uc_flags & ( REQ_WRITE | REQ_ABORT ) )
664 			break;
665 
666 		if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE && signal_pending(current) ) {
667 			/* if this process really wants to die, let it go */
668 			if ( sigismember(&(current->pending.signal), SIGKILL) ||
669 			     sigismember(&(current->pending.signal), SIGINT) )
670 				break;
671 			/* signal is present: after timeout always return
672 			   really smart idea, probably useless ... */
673 			if ( jiffies - vmp->uc_posttime > coda_timeout * HZ )
674 				break;
675 		}
676 		schedule();
677 	}
678 	remove_wait_queue(&vmp->uc_sleep, &wait);
679 	set_current_state(TASK_RUNNING);
680 
681 	return;
682 }
683 
684 
685 /*
686  * coda_upcall will return an error in the case of
687  * failed communication with Venus _or_ will peek at Venus
688  * reply and return Venus' error.
689  *
690  * As venus has 2 types of errors, normal errors (positive) and internal
691  * errors (negative), normal errors are negated, while internal errors
692  * are all mapped to -EINTR, while showing a nice warning message. (jh)
693  *
694  */
695 static int coda_upcall(struct coda_sb_info *sbi,
696 		int inSize, int *outSize,
697 		union inputArgs *buffer)
698 {
699 	struct venus_comm *vcommp;
700 	union outputArgs *out;
701 	struct upc_req *req;
702 	int error = 0;
703 
704 	vcommp = sbi->sbi_vcomm;
705 	if ( !vcommp->vc_inuse ) {
706 		printk("No pseudo device in upcall comms at %p\n", vcommp);
707                 return -ENXIO;
708 	}
709 
710 	/* Format the request message. */
711 	req = upc_alloc();
712 	if (!req) {
713 		printk("Failed to allocate upc_req structure\n");
714 		return -ENOMEM;
715 	}
716 	req->uc_data = (void *)buffer;
717 	req->uc_flags = 0;
718 	req->uc_inSize = inSize;
719 	req->uc_outSize = *outSize ? *outSize : inSize;
720 	req->uc_opcode = ((union inputArgs *)buffer)->ih.opcode;
721 	req->uc_unique = ++vcommp->vc_seq;
722 	init_waitqueue_head(&req->uc_sleep);
723 
724 	/* Fill in the common input args. */
725 	((union inputArgs *)buffer)->ih.unique = req->uc_unique;
726 
727 	/* Append msg to pending queue and poke Venus. */
728 	list_add(&(req->uc_chain), vcommp->vc_pending.prev);
729 
730 	wake_up_interruptible(&vcommp->vc_waitq);
731 	/* We can be interrupted while we wait for Venus to process
732 	 * our request.  If the interrupt occurs before Venus has read
733 	 * the request, we dequeue and return. If it occurs after the
734 	 * read but before the reply, we dequeue, send a signal
735 	 * message, and return. If it occurs after the reply we ignore
736 	 * it. In no case do we want to restart the syscall.  If it
737 	 * was interrupted by a venus shutdown (psdev_close), return
738 	 * ENODEV.  */
739 
740 	/* Go to sleep.  Wake up on signals only after the timeout. */
741 	coda_waitfor_upcall(req, vcommp);
742 
743 	if (vcommp->vc_inuse) {      /* i.e. Venus is still alive */
744 	    /* Op went through, interrupt or not... */
745 	    if (req->uc_flags & REQ_WRITE) {
746 		out = (union outputArgs *)req->uc_data;
747 		/* here we map positive Venus errors to kernel errors */
748 		error = -out->oh.result;
749 		*outSize = req->uc_outSize;
750 		goto exit;
751 	    }
752 	    if ( !(req->uc_flags & REQ_READ) && signal_pending(current)) {
753 		/* Interrupted before venus read it. */
754 		list_del(&(req->uc_chain));
755 		/* perhaps the best way to convince the app to
756 		   give up? */
757 		error = -EINTR;
758 		goto exit;
759 	    }
760 	    if ( (req->uc_flags & REQ_READ) && signal_pending(current) ) {
761 		    /* interrupted after Venus did its read, send signal */
762 		    union inputArgs *sig_inputArgs;
763 		    struct upc_req *sig_req;
764 
765 		    list_del(&(req->uc_chain));
766 		    error = -ENOMEM;
767 		    sig_req = upc_alloc();
768 		    if (!sig_req) goto exit;
769 
770 		    CODA_ALLOC((sig_req->uc_data), char *, sizeof(struct coda_in_hdr));
771 		    if (!sig_req->uc_data) {
772 			upc_free(sig_req);
773 			goto exit;
774 		    }
775 
776 		    error = -EINTR;
777 		    sig_inputArgs = (union inputArgs *)sig_req->uc_data;
778 		    sig_inputArgs->ih.opcode = CODA_SIGNAL;
779 		    sig_inputArgs->ih.unique = req->uc_unique;
780 
781 		    sig_req->uc_flags = REQ_ASYNC;
782 		    sig_req->uc_opcode = sig_inputArgs->ih.opcode;
783 		    sig_req->uc_unique = sig_inputArgs->ih.unique;
784 		    sig_req->uc_inSize = sizeof(struct coda_in_hdr);
785 		    sig_req->uc_outSize = sizeof(struct coda_in_hdr);
786 
787 		    /* insert at head of queue! */
788 		    list_add(&(sig_req->uc_chain), &vcommp->vc_pending);
789 		    wake_up_interruptible(&vcommp->vc_waitq);
790 	    } else {
791 		    printk("Coda: Strange interruption..\n");
792 		    error = -EINTR;
793 	    }
794 	} else {	/* If venus died i.e. !VC_OPEN(vcommp) */
795 	        printk("coda_upcall: Venus dead on (op,un) (%d.%d) flags %d\n",
796 		       req->uc_opcode, req->uc_unique, req->uc_flags);
797 		error = -ENODEV;
798 	}
799 
800  exit:
801 	upc_free(req);
802 	return error;
803 }
804 
805 /*
806     The statements below are part of the Coda opportunistic
807     programming -- taken from the Mach/BSD kernel code for Coda.
808     You don't get correct semantics by stating what needs to be
809     done without guaranteeing the invariants needed for it to happen.
810     When will be have time to find out what exactly is going on?  (pjb)
811 */
812 
813 
814 /*
815  * There are 7 cases where cache invalidations occur.  The semantics
816  *  of each is listed here:
817  *
818  * CODA_FLUSH     -- flush all entries from the name cache and the cnode cache.
819  * CODA_PURGEUSER -- flush all entries from the name cache for a specific user
820  *                  This call is a result of token expiration.
821  *
822  * The next arise as the result of callbacks on a file or directory.
823  * CODA_ZAPFILE   -- flush the cached attributes for a file.
824 
825  * CODA_ZAPDIR    -- flush the attributes for the dir and
826  *                  force a new lookup for all the children
827                     of this dir.
828 
829  *
830  * The next is a result of Venus detecting an inconsistent file.
831  * CODA_PURGEFID  -- flush the attribute for the file
832  *                  purge it and its children from the dcache
833  *
834  * The last  allows Venus to replace local fids with global ones
835  * during reintegration.
836  *
837  * CODA_REPLACE -- replace one CodaFid with another throughout the name cache */
838 
839 int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
840 {
841 	/* Handle invalidation requests. */
842           if ( !sb || !sb->s_root || !sb->s_root->d_inode)
843 		  return 0;
844 
845 	  switch (opcode) {
846 
847 	  case CODA_FLUSH : {
848 		   coda_cache_clear_all(sb);
849 		   shrink_dcache_sb(sb);
850 		   coda_flag_inode(sb->s_root->d_inode, C_FLUSH);
851 		   return(0);
852 	  }
853 
854 	  case CODA_PURGEUSER : {
855 		   coda_cache_clear_all(sb);
856 		   return(0);
857 	  }
858 
859 	  case CODA_ZAPDIR : {
860 	          struct inode *inode;
861 		  struct CodaFid *fid = &out->coda_zapdir.CodaFid;
862 
863 		  inode = coda_fid_to_inode(fid, sb);
864 		  if (inode) {
865 			  coda_flag_inode_children(inode, C_PURGE);
866 	                  coda_flag_inode(inode, C_VATTR);
867 			  iput(inode);
868 		  }
869 
870 		  return(0);
871 	  }
872 
873 	  case CODA_ZAPFILE : {
874 	          struct inode *inode;
875 		  struct CodaFid *fid = &out->coda_zapfile.CodaFid;
876 		  inode = coda_fid_to_inode(fid, sb);
877 		  if ( inode ) {
878 	                  coda_flag_inode(inode, C_VATTR);
879 			  iput(inode);
880 		  }
881 		  return 0;
882 	  }
883 
884 	  case CODA_PURGEFID : {
885 	          struct inode *inode;
886 		  struct CodaFid *fid = &out->coda_purgefid.CodaFid;
887 		  inode = coda_fid_to_inode(fid, sb);
888 		  if ( inode ) {
889 			coda_flag_inode_children(inode, C_PURGE);
890 
891 			/* catch the dentries later if some are still busy */
892 			coda_flag_inode(inode, C_PURGE);
893 			d_prune_aliases(inode);
894 
895 			iput(inode);
896 		  }
897 		  return 0;
898 	  }
899 
900 	  case CODA_REPLACE : {
901 	          struct inode *inode;
902 		  struct CodaFid *oldfid = &out->coda_replace.OldFid;
903 		  struct CodaFid *newfid = &out->coda_replace.NewFid;
904 		  inode = coda_fid_to_inode(oldfid, sb);
905 		  if ( inode ) {
906 			  coda_replace_fid(inode, oldfid, newfid);
907 			  iput(inode);
908 		  }
909 		  return 0;
910 	  }
911 	  }
912 	  return 0;
913 }
914 
915