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