Import 2.3.10pre5
[davej-history.git] / fs / coda / upcall.c
blob62fd62e352ab50622d1b6f02cb5e6614f409663d
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;
583 int venus_statfs(struct super_block *sb, struct statfs *sfs)
585 union inputArgs *inp;
586 union outputArgs *outp;
587 int insize, outsize, error;
589 insize = max(INSIZE(statfs), OUTSIZE(statfs));
590 UPARG(CODA_STATFS);
592 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
594 if (!error) {
595 sfs->f_blocks = outp->coda_statfs.stat.f_blocks;
596 sfs->f_bfree = outp->coda_statfs.stat.f_bfree;
597 sfs->f_bavail = outp->coda_statfs.stat.f_bavail;
598 sfs->f_files = outp->coda_statfs.stat.f_files;
599 sfs->f_ffree = outp->coda_statfs.stat.f_ffree;
600 } else {
601 printk("coda_statfs: Venus returns: %d\n", error);
604 if (inp) CODA_FREE(inp, insize);
605 CDEBUG(D_INODE, " result %d\n",error);
606 EXIT;
607 return error;
611 * coda_upcall and coda_downcall routines.
615 static inline unsigned long coda_waitfor_upcall(struct upc_req *vmp)
617 DECLARE_WAITQUEUE(wait, current);
618 struct timeval begin = { 0, 0 }, end = { 0, 0 };
620 vmp->uc_posttime = jiffies;
622 if (coda_upcall_timestamping)
623 do_gettimeofday(&begin);
625 add_wait_queue(&vmp->uc_sleep, &wait);
626 for (;;) {
627 if ( coda_hard == 0 )
628 current->state = TASK_INTERRUPTIBLE;
629 else
630 current->state = TASK_UNINTERRUPTIBLE;
632 /* got a reply */
633 if ( vmp->uc_flags & REQ_WRITE )
634 break;
636 if ( !coda_hard && signal_pending(current) ) {
637 /* if this process really wants to die, let it go */
638 if ( sigismember(&(current->signal), SIGKILL) ||
639 sigismember(&(current->signal), SIGINT) )
640 break;
641 /* signal is present: after timeout always return
642 really smart idea, probably useless ... */
643 if ( jiffies - vmp->uc_posttime > coda_timeout * HZ )
644 break;
646 schedule();
649 remove_wait_queue(&vmp->uc_sleep, &wait);
650 current->state = TASK_RUNNING;
652 if (coda_upcall_timestamping && begin.tv_sec != 0) {
653 do_gettimeofday(&end);
655 if (end.tv_usec < begin.tv_usec) {
656 end.tv_usec += 1000000; end.tv_sec--;
658 end.tv_sec -= begin.tv_sec;
659 end.tv_usec -= begin.tv_usec;
662 CDEBUG(D_SPECIAL, "begin: %ld.%06ld, elapsed: %ld.%06ld\n",
663 begin.tv_sec, begin.tv_usec, end.tv_sec, end.tv_usec);
665 return ((end.tv_sec * 1000000) + end.tv_usec);
670 * coda_upcall will return an error in the case of
671 * failed communication with Venus _or_ will peek at Venus
672 * reply and return Venus' error.
674 * As venus has 2 types of errors, normal errors (positive) and internal
675 * errors (negative), normal errors are negated, while internal errors
676 * are all mapped to -EINTR, while showing a nice warning message. (jh)
679 static int coda_upcall(struct coda_sb_info *sbi,
680 int inSize, int *outSize,
681 union inputArgs *buffer)
683 unsigned long runtime;
684 struct venus_comm *vcommp;
685 union outputArgs *out;
686 struct upc_req *req;
687 int error = 0;
689 ENTRY;
691 vcommp = &coda_upc_comm;
692 if ( !vcommp->vc_pid ) {
693 printk("No pseudo device in upcall comms at %p\n", vcommp);
694 return -ENXIO;
697 /* Format the request message. */
698 CODA_ALLOC(req,struct upc_req *,sizeof(struct upc_req));
699 req->uc_data = (void *)buffer;
700 req->uc_flags = 0;
701 req->uc_inSize = inSize;
702 req->uc_outSize = *outSize ? *outSize : inSize;
703 req->uc_opcode = ((union inputArgs *)buffer)->ih.opcode;
704 req->uc_unique = ++vcommp->vc_seq;
705 init_waitqueue_head(&req->uc_sleep);
707 /* Fill in the common input args. */
708 ((union inputArgs *)buffer)->ih.unique = req->uc_unique;
710 /* Append msg to pending queue and poke Venus. */
711 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 %x.zzz.\n",
714 current->pid, req->uc_opcode, req->uc_unique, (int)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 0x%x, data at %x\n",
735 current->pid, (int)req, (int)req->uc_data);
736 if (vcommp->vc_pid) { /* 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)
848 /* Handle invalidation requests. */
849 if ( !sb || !sb->s_root || !sb->s_root->d_inode) {
850 printk("coda_downcall: opcode %d, no sb!\n", opcode);
851 return 0;
854 switch (opcode) {
856 case CODA_FLUSH : {
857 clstats(CODA_FLUSH);
858 CDEBUG(D_DOWNCALL, "CODA_FLUSH\n");
859 coda_cache_clear_all(sb);
860 shrink_dcache_sb(sb);
861 coda_flag_inode(sb->s_root->d_inode, C_FLUSH);
862 return(0);
865 case CODA_PURGEUSER : {
866 struct coda_cred *cred = &out->coda_purgeuser.cred;
867 CDEBUG(D_DOWNCALL, "CODA_PURGEUSER\n");
868 if ( !cred ) {
869 printk("PURGEUSER: null cred!\n");
870 return 0;
872 clstats(CODA_PURGEUSER);
873 coda_cache_clear_cred(sb, cred);
874 return(0);
877 case CODA_ZAPDIR : {
878 struct inode *inode;
879 ViceFid *fid = &out->coda_zapdir.CodaFid;
880 CDEBUG(D_DOWNCALL, "zapdir: fid = %s...\n", coda_f2s(fid));
881 clstats(CODA_ZAPDIR);
883 inode = coda_fid_to_inode(fid, sb);
884 if (inode) {
885 CDEBUG(D_DOWNCALL, "zapdir: inode = %ld children flagged\n",
886 inode->i_ino);
887 coda_flag_inode_children(inode, C_PURGE);
888 CDEBUG(D_DOWNCALL, "zapdir: inode = %ld cache cleared\n", inode->i_ino);
889 coda_flag_inode(inode, C_VATTR);
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", inode->i_ino);
904 coda_flag_inode(inode, C_VATTR);
905 } else
906 CDEBUG(D_DOWNCALL, "zapfile: no inode\n");
907 return 0;
910 case CODA_PURGEFID : {
911 struct inode *inode;
912 ViceFid *fid = &out->coda_purgefid.CodaFid;
913 CDEBUG(D_DOWNCALL, "purgefid: fid = %s\n", coda_f2s(fid));
914 clstats(CODA_PURGEFID);
915 inode = coda_fid_to_inode(fid, sb);
916 if ( inode ) {
917 CDEBUG(D_DOWNCALL, "purgefid: inode = %ld\n", inode->i_ino);
918 coda_flag_inode_children(inode, C_PURGE);
919 coda_purge_dentries(inode);
920 }else
921 CDEBUG(D_DOWNCALL, "purgefid: no inode\n");
922 return 0;
925 case CODA_REPLACE : {
926 struct inode *inode;
927 ViceFid *oldfid = &out->coda_replace.OldFid;
928 ViceFid *newfid = &out->coda_replace.NewFid;
929 clstats(CODA_REPLACE);
930 CDEBUG(D_DOWNCALL, "CODA_REPLACE\n");
931 inode = coda_fid_to_inode(oldfid, sb);
932 if ( inode ) {
933 CDEBUG(D_DOWNCALL, "replacefid: inode = %ld\n", inode->i_ino);
934 coda_replace_fid(inode, oldfid, newfid);
935 }else
936 CDEBUG(D_DOWNCALL, "purgefid: no inode\n");
938 return 0;
941 return 0;