more changes on original files
[linux-2.4.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         if (data->vi.out_size > VC_MAXDATASIZE) {
547                 error = -EINVAL;
548                 goto exit;
549         }
550
551         inp->coda_ioctl.VFid = *fid;
552     
553         /* the cmd field was mutated by increasing its size field to
554          * reflect the path and follow args. We need to subtract that
555          * out before sending the command to Venus.  */
556         inp->coda_ioctl.cmd = (cmd & ~(PIOCPARM_MASK << 16));   
557         iocsize = ((cmd >> 16) & PIOCPARM_MASK) - sizeof(char *) - sizeof(int);
558         inp->coda_ioctl.cmd |= (iocsize & PIOCPARM_MASK) <<     16;     
559     
560         /* in->coda_ioctl.rwflag = flag; */
561         inp->coda_ioctl.len = data->vi.in_size;
562         inp->coda_ioctl.data = (char *)(INSIZE(ioctl));
563      
564         /* get the data out of user space */
565         if ( copy_from_user((char*)inp + (long)inp->coda_ioctl.data,
566                             data->vi.in, data->vi.in_size) ) {
567                 error = -EINVAL;
568                 goto exit;
569         }
570
571         error = coda_upcall(coda_sbp(sb), SIZE(ioctl) + data->vi.in_size,
572                             &outsize, inp);
573         
574         if (error) {
575                 printk("coda_pioctl: Venus returns: %d for %s\n", 
576                        error, coda_f2s(fid));
577                 goto exit; 
578         }
579
580         if (outsize < (long)outp->coda_ioctl.data + outp->coda_ioctl.len) {
581                 CDEBUG(D_FILE, "reply size %d < reply len %ld\n", outsize,
582                        (long)outp->coda_ioctl.data + outp->coda_ioctl.len);
583                 error = -EINVAL;
584                 goto exit;
585         }
586
587         if (outp->coda_ioctl.len > data->vi.out_size) {
588                 CDEBUG(D_FILE, "return len %d > request len %d\n",
589                        outp->coda_ioctl.len, data->vi.out_size);
590                 error = -EINVAL;
591                 goto exit;
592         }
593
594         /* Copy out the OUT buffer. */
595         error = verify_area(VERIFY_WRITE, data->vi.out, outp->coda_ioctl.len);
596         if ( error ) goto exit;
597
598         if (copy_to_user(data->vi.out, 
599                          (char *)outp + (long)outp->coda_ioctl.data, 
600                          outp->coda_ioctl.len)) {
601             error = -EINVAL;
602         }
603  exit:
604         CODA_FREE(inp, insize);
605         return error;
606 }
607
608 int venus_statfs(struct super_block *sb, struct statfs *sfs) 
609
610         union inputArgs *inp;
611         union outputArgs *outp;
612         int insize, outsize, error;
613         
614         insize = max_t(unsigned int, INSIZE(statfs), OUTSIZE(statfs));
615         UPARG(CODA_STATFS);
616
617         error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
618         
619         if (!error) {
620                 sfs->f_blocks = outp->coda_statfs.stat.f_blocks;
621                 sfs->f_bfree  = outp->coda_statfs.stat.f_bfree;
622                 sfs->f_bavail = outp->coda_statfs.stat.f_bavail;
623                 sfs->f_files  = outp->coda_statfs.stat.f_files;
624                 sfs->f_ffree  = outp->coda_statfs.stat.f_ffree;
625         } else {
626                 printk("coda_statfs: Venus returns: %d\n", error);
627         }
628
629         CDEBUG(D_INODE, " result %d\n",error);
630         CODA_FREE(inp, insize);
631         return error;
632 }
633
634 /*
635  * coda_upcall and coda_downcall routines.
636  * 
637  */
638
639 static inline unsigned long coda_waitfor_upcall(struct upc_req *vmp,
640                                                 struct venus_comm *vcommp)
641 {
642         DECLARE_WAITQUEUE(wait, current);
643         struct timeval begin = { 0, 0 }, end = { 0, 0 };
644
645         vmp->uc_posttime = jiffies;
646
647         if (coda_upcall_timestamping)
648                 do_gettimeofday(&begin);
649
650         add_wait_queue(&vmp->uc_sleep, &wait);
651         for (;;) {
652                 if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE ) 
653                         set_current_state(TASK_INTERRUPTIBLE);
654                 else
655                         set_current_state(TASK_UNINTERRUPTIBLE);
656
657                 /* venus died */
658                 if ( !vcommp->vc_inuse )
659                         break;
660
661                 /* got a reply */
662                 if ( vmp->uc_flags & ( REQ_WRITE | REQ_ABORT ) )
663                         break;
664
665                 if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE && signal_pending(current) ) {
666                         /* if this process really wants to die, let it go */
667                         if ( sigismember(&(current->pending.signal), SIGKILL) ||
668                              sigismember(&(current->pending.signal), SIGINT) )
669                                 break;
670                         /* signal is present: after timeout always return 
671                            really smart idea, probably useless ... */
672                         if ( jiffies - vmp->uc_posttime > coda_timeout * HZ )
673                                 break; 
674                 }
675                 schedule();
676         }
677         remove_wait_queue(&vmp->uc_sleep, &wait);
678         set_current_state(TASK_RUNNING);
679
680         if (coda_upcall_timestamping && begin.tv_sec != 0) {
681                 do_gettimeofday(&end);
682
683                 if (end.tv_usec < begin.tv_usec) {
684                         end.tv_usec += 1000000; end.tv_sec--;
685                 }
686                 end.tv_sec  -= begin.tv_sec;
687                 end.tv_usec -= begin.tv_usec;
688         }
689
690         CDEBUG(D_SPECIAL, "begin: %ld.%06ld, elapsed: %ld.%06ld\n",
691                 begin.tv_sec, (unsigned long)begin.tv_usec,
692                 end.tv_sec, (unsigned long)end.tv_usec);
693
694         return  ((end.tv_sec * 1000000) + end.tv_usec);
695 }
696
697
698 /* 
699  * coda_upcall will return an error in the case of 
700  * failed communication with Venus _or_ will peek at Venus
701  * reply and return Venus' error.
702  *
703  * As venus has 2 types of errors, normal errors (positive) and internal
704  * errors (negative), normal errors are negated, while internal errors
705  * are all mapped to -EINTR, while showing a nice warning message. (jh)
706  * 
707  */
708 static int coda_upcall(struct coda_sb_info *sbi, 
709                 int inSize, int *outSize, 
710                 union inputArgs *buffer) 
711 {
712         unsigned long runtime; 
713         struct venus_comm *vcommp;
714         union outputArgs *out;
715         struct upc_req *req;
716         int error = 0;
717
718         vcommp = sbi->sbi_vcomm;
719         if ( !vcommp->vc_inuse ) {
720                 printk("No pseudo device in upcall comms at %p\n", vcommp);
721                 return -ENXIO;
722         }
723
724         /* Format the request message. */
725         req = upc_alloc();
726         if (!req) {
727                 printk("Failed to allocate upc_req structure\n");
728                 return -ENOMEM;
729         }
730         req->uc_data = (void *)buffer;
731         req->uc_flags = 0;
732         req->uc_inSize = inSize;
733         req->uc_outSize = *outSize ? *outSize : inSize;
734         req->uc_opcode = ((union inputArgs *)buffer)->ih.opcode;
735         req->uc_unique = ++vcommp->vc_seq;
736         init_waitqueue_head(&req->uc_sleep);
737         
738         /* Fill in the common input args. */
739         ((union inputArgs *)buffer)->ih.unique = req->uc_unique;
740
741         /* Append msg to pending queue and poke Venus. */
742         list_add(&(req->uc_chain), vcommp->vc_pending.prev);
743         
744         CDEBUG(D_UPCALL, 
745                "Proc %d wake Venus for(opc,uniq) =(%d,%d) msg at %p.zzz.\n",
746                current->pid, req->uc_opcode, req->uc_unique, req);
747
748         wake_up_interruptible(&vcommp->vc_waitq);
749         /* We can be interrupted while we wait for Venus to process
750          * our request.  If the interrupt occurs before Venus has read
751          * the request, we dequeue and return. If it occurs after the
752          * read but before the reply, we dequeue, send a signal
753          * message, and return. If it occurs after the reply we ignore
754          * it. In no case do we want to restart the syscall.  If it
755          * was interrupted by a venus shutdown (psdev_close), return
756          * ENODEV.  */
757
758         /* Go to sleep.  Wake up on signals only after the timeout. */
759         runtime = coda_waitfor_upcall(req, vcommp);
760         coda_upcall_stats(((union inputArgs *)buffer)->ih.opcode, runtime);
761
762         CDEBUG(D_TIMING, "opc: %d time: %ld uniq: %d size: %d\n",
763                req->uc_opcode, jiffies - req->uc_posttime, 
764                req->uc_unique, req->uc_outSize);
765         CDEBUG(D_UPCALL, 
766                "..process %d woken up by Venus for req at %p, data at %p\n", 
767                current->pid, req, req->uc_data);
768         if (vcommp->vc_inuse) {      /* i.e. Venus is still alive */
769             /* Op went through, interrupt or not... */
770             if (req->uc_flags & REQ_WRITE) {
771                 out = (union outputArgs *)req->uc_data;
772                 /* here we map positive Venus errors to kernel errors */
773                 error = -out->oh.result;
774                 CDEBUG(D_UPCALL, 
775                        "upcall: (u,o,r) (%ld, %ld, %ld) out at %p\n", 
776                        out->oh.unique, out->oh.opcode, out->oh.result, out);
777                 *outSize = req->uc_outSize;
778                 goto exit;
779             }
780             if ( !(req->uc_flags & REQ_READ) && signal_pending(current)) { 
781                 /* Interrupted before venus read it. */
782                 CDEBUG(D_UPCALL, 
783                        "Interrupted before read:(op,un) (%d.%d), flags = %x\n",
784                        req->uc_opcode, req->uc_unique, req->uc_flags);
785                 list_del(&(req->uc_chain));
786                 /* perhaps the best way to convince the app to
787                    give up? */
788                 error = -EINTR;
789                 goto exit;
790             } 
791             if ( (req->uc_flags & REQ_READ) && signal_pending(current) ) {
792                     /* interrupted after Venus did its read, send signal */
793                     union inputArgs *sig_inputArgs;
794                     struct upc_req *sig_req;
795                     
796                     CDEBUG(D_UPCALL, 
797                            "Sending Venus a signal: op = %d.%d, flags = %x\n",
798                            req->uc_opcode, req->uc_unique, req->uc_flags);
799                     
800                     list_del(&(req->uc_chain));
801                     error = -ENOMEM;
802                     sig_req = upc_alloc();
803                     if (!sig_req) goto exit;
804
805                     CODA_ALLOC((sig_req->uc_data), char *, sizeof(struct coda_in_hdr));
806                     if (!sig_req->uc_data) {
807                         upc_free(sig_req);
808                         goto exit;
809                     }
810                     
811                     error = -EINTR;
812                     sig_inputArgs = (union inputArgs *)sig_req->uc_data;
813                     sig_inputArgs->ih.opcode = CODA_SIGNAL;
814                     sig_inputArgs->ih.unique = req->uc_unique;
815                     
816                     sig_req->uc_flags = REQ_ASYNC;
817                     sig_req->uc_opcode = sig_inputArgs->ih.opcode;
818                     sig_req->uc_unique = sig_inputArgs->ih.unique;
819                     sig_req->uc_inSize = sizeof(struct coda_in_hdr);
820                     sig_req->uc_outSize = sizeof(struct coda_in_hdr);
821                     CDEBUG(D_UPCALL, 
822                            "coda_upcall: enqueing signal msg (%d, %d)\n",
823                            sig_req->uc_opcode, sig_req->uc_unique);
824                     
825                     /* insert at head of queue! */
826                     list_add(&(sig_req->uc_chain), &vcommp->vc_pending);
827                     wake_up_interruptible(&vcommp->vc_waitq);
828             } else {
829                     printk("Coda: Strange interruption..\n");
830                     error = -EINTR;
831             }
832         } else {        /* If venus died i.e. !VC_OPEN(vcommp) */
833                 printk("coda_upcall: Venus dead on (op,un) (%d.%d) flags %d\n",
834                        req->uc_opcode, req->uc_unique, req->uc_flags);
835                 error = -ENODEV;
836         }
837
838  exit:
839         upc_free(req);
840         if (error) 
841                 badclstats();
842         return error;
843 }
844
845 /*  
846     The statements below are part of the Coda opportunistic
847     programming -- taken from the Mach/BSD kernel code for Coda. 
848     You don't get correct semantics by stating what needs to be
849     done without guaranteeing the invariants needed for it to happen.
850     When will be have time to find out what exactly is going on?  (pjb)
851 */
852
853
854 /* 
855  * There are 7 cases where cache invalidations occur.  The semantics
856  *  of each is listed here:
857  *
858  * CODA_FLUSH     -- flush all entries from the name cache and the cnode cache.
859  * CODA_PURGEUSER -- flush all entries from the name cache for a specific user
860  *                  This call is a result of token expiration.
861  *
862  * The next arise as the result of callbacks on a file or directory.
863  * CODA_ZAPFILE   -- flush the cached attributes for a file.
864
865  * CODA_ZAPDIR    -- flush the attributes for the dir and
866  *                  force a new lookup for all the children
867                     of this dir.
868
869  *
870  * The next is a result of Venus detecting an inconsistent file.
871  * CODA_PURGEFID  -- flush the attribute for the file
872  *                  purge it and its children from the dcache
873  *
874  * The last  allows Venus to replace local fids with global ones
875  * during reintegration.
876  *
877  * CODA_REPLACE -- replace one ViceFid with another throughout the name cache */
878
879 int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
880 {
881         /* Handle invalidation requests. */
882           if ( !sb || !sb->s_root || !sb->s_root->d_inode) { 
883                   CDEBUG(D_DOWNCALL, "coda_downcall: opcode %d, no sb!\n", opcode);
884                   return 0; 
885           }
886
887           switch (opcode) {
888
889           case CODA_FLUSH : {
890                    clstats(CODA_FLUSH);
891                    CDEBUG(D_DOWNCALL, "CODA_FLUSH\n");
892                    coda_cache_clear_all(sb, NULL);
893                    shrink_dcache_sb(sb);
894                    coda_flag_inode(sb->s_root->d_inode, C_FLUSH);
895                    return(0);
896           }
897
898           case CODA_PURGEUSER : {
899                    struct coda_cred *cred = &out->coda_purgeuser.cred;
900                    CDEBUG(D_DOWNCALL, "CODA_PURGEUSER\n");
901                    if ( !cred ) {
902                            printk("PURGEUSER: null cred!\n");
903                            return 0;
904                    }
905                    clstats(CODA_PURGEUSER);
906                    coda_cache_clear_all(sb, cred);
907                    return(0);
908           }
909
910           case CODA_ZAPDIR : {
911                   struct inode *inode;
912                   ViceFid *fid = &out->coda_zapdir.CodaFid;
913                   CDEBUG(D_DOWNCALL, "zapdir: fid = %s...\n", coda_f2s(fid));
914                   clstats(CODA_ZAPDIR);
915
916                   inode = coda_fid_to_inode(fid, sb);
917                   if (inode) {
918                           CDEBUG(D_DOWNCALL, "zapdir: inode = %ld children flagged\n", 
919                                  inode->i_ino);
920                           coda_flag_inode_children(inode, C_PURGE);
921                           CDEBUG(D_DOWNCALL, "zapdir: inode = %ld cache cleared\n", inode->i_ino);
922                           coda_flag_inode(inode, C_VATTR);
923                           iput(inode);
924                   } else 
925                           CDEBUG(D_DOWNCALL, "zapdir: no inode\n");
926                   
927                   return(0);
928           }
929
930           case CODA_ZAPFILE : {
931                   struct inode *inode;
932                   struct ViceFid *fid = &out->coda_zapfile.CodaFid;
933                   clstats(CODA_ZAPFILE);
934                   CDEBUG(D_DOWNCALL, "zapfile: fid = %s\n", coda_f2s(fid));
935                   inode = coda_fid_to_inode(fid, sb);
936                   if ( inode ) {
937                           CDEBUG(D_DOWNCALL, "zapfile: inode = %ld\n",
938                                  inode->i_ino);
939                           coda_flag_inode(inode, C_VATTR);
940                           iput(inode);
941                   } else 
942                           CDEBUG(D_DOWNCALL, "zapfile: no inode\n");
943                   return 0;
944           }
945
946           case CODA_PURGEFID : {
947                   struct inode *inode;
948                   ViceFid *fid = &out->coda_purgefid.CodaFid;
949                   CDEBUG(D_DOWNCALL, "purgefid: fid = %s\n", coda_f2s(fid));
950                   clstats(CODA_PURGEFID);
951                   inode = coda_fid_to_inode(fid, sb);
952                   if ( inode ) { 
953                         CDEBUG(D_DOWNCALL, "purgefid: inode = %ld\n",
954                                inode->i_ino);
955                         coda_flag_inode_children(inode, C_PURGE);
956
957                         /* catch the dentries later if some are still busy */
958                         coda_flag_inode(inode, C_PURGE);
959                         d_prune_aliases(inode);
960
961                         iput(inode);
962                   } else 
963                         CDEBUG(D_DOWNCALL, "purgefid: no inode\n");
964                   return 0;
965           }
966
967           case CODA_REPLACE : {
968                   struct inode *inode;
969                   ViceFid *oldfid = &out->coda_replace.OldFid;
970                   ViceFid *newfid = &out->coda_replace.NewFid;
971                   clstats(CODA_REPLACE);
972                   CDEBUG(D_DOWNCALL, "CODA_REPLACE\n");
973                   inode = coda_fid_to_inode(oldfid, sb);
974                   if ( inode ) { 
975                           CDEBUG(D_DOWNCALL, "replacefid: inode = %ld\n",
976                                  inode->i_ino);
977                           coda_replace_fid(inode, oldfid, newfid);
978                           iput(inode);
979                   }else 
980                           CDEBUG(D_DOWNCALL, "purgefid: no inode\n");
981                   
982                   return 0;
983           }
984           }
985           return 0;
986 }
987