2 * Mostly platform independent upcall operations to Venus:
7 * Copyright (C) 1996 Peter J. Braam <braam@maths.ox.ac.uk>,
8 * Michael Callahan <callahan@maths.ox.ac.uk>
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/signal.h>
19 #include <linux/signal.h>
21 #include <linux/types.h>
22 #include <linux/kernel.h>
24 #include <linux/sched.h>
26 #include <linux/file.h>
27 #include <linux/stat.h>
28 #include <linux/errno.h>
29 #include <linux/locks.h>
30 #include <linux/string.h>
31 #include <asm/uaccess.h>
32 #include <linux/vmalloc.h>
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>
41 #define upc_alloc() kmalloc(sizeof(struct upc_req), GFP_KERNEL)
42 #define upc_free(r) kfree(r)
44 static int coda_upcall(struct coda_sb_info *mntinfo, int inSize, int *outSize,
45 union inputArgs *buffer);
47 static void *alloc_upcall(int opcode, int size)
51 CODA_ALLOC(inp, union inputArgs *, size);
53 return ERR_PTR(-ENOMEM);
55 inp->ih.opcode = opcode;
56 inp->ih.pid = current->pid;
57 inp->ih.pgid = current->pgrp;
58 coda_load_creds(&(inp->ih.cred));
65 inp = (union inputArgs *)alloc_upcall(op, insize); \
66 if (IS_ERR(inp)) { return PTR_ERR(inp); }\
67 outp = (union outputArgs *)(inp); \
71 #define INSIZE(tag) sizeof(struct coda_ ## tag ## _in)
72 #define OUTSIZE(tag) sizeof(struct coda_ ## tag ## _out)
73 #define SIZE(tag) max_t(unsigned int, INSIZE(tag), OUTSIZE(tag))
77 int venus_rootfid(struct super_block *sb, ViceFid *fidp)
80 union outputArgs *outp;
81 int insize, outsize, error;
86 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
89 printk("coda_get_rootfid: error %d\n", error);
91 *fidp = (ViceFid) outp->coda_root.VFid;
92 CDEBUG(D_SUPER, "VolumeId: %lx, VnodeId: %lx.\n",
93 fidp->Volume, fidp->Vnode);
96 CODA_FREE(inp, insize);
100 int venus_getattr(struct super_block *sb, struct ViceFid *fid,
101 struct coda_vattr *attr)
103 union inputArgs *inp;
104 union outputArgs *outp;
105 int insize, outsize, error;
107 insize = SIZE(getattr);
109 inp->coda_getattr.VFid = *fid;
111 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
113 *attr = outp->coda_getattr.attr;
115 CODA_FREE(inp, insize);
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);
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 CODA_FREE(inp, insize);
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;
148 offset = INSIZE(lookup);
149 insize = max_t(unsigned int, offset + length +1, OUTSIZE(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 *resfid = outp->coda_lookup.VFid;
162 *type = outp->coda_lookup.vtype;
164 CODA_FREE(inp, insize);
168 int venus_store(struct super_block *sb, struct ViceFid *fid, int flags,
169 struct coda_cred *cred)
171 union inputArgs *inp;
172 union outputArgs *outp;
173 int insize, outsize, error;
175 insize = SIZE(store);
178 memcpy(&(inp->ih.cred), cred, sizeof(*cred));
180 inp->coda_store.VFid = *fid;
181 inp->coda_store.flags = flags;
183 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
185 CODA_FREE(inp, insize);
189 int venus_release(struct super_block *sb, struct ViceFid *fid, int flags)
191 union inputArgs *inp;
192 union outputArgs *outp;
193 int insize, outsize, error;
195 insize = SIZE(release);
198 inp->coda_release.VFid = *fid;
199 inp->coda_release.flags = flags;
201 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
203 CODA_FREE(inp, insize);
207 int venus_close(struct super_block *sb, struct ViceFid *fid, int flags,
208 struct coda_cred *cred)
210 union inputArgs *inp;
211 union outputArgs *outp;
212 int insize, outsize, error;
214 insize = SIZE(release);
217 memcpy(&(inp->ih.cred), cred, sizeof(*cred));
219 inp->coda_close.VFid = *fid;
220 inp->coda_close.flags = flags;
222 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
224 CODA_FREE(inp, insize);
228 int venus_open(struct super_block *sb, struct ViceFid *fid,
229 int flags, struct file **fh)
231 union inputArgs *inp;
232 union outputArgs *outp;
233 int insize, outsize, error;
235 insize = SIZE(open_by_fd);
236 UPARG(CODA_OPEN_BY_FD);
238 inp->coda_open.VFid = *fid;
239 inp->coda_open.flags = flags;
241 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
243 *fh = outp->coda_open_by_fd.fh;
245 CODA_FREE(inp, insize);
249 int venus_mkdir(struct super_block *sb, struct ViceFid *dirfid,
250 const char *name, int length,
251 struct ViceFid *newfid, struct coda_vattr *attrs)
253 union inputArgs *inp;
254 union outputArgs *outp;
255 int insize, outsize, error;
258 offset = INSIZE(mkdir);
259 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(mkdir));
262 inp->coda_mkdir.VFid = *dirfid;
263 inp->coda_mkdir.attr = *attrs;
264 inp->coda_mkdir.name = offset;
265 /* Venus must get null terminated string */
266 memcpy((char *)(inp) + offset, name, length);
267 *((char *)inp + offset + length) = '\0';
269 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
271 *attrs = outp->coda_mkdir.attr;
272 *newfid = outp->coda_mkdir.VFid;
274 CODA_FREE(inp, insize);
279 int venus_rename(struct super_block *sb, struct ViceFid *old_fid,
280 struct ViceFid *new_fid, size_t old_length,
281 size_t new_length, const char *old_name,
282 const char *new_name)
284 union inputArgs *inp;
285 union outputArgs *outp;
286 int insize, outsize, error;
289 offset = INSIZE(rename);
290 insize = max_t(unsigned int, offset + new_length + old_length + 8,
294 inp->coda_rename.sourceFid = *old_fid;
295 inp->coda_rename.destFid = *new_fid;
296 inp->coda_rename.srcname = offset;
298 /* Venus must receive an null terminated string */
299 s = ( old_length & ~0x3) +4; /* round up to word boundary */
300 memcpy((char *)(inp) + offset, old_name, old_length);
301 *((char *)inp + offset + old_length) = '\0';
303 /* another null terminated string for Venus */
305 inp->coda_rename.destname = offset;
306 s = ( new_length & ~0x3) +4; /* round up to word boundary */
307 memcpy((char *)(inp) + offset, new_name, new_length);
308 *((char *)inp + offset + new_length) = '\0';
310 CDEBUG(D_INODE, "destname in packet: %s\n",
311 (char *)inp + (int) inp->coda_rename.destname);
312 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
314 CODA_FREE(inp, insize);
318 int venus_create(struct super_block *sb, struct ViceFid *dirfid,
319 const char *name, int length, int excl, int mode, int rdev,
320 struct ViceFid *newfid, struct coda_vattr *attrs)
322 union inputArgs *inp;
323 union outputArgs *outp;
324 int insize, outsize, error;
327 offset = INSIZE(create);
328 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(create));
331 inp->coda_create.VFid = *dirfid;
332 inp->coda_create.attr.va_mode = mode;
333 inp->coda_create.attr.va_rdev = rdev;
334 inp->coda_create.excl = excl;
335 inp->coda_create.mode = mode;
336 inp->coda_create.name = offset;
338 /* Venus must get null terminated string */
339 memcpy((char *)(inp) + offset, name, length);
340 *((char *)inp + offset + length) = '\0';
342 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
344 *attrs = outp->coda_create.attr;
345 *newfid = outp->coda_create.VFid;
347 CODA_FREE(inp, insize);
351 int venus_rmdir(struct super_block *sb, struct ViceFid *dirfid,
352 const char *name, int length)
354 union inputArgs *inp;
355 union outputArgs *outp;
356 int insize, outsize, error;
359 offset = INSIZE(rmdir);
360 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(rmdir));
363 inp->coda_rmdir.VFid = *dirfid;
364 inp->coda_rmdir.name = offset;
365 memcpy((char *)(inp) + offset, name, length);
366 *((char *)inp + offset + length) = '\0';
368 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
370 CODA_FREE(inp, insize);
374 int venus_remove(struct super_block *sb, struct ViceFid *dirfid,
375 const char *name, int length)
377 union inputArgs *inp;
378 union outputArgs *outp;
379 int error=0, insize, outsize, offset;
381 offset = INSIZE(remove);
382 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(remove));
385 inp->coda_remove.VFid = *dirfid;
386 inp->coda_remove.name = offset;
387 memcpy((char *)(inp) + offset, name, length);
388 *((char *)inp + offset + length) = '\0';
390 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
392 CODA_FREE(inp, insize);
396 int venus_readlink(struct super_block *sb, struct ViceFid *fid,
397 char *buffer, int *length)
399 union inputArgs *inp;
400 union outputArgs *outp;
401 int insize, outsize, error;
405 insize = max_t(unsigned int,
406 INSIZE(readlink), OUTSIZE(readlink)+ *length + 1);
407 UPARG(CODA_READLINK);
409 inp->coda_readlink.VFid = *fid;
411 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
414 retlen = outp->coda_readlink.count;
415 if ( retlen > *length )
418 result = (char *)outp + (long)outp->coda_readlink.data;
419 memcpy(buffer, result, retlen);
420 *(buffer + retlen) = '\0';
423 CDEBUG(D_INODE, " result %d\n",error);
424 CODA_FREE(inp, insize);
430 int venus_link(struct super_block *sb, struct ViceFid *fid,
431 struct ViceFid *dirfid, const char *name, int len )
433 union inputArgs *inp;
434 union outputArgs *outp;
435 int insize, outsize, error;
438 offset = INSIZE(link);
439 insize = max_t(unsigned int, offset + len + 1, OUTSIZE(link));
442 inp->coda_link.sourceFid = *fid;
443 inp->coda_link.destFid = *dirfid;
444 inp->coda_link.tname = offset;
446 /* make sure strings are null terminated */
447 memcpy((char *)(inp) + offset, name, len);
448 *((char *)inp + offset + len) = '\0';
450 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
452 CDEBUG(D_INODE, " result %d\n",error);
453 CODA_FREE(inp, insize);
457 int venus_symlink(struct super_block *sb, struct ViceFid *fid,
458 const char *name, int len,
459 const char *symname, int symlen)
461 union inputArgs *inp;
462 union outputArgs *outp;
463 int insize, outsize, error;
466 offset = INSIZE(symlink);
467 insize = max_t(unsigned int, offset + len + symlen + 8, OUTSIZE(symlink));
470 /* inp->coda_symlink.attr = *tva; XXXXXX */
471 inp->coda_symlink.VFid = *fid;
473 /* Round up to word boundary and null terminate */
474 inp->coda_symlink.srcname = offset;
475 s = ( symlen & ~0x3 ) + 4;
476 memcpy((char *)(inp) + offset, symname, symlen);
477 *((char *)inp + offset + symlen) = '\0';
479 /* Round up to word boundary and null terminate */
481 inp->coda_symlink.tname = offset;
482 s = (len & ~0x3) + 4;
483 memcpy((char *)(inp) + offset, name, len);
484 *((char *)inp + offset + len) = '\0';
486 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
488 CDEBUG(D_INODE, " result %d\n",error);
489 CODA_FREE(inp, insize);
493 int venus_fsync(struct super_block *sb, struct ViceFid *fid)
495 union inputArgs *inp;
496 union outputArgs *outp;
497 int insize, outsize, error;
502 inp->coda_fsync.VFid = *fid;
503 error = coda_upcall(coda_sbp(sb), sizeof(union inputArgs),
506 CODA_FREE(inp, insize);
510 int venus_access(struct super_block *sb, struct ViceFid *fid, int mask)
512 union inputArgs *inp;
513 union outputArgs *outp;
514 int insize, outsize, error;
516 insize = SIZE(access);
519 inp->coda_access.VFid = *fid;
520 inp->coda_access.flags = mask;
522 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
524 CODA_FREE(inp, insize);
529 int venus_pioctl(struct super_block *sb, struct ViceFid *fid,
530 unsigned int cmd, struct PioctlData *data)
532 union inputArgs *inp;
533 union outputArgs *outp;
534 int insize, outsize, error;
537 insize = VC_MAXMSGSIZE;
540 /* build packet for Venus */
541 if (data->vi.in_size > VC_MAXDATASIZE) {
546 if (data->vi.out_size > VC_MAXDATASIZE) {
551 inp->coda_ioctl.VFid = *fid;
553 /* the cmd field was mutated by increasing its size field to
554 * reflect the path and follow args. We need to subtract that
555 * out before sending the command to Venus. */
556 inp->coda_ioctl.cmd = (cmd & ~(PIOCPARM_MASK << 16));
557 iocsize = ((cmd >> 16) & PIOCPARM_MASK) - sizeof(char *) - sizeof(int);
558 inp->coda_ioctl.cmd |= (iocsize & PIOCPARM_MASK) << 16;
560 /* in->coda_ioctl.rwflag = flag; */
561 inp->coda_ioctl.len = data->vi.in_size;
562 inp->coda_ioctl.data = (char *)(INSIZE(ioctl));
564 /* get the data out of user space */
565 if ( copy_from_user((char*)inp + (long)inp->coda_ioctl.data,
566 data->vi.in, data->vi.in_size) ) {
571 error = coda_upcall(coda_sbp(sb), SIZE(ioctl) + data->vi.in_size,
575 printk("coda_pioctl: Venus returns: %d for %s\n",
576 error, coda_f2s(fid));
580 if (outsize < (long)outp->coda_ioctl.data + outp->coda_ioctl.len) {
581 CDEBUG(D_FILE, "reply size %d < reply len %ld\n", outsize,
582 (long)outp->coda_ioctl.data + outp->coda_ioctl.len);
587 if (outp->coda_ioctl.len > data->vi.out_size) {
588 CDEBUG(D_FILE, "return len %d > request len %d\n",
589 outp->coda_ioctl.len, data->vi.out_size);
594 /* Copy out the OUT buffer. */
595 error = verify_area(VERIFY_WRITE, data->vi.out, outp->coda_ioctl.len);
596 if ( error ) goto exit;
598 if (copy_to_user(data->vi.out,
599 (char *)outp + (long)outp->coda_ioctl.data,
600 outp->coda_ioctl.len)) {
604 CODA_FREE(inp, insize);
608 int venus_statfs(struct super_block *sb, struct statfs *sfs)
610 union inputArgs *inp;
611 union outputArgs *outp;
612 int insize, outsize, error;
614 insize = max_t(unsigned int, INSIZE(statfs), OUTSIZE(statfs));
617 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
620 sfs->f_blocks = outp->coda_statfs.stat.f_blocks;
621 sfs->f_bfree = outp->coda_statfs.stat.f_bfree;
622 sfs->f_bavail = outp->coda_statfs.stat.f_bavail;
623 sfs->f_files = outp->coda_statfs.stat.f_files;
624 sfs->f_ffree = outp->coda_statfs.stat.f_ffree;
626 printk("coda_statfs: Venus returns: %d\n", error);
629 CDEBUG(D_INODE, " result %d\n",error);
630 CODA_FREE(inp, insize);
635 * coda_upcall and coda_downcall routines.
639 static inline unsigned long coda_waitfor_upcall(struct upc_req *vmp,
640 struct venus_comm *vcommp)
642 DECLARE_WAITQUEUE(wait, current);
643 struct timeval begin = { 0, 0 }, end = { 0, 0 };
645 vmp->uc_posttime = jiffies;
647 if (coda_upcall_timestamping)
648 do_gettimeofday(&begin);
650 add_wait_queue(&vmp->uc_sleep, &wait);
652 if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE )
653 set_current_state(TASK_INTERRUPTIBLE);
655 set_current_state(TASK_UNINTERRUPTIBLE);
658 if ( !vcommp->vc_inuse )
662 if ( vmp->uc_flags & ( REQ_WRITE | REQ_ABORT ) )
665 if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE && signal_pending(current) ) {
666 /* if this process really wants to die, let it go */
667 if ( sigismember(&(current->pending.signal), SIGKILL) ||
668 sigismember(&(current->pending.signal), SIGINT) )
670 /* signal is present: after timeout always return
671 really smart idea, probably useless ... */
672 if ( jiffies - vmp->uc_posttime > coda_timeout * HZ )
677 remove_wait_queue(&vmp->uc_sleep, &wait);
678 set_current_state(TASK_RUNNING);
680 if (coda_upcall_timestamping && begin.tv_sec != 0) {
681 do_gettimeofday(&end);
683 if (end.tv_usec < begin.tv_usec) {
684 end.tv_usec += 1000000; end.tv_sec--;
686 end.tv_sec -= begin.tv_sec;
687 end.tv_usec -= begin.tv_usec;
690 CDEBUG(D_SPECIAL, "begin: %ld.%06ld, elapsed: %ld.%06ld\n",
691 begin.tv_sec, (unsigned long)begin.tv_usec,
692 end.tv_sec, (unsigned long)end.tv_usec);
694 return ((end.tv_sec * 1000000) + end.tv_usec);
699 * coda_upcall will return an error in the case of
700 * failed communication with Venus _or_ will peek at Venus
701 * reply and return Venus' error.
703 * As venus has 2 types of errors, normal errors (positive) and internal
704 * errors (negative), normal errors are negated, while internal errors
705 * are all mapped to -EINTR, while showing a nice warning message. (jh)
708 static int coda_upcall(struct coda_sb_info *sbi,
709 int inSize, int *outSize,
710 union inputArgs *buffer)
712 unsigned long runtime;
713 struct venus_comm *vcommp;
714 union outputArgs *out;
718 vcommp = sbi->sbi_vcomm;
719 if ( !vcommp->vc_inuse ) {
720 printk("No pseudo device in upcall comms at %p\n", vcommp);
724 /* Format the request message. */
727 printk("Failed to allocate upc_req structure\n");
730 req->uc_data = (void *)buffer;
732 req->uc_inSize = inSize;
733 req->uc_outSize = *outSize ? *outSize : inSize;
734 req->uc_opcode = ((union inputArgs *)buffer)->ih.opcode;
735 req->uc_unique = ++vcommp->vc_seq;
736 init_waitqueue_head(&req->uc_sleep);
738 /* Fill in the common input args. */
739 ((union inputArgs *)buffer)->ih.unique = req->uc_unique;
741 /* Append msg to pending queue and poke Venus. */
742 list_add(&(req->uc_chain), vcommp->vc_pending.prev);
745 "Proc %d wake Venus for(opc,uniq) =(%d,%d) msg at %p.zzz.\n",
746 current->pid, req->uc_opcode, req->uc_unique, req);
748 wake_up_interruptible(&vcommp->vc_waitq);
749 /* We can be interrupted while we wait for Venus to process
750 * our request. If the interrupt occurs before Venus has read
751 * the request, we dequeue and return. If it occurs after the
752 * read but before the reply, we dequeue, send a signal
753 * message, and return. If it occurs after the reply we ignore
754 * it. In no case do we want to restart the syscall. If it
755 * was interrupted by a venus shutdown (psdev_close), return
758 /* Go to sleep. Wake up on signals only after the timeout. */
759 runtime = coda_waitfor_upcall(req, vcommp);
760 coda_upcall_stats(((union inputArgs *)buffer)->ih.opcode, runtime);
762 CDEBUG(D_TIMING, "opc: %d time: %ld uniq: %d size: %d\n",
763 req->uc_opcode, jiffies - req->uc_posttime,
764 req->uc_unique, req->uc_outSize);
766 "..process %d woken up by Venus for req at %p, data at %p\n",
767 current->pid, req, req->uc_data);
768 if (vcommp->vc_inuse) { /* i.e. Venus is still alive */
769 /* Op went through, interrupt or not... */
770 if (req->uc_flags & REQ_WRITE) {
771 out = (union outputArgs *)req->uc_data;
772 /* here we map positive Venus errors to kernel errors */
773 error = -out->oh.result;
775 "upcall: (u,o,r) (%ld, %ld, %ld) out at %p\n",
776 out->oh.unique, out->oh.opcode, out->oh.result, out);
777 *outSize = req->uc_outSize;
780 if ( !(req->uc_flags & REQ_READ) && signal_pending(current)) {
781 /* Interrupted before venus read it. */
783 "Interrupted before read:(op,un) (%d.%d), flags = %x\n",
784 req->uc_opcode, req->uc_unique, req->uc_flags);
785 list_del(&(req->uc_chain));
786 /* perhaps the best way to convince the app to
791 if ( (req->uc_flags & REQ_READ) && signal_pending(current) ) {
792 /* interrupted after Venus did its read, send signal */
793 union inputArgs *sig_inputArgs;
794 struct upc_req *sig_req;
797 "Sending Venus a signal: op = %d.%d, flags = %x\n",
798 req->uc_opcode, req->uc_unique, req->uc_flags);
800 list_del(&(req->uc_chain));
802 sig_req = upc_alloc();
803 if (!sig_req) goto exit;
805 CODA_ALLOC((sig_req->uc_data), char *, sizeof(struct coda_in_hdr));
806 if (!sig_req->uc_data) {
812 sig_inputArgs = (union inputArgs *)sig_req->uc_data;
813 sig_inputArgs->ih.opcode = CODA_SIGNAL;
814 sig_inputArgs->ih.unique = req->uc_unique;
816 sig_req->uc_flags = REQ_ASYNC;
817 sig_req->uc_opcode = sig_inputArgs->ih.opcode;
818 sig_req->uc_unique = sig_inputArgs->ih.unique;
819 sig_req->uc_inSize = sizeof(struct coda_in_hdr);
820 sig_req->uc_outSize = sizeof(struct coda_in_hdr);
822 "coda_upcall: enqueing signal msg (%d, %d)\n",
823 sig_req->uc_opcode, sig_req->uc_unique);
825 /* insert at head of queue! */
826 list_add(&(sig_req->uc_chain), &vcommp->vc_pending);
827 wake_up_interruptible(&vcommp->vc_waitq);
829 printk("Coda: Strange interruption..\n");
832 } else { /* If venus died i.e. !VC_OPEN(vcommp) */
833 printk("coda_upcall: Venus dead on (op,un) (%d.%d) flags %d\n",
834 req->uc_opcode, req->uc_unique, req->uc_flags);
846 The statements below are part of the Coda opportunistic
847 programming -- taken from the Mach/BSD kernel code for Coda.
848 You don't get correct semantics by stating what needs to be
849 done without guaranteeing the invariants needed for it to happen.
850 When will be have time to find out what exactly is going on? (pjb)
855 * There are 7 cases where cache invalidations occur. The semantics
856 * of each is listed here:
858 * CODA_FLUSH -- flush all entries from the name cache and the cnode cache.
859 * CODA_PURGEUSER -- flush all entries from the name cache for a specific user
860 * This call is a result of token expiration.
862 * The next arise as the result of callbacks on a file or directory.
863 * CODA_ZAPFILE -- flush the cached attributes for a file.
865 * CODA_ZAPDIR -- flush the attributes for the dir and
866 * force a new lookup for all the children
870 * The next is a result of Venus detecting an inconsistent file.
871 * CODA_PURGEFID -- flush the attribute for the file
872 * purge it and its children from the dcache
874 * The last allows Venus to replace local fids with global ones
875 * during reintegration.
877 * CODA_REPLACE -- replace one ViceFid with another throughout the name cache */
879 int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
881 /* Handle invalidation requests. */
882 if ( !sb || !sb->s_root || !sb->s_root->d_inode) {
883 CDEBUG(D_DOWNCALL, "coda_downcall: opcode %d, no sb!\n", opcode);
891 CDEBUG(D_DOWNCALL, "CODA_FLUSH\n");
892 coda_cache_clear_all(sb, NULL);
893 shrink_dcache_sb(sb);
894 coda_flag_inode(sb->s_root->d_inode, C_FLUSH);
898 case CODA_PURGEUSER : {
899 struct coda_cred *cred = &out->coda_purgeuser.cred;
900 CDEBUG(D_DOWNCALL, "CODA_PURGEUSER\n");
902 printk("PURGEUSER: null cred!\n");
905 clstats(CODA_PURGEUSER);
906 coda_cache_clear_all(sb, cred);
912 ViceFid *fid = &out->coda_zapdir.CodaFid;
913 CDEBUG(D_DOWNCALL, "zapdir: fid = %s...\n", coda_f2s(fid));
914 clstats(CODA_ZAPDIR);
916 inode = coda_fid_to_inode(fid, sb);
918 CDEBUG(D_DOWNCALL, "zapdir: inode = %ld children flagged\n",
920 coda_flag_inode_children(inode, C_PURGE);
921 CDEBUG(D_DOWNCALL, "zapdir: inode = %ld cache cleared\n", inode->i_ino);
922 coda_flag_inode(inode, C_VATTR);
925 CDEBUG(D_DOWNCALL, "zapdir: no inode\n");
930 case CODA_ZAPFILE : {
932 struct ViceFid *fid = &out->coda_zapfile.CodaFid;
933 clstats(CODA_ZAPFILE);
934 CDEBUG(D_DOWNCALL, "zapfile: fid = %s\n", coda_f2s(fid));
935 inode = coda_fid_to_inode(fid, sb);
937 CDEBUG(D_DOWNCALL, "zapfile: inode = %ld\n",
939 coda_flag_inode(inode, C_VATTR);
942 CDEBUG(D_DOWNCALL, "zapfile: no inode\n");
946 case CODA_PURGEFID : {
948 ViceFid *fid = &out->coda_purgefid.CodaFid;
949 CDEBUG(D_DOWNCALL, "purgefid: fid = %s\n", coda_f2s(fid));
950 clstats(CODA_PURGEFID);
951 inode = coda_fid_to_inode(fid, sb);
953 CDEBUG(D_DOWNCALL, "purgefid: inode = %ld\n",
955 coda_flag_inode_children(inode, C_PURGE);
957 /* catch the dentries later if some are still busy */
958 coda_flag_inode(inode, C_PURGE);
959 d_prune_aliases(inode);
963 CDEBUG(D_DOWNCALL, "purgefid: no inode\n");
967 case CODA_REPLACE : {
969 ViceFid *oldfid = &out->coda_replace.OldFid;
970 ViceFid *newfid = &out->coda_replace.NewFid;
971 clstats(CODA_REPLACE);
972 CDEBUG(D_DOWNCALL, "CODA_REPLACE\n");
973 inode = coda_fid_to_inode(oldfid, sb);
975 CDEBUG(D_DOWNCALL, "replacefid: inode = %ld\n",
977 coda_replace_fid(inode, oldfid, newfid);
980 CDEBUG(D_DOWNCALL, "purgefid: no inode\n");