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