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 
44 static int coda_upcall(struct coda_sb_info *mntinfo, int inSize, int *outSize,
45 		       union inputArgs *buffer);
46 
alloc_upcall(int opcode,int size)47 static void *alloc_upcall(int opcode, int size)
48 {
49 	union inputArgs *inp;
50 
51 	CODA_ALLOC(inp, union inputArgs *, size);
52         if (!inp)
53 		return ERR_PTR(-ENOMEM);
54 
55         inp->ih.opcode = opcode;
56 	inp->ih.pid = current->pid;
57 	inp->ih.pgid = current->pgrp;
58 	coda_load_creds(&(inp->ih.cred));
59 
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 */
venus_rootfid(struct super_block * sb,ViceFid * fidp)77 int 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 
venus_getattr(struct super_block * sb,struct ViceFid * fid,struct coda_vattr * attr)100 int 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 
venus_setattr(struct super_block * sb,struct ViceFid * fid,struct coda_vattr * vattr)119 int 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 
venus_lookup(struct super_block * sb,struct ViceFid * fid,const char * name,int length,int * type,struct ViceFid * resfid)139 int 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 
venus_store(struct super_block * sb,struct ViceFid * fid,int flags,struct coda_cred * cred)168 int 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 
venus_release(struct super_block * sb,struct ViceFid * fid,int flags)189 int 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 
venus_close(struct super_block * sb,struct ViceFid * fid,int flags,struct coda_cred * cred)207 int 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 
venus_open(struct super_block * sb,struct ViceFid * fid,int flags,struct file ** fh)228 int 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 
venus_mkdir(struct super_block * sb,struct ViceFid * dirfid,const char * name,int length,struct ViceFid * newfid,struct coda_vattr * attrs)249 int 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 
venus_rename(struct super_block * sb,struct ViceFid * old_fid,struct ViceFid * new_fid,size_t old_length,size_t new_length,const char * old_name,const char * new_name)279 int 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 
venus_create(struct super_block * sb,struct ViceFid * dirfid,const char * name,int length,int excl,int mode,int rdev,struct ViceFid * newfid,struct coda_vattr * attrs)318 int 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 
venus_rmdir(struct super_block * sb,struct ViceFid * dirfid,const char * name,int length)351 int 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 
venus_remove(struct super_block * sb,struct ViceFid * dirfid,const char * name,int length)374 int 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 
venus_readlink(struct super_block * sb,struct ViceFid * fid,char * buffer,int * length)396 int 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 
venus_link(struct super_block * sb,struct ViceFid * fid,struct ViceFid * dirfid,const char * name,int len)430 int 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 
venus_symlink(struct super_block * sb,struct ViceFid * fid,const char * name,int len,const char * symname,int symlen)457 int 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 
venus_fsync(struct super_block * sb,struct ViceFid * fid)493 int 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 
venus_access(struct super_block * sb,struct ViceFid * fid,int mask)510 int 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 
venus_pioctl(struct super_block * sb,struct ViceFid * fid,unsigned int cmd,struct PioctlData * data)529 int 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         if (data->vi.out_size > VC_MAXDATASIZE) {
547 		error = -EINVAL;
548 		goto exit;
549 	}
550 
551         inp->coda_ioctl.VFid = *fid;
552 
553         /* the cmd field was mutated by increasing its size field to
554          * reflect the path and follow args. We need to subtract that
555          * out before sending the command to Venus.  */
556         inp->coda_ioctl.cmd = (cmd & ~(PIOCPARM_MASK << 16));
557         iocsize = ((cmd >> 16) & PIOCPARM_MASK) - sizeof(char *) - sizeof(int);
558         inp->coda_ioctl.cmd |= (iocsize & PIOCPARM_MASK) <<	16;
559 
560         /* in->coda_ioctl.rwflag = flag; */
561         inp->coda_ioctl.len = data->vi.in_size;
562         inp->coda_ioctl.data = (char *)(INSIZE(ioctl));
563 
564         /* get the data out of user space */
565         if ( copy_from_user((char*)inp + (long)inp->coda_ioctl.data,
566 			    data->vi.in, data->vi.in_size) ) {
567 		error = -EINVAL;
568 	        goto exit;
569 	}
570 
571         error = coda_upcall(coda_sbp(sb), SIZE(ioctl) + data->vi.in_size,
572                             &outsize, inp);
573 
574         if (error) {
575 	        printk("coda_pioctl: Venus returns: %d for %s\n",
576 		       error, coda_f2s(fid));
577 		goto exit;
578 	}
579 
580 	if (outsize < (long)outp->coda_ioctl.data + outp->coda_ioctl.len) {
581                 CDEBUG(D_FILE, "reply size %d < reply len %ld\n", outsize,
582 		       (long)outp->coda_ioctl.data + outp->coda_ioctl.len);
583 		error = -EINVAL;
584 		goto exit;
585 	}
586 
587         if (outp->coda_ioctl.len > data->vi.out_size) {
588                 CDEBUG(D_FILE, "return len %d > request len %d\n",
589 		       outp->coda_ioctl.len, data->vi.out_size);
590 		error = -EINVAL;
591 		goto exit;
592         }
593 
594 	/* Copy out the OUT buffer. */
595 	error = verify_area(VERIFY_WRITE, data->vi.out, outp->coda_ioctl.len);
596 	if ( error ) goto exit;
597 
598 	if (copy_to_user(data->vi.out,
599 			 (char *)outp + (long)outp->coda_ioctl.data,
600 			 outp->coda_ioctl.len)) {
601 	    error = -EINVAL;
602 	}
603  exit:
604 	CODA_FREE(inp, insize);
605 	return error;
606 }
607 
venus_statfs(struct super_block * sb,struct statfs * sfs)608 int venus_statfs(struct super_block *sb, struct statfs *sfs)
609 {
610         union inputArgs *inp;
611         union outputArgs *outp;
612         int insize, outsize, error;
613 
614 	insize = max_t(unsigned int, INSIZE(statfs), OUTSIZE(statfs));
615 	UPARG(CODA_STATFS);
616 
617         error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
618 
619         if (!error) {
620 		sfs->f_blocks = outp->coda_statfs.stat.f_blocks;
621 		sfs->f_bfree  = outp->coda_statfs.stat.f_bfree;
622 		sfs->f_bavail = outp->coda_statfs.stat.f_bavail;
623 		sfs->f_files  = outp->coda_statfs.stat.f_files;
624 		sfs->f_ffree  = outp->coda_statfs.stat.f_ffree;
625 	} else {
626 		printk("coda_statfs: Venus returns: %d\n", error);
627 	}
628 
629         CDEBUG(D_INODE, " result %d\n",error);
630         CODA_FREE(inp, insize);
631         return error;
632 }
633 
634 /*
635  * coda_upcall and coda_downcall routines.
636  *
637  */
638 
coda_waitfor_upcall(struct upc_req * vmp,struct venus_comm * vcommp)639 static inline unsigned long coda_waitfor_upcall(struct upc_req *vmp,
640 						struct venus_comm *vcommp)
641 {
642 	DECLARE_WAITQUEUE(wait, current);
643  	struct timeval begin = { 0, 0 }, end = { 0, 0 };
644 
645 	vmp->uc_posttime = jiffies;
646 
647 	if (coda_upcall_timestamping)
648 		do_gettimeofday(&begin);
649 
650 	add_wait_queue(&vmp->uc_sleep, &wait);
651 	for (;;) {
652 		if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE )
653 			set_current_state(TASK_INTERRUPTIBLE);
654 		else
655 			set_current_state(TASK_UNINTERRUPTIBLE);
656 
657                 /* venus died */
658                 if ( !vcommp->vc_inuse )
659                         break;
660 
661 		/* got a reply */
662 		if ( vmp->uc_flags & ( REQ_WRITE | REQ_ABORT ) )
663 			break;
664 
665 		if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE && signal_pending(current) ) {
666 			/* if this process really wants to die, let it go */
667 			if ( sigismember(&(current->pending.signal), SIGKILL) ||
668 			     sigismember(&(current->pending.signal), SIGINT) )
669 				break;
670 			/* signal is present: after timeout always return
671 			   really smart idea, probably useless ... */
672 			if ( jiffies - vmp->uc_posttime > coda_timeout * HZ )
673 				break;
674 		}
675 		schedule();
676 	}
677 	remove_wait_queue(&vmp->uc_sleep, &wait);
678 	set_current_state(TASK_RUNNING);
679 
680 	if (coda_upcall_timestamping && begin.tv_sec != 0) {
681 		do_gettimeofday(&end);
682 
683 		if (end.tv_usec < begin.tv_usec) {
684 			end.tv_usec += 1000000; end.tv_sec--;
685 		}
686 		end.tv_sec  -= begin.tv_sec;
687 		end.tv_usec -= begin.tv_usec;
688 	}
689 
690 	CDEBUG(D_SPECIAL, "begin: %ld.%06ld, elapsed: %ld.%06ld\n",
691 		begin.tv_sec, (unsigned long)begin.tv_usec,
692 		end.tv_sec, (unsigned long)end.tv_usec);
693 
694 	return 	((end.tv_sec * 1000000) + end.tv_usec);
695 }
696 
697 
698 /*
699  * coda_upcall will return an error in the case of
700  * failed communication with Venus _or_ will peek at Venus
701  * reply and return Venus' error.
702  *
703  * As venus has 2 types of errors, normal errors (positive) and internal
704  * errors (negative), normal errors are negated, while internal errors
705  * are all mapped to -EINTR, while showing a nice warning message. (jh)
706  *
707  */
coda_upcall(struct coda_sb_info * sbi,int inSize,int * outSize,union inputArgs * buffer)708 static int coda_upcall(struct coda_sb_info *sbi,
709 		int inSize, int *outSize,
710 		union inputArgs *buffer)
711 {
712 	unsigned long runtime;
713 	struct venus_comm *vcommp;
714 	union outputArgs *out;
715 	struct upc_req *req;
716 	int error = 0;
717 
718 	vcommp = sbi->sbi_vcomm;
719 	if ( !vcommp->vc_inuse ) {
720 		printk("No pseudo device in upcall comms at %p\n", vcommp);
721                 return -ENXIO;
722 	}
723 
724 	/* Format the request message. */
725 	req = upc_alloc();
726 	if (!req) {
727 		printk("Failed to allocate upc_req structure\n");
728 		return -ENOMEM;
729 	}
730 	req->uc_data = (void *)buffer;
731 	req->uc_flags = 0;
732 	req->uc_inSize = inSize;
733 	req->uc_outSize = *outSize ? *outSize : inSize;
734 	req->uc_opcode = ((union inputArgs *)buffer)->ih.opcode;
735 	req->uc_unique = ++vcommp->vc_seq;
736 	init_waitqueue_head(&req->uc_sleep);
737 
738 	/* Fill in the common input args. */
739 	((union inputArgs *)buffer)->ih.unique = req->uc_unique;
740 
741 	/* Append msg to pending queue and poke Venus. */
742 	list_add(&(req->uc_chain), vcommp->vc_pending.prev);
743 
744 	CDEBUG(D_UPCALL,
745 	       "Proc %d wake Venus for(opc,uniq) =(%d,%d) msg at %p.zzz.\n",
746 	       current->pid, req->uc_opcode, req->uc_unique, req);
747 
748 	wake_up_interruptible(&vcommp->vc_waitq);
749 	/* We can be interrupted while we wait for Venus to process
750 	 * our request.  If the interrupt occurs before Venus has read
751 	 * the request, we dequeue and return. If it occurs after the
752 	 * read but before the reply, we dequeue, send a signal
753 	 * message, and return. If it occurs after the reply we ignore
754 	 * it. In no case do we want to restart the syscall.  If it
755 	 * was interrupted by a venus shutdown (psdev_close), return
756 	 * ENODEV.  */
757 
758 	/* Go to sleep.  Wake up on signals only after the timeout. */
759 	runtime = coda_waitfor_upcall(req, vcommp);
760 	coda_upcall_stats(((union inputArgs *)buffer)->ih.opcode, runtime);
761 
762 	CDEBUG(D_TIMING, "opc: %d time: %ld uniq: %d size: %d\n",
763 	       req->uc_opcode, jiffies - req->uc_posttime,
764 	       req->uc_unique, req->uc_outSize);
765 	CDEBUG(D_UPCALL,
766 	       "..process %d woken up by Venus for req at %p, data at %p\n",
767 	       current->pid, req, req->uc_data);
768 	if (vcommp->vc_inuse) {      /* i.e. Venus is still alive */
769 	    /* Op went through, interrupt or not... */
770 	    if (req->uc_flags & REQ_WRITE) {
771 		out = (union outputArgs *)req->uc_data;
772 		/* here we map positive Venus errors to kernel errors */
773 		error = -out->oh.result;
774 		CDEBUG(D_UPCALL,
775 		       "upcall: (u,o,r) (%ld, %ld, %ld) out at %p\n",
776 		       out->oh.unique, out->oh.opcode, out->oh.result, out);
777 		*outSize = req->uc_outSize;
778 		goto exit;
779 	    }
780 	    if ( !(req->uc_flags & REQ_READ) && signal_pending(current)) {
781 		/* Interrupted before venus read it. */
782 		CDEBUG(D_UPCALL,
783 		       "Interrupted before read:(op,un) (%d.%d), flags = %x\n",
784 		       req->uc_opcode, req->uc_unique, req->uc_flags);
785 		list_del(&(req->uc_chain));
786 		/* perhaps the best way to convince the app to
787 		   give up? */
788 		error = -EINTR;
789 		goto exit;
790 	    }
791 	    if ( (req->uc_flags & REQ_READ) && signal_pending(current) ) {
792 		    /* interrupted after Venus did its read, send signal */
793 		    union inputArgs *sig_inputArgs;
794 		    struct upc_req *sig_req;
795 
796 		    CDEBUG(D_UPCALL,
797 			   "Sending Venus a signal: op = %d.%d, flags = %x\n",
798 			   req->uc_opcode, req->uc_unique, req->uc_flags);
799 
800 		    list_del(&(req->uc_chain));
801 		    error = -ENOMEM;
802 		    sig_req = upc_alloc();
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 			upc_free(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 		    CDEBUG(D_UPCALL,
822 			   "coda_upcall: enqueing signal msg (%d, %d)\n",
823 			   sig_req->uc_opcode, sig_req->uc_unique);
824 
825 		    /* insert at head of queue! */
826 		    list_add(&(sig_req->uc_chain), &vcommp->vc_pending);
827 		    wake_up_interruptible(&vcommp->vc_waitq);
828 	    } else {
829 		    printk("Coda: Strange interruption..\n");
830 		    error = -EINTR;
831 	    }
832 	} else {	/* If venus died i.e. !VC_OPEN(vcommp) */
833 	        printk("coda_upcall: Venus dead on (op,un) (%d.%d) flags %d\n",
834 		       req->uc_opcode, req->uc_unique, req->uc_flags);
835 		error = -ENODEV;
836 	}
837 
838  exit:
839 	upc_free(req);
840 	if (error)
841 	        badclstats();
842 	return error;
843 }
844 
845 /*
846     The statements below are part of the Coda opportunistic
847     programming -- taken from the Mach/BSD kernel code for Coda.
848     You don't get correct semantics by stating what needs to be
849     done without guaranteeing the invariants needed for it to happen.
850     When will be have time to find out what exactly is going on?  (pjb)
851 */
852 
853 
854 /*
855  * There are 7 cases where cache invalidations occur.  The semantics
856  *  of each is listed here:
857  *
858  * CODA_FLUSH     -- flush all entries from the name cache and the cnode cache.
859  * CODA_PURGEUSER -- flush all entries from the name cache for a specific user
860  *                  This call is a result of token expiration.
861  *
862  * The next arise as the result of callbacks on a file or directory.
863  * CODA_ZAPFILE   -- flush the cached attributes for a file.
864 
865  * CODA_ZAPDIR    -- flush the attributes for the dir and
866  *                  force a new lookup for all the children
867                     of this dir.
868 
869  *
870  * The next is a result of Venus detecting an inconsistent file.
871  * CODA_PURGEFID  -- flush the attribute for the file
872  *                  purge it and its children from the dcache
873  *
874  * The last  allows Venus to replace local fids with global ones
875  * during reintegration.
876  *
877  * CODA_REPLACE -- replace one ViceFid with another throughout the name cache */
878 
coda_downcall(int opcode,union outputArgs * out,struct super_block * sb)879 int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
880 {
881 	/* Handle invalidation requests. */
882           if ( !sb || !sb->s_root || !sb->s_root->d_inode) {
883 	          CDEBUG(D_DOWNCALL, "coda_downcall: opcode %d, no sb!\n", opcode);
884 		  return 0;
885 	  }
886 
887 	  switch (opcode) {
888 
889 	  case CODA_FLUSH : {
890 	           clstats(CODA_FLUSH);
891 		   CDEBUG(D_DOWNCALL, "CODA_FLUSH\n");
892 		   coda_cache_clear_all(sb, NULL);
893 		   shrink_dcache_sb(sb);
894 		   coda_flag_inode(sb->s_root->d_inode, C_FLUSH);
895 		   return(0);
896 	  }
897 
898 	  case CODA_PURGEUSER : {
899 	           struct coda_cred *cred = &out->coda_purgeuser.cred;
900 		   CDEBUG(D_DOWNCALL, "CODA_PURGEUSER\n");
901 		   if ( !cred ) {
902 		           printk("PURGEUSER: null cred!\n");
903 			   return 0;
904 		   }
905 		   clstats(CODA_PURGEUSER);
906 		   coda_cache_clear_all(sb, cred);
907 		   return(0);
908 	  }
909 
910 	  case CODA_ZAPDIR : {
911 	          struct inode *inode;
912 		  ViceFid *fid = &out->coda_zapdir.CodaFid;
913 		  CDEBUG(D_DOWNCALL, "zapdir: fid = %s...\n", coda_f2s(fid));
914 		  clstats(CODA_ZAPDIR);
915 
916 		  inode = coda_fid_to_inode(fid, sb);
917 		  if (inode) {
918 			  CDEBUG(D_DOWNCALL, "zapdir: inode = %ld children flagged\n",
919 				 inode->i_ino);
920 			  coda_flag_inode_children(inode, C_PURGE);
921 			  CDEBUG(D_DOWNCALL, "zapdir: inode = %ld cache cleared\n", inode->i_ino);
922 	                  coda_flag_inode(inode, C_VATTR);
923 			  iput(inode);
924 		  } else
925 			  CDEBUG(D_DOWNCALL, "zapdir: no inode\n");
926 
927 		  return(0);
928 	  }
929 
930 	  case CODA_ZAPFILE : {
931 	          struct inode *inode;
932 		  struct ViceFid *fid = &out->coda_zapfile.CodaFid;
933 		  clstats(CODA_ZAPFILE);
934 		  CDEBUG(D_DOWNCALL, "zapfile: fid = %s\n", coda_f2s(fid));
935 		  inode = coda_fid_to_inode(fid, sb);
936 		  if ( inode ) {
937 			  CDEBUG(D_DOWNCALL, "zapfile: inode = %ld\n",
938 				 inode->i_ino);
939 	                  coda_flag_inode(inode, C_VATTR);
940 			  iput(inode);
941 		  } else
942 			  CDEBUG(D_DOWNCALL, "zapfile: no inode\n");
943 		  return 0;
944 	  }
945 
946 	  case CODA_PURGEFID : {
947 	          struct inode *inode;
948 		  ViceFid *fid = &out->coda_purgefid.CodaFid;
949 		  CDEBUG(D_DOWNCALL, "purgefid: fid = %s\n", coda_f2s(fid));
950 		  clstats(CODA_PURGEFID);
951 		  inode = coda_fid_to_inode(fid, sb);
952 		  if ( inode ) {
953 			CDEBUG(D_DOWNCALL, "purgefid: inode = %ld\n",
954 			       inode->i_ino);
955 			coda_flag_inode_children(inode, C_PURGE);
956 
957 			/* catch the dentries later if some are still busy */
958 			coda_flag_inode(inode, C_PURGE);
959 			d_prune_aliases(inode);
960 
961 			iput(inode);
962 		  } else
963 			CDEBUG(D_DOWNCALL, "purgefid: no inode\n");
964 		  return 0;
965 	  }
966 
967 	  case CODA_REPLACE : {
968 	          struct inode *inode;
969 		  ViceFid *oldfid = &out->coda_replace.OldFid;
970 		  ViceFid *newfid = &out->coda_replace.NewFid;
971 		  clstats(CODA_REPLACE);
972 		  CDEBUG(D_DOWNCALL, "CODA_REPLACE\n");
973 		  inode = coda_fid_to_inode(oldfid, sb);
974 		  if ( inode ) {
975 			  CDEBUG(D_DOWNCALL, "replacefid: inode = %ld\n",
976 				 inode->i_ino);
977 			  coda_replace_fid(inode, oldfid, newfid);
978 			  iput(inode);
979 		  }else
980 			  CDEBUG(D_DOWNCALL, "purgefid: no inode\n");
981 
982 		  return 0;
983 	  }
984 	  }
985 	  return 0;
986 }
987 
988