Merge /spare/repo/linux-2.6/
[linux-2.6] / 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
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