Import 2.3.1pre2
[davej-history.git] / fs / coda / upcall.c
bloba0c1092b28758bcbfd30d1c424234af7f0f244d0
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/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>
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>
42 static int coda_upcall(struct coda_sb_info *mntinfo, int inSize, int *outSize,
43 union inputArgs *buffer);
45 #define UPARG(op)\
46 do {\
47 CODA_ALLOC(inp, union inputArgs *, insize);\
48 if ( !inp ) { return -ENOMEM; }\
49 outp = (union outputArgs *) (inp);\
50 inp->ih.opcode = (op);\
51 inp->ih.pid = current->pid;\
52 inp->ih.pgid = current->pgrp;\
53 coda_load_creds(&(inp->ih.cred));\
54 outsize = insize;\
55 } while (0)
57 static inline int max(int a, int b)
59 if ( a > b )
60 return a;
61 else
62 return b;
65 #define INSIZE(tag) sizeof(struct coda_ ## tag ## _in)
66 #define OUTSIZE(tag) sizeof(struct coda_ ## tag ## _out)
67 #define SIZE(tag) max(INSIZE(tag), OUTSIZE(tag))
70 /* the upcalls */
71 int venus_rootfid(struct super_block *sb, ViceFid *fidp)
73 union inputArgs *inp;
74 union outputArgs *outp;
75 int insize, outsize, error;
76 ENTRY;
78 insize = SIZE(root);
79 UPARG(CODA_ROOT);
81 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
83 if (error) {
84 printk("coda_get_rootfid: error %d\n", error);
85 } else {
86 *fidp = (ViceFid) outp->coda_root.VFid;
87 CDEBUG(D_SUPER, "VolumeId: %lx, VnodeId: %lx.\n",
88 fidp->Volume, fidp->Vnode);
91 if (inp) CODA_FREE(inp, insize);
92 EXIT;
93 return error;
96 int venus_getattr(struct super_block *sb, struct ViceFid *fid,
97 struct coda_vattr *attr)
99 union inputArgs *inp;
100 union outputArgs *outp;
101 int insize, outsize, error;
102 ENTRY;
104 insize = SIZE(getattr);
105 UPARG(CODA_GETATTR);
106 inp->coda_getattr.VFid = *fid;
108 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
110 if ( !error )
111 *attr = outp->coda_getattr.attr;
113 if (inp)
114 CODA_FREE(inp, insize);
115 EXIT;
116 return error;
119 int venus_setattr(struct super_block *sb, struct ViceFid *fid,
120 struct coda_vattr *vattr)
122 union inputArgs *inp;
123 union outputArgs *outp;
124 int insize, outsize, error;
126 insize= SIZE(setattr);
127 UPARG(CODA_SETATTR);
129 inp->coda_setattr.VFid = *fid;
130 inp->coda_setattr.attr = *vattr;
132 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
134 CDEBUG(D_SUPER, " result %d\n", error);
135 if ( inp ) CODA_FREE(inp, insize);
136 return error;
139 int venus_lookup(struct super_block *sb, struct ViceFid *fid,
140 const char *name, int length, int * type,
141 struct ViceFid *resfid)
143 union inputArgs *inp;
144 union outputArgs *outp;
145 int insize, outsize, error;
146 int offset;
148 offset = INSIZE(lookup);
149 insize = max(offset + length +1, OUTSIZE(lookup));
150 UPARG(CODA_LOOKUP);
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';
159 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
161 if ( !error ) {
162 *resfid = outp->coda_lookup.VFid;
163 *type = outp->coda_lookup.vtype;
165 if (inp) CODA_FREE(inp, insize);
167 return error;
171 int venus_release(struct super_block *sb, struct ViceFid *fid, int flags,
172 struct coda_cred *cred)
174 union inputArgs *inp;
175 union outputArgs *outp;
176 int insize, outsize, error;
178 insize = SIZE(close);
179 UPARG(CODA_CLOSE);
181 if ( cred ) {
182 memcpy(&(inp->ih.cred), cred, sizeof(*cred));
183 } else
184 printk("CODA: close without valid file creds.\n");
186 inp->coda_close.VFid = *fid;
187 inp->coda_close.flags = flags;
189 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
191 if (inp)
192 CODA_FREE(inp, insize);
193 return error;
196 int venus_open(struct super_block *sb, struct ViceFid *fid,
197 int flags, ino_t *ino, dev_t *dev)
199 union inputArgs *inp;
200 union outputArgs *outp;
201 int insize, outsize, error;
203 insize = SIZE(open);
204 UPARG(CODA_OPEN);
206 inp->coda_open.VFid = *fid;
207 inp->coda_open.flags = flags;
209 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
211 if ( !error ) {
212 *ino = outp->coda_open.inode;
213 *dev = outp->coda_open.dev;
214 } else {
215 *ino = 0;
216 *dev = 0;
219 if (inp)
220 CODA_FREE(inp, insize);
222 return error;
225 int venus_mkdir(struct super_block *sb, struct ViceFid *dirfid,
226 const char *name, int length,
227 struct ViceFid *newfid, struct coda_vattr *attrs)
229 union inputArgs *inp;
230 union outputArgs *outp;
231 int insize, outsize, error;
232 int offset;
234 offset = INSIZE(mkdir);
235 insize = max(offset + length + 1, OUTSIZE(mkdir));
236 UPARG(CODA_MKDIR);
238 inp->coda_mkdir.VFid = *dirfid;
239 inp->coda_mkdir.attr = *attrs;
240 inp->coda_mkdir.name = offset;
241 /* Venus must get null terminated string */
242 memcpy((char *)(inp) + offset, name, length);
243 *((char *)inp + offset + length) = '\0';
245 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
247 *attrs = outp->coda_mkdir.attr;
248 *newfid = outp->coda_mkdir.VFid;
250 if (inp)
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 if (inp) 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 if (inp)
325 CODA_FREE(inp, insize);
326 return error;
329 int venus_rmdir(struct super_block *sb, struct ViceFid *dirfid,
330 const char *name, int length)
332 union inputArgs *inp;
333 union outputArgs *outp;
334 int insize, outsize, error;
335 int offset;
337 offset = INSIZE(rmdir);
338 insize = max(offset + length + 1, OUTSIZE(rmdir));
339 UPARG(CODA_RMDIR);
341 inp->coda_rmdir.VFid = *dirfid;
342 inp->coda_rmdir.name = offset;
343 memcpy((char *)(inp) + offset, name, length);
344 *((char *)inp + offset + length) = '\0';
346 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
347 if ( inp )
348 CODA_FREE(inp, insize);
349 return error;
352 int venus_remove(struct super_block *sb, struct ViceFid *dirfid,
353 const char *name, int length)
355 union inputArgs *inp;
356 union outputArgs *outp;
357 int error=0, insize, outsize, offset;
359 offset = INSIZE(remove);
360 insize = max(offset + length + 1, OUTSIZE(remove));
361 UPARG(CODA_REMOVE);
363 inp->coda_remove.VFid = *dirfid;
364 inp->coda_remove.name = offset;
365 memcpy((char *)(inp) + offset, name, length);
366 *((char *)inp + offset + length) = '\0';
368 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
369 if ( inp )
370 CODA_FREE(inp, insize);
371 return error;
374 int venus_readlink(struct super_block *sb, struct ViceFid *fid,
375 char *buffer, int *length)
377 union inputArgs *inp;
378 union outputArgs *outp;
379 int insize, outsize, error;
380 int retlen;
381 char *result;
383 insize = max(INSIZE(readlink), OUTSIZE(readlink)+ *length + 1);
384 UPARG(CODA_READLINK);
386 inp->coda_readlink.VFid = *fid;
388 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
390 if (! error) {
391 retlen = outp->coda_readlink.count;
392 if ( retlen > *length )
393 retlen = *length;
394 *length = retlen;
395 result = (char *)outp + (int)outp->coda_readlink.data;
396 memcpy(buffer, result, retlen);
397 *(buffer + retlen) = '\0';
400 if (inp) CODA_FREE(inp, insize);
401 CDEBUG(D_INODE, " result %d\n",error);
402 EXIT;
403 return error;
408 int venus_link(struct super_block *sb, struct ViceFid *fid,
409 struct ViceFid *dirfid, const char *name, int len )
411 union inputArgs *inp;
412 union outputArgs *outp;
413 int insize, outsize, error;
414 int offset;
416 offset = INSIZE(link);
417 insize = max(offset + len + 1, OUTSIZE(link));
418 UPARG(CODA_LINK);
420 inp->coda_link.sourceFid = *fid;
421 inp->coda_link.destFid = *dirfid;
422 inp->coda_link.tname = offset;
424 /* make sure strings are null terminated */
425 memcpy((char *)(inp) + offset, name, len);
426 *((char *)inp + offset + len) = '\0';
428 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
430 if (inp)
431 CODA_FREE(inp, insize);
432 CDEBUG(D_INODE, " result %d\n",error);
433 EXIT;
434 return error;
437 int venus_symlink(struct super_block *sb, struct ViceFid *fid,
438 const char *name, int len,
439 const char *symname, int symlen)
441 union inputArgs *inp;
442 union outputArgs *outp;
443 int insize, outsize, error;
444 int offset, s;
446 offset = INSIZE(symlink);
447 insize = max(offset + len + symlen + 8, OUTSIZE(symlink));
448 UPARG(CODA_SYMLINK);
450 /* inp->coda_symlink.attr = *tva; XXXXXX */
451 inp->coda_symlink.VFid = *fid;
453 /* Round up to word boundary and null terminate */
454 inp->coda_symlink.srcname = offset;
455 s = ( symlen & ~0x3 ) + 4;
456 memcpy((char *)(inp) + offset, symname, symlen);
457 *((char *)inp + offset + symlen) = '\0';
459 /* Round up to word boundary and null terminate */
460 offset += s;
461 inp->coda_symlink.tname = offset;
462 s = (len & ~0x3) + 4;
463 memcpy((char *)(inp) + offset, name, len);
464 *((char *)inp + offset + len) = '\0';
466 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
468 if (inp)
469 CODA_FREE(inp, insize);
470 CDEBUG(D_INODE, " result %d\n",error);
471 EXIT;
472 return error;
475 int venus_fsync(struct super_block *sb, struct ViceFid *fid)
477 union inputArgs *inp;
478 union outputArgs *outp;
479 int insize, outsize, error;
481 insize=SIZE(fsync);
482 UPARG(CODA_FSYNC);
484 inp->coda_fsync.VFid = *fid;
485 error = coda_upcall(coda_sbp(sb), sizeof(union inputArgs),
486 &outsize, inp);
488 if ( inp )
489 CODA_FREE(inp, insize);
490 return error;
493 int venus_access(struct super_block *sb, struct ViceFid *fid, int mask)
495 union inputArgs *inp;
496 union outputArgs *outp;
497 int insize, outsize, error;
499 insize = SIZE(access);
500 UPARG(CODA_ACCESS);
502 inp->coda_access.VFid = *fid;
503 inp->coda_access.flags = mask;
505 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
507 if (inp) CODA_FREE(inp, insize);
508 EXIT;
509 return error;
513 int venus_pioctl(struct super_block *sb, struct ViceFid *fid,
514 unsigned int cmd, struct PioctlData *data)
516 union inputArgs *inp;
517 union outputArgs *outp;
518 int insize, outsize, error;
519 int iocsize;
521 insize = VC_MAXMSGSIZE;
522 UPARG(CODA_IOCTL);
524 /* build packet for Venus */
525 if (data->vi.in_size > VC_MAXDATASIZE) {
526 error = EINVAL;
527 goto exit;
530 inp->coda_ioctl.VFid = *fid;
532 /* the cmd field was mutated by increasing its size field to
533 * reflect the path and follow args. We need to subtract that
534 * out before sending the command to Venus. */
535 inp->coda_ioctl.cmd = (cmd & ~(PIOCPARM_MASK << 16));
536 iocsize = ((cmd >> 16) & PIOCPARM_MASK) - sizeof(char *) - sizeof(int);
537 inp->coda_ioctl.cmd |= (iocsize & PIOCPARM_MASK) << 16;
539 /* in->coda_ioctl.rwflag = flag; */
540 inp->coda_ioctl.len = data->vi.in_size;
541 inp->coda_ioctl.data = (char *)(INSIZE(ioctl));
543 /* get the data out of user space */
544 if ( copy_from_user((char*)inp + (int)inp->coda_ioctl.data,
545 data->vi.in, data->vi.in_size) ) {
546 error = EINVAL;
547 goto exit;
550 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
552 if (error) {
553 printk("coda_pioctl: Venus returns: %d for %s\n",
554 error, coda_f2s(fid));
555 goto exit;
558 /* Copy out the OUT buffer. */
559 if (outp->coda_ioctl.len > data->vi.out_size) {
560 CDEBUG(D_FILE, "return len %d <= request len %d\n",
561 outp->coda_ioctl.len,
562 data->vi.out_size);
563 error = EINVAL;
564 } else {
565 error = verify_area(VERIFY_WRITE, data->vi.out,
566 data->vi.out_size);
567 if ( error ) goto exit;
569 if (copy_to_user(data->vi.out,
570 (char *)outp + (int)outp->coda_ioctl.data,
571 data->vi.out_size)) {
572 error = EINVAL;
573 goto exit;
577 exit:
578 if (inp)
579 CODA_FREE(inp, insize);
580 return error;
584 * coda_upcall and coda_downcall routines.
588 static inline unsigned long coda_waitfor_upcall(struct upc_req *vmp)
590 DECLARE_WAITQUEUE(wait, current);
591 unsigned long posttime;
593 vmp->uc_posttime = jiffies;
594 posttime = jiffies;
596 add_wait_queue(&vmp->uc_sleep, &wait);
597 for (;;) {
598 if ( coda_hard == 0 )
599 current->state = TASK_INTERRUPTIBLE;
600 else
601 current->state = TASK_UNINTERRUPTIBLE;
603 /* got a reply */
604 if ( vmp->uc_flags & REQ_WRITE )
605 break;
607 if ( !coda_hard && signal_pending(current) ) {
608 /* if this process really wants to die, let it go */
609 if ( sigismember(&(current->signal), SIGKILL) ||
610 sigismember(&(current->signal), SIGINT) )
611 break;
612 /* signal is present: after timeout always return
613 really smart idea, probably useless ... */
614 if ( jiffies - vmp->uc_posttime > coda_timeout * HZ )
615 break;
617 schedule();
620 remove_wait_queue(&vmp->uc_sleep, &wait);
621 current->state = TASK_RUNNING;
623 CDEBUG(D_SPECIAL, "posttime: %ld, returned: %ld\n", posttime, jiffies-posttime);
624 return (jiffies - posttime);
630 * coda_upcall will return an error in the case of
631 * failed communication with Venus _or_ will peek at Venus
632 * reply and return Venus' error.
634 * As venus has 2 types of errors, normal errors (positive) and internal
635 * errors (negative), normal errors are negated, while internal errors
636 * are all mapped to -EINTR, while showing a nice warning message. (jh)
639 static int coda_upcall(struct coda_sb_info *sbi,
640 int inSize, int *outSize,
641 union inputArgs *buffer)
643 unsigned long runtime;
644 struct venus_comm *vcommp;
645 union outputArgs *out;
646 struct upc_req *req;
647 int error = 0;
649 ENTRY;
651 vcommp = &coda_upc_comm;
652 if ( !vcommp->vc_pid ) {
653 printk("No pseudo device in upcall comms at %p\n", vcommp);
654 return -ENXIO;
657 /* Format the request message. */
658 CODA_ALLOC(req,struct upc_req *,sizeof(struct upc_req));
659 req->uc_data = (void *)buffer;
660 req->uc_flags = 0;
661 req->uc_inSize = inSize;
662 req->uc_outSize = *outSize ? *outSize : inSize;
663 req->uc_opcode = ((union inputArgs *)buffer)->ih.opcode;
664 req->uc_unique = ++vcommp->vc_seq;
665 init_waitqueue_head(&req->uc_sleep);
667 /* Fill in the common input args. */
668 ((union inputArgs *)buffer)->ih.unique = req->uc_unique;
670 /* Append msg to pending queue and poke Venus. */
671 list_add(&(req->uc_chain), vcommp->vc_pending.prev);
672 CDEBUG(D_UPCALL,
673 "Proc %d wake Venus for(opc,uniq) =(%d,%d) msg at %x.zzz.\n",
674 current->pid, req->uc_opcode, req->uc_unique, (int)req);
676 wake_up_interruptible(&vcommp->vc_waitq);
677 /* We can be interrupted while we wait for Venus to process
678 * our request. If the interrupt occurs before Venus has read
679 * the request, we dequeue and return. If it occurs after the
680 * read but before the reply, we dequeue, send a signal
681 * message, and return. If it occurs after the reply we ignore
682 * it. In no case do we want to restart the syscall. If it
683 * was interrupted by a venus shutdown (psdev_close), return
684 * ENODEV. */
686 /* Go to sleep. Wake up on signals only after the timeout. */
687 runtime = coda_waitfor_upcall(req);
688 coda_upcall_stats(((union inputArgs *)buffer)->ih.opcode, runtime);
690 CDEBUG(D_TIMING, "opc: %d time: %ld uniq: %d size: %d\n",
691 req->uc_opcode, jiffies - req->uc_posttime,
692 req->uc_unique, req->uc_outSize);
693 CDEBUG(D_UPCALL,
694 "..process %d woken up by Venus for req at 0x%x, data at %x\n",
695 current->pid, (int)req, (int)req->uc_data);
696 if (vcommp->vc_pid) { /* i.e. Venus is still alive */
697 /* Op went through, interrupt or not... */
698 if (req->uc_flags & REQ_WRITE) {
699 out = (union outputArgs *)req->uc_data;
700 /* here we map positive Venus errors to kernel errors */
701 if ( out->oh.result < 0 ) {
702 printk("Tell Peter: Venus returns negative error %ld, for oc %ld!\n",
703 out->oh.result, out->oh.opcode);
704 out->oh.result = EINTR;
706 error = -out->oh.result;
707 CDEBUG(D_UPCALL,
708 "upcall: (u,o,r) (%ld, %ld, %ld) out at %p\n",
709 out->oh.unique, out->oh.opcode, out->oh.result, out);
710 *outSize = req->uc_outSize;
711 goto exit;
713 if ( !(req->uc_flags & REQ_READ) && signal_pending(current)) {
714 /* Interrupted before venus read it. */
715 CDEBUG(D_UPCALL,
716 "Interrupted before read:(op,un) (%d.%d), flags = %x\n",
717 req->uc_opcode, req->uc_unique, req->uc_flags);
718 list_del(&(req->uc_chain));
719 /* perhaps the best way to convince the app to
720 give up? */
721 error = -EINTR;
722 goto exit;
724 if ( (req->uc_flags & REQ_READ) && signal_pending(current) ) {
725 /* interrupted after Venus did its read, send signal */
726 union inputArgs *sig_inputArgs;
727 struct upc_req *sig_req;
729 CDEBUG(D_UPCALL,
730 "Sending Venus a signal: op = %d.%d, flags = %x\n",
731 req->uc_opcode, req->uc_unique, req->uc_flags);
733 list_del(&(req->uc_chain));
734 error = -EINTR;
735 CODA_ALLOC(sig_req, struct upc_req *, sizeof (struct upc_req));
736 CODA_ALLOC((sig_req->uc_data), char *, sizeof(struct coda_in_hdr));
738 sig_inputArgs = (union inputArgs *)sig_req->uc_data;
739 sig_inputArgs->ih.opcode = CODA_SIGNAL;
740 sig_inputArgs->ih.unique = req->uc_unique;
742 sig_req->uc_flags = REQ_ASYNC;
743 sig_req->uc_opcode = sig_inputArgs->ih.opcode;
744 sig_req->uc_unique = sig_inputArgs->ih.unique;
745 sig_req->uc_inSize = sizeof(struct coda_in_hdr);
746 sig_req->uc_outSize = sizeof(struct coda_in_hdr);
747 CDEBUG(D_UPCALL,
748 "coda_upcall: enqueing signal msg (%d, %d)\n",
749 sig_req->uc_opcode, sig_req->uc_unique);
751 /* insert at head of queue! */
752 list_add(&(sig_req->uc_chain), &vcommp->vc_pending);
753 wake_up_interruptible(&vcommp->vc_waitq);
754 } else {
755 printk("Coda: Strange interruption..\n");
756 error = -EINTR;
758 } else { /* If venus died i.e. !VC_OPEN(vcommp) */
759 printk("coda_upcall: Venus dead on (op,un) (%d.%d) flags %d\n",
760 req->uc_opcode, req->uc_unique, req->uc_flags);
761 error = -ENODEV;
764 exit:
765 CODA_FREE(req, sizeof(struct upc_req));
766 if (error)
767 badclstats();
768 return error;
772 The statements below are part of the Coda opportunistic
773 programming -- taken from the Mach/BSD kernel code for Coda.
774 You don't get correct semantics by stating what needs to be
775 done without guaranteeing the invariants needed for it to happen.
776 When will be have time to find out what exactly is going on? (pjb)
781 * There are 7 cases where cache invalidations occur. The semantics
782 * of each is listed here:
784 * CODA_FLUSH -- flush all entries from the name cache and the cnode cache.
785 * CODA_PURGEUSER -- flush all entries from the name cache for a specific user
786 * This call is a result of token expiration.
788 * The next arise as the result of callbacks on a file or directory.
789 * CODA_ZAPFILE -- flush the cached attributes for a file.
791 * CODA_ZAPDIR -- flush the attributes for the dir and
792 * force a new lookup for all the children
793 of this dir.
796 * The next is a result of Venus detecting an inconsistent file.
797 * CODA_PURGEFID -- flush the attribute for the file
798 * purge it and its children from the dcache
800 * The last allows Venus to replace local fids with global ones
801 * during reintegration.
803 * CODA_REPLACE -- replace one ViceFid with another throughout the name cache */
805 int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
808 /* Handle invalidation requests. */
809 if ( !sb || !sb->s_root || !sb->s_root->d_inode) {
810 printk("coda_downcall: opcode %d, no sb!\n", opcode);
811 return 0;
814 switch (opcode) {
816 case CODA_FLUSH : {
817 clstats(CODA_FLUSH);
818 CDEBUG(D_DOWNCALL, "CODA_FLUSH\n");
819 coda_cache_clear_all(sb);
820 shrink_dcache_sb(sb);
821 coda_flag_inode(sb->s_root->d_inode, C_FLUSH);
822 return(0);
825 case CODA_PURGEUSER : {
826 struct coda_cred *cred = &out->coda_purgeuser.cred;
827 CDEBUG(D_DOWNCALL, "CODA_PURGEUSER\n");
828 if ( !cred ) {
829 printk("PURGEUSER: null cred!\n");
830 return 0;
832 clstats(CODA_PURGEUSER);
833 coda_cache_clear_cred(sb, cred);
834 return(0);
837 case CODA_ZAPDIR : {
838 struct inode *inode;
839 ViceFid *fid = &out->coda_zapdir.CodaFid;
840 CDEBUG(D_DOWNCALL, "zapdir: fid = %s...\n", coda_f2s(fid));
841 clstats(CODA_ZAPDIR);
843 inode = coda_fid_to_inode(fid, sb);
844 if (inode) {
845 CDEBUG(D_DOWNCALL, "zapdir: inode = %ld children flagged\n",
846 inode->i_ino);
847 coda_flag_inode_children(inode, C_PURGE);
848 CDEBUG(D_DOWNCALL, "zapdir: inode = %ld cache cleared\n", inode->i_ino);
849 coda_flag_inode(inode, C_VATTR);
850 } else
851 CDEBUG(D_DOWNCALL, "zapdir: no inode\n");
853 return(0);
856 case CODA_ZAPFILE : {
857 struct inode *inode;
858 struct ViceFid *fid = &out->coda_zapfile.CodaFid;
859 clstats(CODA_ZAPFILE);
860 CDEBUG(D_DOWNCALL, "zapfile: fid = %s\n", coda_f2s(fid));
861 inode = coda_fid_to_inode(fid, sb);
862 if ( inode ) {
863 CDEBUG(D_DOWNCALL, "zapfile: inode = %ld\n", inode->i_ino);
864 coda_flag_inode(inode, C_VATTR);
865 } else
866 CDEBUG(D_DOWNCALL, "zapfile: no inode\n");
867 return 0;
870 case CODA_PURGEFID : {
871 struct inode *inode;
872 ViceFid *fid = &out->coda_purgefid.CodaFid;
873 CDEBUG(D_DOWNCALL, "purgefid: fid = %s\n", coda_f2s(fid));
874 clstats(CODA_PURGEFID);
875 inode = coda_fid_to_inode(fid, sb);
876 if ( inode ) {
877 CDEBUG(D_DOWNCALL, "purgefid: inode = %ld\n", inode->i_ino);
878 coda_flag_inode_children(inode, C_PURGE);
879 coda_purge_dentries(inode);
880 }else
881 CDEBUG(D_DOWNCALL, "purgefid: no inode\n");
882 return 0;
885 case CODA_REPLACE : {
886 struct inode *inode;
887 ViceFid *oldfid = &out->coda_replace.OldFid;
888 ViceFid *newfid = &out->coda_replace.NewFid;
889 clstats(CODA_REPLACE);
890 CDEBUG(D_DOWNCALL, "CODA_REPLACE\n");
891 inode = coda_fid_to_inode(oldfid, sb);
892 if ( inode ) {
893 CDEBUG(D_DOWNCALL, "replacefid: inode = %ld\n", inode->i_ino);
894 coda_replace_fid(inode, oldfid, newfid);
895 }else
896 CDEBUG(D_DOWNCALL, "purgefid: no inode\n");
898 return 0;
901 return 0;