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