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