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/segment.h>
19 #include <asm/signal.h>
20 #include <linux/signal.h>
22 #include <linux/types.h>
23 #include <linux/kernel.h>
25 #include <linux/sched.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
);
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));\
57 static inline int max(int a
, int 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))
71 int venus_rootfid(struct super_block
*sb
, ViceFid
*fidp
)
74 union outputArgs
*outp
;
75 int insize
, outsize
, error
;
81 error
= coda_upcall(coda_sbp(sb
), insize
, &outsize
, inp
);
84 printk("coda_get_rootfid: error %d\n", error
);
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
);
96 int venus_getattr(struct super_block
*sb
, struct ViceFid
*fid
,
97 struct coda_vattr
*attr
)
100 union outputArgs
*outp
;
101 int insize
, outsize
, error
;
104 insize
= SIZE(getattr
);
106 inp
->coda_getattr
.VFid
= *fid
;
108 error
= coda_upcall(coda_sbp(sb
), insize
, &outsize
, inp
);
111 *attr
= outp
->coda_getattr
.attr
;
114 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 if ( inp
) 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(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
);
162 *resfid
= outp
->coda_lookup
.VFid
;
163 *type
= outp
->coda_lookup
.vtype
;
165 if (inp
) CODA_FREE(inp
, insize
);
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
);
182 memcpy(&(inp
->ih
.cred
), cred
, sizeof(*cred
));
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
);
192 CODA_FREE(inp
, insize
);
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
;
206 inp
->coda_open
.VFid
= *fid
;
207 inp
->coda_open
.flags
= flags
;
209 error
= coda_upcall(coda_sbp(sb
), insize
, &outsize
, inp
);
212 *ino
= outp
->coda_open
.inode
;
213 *dev
= outp
->coda_open
.dev
;
220 CODA_FREE(inp
, insize
);
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
;
234 offset
= INSIZE(mkdir
);
235 insize
= max(offset
+ length
+ 1, OUTSIZE(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
;
251 CODA_FREE(inp
, insize
);
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
;
266 offset
= INSIZE(rename
);
267 insize
= max(offset
+ new_length
+ old_length
+ 8,
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 */
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
);
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
;
304 offset
= INSIZE(create
);
305 insize
= max(offset
+ length
+ 1, OUTSIZE(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
;
325 CODA_FREE(inp
, insize
);
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
;
337 offset
= INSIZE(rmdir
);
338 insize
= max(offset
+ length
+ 1, OUTSIZE(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
);
348 CODA_FREE(inp
, insize
);
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
));
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
);
370 CODA_FREE(inp
, insize
);
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
;
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
);
391 retlen
= outp
->coda_readlink
.count
;
392 if ( retlen
> *length
)
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
);
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
;
416 offset
= INSIZE(link
);
417 insize
= max(offset
+ len
+ 1, OUTSIZE(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
);
431 CODA_FREE(inp
, insize
);
432 CDEBUG(D_INODE
, " result %d\n",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
;
446 offset
= INSIZE(symlink
);
447 insize
= max(offset
+ len
+ symlen
+ 8, OUTSIZE(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 */
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
);
469 CODA_FREE(inp
, insize
);
470 CDEBUG(D_INODE
, " result %d\n",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
;
484 inp
->coda_fsync
.VFid
= *fid
;
485 error
= coda_upcall(coda_sbp(sb
), sizeof(union inputArgs
),
489 CODA_FREE(inp
, insize
);
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
);
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
);
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
;
521 insize
= VC_MAXMSGSIZE
;
524 /* build packet for Venus */
525 if (data
->vi
.in_size
> VC_MAXDATASIZE
) {
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
) ) {
550 error
= coda_upcall(coda_sbp(sb
), insize
, &outsize
, inp
);
553 printk("coda_pioctl: Venus returns: %d for %s\n",
554 error
, coda_f2s(fid
));
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
,
565 error
= verify_area(VERIFY_WRITE
, data
->vi
.out
,
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
)) {
579 CODA_FREE(inp
, insize
);
584 * coda_upcall and coda_downcall routines.
588 static inline unsigned long coda_waitfor_upcall(struct upc_req
*vmp
)
590 struct wait_queue wait
= { current
, NULL
};
591 unsigned long posttime
;
593 vmp
->uc_posttime
= jiffies
;
596 add_wait_queue(&vmp
->uc_sleep
, &wait
);
598 if ( coda_hard
== 0 )
599 current
->state
= TASK_INTERRUPTIBLE
;
601 current
->state
= TASK_UNINTERRUPTIBLE
;
604 if ( vmp
->uc_flags
& REQ_WRITE
)
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
) )
612 /* signal is present: after timeout always return
613 really smart idea, probably useless ... */
614 if ( jiffies
- vmp
->uc_posttime
> coda_timeout
* HZ
)
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
;
651 vcommp
= &coda_upc_comm
;
652 if ( !vcommp
->vc_pid
) {
653 printk("No pseudo device in upcall comms at %p\n", vcommp
);
657 /* Format the request message. */
658 CODA_ALLOC(req
,struct upc_req
*,sizeof(struct upc_req
));
659 req
->uc_data
= (void *)buffer
;
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 req
->uc_sleep
= NULL
;
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
);
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
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
);
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
;
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
;
713 if ( !(req
->uc_flags
& REQ_READ
) && signal_pending(current
)) {
714 /* Interrupted before venus read it. */
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
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
;
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
));
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
);
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
);
755 printk("Coda: Strange interruption..\n");
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
);
765 CODA_FREE(req
, sizeof(struct upc_req
));
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
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
);
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
);
825 case CODA_PURGEUSER
: {
826 struct coda_cred
*cred
= &out
->coda_purgeuser
.cred
;
827 CDEBUG(D_DOWNCALL
, "CODA_PURGEUSER\n");
829 printk("PURGEUSER: null cred!\n");
832 clstats(CODA_PURGEUSER
);
833 coda_cache_clear_cred(sb
, cred
);
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
);
845 CDEBUG(D_DOWNCALL
, "zapdir: inode = %ld children flagged\n",
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
);
851 CDEBUG(D_DOWNCALL
, "zapdir: no inode\n");
856 case CODA_ZAPFILE
: {
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
);
863 CDEBUG(D_DOWNCALL
, "zapfile: inode = %ld\n", inode
->i_ino
);
864 coda_flag_inode(inode
, C_VATTR
);
866 CDEBUG(D_DOWNCALL
, "zapfile: no inode\n");
870 case CODA_PURGEFID
: {
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
);
877 CDEBUG(D_DOWNCALL
, "purgefid: inode = %ld\n", inode
->i_ino
);
878 coda_flag_inode_children(inode
, C_PURGE
);
879 coda_purge_dentries(inode
);
881 CDEBUG(D_DOWNCALL
, "purgefid: no inode\n");
885 case CODA_REPLACE
: {
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
);
893 CDEBUG(D_DOWNCALL
, "replacefid: inode = %ld\n", inode
->i_ino
);
894 coda_replace_fid(inode
, oldfid
, newfid
);
896 CDEBUG(D_DOWNCALL
, "purgefid: no inode\n");