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