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