File: /usr/src/linux/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/segment.h>
19     #include <asm/signal.h>
20     #include <linux/signal.h>
21     
22     #include <linux/types.h>
23     #include <linux/kernel.h>
24     #include <linux/mm.h>
25     #include <linux/sched.h>
26     #include <linux/fs.h>
27     #include <linux/file.h>
28     #include <linux/stat.h>
29     #include <linux/errno.h>
30     #include <linux/locks.h>
31     #include <linux/string.h>
32     #include <asm/uaccess.h>
33     #include <linux/vmalloc.h>
34     
35     #include <linux/coda.h>
36     #include <linux/coda_linux.h>
37     #include <linux/coda_psdev.h>
38     #include <linux/coda_fs_i.h>
39     #include <linux/coda_cache.h>
40     #include <linux/coda_proc.h> 
41     
42     #define upc_alloc() kmalloc(sizeof(struct upc_req), GFP_KERNEL)
43     #define upc_free(r) kfree(r)
44     
45     static int coda_upcall(struct coda_sb_info *mntinfo, int inSize, int *outSize, 
46     		       union inputArgs *buffer);
47     
48     static void *alloc_upcall(int opcode, int size)
49     {
50     	union inputArgs *inp;
51     
52     	CODA_ALLOC(inp, union inputArgs *, size);
53             if (!inp)
54     		return ERR_PTR(-ENOMEM);
55     
56             inp->ih.opcode = opcode;
57     	inp->ih.pid = current->pid;
58     	inp->ih.pgid = current->pgrp;
59     	coda_load_creds(&(inp->ih.cred));
60     
61     	return (void*)inp;
62     }
63     
64     #define UPARG(op)\
65     do {\
66     	inp = (union inputArgs *)alloc_upcall(op, insize); \
67             if (IS_ERR(inp)) { return PTR_ERR(inp); }\
68             outp = (union outputArgs *)(inp); \
69             outsize = insize; \
70     } while (0)
71     
72     #define INSIZE(tag) sizeof(struct coda_ ## tag ## _in)
73     #define OUTSIZE(tag) sizeof(struct coda_ ## tag ## _out)
74     #define SIZE(tag)  max_t(unsigned int, INSIZE(tag), OUTSIZE(tag))
75     
76     
77     /* the upcalls */
78     int venus_rootfid(struct super_block *sb, ViceFid *fidp)
79     {
80             union inputArgs *inp;
81             union outputArgs *outp;
82             int insize, outsize, error;
83     	ENTRY;
84     
85             insize = SIZE(root);
86             UPARG(CODA_ROOT);
87     
88     	error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
89     	
90     	if (error) {
91     	        printk("coda_get_rootfid: error %d\n", error);
92     	} else {
93     		*fidp = (ViceFid) outp->coda_root.VFid;
94     		CDEBUG(D_SUPER, "VolumeId: %lx, VnodeId: %lx.\n",
95     		       fidp->Volume, fidp->Vnode);
96     	}
97     
98     	CODA_FREE(inp, insize);
99             EXIT;
100     	return error;
101     }
102     
103     int venus_getattr(struct super_block *sb, struct ViceFid *fid, 
104     		     struct coda_vattr *attr) 
105     {
106             union inputArgs *inp;
107             union outputArgs *outp;
108             int insize, outsize, error;
109     	ENTRY;
110     
111             insize = SIZE(getattr); 
112     	UPARG(CODA_GETATTR);
113             inp->coda_getattr.VFid = *fid;
114     
115             error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
116     	
117     	*attr = outp->coda_getattr.attr;
118     
119     	CODA_FREE(inp, insize);
120             EXIT;
121             return error;
122     }
123     
124     int venus_setattr(struct super_block *sb, struct ViceFid *fid, 
125     		  struct coda_vattr *vattr)
126     {
127             union inputArgs *inp;
128             union outputArgs *outp;
129             int insize, outsize, error;
130     	
131     	insize = SIZE(setattr);
132     	UPARG(CODA_SETATTR);
133     
134             inp->coda_setattr.VFid = *fid;
135     	inp->coda_setattr.attr = *vattr;
136     
137             error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
138     
139             CDEBUG(D_SUPER, " result %d\n", error); 
140             CODA_FREE(inp, insize);
141             return error;
142     }
143     
144     int venus_lookup(struct super_block *sb, struct ViceFid *fid, 
145     		    const char *name, int length, int * type, 
146     		    struct ViceFid *resfid)
147     {
148             union inputArgs *inp;
149             union outputArgs *outp;
150             int insize, outsize, error;
151     	int offset;
152     
153     	offset = INSIZE(lookup);
154             insize = max_t(unsigned int, offset + length +1, OUTSIZE(lookup));
155     	UPARG(CODA_LOOKUP);
156     
157             inp->coda_lookup.VFid = *fid;
158     	inp->coda_lookup.name = offset;
159     	inp->coda_lookup.flags = CLU_CASE_SENSITIVE;
160             /* send Venus a null terminated string */
161             memcpy((char *)(inp) + offset, name, length);
162             *((char *)inp + offset + length) = '\0';
163     
164             error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
165     
166     	*resfid = outp->coda_lookup.VFid;
167     	*type = outp->coda_lookup.vtype;
168     
169     	CODA_FREE(inp, insize);
170     	return error;
171     }
172     
173     int venus_store(struct super_block *sb, struct ViceFid *fid, int flags,
174                     struct coda_cred *cred)
175     {
176             union inputArgs *inp;
177             union outputArgs *outp;
178             int insize, outsize, error;
179     	
180     	insize = SIZE(store);
181     	UPARG(CODA_STORE);
182     	
183     	if ( cred ) {
184     		memcpy(&(inp->ih.cred), cred, sizeof(*cred));
185     	} else 
186     		printk("CODA: store without valid file creds.\n");
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 ViceFid *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 ViceFid *fid, int flags,
216                     struct coda_cred *cred)
217     {
218     	union inputArgs *inp;
219     	union outputArgs *outp;
220     	int insize, outsize, error;
221     	
222     	insize = SIZE(release);
223     	UPARG(CODA_CLOSE);
224     	
225     	if ( cred ) {
226     		memcpy(&(inp->ih.cred), cred, sizeof(*cred));
227     	} else 
228     		printk("CODA: close without valid file creds.\n");
229     	
230             inp->coda_close.VFid = *fid;
231             inp->coda_close.flags = flags;
232     
233             error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
234     
235     	CODA_FREE(inp, insize);
236             return error;
237     }
238     
239     int venus_open(struct super_block *sb, struct ViceFid *fid,
240     		  int flags, struct file **fh)
241     {
242             union inputArgs *inp;
243             union outputArgs *outp;
244             int insize, outsize, error;
245            
246     	insize = SIZE(open_by_fd);
247     	UPARG(CODA_OPEN_BY_FD);
248     
249             inp->coda_open.VFid = *fid;
250             inp->coda_open.flags = flags;
251     
252             error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
253     
254     	*fh = outp->coda_open_by_fd.fh;
255     
256     	CODA_FREE(inp, insize);
257     	return error;
258     }	
259     
260     int venus_mkdir(struct super_block *sb, struct ViceFid *dirfid, 
261     		   const char *name, int length, 
262     		   struct ViceFid *newfid, struct coda_vattr *attrs)
263     {
264             union inputArgs *inp;
265             union outputArgs *outp;
266             int insize, outsize, error;
267             int offset;
268     
269     	offset = INSIZE(mkdir);
270     	insize = max_t(unsigned int, offset + length + 1, OUTSIZE(mkdir));
271     	UPARG(CODA_MKDIR);
272     
273             inp->coda_mkdir.VFid = *dirfid;
274             inp->coda_mkdir.attr = *attrs;
275     	inp->coda_mkdir.name = offset;
276             /* Venus must get null terminated string */
277             memcpy((char *)(inp) + offset, name, length);
278             *((char *)inp + offset + length) = '\0';
279             
280             error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
281     
282     	*attrs = outp->coda_mkdir.attr;
283     	*newfid = outp->coda_mkdir.VFid;
284     
285     	CODA_FREE(inp, insize);
286     	return error;        
287     }
288     
289     
290     int venus_rename(struct super_block *sb, struct ViceFid *old_fid, 
291     		 struct ViceFid *new_fid, size_t old_length, 
292     		 size_t new_length, const char *old_name, 
293     		 const char *new_name)
294     {
295     	union inputArgs *inp;
296             union outputArgs *outp;
297             int insize, outsize, error; 
298     	int offset, s;
299     	
300     	offset = INSIZE(rename);
301     	insize = max_t(unsigned int, offset + new_length + old_length + 8,
302     		     OUTSIZE(rename)); 
303      	UPARG(CODA_RENAME);
304     
305             inp->coda_rename.sourceFid = *old_fid;
306             inp->coda_rename.destFid =  *new_fid;
307             inp->coda_rename.srcname = offset;
308     
309             /* Venus must receive an null terminated string */
310             s = ( old_length & ~0x3) +4; /* round up to word boundary */
311             memcpy((char *)(inp) + offset, old_name, old_length);
312             *((char *)inp + offset + old_length) = '\0';
313     
314             /* another null terminated string for Venus */
315             offset += s;
316             inp->coda_rename.destname = offset;
317             s = ( new_length & ~0x3) +4; /* round up to word boundary */
318             memcpy((char *)(inp) + offset, new_name, new_length);
319             *((char *)inp + offset + new_length) = '\0';
320     
321             CDEBUG(D_INODE, "destname in packet: %s\n", 
322                   (char *)inp + (int) inp->coda_rename.destname);
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 ViceFid *dirfid, 
330     		    const char *name, int length, int excl, int mode, int rdev,
331     		    struct ViceFid *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.attr.va_rdev = rdev;
345     	inp->coda_create.excl = excl;
346             inp->coda_create.mode = mode;
347             inp->coda_create.name = offset;
348     
349             /* Venus must get null terminated string */
350             memcpy((char *)(inp) + offset, name, length);
351             *((char *)inp + offset + length) = '\0';
352                     
353             error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
354     
355     	*attrs = outp->coda_create.attr;
356     	*newfid = outp->coda_create.VFid;
357     
358     	CODA_FREE(inp, insize);
359     	return error;        
360     }
361     
362     int venus_rmdir(struct super_block *sb, struct ViceFid *dirfid, 
363     		    const char *name, int length)
364     {
365             union inputArgs *inp;
366             union outputArgs *outp;
367             int insize, outsize, error;
368             int offset;
369     
370             offset = INSIZE(rmdir);
371     	insize = max_t(unsigned int, offset + length + 1, OUTSIZE(rmdir));
372     	UPARG(CODA_RMDIR);
373     
374             inp->coda_rmdir.VFid = *dirfid;
375             inp->coda_rmdir.name = offset;
376             memcpy((char *)(inp) + offset, name, length);
377     	*((char *)inp + offset + length) = '\0';
378             
379             error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
380     
381     	CODA_FREE(inp, insize);
382     	return error;
383     }
384     
385     int venus_remove(struct super_block *sb, struct ViceFid *dirfid, 
386     		    const char *name, int length)
387     {
388             union inputArgs *inp;
389             union outputArgs *outp;
390             int error=0, insize, outsize, offset;
391     
392             offset = INSIZE(remove);
393     	insize = max_t(unsigned int, offset + length + 1, OUTSIZE(remove));
394     	UPARG(CODA_REMOVE);
395     
396             inp->coda_remove.VFid = *dirfid;
397             inp->coda_remove.name = offset;
398             memcpy((char *)(inp) + offset, name, length);
399     	*((char *)inp + offset + length) = '\0';
400             
401             error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
402     
403     	CODA_FREE(inp, insize);
404     	return error;
405     }
406     
407     int venus_readlink(struct super_block *sb, struct ViceFid *fid, 
408     		      char *buffer, int *length)
409     { 
410             union inputArgs *inp;
411             union outputArgs *outp;
412             int insize, outsize, error;
413             int retlen;
414             char *result;
415             
416     	insize = max_t(unsigned int,
417     		     INSIZE(readlink), OUTSIZE(readlink)+ *length + 1);
418     	UPARG(CODA_READLINK);
419     
420             inp->coda_readlink.VFid = *fid;
421         
422             error =  coda_upcall(coda_sbp(sb), insize, &outsize, inp);
423     	
424     	if (! error) {
425                     retlen = outp->coda_readlink.count;
426     		if ( retlen > *length )
427     		        retlen = *length;
428     		*length = retlen;
429     		result =  (char *)outp + (long)outp->coda_readlink.data;
430     		memcpy(buffer, result, retlen);
431     		*(buffer + retlen) = '\0';
432     	}
433             
434             CDEBUG(D_INODE, " result %d\n",error);
435             EXIT;
436             CODA_FREE(inp, insize);
437             return error;
438     }
439     
440     
441     
442     int venus_link(struct super_block *sb, struct ViceFid *fid, 
443     		  struct ViceFid *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             CDEBUG(D_INODE, " result %d\n",error);
465             EXIT;
466     	CODA_FREE(inp, insize);
467             return error;
468     }
469     
470     int venus_symlink(struct super_block *sb, struct ViceFid *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             CDEBUG(D_INODE, " result %d\n",error);
502             EXIT;
503     	CODA_FREE(inp, insize);
504             return error;
505     }
506     
507     int venus_fsync(struct super_block *sb, struct ViceFid *fid)
508     {
509             union inputArgs *inp;
510             union outputArgs *outp; 
511     	int insize, outsize, error;
512     	
513     	insize=SIZE(fsync);
514     	UPARG(CODA_FSYNC);
515     
516             inp->coda_fsync.VFid = *fid;
517             error = coda_upcall(coda_sbp(sb), sizeof(union inputArgs), 
518                                 &outsize, inp);
519     
520     	CODA_FREE(inp, insize);
521     	return error;
522     }
523     
524     int venus_access(struct super_block *sb, struct ViceFid *fid, int mask)
525     {
526             union inputArgs *inp;
527             union outputArgs *outp; 
528     	int insize, outsize, error;
529     
530     	insize = SIZE(access);
531     	UPARG(CODA_ACCESS);
532     
533             inp->coda_access.VFid = *fid;
534             inp->coda_access.flags = mask;
535     
536     	error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
537     
538     	CODA_FREE(inp, insize);
539             EXIT;
540     	return error;
541     }
542     
543     
544     int venus_pioctl(struct super_block *sb, struct ViceFid *fid,
545     		 unsigned int cmd, struct PioctlData *data)
546     {
547             union inputArgs *inp;
548             union outputArgs *outp;  
549     	int insize, outsize, error;
550     	int iocsize;
551     
552     	insize = VC_MAXMSGSIZE;
553     	UPARG(CODA_IOCTL);
554     
555             /* build packet for Venus */
556             if (data->vi.in_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     	/* Copy out the OUT buffer. */
591             if (outp->coda_ioctl.len > data->vi.out_size) {
592                     CDEBUG(D_FILE, "return len %d <= request len %d\n",
593                           outp->coda_ioctl.len, 
594                           data->vi.out_size);
595     		error = -EINVAL;
596             } else {
597     		error = verify_area(VERIFY_WRITE, data->vi.out, 
598                                         data->vi.out_size);
599     		if ( error ) goto exit;
600     
601     		if (copy_to_user(data->vi.out, 
602     				 (char *)outp + (long)outp->coda_ioctl.data, 
603     				 data->vi.out_size)) {
604     			error = -EINVAL;
605     			goto exit;
606     		}
607             }
608     
609      exit:
610     	CODA_FREE(inp, insize);
611     	return error;
612     }
613     
614     int venus_statfs(struct super_block *sb, struct statfs *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(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             CDEBUG(D_INODE, " result %d\n",error);
636             EXIT;
637             CODA_FREE(inp, insize);
638             return error;
639     }
640     
641     /*
642      * coda_upcall and coda_downcall routines.
643      * 
644      */
645     
646     static inline unsigned long coda_waitfor_upcall(struct upc_req *vmp,
647     						struct venus_comm *vcommp)
648     {
649     	DECLARE_WAITQUEUE(wait, current);
650      	struct timeval begin = { 0, 0 }, end = { 0, 0 };
651     
652     	vmp->uc_posttime = jiffies;
653     
654     	if (coda_upcall_timestamping)
655     		do_gettimeofday(&begin);
656     
657     	add_wait_queue(&vmp->uc_sleep, &wait);
658     	for (;;) {
659     		if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE ) 
660     			set_current_state(TASK_INTERRUPTIBLE);
661     		else
662     			set_current_state(TASK_UNINTERRUPTIBLE);
663     
664                     /* venus died */
665                     if ( !vcommp->vc_inuse )
666                             break;
667     
668     		/* got a reply */
669     		if ( vmp->uc_flags & ( REQ_WRITE | REQ_ABORT ) )
670     			break;
671     
672     		if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE && signal_pending(current) ) {
673     			/* if this process really wants to die, let it go */
674     			if ( sigismember(&(current->pending.signal), SIGKILL) ||
675     			     sigismember(&(current->pending.signal), SIGINT) )
676     				break;
677     			/* signal is present: after timeout always return 
678     			   really smart idea, probably useless ... */
679     			if ( jiffies - vmp->uc_posttime > coda_timeout * HZ )
680     				break; 
681     		}
682     		schedule();
683     	}
684     	remove_wait_queue(&vmp->uc_sleep, &wait);
685     	set_current_state(TASK_RUNNING);
686     
687     	if (coda_upcall_timestamping && begin.tv_sec != 0) {
688     		do_gettimeofday(&end);
689     
690     		if (end.tv_usec < begin.tv_usec) {
691     			end.tv_usec += 1000000; end.tv_sec--;
692     		}
693     		end.tv_sec  -= begin.tv_sec;
694     		end.tv_usec -= begin.tv_usec;
695     	}
696     
697     	CDEBUG(D_SPECIAL, "begin: %ld.%06ld, elapsed: %ld.%06ld\n",
698     		begin.tv_sec, (unsigned long)begin.tv_usec,
699     		end.tv_sec, (unsigned long)end.tv_usec);
700     
701     	return 	((end.tv_sec * 1000000) + end.tv_usec);
702     }
703     
704     
705     /* 
706      * coda_upcall will return an error in the case of 
707      * failed communication with Venus _or_ will peek at Venus
708      * reply and return Venus' error.
709      *
710      * As venus has 2 types of errors, normal errors (positive) and internal
711      * errors (negative), normal errors are negated, while internal errors
712      * are all mapped to -EINTR, while showing a nice warning message. (jh)
713      * 
714      */
715     static int coda_upcall(struct coda_sb_info *sbi, 
716     		int inSize, int *outSize, 
717     		union inputArgs *buffer) 
718     {
719     	unsigned long runtime; 
720     	struct venus_comm *vcommp;
721     	union outputArgs *out;
722     	struct upc_req *req;
723     	int error = 0;
724     
725     	ENTRY;
726     
727     	vcommp = sbi->sbi_vcomm;
728     	if ( !vcommp->vc_inuse ) {
729     		printk("No pseudo device in upcall comms at %p\n", vcommp);
730                     return -ENXIO;
731     	}
732     
733     	/* Format the request message. */
734     	req = upc_alloc();
735     	if (!req) {
736     		printk("Failed to allocate upc_req structure\n");
737     		return -ENOMEM;
738     	}
739     	req->uc_data = (void *)buffer;
740     	req->uc_flags = 0;
741     	req->uc_inSize = inSize;
742     	req->uc_outSize = *outSize ? *outSize : inSize;
743     	req->uc_opcode = ((union inputArgs *)buffer)->ih.opcode;
744     	req->uc_unique = ++vcommp->vc_seq;
745     	init_waitqueue_head(&req->uc_sleep);
746     	
747     	/* Fill in the common input args. */
748     	((union inputArgs *)buffer)->ih.unique = req->uc_unique;
749     
750     	/* Append msg to pending queue and poke Venus. */
751     	list_add(&(req->uc_chain), vcommp->vc_pending.prev);
752             
753     	CDEBUG(D_UPCALL, 
754     	       "Proc %d wake Venus for(opc,uniq) =(%d,%d) msg at %p.zzz.\n",
755     	       current->pid, req->uc_opcode, req->uc_unique, req);
756     
757     	wake_up_interruptible(&vcommp->vc_waitq);
758     	/* We can be interrupted while we wait for Venus to process
759     	 * our request.  If the interrupt occurs before Venus has read
760     	 * the request, we dequeue and return. If it occurs after the
761     	 * read but before the reply, we dequeue, send a signal
762     	 * message, and return. If it occurs after the reply we ignore
763     	 * it. In no case do we want to restart the syscall.  If it
764     	 * was interrupted by a venus shutdown (psdev_close), return
765     	 * ENODEV.  */
766     
767     	/* Go to sleep.  Wake up on signals only after the timeout. */
768     	runtime = coda_waitfor_upcall(req, vcommp);
769     	coda_upcall_stats(((union inputArgs *)buffer)->ih.opcode, runtime);
770     
771     	CDEBUG(D_TIMING, "opc: %d time: %ld uniq: %d size: %d\n",
772     	       req->uc_opcode, jiffies - req->uc_posttime, 
773     	       req->uc_unique, req->uc_outSize);
774     	CDEBUG(D_UPCALL, 
775     	       "..process %d woken up by Venus for req at %p, data at %p\n", 
776     	       current->pid, req, req->uc_data);
777     	if (vcommp->vc_inuse) {      /* i.e. Venus is still alive */
778     	    /* Op went through, interrupt or not... */
779     	    if (req->uc_flags & REQ_WRITE) {
780     		out = (union outputArgs *)req->uc_data;
781     		/* here we map positive Venus errors to kernel errors */
782     		error = -out->oh.result;
783     		CDEBUG(D_UPCALL, 
784     		       "upcall: (u,o,r) (%ld, %ld, %ld) out at %p\n", 
785     		       out->oh.unique, out->oh.opcode, out->oh.result, out);
786     		*outSize = req->uc_outSize;
787     		goto exit;
788     	    }
789     	    if ( !(req->uc_flags & REQ_READ) && signal_pending(current)) { 
790     		/* Interrupted before venus read it. */
791     		CDEBUG(D_UPCALL, 
792     		       "Interrupted before read:(op,un) (%d.%d), flags = %x\n",
793     		       req->uc_opcode, req->uc_unique, req->uc_flags);
794     		list_del(&(req->uc_chain));
795     		/* perhaps the best way to convince the app to
796     		   give up? */
797     		error = -EINTR;
798     		goto exit;
799     	    } 
800     	    if ( (req->uc_flags & REQ_READ) && signal_pending(current) ) {
801     		    /* interrupted after Venus did its read, send signal */
802     		    union inputArgs *sig_inputArgs;
803     		    struct upc_req *sig_req;
804     		    
805     		    CDEBUG(D_UPCALL, 
806     			   "Sending Venus a signal: op = %d.%d, flags = %x\n",
807     			   req->uc_opcode, req->uc_unique, req->uc_flags);
808     		    
809     		    list_del(&(req->uc_chain));
810     		    error = -ENOMEM;
811     		    sig_req = upc_alloc();
812     		    if (!sig_req) goto exit;
813     
814     		    CODA_ALLOC((sig_req->uc_data), char *, sizeof(struct coda_in_hdr));
815     		    if (!sig_req->uc_data) {
816     			upc_free(sig_req);
817     			goto exit;
818     		    }
819     		    
820     		    error = -EINTR;
821     		    sig_inputArgs = (union inputArgs *)sig_req->uc_data;
822     		    sig_inputArgs->ih.opcode = CODA_SIGNAL;
823     		    sig_inputArgs->ih.unique = req->uc_unique;
824     		    
825     		    sig_req->uc_flags = REQ_ASYNC;
826     		    sig_req->uc_opcode = sig_inputArgs->ih.opcode;
827     		    sig_req->uc_unique = sig_inputArgs->ih.unique;
828     		    sig_req->uc_inSize = sizeof(struct coda_in_hdr);
829     		    sig_req->uc_outSize = sizeof(struct coda_in_hdr);
830     		    CDEBUG(D_UPCALL, 
831     			   "coda_upcall: enqueing signal msg (%d, %d)\n",
832     			   sig_req->uc_opcode, sig_req->uc_unique);
833     		    
834     		    /* insert at head of queue! */
835     		    list_add(&(sig_req->uc_chain), &vcommp->vc_pending);
836     		    wake_up_interruptible(&vcommp->vc_waitq);
837     	    } else {
838     		    printk("Coda: Strange interruption..\n");
839     		    error = -EINTR;
840     	    }
841     	} else {	/* If venus died i.e. !VC_OPEN(vcommp) */
842     	        printk("coda_upcall: Venus dead on (op,un) (%d.%d) flags %d\n",
843     		       req->uc_opcode, req->uc_unique, req->uc_flags);
844     		error = -ENODEV;
845     	}
846     
847      exit:
848     	upc_free(req);
849     	if (error) 
850     	        badclstats();
851     	return error;
852     }
853     
854     /*  
855         The statements below are part of the Coda opportunistic
856         programming -- taken from the Mach/BSD kernel code for Coda. 
857         You don't get correct semantics by stating what needs to be
858         done without guaranteeing the invariants needed for it to happen.
859         When will be have time to find out what exactly is going on?  (pjb)
860     */
861     
862     
863     /* 
864      * There are 7 cases where cache invalidations occur.  The semantics
865      *  of each is listed here:
866      *
867      * CODA_FLUSH     -- flush all entries from the name cache and the cnode cache.
868      * CODA_PURGEUSER -- flush all entries from the name cache for a specific user
869      *                  This call is a result of token expiration.
870      *
871      * The next arise as the result of callbacks on a file or directory.
872      * CODA_ZAPFILE   -- flush the cached attributes for a file.
873     
874      * CODA_ZAPDIR    -- flush the attributes for the dir and
875      *                  force a new lookup for all the children
876                         of this dir.
877     
878      *
879      * The next is a result of Venus detecting an inconsistent file.
880      * CODA_PURGEFID  -- flush the attribute for the file
881      *                  purge it and its children from the dcache
882      *
883      * The last  allows Venus to replace local fids with global ones
884      * during reintegration.
885      *
886      * CODA_REPLACE -- replace one ViceFid with another throughout the name cache */
887     
888     int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
889     {
890     	/* Handle invalidation requests. */
891               if ( !sb || !sb->s_root || !sb->s_root->d_inode) { 
892     	          CDEBUG(D_DOWNCALL, "coda_downcall: opcode %d, no sb!\n", opcode);
893     		  return 0; 
894     	  }
895     
896     	  switch (opcode) {
897     
898     	  case CODA_FLUSH : {
899     	           clstats(CODA_FLUSH);
900     		   CDEBUG(D_DOWNCALL, "CODA_FLUSH\n");
901     		   coda_cache_clear_all(sb, NULL);
902     		   shrink_dcache_sb(sb);
903     		   coda_flag_inode(sb->s_root->d_inode, C_FLUSH);
904     		   return(0);
905     	  }
906     
907     	  case CODA_PURGEUSER : {
908     	           struct coda_cred *cred = &out->coda_purgeuser.cred;
909     		   CDEBUG(D_DOWNCALL, "CODA_PURGEUSER\n");
910     		   if ( !cred ) {
911     		           printk("PURGEUSER: null cred!\n");
912     			   return 0;
913     		   }
914     		   clstats(CODA_PURGEUSER);
915     		   coda_cache_clear_all(sb, cred);
916     		   return(0);
917     	  }
918     
919     	  case CODA_ZAPDIR : {
920     	          struct inode *inode;
921     		  ViceFid *fid = &out->coda_zapdir.CodaFid;
922     		  CDEBUG(D_DOWNCALL, "zapdir: fid = %s...\n", coda_f2s(fid));
923     		  clstats(CODA_ZAPDIR);
924     
925     		  inode = coda_fid_to_inode(fid, sb);
926     		  if (inode) {
927     			  CDEBUG(D_DOWNCALL, "zapdir: inode = %ld children flagged\n", 
928     				 inode->i_ino);
929     			  coda_flag_inode_children(inode, C_PURGE);
930     			  CDEBUG(D_DOWNCALL, "zapdir: inode = %ld cache cleared\n", inode->i_ino);
931     	                  coda_flag_inode(inode, C_VATTR);
932     			  iput(inode);
933     		  } else 
934     			  CDEBUG(D_DOWNCALL, "zapdir: no inode\n");
935     		  
936     		  return(0);
937     	  }
938     
939     	  case CODA_ZAPFILE : {
940     	          struct inode *inode;
941     		  struct ViceFid *fid = &out->coda_zapfile.CodaFid;
942     		  clstats(CODA_ZAPFILE);
943     		  CDEBUG(D_DOWNCALL, "zapfile: fid = %s\n", coda_f2s(fid));
944     		  inode = coda_fid_to_inode(fid, sb);
945     		  if ( inode ) {
946     			  CDEBUG(D_DOWNCALL, "zapfile: inode = %ld\n",
947     				 inode->i_ino);
948     	                  coda_flag_inode(inode, C_VATTR);
949     			  iput(inode);
950     		  } else 
951     			  CDEBUG(D_DOWNCALL, "zapfile: no inode\n");
952     		  return 0;
953     	  }
954     
955     	  case CODA_PURGEFID : {
956     	          struct inode *inode;
957     		  ViceFid *fid = &out->coda_purgefid.CodaFid;
958     		  CDEBUG(D_DOWNCALL, "purgefid: fid = %s\n", coda_f2s(fid));
959     		  clstats(CODA_PURGEFID);
960     		  inode = coda_fid_to_inode(fid, sb);
961     		  if ( inode ) { 
962     			CDEBUG(D_DOWNCALL, "purgefid: inode = %ld\n",
963     			       inode->i_ino);
964     			coda_flag_inode_children(inode, C_PURGE);
965     
966     			/* catch the dentries later if some are still busy */
967     			coda_flag_inode(inode, C_PURGE);
968     			d_prune_aliases(inode);
969     
970     			iput(inode);
971     		  } else 
972     			CDEBUG(D_DOWNCALL, "purgefid: no inode\n");
973     		  return 0;
974     	  }
975     
976     	  case CODA_REPLACE : {
977     	          struct inode *inode;
978     		  ViceFid *oldfid = &out->coda_replace.OldFid;
979     		  ViceFid *newfid = &out->coda_replace.NewFid;
980     		  clstats(CODA_REPLACE);
981     		  CDEBUG(D_DOWNCALL, "CODA_REPLACE\n");
982     		  inode = coda_fid_to_inode(oldfid, sb);
983     		  if ( inode ) { 
984     			  CDEBUG(D_DOWNCALL, "replacefid: inode = %ld\n",
985     				 inode->i_ino);
986     			  coda_replace_fid(inode, oldfid, newfid);
987     			  iput(inode);
988     		  }else 
989     			  CDEBUG(D_DOWNCALL, "purgefid: no inode\n");
990     		  
991     		  return 0;
992     	  }
993     	  }
994     	  return 0;
995     }
996     
997