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 inp->coda_ioctl.VFid = *fid;
548 /* the cmd field was mutated by increasing its size field to
549 * reflect the path and follow args. We need to subtract that
550 * out before sending the command to Venus. */
551 inp->coda_ioctl.cmd = (cmd & ~(PIOCPARM_MASK << 16));
552 iocsize = ((cmd >> 16) & PIOCPARM_MASK) - sizeof(char *) - sizeof(int);
553 inp->coda_ioctl.cmd |= (iocsize & PIOCPARM_MASK) << 16;
555 /* in->coda_ioctl.rwflag = flag; */
556 inp->coda_ioctl.len = data->vi.in_size;
557 inp->coda_ioctl.data = (char *)(INSIZE(ioctl));
559 /* get the data out of user space */
560 if ( copy_from_user((char*)inp + (long)inp->coda_ioctl.data,
561 data->vi.in, data->vi.in_size) ) {
566 error = coda_upcall(coda_sbp(sb), SIZE(ioctl) + data->vi.in_size,
570 printk("coda_pioctl: Venus returns: %d for %s\n",
571 error, coda_f2s(fid));
575 /* Copy out the OUT buffer. */
576 if (outp->coda_ioctl.len > data->vi.out_size) {
577 CDEBUG(D_FILE, "return len %d <= request len %d\n",
578 outp->coda_ioctl.len,
582 error = verify_area(VERIFY_WRITE, data->vi.out,
584 if ( error ) goto exit;
586 if (copy_to_user(data->vi.out,
587 (char *)outp + (long)outp->coda_ioctl.data,
588 data->vi.out_size)) {
595 CODA_FREE(inp, insize);
599 int venus_statfs(struct super_block *sb, struct statfs *sfs)
601 union inputArgs *inp;
602 union outputArgs *outp;
603 int insize, outsize, error;
605 insize = max_t(unsigned int, INSIZE(statfs), OUTSIZE(statfs));
608 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
611 sfs->f_blocks = outp->coda_statfs.stat.f_blocks;
612 sfs->f_bfree = outp->coda_statfs.stat.f_bfree;
613 sfs->f_bavail = outp->coda_statfs.stat.f_bavail;
614 sfs->f_files = outp->coda_statfs.stat.f_files;
615 sfs->f_ffree = outp->coda_statfs.stat.f_ffree;
617 printk("coda_statfs: Venus returns: %d\n", error);
620 CDEBUG(D_INODE, " result %d\n",error);
621 CODA_FREE(inp, insize);
626 * coda_upcall and coda_downcall routines.
630 static inline unsigned long coda_waitfor_upcall(struct upc_req *vmp,
631 struct venus_comm *vcommp)
633 DECLARE_WAITQUEUE(wait, current);
634 struct timeval begin = { 0, 0 }, end = { 0, 0 };
636 vmp->uc_posttime = jiffies;
638 if (coda_upcall_timestamping)
639 do_gettimeofday(&begin);
641 add_wait_queue(&vmp->uc_sleep, &wait);
643 if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE )
644 set_current_state(TASK_INTERRUPTIBLE);
646 set_current_state(TASK_UNINTERRUPTIBLE);
649 if ( !vcommp->vc_inuse )
653 if ( vmp->uc_flags & ( REQ_WRITE | REQ_ABORT ) )
656 if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE && signal_pending(current) ) {
657 /* if this process really wants to die, let it go */
658 if ( sigismember(&(current->pending.signal), SIGKILL) ||
659 sigismember(&(current->pending.signal), SIGINT) )
661 /* signal is present: after timeout always return
662 really smart idea, probably useless ... */
663 if ( jiffies - vmp->uc_posttime > coda_timeout * HZ )
668 remove_wait_queue(&vmp->uc_sleep, &wait);
669 set_current_state(TASK_RUNNING);
671 if (coda_upcall_timestamping && begin.tv_sec != 0) {
672 do_gettimeofday(&end);
674 if (end.tv_usec < begin.tv_usec) {
675 end.tv_usec += 1000000; end.tv_sec--;
677 end.tv_sec -= begin.tv_sec;
678 end.tv_usec -= begin.tv_usec;
681 CDEBUG(D_SPECIAL, "begin: %ld.%06ld, elapsed: %ld.%06ld\n",
682 begin.tv_sec, (unsigned long)begin.tv_usec,
683 end.tv_sec, (unsigned long)end.tv_usec);
685 return ((end.tv_sec * 1000000) + end.tv_usec);
690 * coda_upcall will return an error in the case of
691 * failed communication with Venus _or_ will peek at Venus
692 * reply and return Venus' error.
694 * As venus has 2 types of errors, normal errors (positive) and internal
695 * errors (negative), normal errors are negated, while internal errors
696 * are all mapped to -EINTR, while showing a nice warning message. (jh)
699 static int coda_upcall(struct coda_sb_info *sbi,
700 int inSize, int *outSize,
701 union inputArgs *buffer)
703 unsigned long runtime;
704 struct venus_comm *vcommp;
705 union outputArgs *out;
709 vcommp = sbi->sbi_vcomm;
710 if ( !vcommp->vc_inuse ) {
711 printk("No pseudo device in upcall comms at %p\n", vcommp);
715 /* Format the request message. */
718 printk("Failed to allocate upc_req structure\n");
721 req->uc_data = (void *)buffer;
723 req->uc_inSize = inSize;
724 req->uc_outSize = *outSize ? *outSize : inSize;
725 req->uc_opcode = ((union inputArgs *)buffer)->ih.opcode;
726 req->uc_unique = ++vcommp->vc_seq;
727 init_waitqueue_head(&req->uc_sleep);
729 /* Fill in the common input args. */
730 ((union inputArgs *)buffer)->ih.unique = req->uc_unique;
732 /* Append msg to pending queue and poke Venus. */
733 list_add(&(req->uc_chain), vcommp->vc_pending.prev);
736 "Proc %d wake Venus for(opc,uniq) =(%d,%d) msg at %p.zzz.\n",
737 current->pid, req->uc_opcode, req->uc_unique, req);
739 wake_up_interruptible(&vcommp->vc_waitq);
740 /* We can be interrupted while we wait for Venus to process
741 * our request. If the interrupt occurs before Venus has read
742 * the request, we dequeue and return. If it occurs after the
743 * read but before the reply, we dequeue, send a signal
744 * message, and return. If it occurs after the reply we ignore
745 * it. In no case do we want to restart the syscall. If it
746 * was interrupted by a venus shutdown (psdev_close), return
749 /* Go to sleep. Wake up on signals only after the timeout. */
750 runtime = coda_waitfor_upcall(req, vcommp);
751 coda_upcall_stats(((union inputArgs *)buffer)->ih.opcode, runtime);
753 CDEBUG(D_TIMING, "opc: %d time: %ld uniq: %d size: %d\n",
754 req->uc_opcode, jiffies - req->uc_posttime,
755 req->uc_unique, req->uc_outSize);
757 "..process %d woken up by Venus for req at %p, data at %p\n",
758 current->pid, req, req->uc_data);
759 if (vcommp->vc_inuse) { /* i.e. Venus is still alive */
760 /* Op went through, interrupt or not... */
761 if (req->uc_flags & REQ_WRITE) {
762 out = (union outputArgs *)req->uc_data;
763 /* here we map positive Venus errors to kernel errors */
764 error = -out->oh.result;
766 "upcall: (u,o,r) (%ld, %ld, %ld) out at %p\n",
767 out->oh.unique, out->oh.opcode, out->oh.result, out);
768 *outSize = req->uc_outSize;
771 if ( !(req->uc_flags & REQ_READ) && signal_pending(current)) {
772 /* Interrupted before venus read it. */
774 "Interrupted before read:(op,un) (%d.%d), flags = %x\n",
775 req->uc_opcode, req->uc_unique, req->uc_flags);
776 list_del(&(req->uc_chain));
777 /* perhaps the best way to convince the app to
782 if ( (req->uc_flags & REQ_READ) && signal_pending(current) ) {
783 /* interrupted after Venus did its read, send signal */
784 union inputArgs *sig_inputArgs;
785 struct upc_req *sig_req;
788 "Sending Venus a signal: op = %d.%d, flags = %x\n",
789 req->uc_opcode, req->uc_unique, req->uc_flags);
791 list_del(&(req->uc_chain));
793 sig_req = upc_alloc();
794 if (!sig_req) goto exit;
796 CODA_ALLOC((sig_req->uc_data), char *, sizeof(struct coda_in_hdr));
797 if (!sig_req->uc_data) {
803 sig_inputArgs = (union inputArgs *)sig_req->uc_data;
804 sig_inputArgs->ih.opcode = CODA_SIGNAL;
805 sig_inputArgs->ih.unique = req->uc_unique;
807 sig_req->uc_flags = REQ_ASYNC;
808 sig_req->uc_opcode = sig_inputArgs->ih.opcode;
809 sig_req->uc_unique = sig_inputArgs->ih.unique;
810 sig_req->uc_inSize = sizeof(struct coda_in_hdr);
811 sig_req->uc_outSize = sizeof(struct coda_in_hdr);
813 "coda_upcall: enqueing signal msg (%d, %d)\n",
814 sig_req->uc_opcode, sig_req->uc_unique);
816 /* insert at head of queue! */
817 list_add(&(sig_req->uc_chain), &vcommp->vc_pending);
818 wake_up_interruptible(&vcommp->vc_waitq);
820 printk("Coda: Strange interruption..\n");
823 } else { /* If venus died i.e. !VC_OPEN(vcommp) */
824 printk("coda_upcall: Venus dead on (op,un) (%d.%d) flags %d\n",
825 req->uc_opcode, req->uc_unique, req->uc_flags);
837 The statements below are part of the Coda opportunistic
838 programming -- taken from the Mach/BSD kernel code for Coda.
839 You don't get correct semantics by stating what needs to be
840 done without guaranteeing the invariants needed for it to happen.
841 When will be have time to find out what exactly is going on? (pjb)
846 * There are 7 cases where cache invalidations occur. The semantics
847 * of each is listed here:
849 * CODA_FLUSH -- flush all entries from the name cache and the cnode cache.
850 * CODA_PURGEUSER -- flush all entries from the name cache for a specific user
851 * This call is a result of token expiration.
853 * The next arise as the result of callbacks on a file or directory.
854 * CODA_ZAPFILE -- flush the cached attributes for a file.
856 * CODA_ZAPDIR -- flush the attributes for the dir and
857 * force a new lookup for all the children
861 * The next is a result of Venus detecting an inconsistent file.
862 * CODA_PURGEFID -- flush the attribute for the file
863 * purge it and its children from the dcache
865 * The last allows Venus to replace local fids with global ones
866 * during reintegration.
868 * CODA_REPLACE -- replace one ViceFid with another throughout the name cache */
870 int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
872 /* Handle invalidation requests. */
873 if ( !sb || !sb->s_root || !sb->s_root->d_inode) {
874 CDEBUG(D_DOWNCALL, "coda_downcall: opcode %d, no sb!\n", opcode);
882 CDEBUG(D_DOWNCALL, "CODA_FLUSH\n");
883 coda_cache_clear_all(sb, NULL);
884 shrink_dcache_sb(sb);
885 coda_flag_inode(sb->s_root->d_inode, C_FLUSH);
889 case CODA_PURGEUSER : {
890 struct coda_cred *cred = &out->coda_purgeuser.cred;
891 CDEBUG(D_DOWNCALL, "CODA_PURGEUSER\n");
893 printk("PURGEUSER: null cred!\n");
896 clstats(CODA_PURGEUSER);
897 coda_cache_clear_all(sb, cred);
903 ViceFid *fid = &out->coda_zapdir.CodaFid;
904 CDEBUG(D_DOWNCALL, "zapdir: fid = %s...\n", coda_f2s(fid));
905 clstats(CODA_ZAPDIR);
907 inode = coda_fid_to_inode(fid, sb);
909 CDEBUG(D_DOWNCALL, "zapdir: inode = %ld children flagged\n",
911 coda_flag_inode_children(inode, C_PURGE);
912 CDEBUG(D_DOWNCALL, "zapdir: inode = %ld cache cleared\n", inode->i_ino);
913 coda_flag_inode(inode, C_VATTR);
916 CDEBUG(D_DOWNCALL, "zapdir: no inode\n");
921 case CODA_ZAPFILE : {
923 struct ViceFid *fid = &out->coda_zapfile.CodaFid;
924 clstats(CODA_ZAPFILE);
925 CDEBUG(D_DOWNCALL, "zapfile: fid = %s\n", coda_f2s(fid));
926 inode = coda_fid_to_inode(fid, sb);
928 CDEBUG(D_DOWNCALL, "zapfile: inode = %ld\n",
930 coda_flag_inode(inode, C_VATTR);
933 CDEBUG(D_DOWNCALL, "zapfile: no inode\n");
937 case CODA_PURGEFID : {
939 ViceFid *fid = &out->coda_purgefid.CodaFid;
940 CDEBUG(D_DOWNCALL, "purgefid: fid = %s\n", coda_f2s(fid));
941 clstats(CODA_PURGEFID);
942 inode = coda_fid_to_inode(fid, sb);
944 CDEBUG(D_DOWNCALL, "purgefid: inode = %ld\n",
946 coda_flag_inode_children(inode, C_PURGE);
948 /* catch the dentries later if some are still busy */
949 coda_flag_inode(inode, C_PURGE);
950 d_prune_aliases(inode);
954 CDEBUG(D_DOWNCALL, "purgefid: no inode\n");
958 case CODA_REPLACE : {
960 ViceFid *oldfid = &out->coda_replace.OldFid;
961 ViceFid *newfid = &out->coda_replace.NewFid;
962 clstats(CODA_REPLACE);
963 CDEBUG(D_DOWNCALL, "CODA_REPLACE\n");
964 inode = coda_fid_to_inode(oldfid, sb);
966 CDEBUG(D_DOWNCALL, "replacefid: inode = %ld\n",
968 coda_replace_fid(inode, oldfid, newfid);
971 CDEBUG(D_DOWNCALL, "purgefid: no inode\n");