coda: ignore returned values when upcalls return errors
[pandora-kernel.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 coda_sb_info *mntinfo, 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_sbp(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_sbp(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_sbp(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_sbp(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_sbp(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_sbp(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_sbp(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_sbp(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_sbp(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_sbp(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_sbp(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_sbp(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_sbp(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_sbp(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_sbp(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_sbp(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_sbp(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_sbp(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_sbp(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_sbp(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  */
723 static int coda_upcall(struct coda_sb_info *sbi,
724                        int inSize, int *outSize,
725                        union inputArgs *buffer)
726 {
727         struct venus_comm *vcommp;
728         union outputArgs *out;
729         union inputArgs *sig_inputArgs;
730         struct upc_req *req, *sig_req;
731         int error = 0;
732
733         vcommp = sbi->sbi_vcomm;
734         if (!vcommp->vc_inuse) {
735                 printk(KERN_NOTICE "coda: Venus dead, not sending upcall\n");
736                 return -ENXIO;
737         }
738
739         /* Format the request message. */
740         req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
741         if (!req)
742                 return -ENOMEM;
743
744         req->uc_data = (void *)buffer;
745         req->uc_flags = 0;
746         req->uc_inSize = inSize;
747         req->uc_outSize = *outSize ? *outSize : inSize;
748         req->uc_opcode = ((union inputArgs *)buffer)->ih.opcode;
749         req->uc_unique = ++vcommp->vc_seq;
750         init_waitqueue_head(&req->uc_sleep);
751
752         /* Fill in the common input args. */
753         ((union inputArgs *)buffer)->ih.unique = req->uc_unique;
754
755         /* Append msg to pending queue and poke Venus. */
756         list_add_tail(&req->uc_chain, &vcommp->vc_pending);
757
758         wake_up_interruptible(&vcommp->vc_waitq);
759         /* We can be interrupted while we wait for Venus to process
760          * our request.  If the interrupt occurs before Venus has read
761          * the request, we dequeue and return. If it occurs after the
762          * read but before the reply, we dequeue, send a signal
763          * message, and return. If it occurs after the reply we ignore
764          * it. In no case do we want to restart the syscall.  If it
765          * was interrupted by a venus shutdown (psdev_close), return
766          * ENODEV.  */
767
768         /* Go to sleep.  Wake up on signals only after the timeout. */
769         coda_waitfor_upcall(req);
770
771         /* Op went through, interrupt or not... */
772         if (req->uc_flags & REQ_WRITE) {
773                 out = (union outputArgs *)req->uc_data;
774                 /* here we map positive Venus errors to kernel errors */
775                 error = -out->oh.result;
776                 *outSize = req->uc_outSize;
777                 goto exit;
778         }
779
780         error = -EINTR;
781         if ((req->uc_flags & REQ_ABORT) || !signal_pending(current)) {
782                 printk(KERN_WARNING "coda: Unexpected interruption.\n");
783                 goto exit;
784         }
785
786         /* Interrupted before venus read it. */
787         if (!(req->uc_flags & REQ_READ))
788                 goto exit;
789
790         /* Venus saw the upcall, make sure we can send interrupt signal */
791         if (!vcommp->vc_inuse) {
792                 printk(KERN_INFO "coda: Venus dead, not sending signal.\n");
793                 goto exit;
794         }
795
796         error = -ENOMEM;
797         sig_req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
798         if (!sig_req) goto exit;
799
800         CODA_ALLOC((sig_req->uc_data), char *, sizeof(struct coda_in_hdr));
801         if (!sig_req->uc_data) {
802                 kfree(sig_req);
803                 goto exit;
804         }
805
806         error = -EINTR;
807         sig_inputArgs = (union inputArgs *)sig_req->uc_data;
808         sig_inputArgs->ih.opcode = CODA_SIGNAL;
809         sig_inputArgs->ih.unique = req->uc_unique;
810
811         sig_req->uc_flags = REQ_ASYNC;
812         sig_req->uc_opcode = sig_inputArgs->ih.opcode;
813         sig_req->uc_unique = sig_inputArgs->ih.unique;
814         sig_req->uc_inSize = sizeof(struct coda_in_hdr);
815         sig_req->uc_outSize = sizeof(struct coda_in_hdr);
816
817         /* insert at head of queue! */
818         list_add(&(sig_req->uc_chain), &vcommp->vc_pending);
819         wake_up_interruptible(&vcommp->vc_waitq);
820
821 exit:
822         kfree(req);
823         return error;
824 }
825
826 /*  
827     The statements below are part of the Coda opportunistic
828     programming -- taken from the Mach/BSD kernel code for Coda. 
829     You don't get correct semantics by stating what needs to be
830     done without guaranteeing the invariants needed for it to happen.
831     When will be have time to find out what exactly is going on?  (pjb)
832 */
833
834
835 /* 
836  * There are 7 cases where cache invalidations occur.  The semantics
837  *  of each is listed here:
838  *
839  * CODA_FLUSH     -- flush all entries from the name cache and the cnode cache.
840  * CODA_PURGEUSER -- flush all entries from the name cache for a specific user
841  *                  This call is a result of token expiration.
842  *
843  * The next arise as the result of callbacks on a file or directory.
844  * CODA_ZAPFILE   -- flush the cached attributes for a file.
845
846  * CODA_ZAPDIR    -- flush the attributes for the dir and
847  *                  force a new lookup for all the children
848                     of this dir.
849
850  *
851  * The next is a result of Venus detecting an inconsistent file.
852  * CODA_PURGEFID  -- flush the attribute for the file
853  *                  purge it and its children from the dcache
854  *
855  * The last  allows Venus to replace local fids with global ones
856  * during reintegration.
857  *
858  * CODA_REPLACE -- replace one CodaFid with another throughout the name cache */
859
860 int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
861 {
862         /* Handle invalidation requests. */
863           if ( !sb || !sb->s_root || !sb->s_root->d_inode)
864                   return 0; 
865
866           switch (opcode) {
867
868           case CODA_FLUSH : {
869                    coda_cache_clear_all(sb);
870                    shrink_dcache_sb(sb);
871                    coda_flag_inode(sb->s_root->d_inode, C_FLUSH);
872                    return(0);
873           }
874
875           case CODA_PURGEUSER : {
876                    coda_cache_clear_all(sb);
877                    return(0);
878           }
879
880           case CODA_ZAPDIR : {
881                   struct inode *inode;
882                   struct CodaFid *fid = &out->coda_zapdir.CodaFid;
883
884                   inode = coda_fid_to_inode(fid, sb);
885                   if (inode) {
886                           coda_flag_inode_children(inode, C_PURGE);
887                           coda_flag_inode(inode, C_VATTR);
888                           iput(inode);
889                   }
890                   
891                   return(0);
892           }
893
894           case CODA_ZAPFILE : {
895                   struct inode *inode;
896                   struct CodaFid *fid = &out->coda_zapfile.CodaFid;
897                   inode = coda_fid_to_inode(fid, sb);
898                   if ( inode ) {
899                           coda_flag_inode(inode, C_VATTR);
900                           iput(inode);
901                   }
902                   return 0;
903           }
904
905           case CODA_PURGEFID : {
906                   struct inode *inode;
907                   struct CodaFid *fid = &out->coda_purgefid.CodaFid;
908                   inode = coda_fid_to_inode(fid, sb);
909                   if ( inode ) { 
910                         coda_flag_inode_children(inode, C_PURGE);
911
912                         /* catch the dentries later if some are still busy */
913                         coda_flag_inode(inode, C_PURGE);
914                         d_prune_aliases(inode);
915
916                         iput(inode);
917                   }
918                   return 0;
919           }
920
921           case CODA_REPLACE : {
922                   struct inode *inode;
923                   struct CodaFid *oldfid = &out->coda_replace.OldFid;
924                   struct CodaFid *newfid = &out->coda_replace.NewFid;
925                   inode = coda_fid_to_inode(oldfid, sb);
926                   if ( inode ) { 
927                           coda_replace_fid(inode, oldfid, newfid);
928                           iput(inode);
929                   }
930                   return 0;
931           }
932           }
933           return 0;
934 }
935