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