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