Merge with Linux 2.4.0-test3-pre2.
[linux-2.6/linux-mips.git] / fs / coda / upcall.c
blob206c9d8b05efeb58b20af72405f9619d8fff0539
1 /*
2 * Mostly platform independent upcall operations to Venus:
3 * -- upcalls
4 * -- upcall routines
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
13 * Carnegie Mellon University encourages users of this code to contribute
14 * improvements to the Coda project. Contact Peter Braam <coda@cs.cmu.edu>.
17 #include <asm/system.h>
18 #include <asm/segment.h>
19 #include <asm/signal.h>
20 #include <linux/signal.h>
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>
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>
43 static int coda_upcall(struct coda_sb_info *mntinfo, int inSize, int *outSize,
44 union inputArgs *buffer);
46 static void *alloc_upcall(int opcode, int size)
48 union inputArgs *inp;
50 CODA_ALLOC(inp, union inputArgs *, size);
51 if (!inp)
52 return ERR_PTR(-ENOMEM);
54 inp->ih.opcode = opcode;
55 inp->ih.pid = current->pid;
56 inp->ih.pgid = current->pgrp;
57 coda_load_creds(&(inp->ih.cred));
59 return (void*)inp;
62 #define UPARG(op)\
63 do {\
64 inp = (union inputArgs *)alloc_upcall(op, insize); \
65 if (IS_ERR(inp)) { return PTR_ERR(inp); }\
66 outp = (union outputArgs *)(inp); \
67 outsize = insize; \
68 } while (0)
70 static inline int max(int a, int b)
72 if ( a > b )
73 return a;
74 else
75 return b;
78 #define INSIZE(tag) sizeof(struct coda_ ## tag ## _in)
79 #define OUTSIZE(tag) sizeof(struct coda_ ## tag ## _out)
80 #define SIZE(tag) max(INSIZE(tag), OUTSIZE(tag))
83 /* the upcalls */
84 int venus_rootfid(struct super_block *sb, ViceFid *fidp)
86 union inputArgs *inp;
87 union outputArgs *outp;
88 int insize, outsize, error;
89 ENTRY;
91 insize = SIZE(root);
92 UPARG(CODA_ROOT);
94 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
96 if (error) {
97 printk("coda_get_rootfid: error %d\n", error);
98 } else {
99 *fidp = (ViceFid) outp->coda_root.VFid;
100 CDEBUG(D_SUPER, "VolumeId: %lx, VnodeId: %lx.\n",
101 fidp->Volume, fidp->Vnode);
104 CODA_FREE(inp, insize);
105 EXIT;
106 return error;
109 int venus_getattr(struct super_block *sb, struct ViceFid *fid,
110 struct coda_vattr *attr)
112 union inputArgs *inp;
113 union outputArgs *outp;
114 int insize, outsize, error;
115 ENTRY;
117 insize = SIZE(getattr);
118 UPARG(CODA_GETATTR);
119 inp->coda_getattr.VFid = *fid;
121 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
123 *attr = outp->coda_getattr.attr;
125 CODA_FREE(inp, insize);
126 EXIT;
127 return error;
130 int venus_setattr(struct super_block *sb, struct ViceFid *fid,
131 struct coda_vattr *vattr)
133 union inputArgs *inp;
134 union outputArgs *outp;
135 int insize, outsize, error;
137 insize = SIZE(setattr);
138 UPARG(CODA_SETATTR);
140 inp->coda_setattr.VFid = *fid;
141 inp->coda_setattr.attr = *vattr;
143 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
145 CDEBUG(D_SUPER, " result %d\n", error);
146 CODA_FREE(inp, insize);
147 return error;
150 int venus_lookup(struct super_block *sb, struct ViceFid *fid,
151 const char *name, int length, int * type,
152 struct ViceFid *resfid)
154 union inputArgs *inp;
155 union outputArgs *outp;
156 int insize, outsize, error;
157 int offset;
159 offset = INSIZE(lookup);
160 insize = max(offset + length +1, OUTSIZE(lookup));
161 UPARG(CODA_LOOKUP);
163 inp->coda_lookup.VFid = *fid;
164 inp->coda_lookup.name = offset;
165 inp->coda_lookup.flags = CLU_CASE_SENSITIVE;
166 /* send Venus a null terminated string */
167 memcpy((char *)(inp) + offset, name, length);
168 *((char *)inp + offset + length) = '\0';
170 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
172 *resfid = outp->coda_lookup.VFid;
173 *type = outp->coda_lookup.vtype;
175 CODA_FREE(inp, insize);
176 return error;
180 int venus_release(struct super_block *sb, struct ViceFid *fid, int flags,
181 struct coda_cred *cred)
183 union inputArgs *inp;
184 union outputArgs *outp;
185 int insize, outsize, error;
187 insize = SIZE(close);
188 UPARG(CODA_CLOSE);
190 if ( cred ) {
191 memcpy(&(inp->ih.cred), cred, sizeof(*cred));
192 } else
193 printk("CODA: close without valid file creds.\n");
195 inp->coda_close.VFid = *fid;
196 inp->coda_close.flags = flags;
198 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
200 CODA_FREE(inp, insize);
201 return error;
204 int venus_open(struct super_block *sb, struct ViceFid *fid,
205 int flags, ino_t *ino, dev_t *dev)
207 union inputArgs *inp;
208 union outputArgs *outp;
209 int insize, outsize, error;
211 insize = SIZE(open);
212 UPARG(CODA_OPEN);
214 inp->coda_open.VFid = *fid;
215 inp->coda_open.flags = flags;
217 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
219 *ino = outp->coda_open.inode;
220 *dev = outp->coda_open.dev;
222 CODA_FREE(inp, insize);
223 return error;
226 int venus_mkdir(struct super_block *sb, struct ViceFid *dirfid,
227 const char *name, int length,
228 struct ViceFid *newfid, struct coda_vattr *attrs)
230 union inputArgs *inp;
231 union outputArgs *outp;
232 int insize, outsize, error;
233 int offset;
235 offset = INSIZE(mkdir);
236 insize = max(offset + length + 1, OUTSIZE(mkdir));
237 UPARG(CODA_MKDIR);
239 inp->coda_mkdir.VFid = *dirfid;
240 inp->coda_mkdir.attr = *attrs;
241 inp->coda_mkdir.name = offset;
242 /* Venus must get null terminated string */
243 memcpy((char *)(inp) + offset, name, length);
244 *((char *)inp + offset + length) = '\0';
246 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
248 *attrs = outp->coda_mkdir.attr;
249 *newfid = outp->coda_mkdir.VFid;
251 CODA_FREE(inp, insize);
252 return error;
256 int venus_rename(struct super_block *sb, struct ViceFid *old_fid,
257 struct ViceFid *new_fid, size_t old_length,
258 size_t new_length, const char *old_name,
259 const char *new_name)
261 union inputArgs *inp;
262 union outputArgs *outp;
263 int insize, outsize, error;
264 int offset, s;
266 offset = INSIZE(rename);
267 insize = max(offset + new_length + old_length + 8,
268 OUTSIZE(rename));
269 UPARG(CODA_RENAME);
271 inp->coda_rename.sourceFid = *old_fid;
272 inp->coda_rename.destFid = *new_fid;
273 inp->coda_rename.srcname = offset;
275 /* Venus must receive an null terminated string */
276 s = ( old_length & ~0x3) +4; /* round up to word boundary */
277 memcpy((char *)(inp) + offset, old_name, old_length);
278 *((char *)inp + offset + old_length) = '\0';
280 /* another null terminated string for Venus */
281 offset += s;
282 inp->coda_rename.destname = offset;
283 s = ( new_length & ~0x3) +4; /* round up to word boundary */
284 memcpy((char *)(inp) + offset, new_name, new_length);
285 *((char *)inp + offset + new_length) = '\0';
287 CDEBUG(D_INODE, "destname in packet: %s\n",
288 (char *)inp + (int) inp->coda_rename.destname);
289 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
291 CODA_FREE(inp, insize);
292 return error;
295 int venus_create(struct super_block *sb, struct ViceFid *dirfid,
296 const char *name, int length, int excl, int mode, int rdev,
297 struct ViceFid *newfid, struct coda_vattr *attrs)
299 union inputArgs *inp;
300 union outputArgs *outp;
301 int insize, outsize, error;
302 int offset;
304 offset = INSIZE(create);
305 insize = max(offset + length + 1, OUTSIZE(create));
306 UPARG(CODA_CREATE);
308 inp->coda_create.VFid = *dirfid;
309 inp->coda_create.attr.va_mode = mode;
310 inp->coda_create.attr.va_rdev = rdev;
311 inp->coda_create.excl = excl;
312 inp->coda_create.mode = mode;
313 inp->coda_create.name = offset;
315 /* Venus must get null terminated string */
316 memcpy((char *)(inp) + offset, name, length);
317 *((char *)inp + offset + length) = '\0';
319 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
321 *attrs = outp->coda_create.attr;
322 *newfid = outp->coda_create.VFid;
324 CODA_FREE(inp, insize);
325 return error;
328 int venus_rmdir(struct super_block *sb, struct ViceFid *dirfid,
329 const char *name, int length)
331 union inputArgs *inp;
332 union outputArgs *outp;
333 int insize, outsize, error;
334 int offset;
336 offset = INSIZE(rmdir);
337 insize = max(offset + length + 1, OUTSIZE(rmdir));
338 UPARG(CODA_RMDIR);
340 inp->coda_rmdir.VFid = *dirfid;
341 inp->coda_rmdir.name = offset;
342 memcpy((char *)(inp) + offset, name, length);
343 *((char *)inp + offset + length) = '\0';
345 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
347 CODA_FREE(inp, insize);
348 return error;
351 int venus_remove(struct super_block *sb, struct ViceFid *dirfid,
352 const char *name, int length)
354 union inputArgs *inp;
355 union outputArgs *outp;
356 int error=0, insize, outsize, offset;
358 offset = INSIZE(remove);
359 insize = max(offset + length + 1, OUTSIZE(remove));
360 UPARG(CODA_REMOVE);
362 inp->coda_remove.VFid = *dirfid;
363 inp->coda_remove.name = offset;
364 memcpy((char *)(inp) + offset, name, length);
365 *((char *)inp + offset + length) = '\0';
367 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
369 CODA_FREE(inp, insize);
370 return error;
373 int venus_readlink(struct super_block *sb, struct ViceFid *fid,
374 char *buffer, int *length)
376 union inputArgs *inp;
377 union outputArgs *outp;
378 int insize, outsize, error;
379 int retlen;
380 char *result;
382 insize = max(INSIZE(readlink), OUTSIZE(readlink)+ *length + 1);
383 UPARG(CODA_READLINK);
385 inp->coda_readlink.VFid = *fid;
387 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
389 if (! error) {
390 retlen = outp->coda_readlink.count;
391 if ( retlen > *length )
392 retlen = *length;
393 *length = retlen;
394 result = (char *)outp + (long)outp->coda_readlink.data;
395 memcpy(buffer, result, retlen);
396 *(buffer + retlen) = '\0';
399 CDEBUG(D_INODE, " result %d\n",error);
400 EXIT;
401 CODA_FREE(inp, insize);
402 return error;
407 int venus_link(struct super_block *sb, struct ViceFid *fid,
408 struct ViceFid *dirfid, const char *name, int len )
410 union inputArgs *inp;
411 union outputArgs *outp;
412 int insize, outsize, error;
413 int offset;
415 offset = INSIZE(link);
416 insize = max(offset + len + 1, OUTSIZE(link));
417 UPARG(CODA_LINK);
419 inp->coda_link.sourceFid = *fid;
420 inp->coda_link.destFid = *dirfid;
421 inp->coda_link.tname = offset;
423 /* make sure strings are null terminated */
424 memcpy((char *)(inp) + offset, name, len);
425 *((char *)inp + offset + len) = '\0';
427 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
429 CDEBUG(D_INODE, " result %d\n",error);
430 EXIT;
431 CODA_FREE(inp, insize);
432 return error;
435 int venus_symlink(struct super_block *sb, struct ViceFid *fid,
436 const char *name, int len,
437 const char *symname, int symlen)
439 union inputArgs *inp;
440 union outputArgs *outp;
441 int insize, outsize, error;
442 int offset, s;
444 offset = INSIZE(symlink);
445 insize = max(offset + len + symlen + 8, OUTSIZE(symlink));
446 UPARG(CODA_SYMLINK);
448 /* inp->coda_symlink.attr = *tva; XXXXXX */
449 inp->coda_symlink.VFid = *fid;
451 /* Round up to word boundary and null terminate */
452 inp->coda_symlink.srcname = offset;
453 s = ( symlen & ~0x3 ) + 4;
454 memcpy((char *)(inp) + offset, symname, symlen);
455 *((char *)inp + offset + symlen) = '\0';
457 /* Round up to word boundary and null terminate */
458 offset += s;
459 inp->coda_symlink.tname = offset;
460 s = (len & ~0x3) + 4;
461 memcpy((char *)(inp) + offset, name, len);
462 *((char *)inp + offset + len) = '\0';
464 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
466 CDEBUG(D_INODE, " result %d\n",error);
467 EXIT;
468 CODA_FREE(inp, insize);
469 return error;
472 int venus_fsync(struct super_block *sb, struct ViceFid *fid)
474 union inputArgs *inp;
475 union outputArgs *outp;
476 int insize, outsize, error;
478 insize=SIZE(fsync);
479 UPARG(CODA_FSYNC);
481 inp->coda_fsync.VFid = *fid;
482 error = coda_upcall(coda_sbp(sb), sizeof(union inputArgs),
483 &outsize, inp);
485 CODA_FREE(inp, insize);
486 return error;
489 int venus_access(struct super_block *sb, struct ViceFid *fid, int mask)
491 union inputArgs *inp;
492 union outputArgs *outp;
493 int insize, outsize, error;
495 insize = SIZE(access);
496 UPARG(CODA_ACCESS);
498 inp->coda_access.VFid = *fid;
499 inp->coda_access.flags = mask;
501 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
503 CODA_FREE(inp, insize);
504 EXIT;
505 return error;
509 int venus_pioctl(struct super_block *sb, struct ViceFid *fid,
510 unsigned int cmd, struct PioctlData *data)
512 union inputArgs *inp;
513 union outputArgs *outp;
514 int insize, outsize, error;
515 int iocsize;
517 insize = VC_MAXMSGSIZE;
518 UPARG(CODA_IOCTL);
520 /* build packet for Venus */
521 if (data->vi.in_size > VC_MAXDATASIZE) {
522 error = EINVAL;
523 goto exit;
526 inp->coda_ioctl.VFid = *fid;
528 /* the cmd field was mutated by increasing its size field to
529 * reflect the path and follow args. We need to subtract that
530 * out before sending the command to Venus. */
531 inp->coda_ioctl.cmd = (cmd & ~(PIOCPARM_MASK << 16));
532 iocsize = ((cmd >> 16) & PIOCPARM_MASK) - sizeof(char *) - sizeof(int);
533 inp->coda_ioctl.cmd |= (iocsize & PIOCPARM_MASK) << 16;
535 /* in->coda_ioctl.rwflag = flag; */
536 inp->coda_ioctl.len = data->vi.in_size;
537 inp->coda_ioctl.data = (char *)(INSIZE(ioctl));
539 /* get the data out of user space */
540 if ( copy_from_user((char*)inp + (long)inp->coda_ioctl.data,
541 data->vi.in, data->vi.in_size) ) {
542 error = EINVAL;
543 goto exit;
546 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
548 if (error) {
549 printk("coda_pioctl: Venus returns: %d for %s\n",
550 error, coda_f2s(fid));
551 goto exit;
554 /* Copy out the OUT buffer. */
555 if (outp->coda_ioctl.len > data->vi.out_size) {
556 CDEBUG(D_FILE, "return len %d <= request len %d\n",
557 outp->coda_ioctl.len,
558 data->vi.out_size);
559 error = EINVAL;
560 } else {
561 error = verify_area(VERIFY_WRITE, data->vi.out,
562 data->vi.out_size);
563 if ( error ) goto exit;
565 if (copy_to_user(data->vi.out,
566 (char *)outp + (long)outp->coda_ioctl.data,
567 data->vi.out_size)) {
568 error = EINVAL;
569 goto exit;
573 exit:
574 CODA_FREE(inp, insize);
575 return error;
578 int venus_statfs(struct super_block *sb, struct statfs *sfs)
580 union inputArgs *inp;
581 union outputArgs *outp;
582 int insize, outsize, error;
584 insize = max(INSIZE(statfs), OUTSIZE(statfs));
585 UPARG(CODA_STATFS);
587 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
589 if (!error) {
590 sfs->f_blocks = outp->coda_statfs.stat.f_blocks;
591 sfs->f_bfree = outp->coda_statfs.stat.f_bfree;
592 sfs->f_bavail = outp->coda_statfs.stat.f_bavail;
593 sfs->f_files = outp->coda_statfs.stat.f_files;
594 sfs->f_ffree = outp->coda_statfs.stat.f_ffree;
595 } else {
596 printk("coda_statfs: Venus returns: %d\n", error);
599 CDEBUG(D_INODE, " result %d\n",error);
600 EXIT;
601 CODA_FREE(inp, insize);
602 return error;
606 * coda_upcall and coda_downcall routines.
610 static inline unsigned long coda_waitfor_upcall(struct upc_req *vmp)
612 DECLARE_WAITQUEUE(wait, current);
613 struct timeval begin = { 0, 0 }, end = { 0, 0 };
615 vmp->uc_posttime = jiffies;
617 if (coda_upcall_timestamping)
618 do_gettimeofday(&begin);
620 add_wait_queue(&vmp->uc_sleep, &wait);
621 for (;;) {
622 if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE )
623 set_current_state(TASK_INTERRUPTIBLE);
624 else
625 set_current_state(TASK_UNINTERRUPTIBLE);
627 /* venus died */
628 if ( !coda_upc_comm.vc_inuse )
629 break;
631 /* got a reply */
632 if ( vmp->uc_flags & ( REQ_WRITE | REQ_ABORT ) )
633 break;
635 if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE && signal_pending(current) ) {
636 /* if this process really wants to die, let it go */
637 if ( sigismember(&(current->signal), SIGKILL) ||
638 sigismember(&(current->signal), SIGINT) )
639 break;
640 /* signal is present: after timeout always return
641 really smart idea, probably useless ... */
642 if ( jiffies - vmp->uc_posttime > coda_timeout * HZ )
643 break;
645 schedule();
647 remove_wait_queue(&vmp->uc_sleep, &wait);
648 current->state = TASK_RUNNING;
650 if (coda_upcall_timestamping && begin.tv_sec != 0) {
651 do_gettimeofday(&end);
653 if (end.tv_usec < begin.tv_usec) {
654 end.tv_usec += 1000000; end.tv_sec--;
656 end.tv_sec -= begin.tv_sec;
657 end.tv_usec -= begin.tv_usec;
660 CDEBUG(D_SPECIAL, "begin: %ld.%06ld, elapsed: %ld.%06ld\n",
661 begin.tv_sec, (unsigned long)begin.tv_usec,
662 end.tv_sec, (unsigned long)end.tv_usec);
664 return ((end.tv_sec * 1000000) + end.tv_usec);
669 * coda_upcall will return an error in the case of
670 * failed communication with Venus _or_ will peek at Venus
671 * reply and return Venus' error.
673 * As venus has 2 types of errors, normal errors (positive) and internal
674 * errors (negative), normal errors are negated, while internal errors
675 * are all mapped to -EINTR, while showing a nice warning message. (jh)
678 static int coda_upcall(struct coda_sb_info *sbi,
679 int inSize, int *outSize,
680 union inputArgs *buffer)
682 unsigned long runtime;
683 struct venus_comm *vcommp;
684 union outputArgs *out;
685 struct upc_req *req;
686 int error = 0;
688 ENTRY;
690 vcommp = &coda_upc_comm;
691 if ( !vcommp->vc_inuse ) {
692 printk("No pseudo device in upcall comms at %p\n", vcommp);
693 return -ENXIO;
696 /* Format the request message. */
697 CODA_ALLOC(req,struct upc_req *,sizeof(struct upc_req));
698 req->uc_data = (void *)buffer;
699 req->uc_flags = 0;
700 req->uc_inSize = inSize;
701 req->uc_outSize = *outSize ? *outSize : inSize;
702 req->uc_opcode = ((union inputArgs *)buffer)->ih.opcode;
703 req->uc_unique = ++vcommp->vc_seq;
704 init_waitqueue_head(&req->uc_sleep);
706 /* Fill in the common input args. */
707 ((union inputArgs *)buffer)->ih.unique = req->uc_unique;
709 /* Append msg to pending queue and poke Venus. */
710 list_add(&(req->uc_chain), vcommp->vc_pending.prev);
712 CDEBUG(D_UPCALL,
713 "Proc %d wake Venus for(opc,uniq) =(%d,%d) msg at %p.zzz.\n",
714 current->pid, req->uc_opcode, req->uc_unique, req);
716 wake_up_interruptible(&vcommp->vc_waitq);
717 /* We can be interrupted while we wait for Venus to process
718 * our request. If the interrupt occurs before Venus has read
719 * the request, we dequeue and return. If it occurs after the
720 * read but before the reply, we dequeue, send a signal
721 * message, and return. If it occurs after the reply we ignore
722 * it. In no case do we want to restart the syscall. If it
723 * was interrupted by a venus shutdown (psdev_close), return
724 * ENODEV. */
726 /* Go to sleep. Wake up on signals only after the timeout. */
727 runtime = coda_waitfor_upcall(req);
728 coda_upcall_stats(((union inputArgs *)buffer)->ih.opcode, runtime);
730 CDEBUG(D_TIMING, "opc: %d time: %ld uniq: %d size: %d\n",
731 req->uc_opcode, jiffies - req->uc_posttime,
732 req->uc_unique, req->uc_outSize);
733 CDEBUG(D_UPCALL,
734 "..process %d woken up by Venus for req at %p, data at %p\n",
735 current->pid, req, req->uc_data);
736 if (vcommp->vc_inuse) { /* i.e. Venus is still alive */
737 /* Op went through, interrupt or not... */
738 if (req->uc_flags & REQ_WRITE) {
739 out = (union outputArgs *)req->uc_data;
740 /* here we map positive Venus errors to kernel errors */
741 if ( out->oh.result < 0 ) {
742 printk("Tell Peter: Venus returns negative error %ld, for oc %ld!\n",
743 out->oh.result, out->oh.opcode);
744 out->oh.result = EINTR;
746 error = -out->oh.result;
747 CDEBUG(D_UPCALL,
748 "upcall: (u,o,r) (%ld, %ld, %ld) out at %p\n",
749 out->oh.unique, out->oh.opcode, out->oh.result, out);
750 *outSize = req->uc_outSize;
751 goto exit;
753 if ( !(req->uc_flags & REQ_READ) && signal_pending(current)) {
754 /* Interrupted before venus read it. */
755 CDEBUG(D_UPCALL,
756 "Interrupted before read:(op,un) (%d.%d), flags = %x\n",
757 req->uc_opcode, req->uc_unique, req->uc_flags);
758 list_del(&(req->uc_chain));
759 /* perhaps the best way to convince the app to
760 give up? */
761 error = -EINTR;
762 goto exit;
764 if ( (req->uc_flags & REQ_READ) && signal_pending(current) ) {
765 /* interrupted after Venus did its read, send signal */
766 union inputArgs *sig_inputArgs;
767 struct upc_req *sig_req;
769 CDEBUG(D_UPCALL,
770 "Sending Venus a signal: op = %d.%d, flags = %x\n",
771 req->uc_opcode, req->uc_unique, req->uc_flags);
773 list_del(&(req->uc_chain));
774 error = -EINTR;
775 CODA_ALLOC(sig_req, struct upc_req *, sizeof (struct upc_req));
776 CODA_ALLOC((sig_req->uc_data), char *, sizeof(struct coda_in_hdr));
778 sig_inputArgs = (union inputArgs *)sig_req->uc_data;
779 sig_inputArgs->ih.opcode = CODA_SIGNAL;
780 sig_inputArgs->ih.unique = req->uc_unique;
782 sig_req->uc_flags = REQ_ASYNC;
783 sig_req->uc_opcode = sig_inputArgs->ih.opcode;
784 sig_req->uc_unique = sig_inputArgs->ih.unique;
785 sig_req->uc_inSize = sizeof(struct coda_in_hdr);
786 sig_req->uc_outSize = sizeof(struct coda_in_hdr);
787 CDEBUG(D_UPCALL,
788 "coda_upcall: enqueing signal msg (%d, %d)\n",
789 sig_req->uc_opcode, sig_req->uc_unique);
791 /* insert at head of queue! */
792 list_add(&(sig_req->uc_chain), &vcommp->vc_pending);
793 wake_up_interruptible(&vcommp->vc_waitq);
794 } else {
795 printk("Coda: Strange interruption..\n");
796 error = -EINTR;
798 } else { /* If venus died i.e. !VC_OPEN(vcommp) */
799 printk("coda_upcall: Venus dead on (op,un) (%d.%d) flags %d\n",
800 req->uc_opcode, req->uc_unique, req->uc_flags);
801 error = -ENODEV;
804 exit:
805 CODA_FREE(req, sizeof(struct upc_req));
806 if (error)
807 badclstats();
808 return error;
812 The statements below are part of the Coda opportunistic
813 programming -- taken from the Mach/BSD kernel code for Coda.
814 You don't get correct semantics by stating what needs to be
815 done without guaranteeing the invariants needed for it to happen.
816 When will be have time to find out what exactly is going on? (pjb)
821 * There are 7 cases where cache invalidations occur. The semantics
822 * of each is listed here:
824 * CODA_FLUSH -- flush all entries from the name cache and the cnode cache.
825 * CODA_PURGEUSER -- flush all entries from the name cache for a specific user
826 * This call is a result of token expiration.
828 * The next arise as the result of callbacks on a file or directory.
829 * CODA_ZAPFILE -- flush the cached attributes for a file.
831 * CODA_ZAPDIR -- flush the attributes for the dir and
832 * force a new lookup for all the children
833 of this dir.
836 * The next is a result of Venus detecting an inconsistent file.
837 * CODA_PURGEFID -- flush the attribute for the file
838 * purge it and its children from the dcache
840 * The last allows Venus to replace local fids with global ones
841 * during reintegration.
843 * CODA_REPLACE -- replace one ViceFid with another throughout the name cache */
845 int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
847 /* Handle invalidation requests. */
848 if ( !sb || !sb->s_root || !sb->s_root->d_inode) {
849 CDEBUG(D_DOWNCALL, "coda_downcall: opcode %d, no sb!\n", opcode);
850 return 0;
853 switch (opcode) {
855 case CODA_FLUSH : {
856 clstats(CODA_FLUSH);
857 CDEBUG(D_DOWNCALL, "CODA_FLUSH\n");
858 coda_cache_clear_all(sb);
859 shrink_dcache_sb(sb);
860 coda_flag_inode(sb->s_root->d_inode, C_FLUSH);
861 return(0);
864 case CODA_PURGEUSER : {
865 struct coda_cred *cred = &out->coda_purgeuser.cred;
866 CDEBUG(D_DOWNCALL, "CODA_PURGEUSER\n");
867 if ( !cred ) {
868 printk("PURGEUSER: null cred!\n");
869 return 0;
871 clstats(CODA_PURGEUSER);
872 coda_cache_clear_cred(sb, cred);
873 return(0);
876 case CODA_ZAPDIR : {
877 struct inode *inode;
878 ViceFid *fid = &out->coda_zapdir.CodaFid;
879 CDEBUG(D_DOWNCALL, "zapdir: fid = %s...\n", coda_f2s(fid));
880 clstats(CODA_ZAPDIR);
882 inode = coda_fid_to_inode(fid, sb);
883 if (inode) {
884 CDEBUG(D_DOWNCALL, "zapdir: inode = %ld children flagged\n",
885 inode->i_ino);
886 coda_flag_inode_children(inode, C_PURGE);
887 CDEBUG(D_DOWNCALL, "zapdir: inode = %ld cache cleared\n", inode->i_ino);
888 coda_flag_inode(inode, C_VATTR);
889 iput(inode);
890 } else
891 CDEBUG(D_DOWNCALL, "zapdir: no inode\n");
893 return(0);
896 case CODA_ZAPFILE : {
897 struct inode *inode;
898 struct ViceFid *fid = &out->coda_zapfile.CodaFid;
899 clstats(CODA_ZAPFILE);
900 CDEBUG(D_DOWNCALL, "zapfile: fid = %s\n", coda_f2s(fid));
901 inode = coda_fid_to_inode(fid, sb);
902 if ( inode ) {
903 CDEBUG(D_DOWNCALL, "zapfile: inode = %ld\n",
904 inode->i_ino);
905 coda_flag_inode(inode, C_VATTR);
906 iput(inode);
907 } else
908 CDEBUG(D_DOWNCALL, "zapfile: no inode\n");
909 return 0;
912 case CODA_PURGEFID : {
913 struct inode *inode;
914 ViceFid *fid = &out->coda_purgefid.CodaFid;
915 CDEBUG(D_DOWNCALL, "purgefid: fid = %s\n", coda_f2s(fid));
916 clstats(CODA_PURGEFID);
917 inode = coda_fid_to_inode(fid, sb);
918 if ( inode ) {
919 CDEBUG(D_DOWNCALL, "purgefid: inode = %ld\n",
920 inode->i_ino);
921 coda_flag_inode_children(inode, C_PURGE);
922 coda_purge_dentries(inode);
923 iput(inode);
924 } else
925 CDEBUG(D_DOWNCALL, "purgefid: no inode\n");
926 return 0;
929 case CODA_REPLACE : {
930 struct inode *inode;
931 ViceFid *oldfid = &out->coda_replace.OldFid;
932 ViceFid *newfid = &out->coda_replace.NewFid;
933 clstats(CODA_REPLACE);
934 CDEBUG(D_DOWNCALL, "CODA_REPLACE\n");
935 inode = coda_fid_to_inode(oldfid, sb);
936 if ( inode ) {
937 CDEBUG(D_DOWNCALL, "replacefid: inode = %ld\n",
938 inode->i_ino);
939 coda_replace_fid(inode, oldfid, newfid);
940 iput(inode);
941 }else
942 CDEBUG(D_DOWNCALL, "purgefid: no inode\n");
944 return 0;
947 return 0;