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/file.h>
28 #include <linux/stat.h>
29 #include <linux/errno.h>
30 #include <linux/locks.h>
31 #include <linux/string.h>
32 #include <asm/uaccess.h>
33 #include <linux/vmalloc.h>
35 #include <linux/coda.h>
36 #include <linux/coda_linux.h>
37 #include <linux/coda_psdev.h>
38 #include <linux/coda_fs_i.h>
39 #include <linux/coda_cache.h>
40 #include <linux/coda_proc.h>
43 static int coda_upcall(struct coda_sb_info
*mntinfo
, int inSize
, int *outSize
,
44 union inputArgs
*buffer
);
46 static void *alloc_upcall(int opcode
, int size
)
50 CODA_ALLOC(inp
, union inputArgs
*, size
);
52 return ERR_PTR(-ENOMEM
);
54 inp
->ih
.opcode
= opcode
;
55 inp
->ih
.pid
= current
->pid
;
56 inp
->ih
.pgid
= current
->pgrp
;
57 coda_load_creds(&(inp
->ih
.cred
));
64 inp = (union inputArgs *)alloc_upcall(op, insize); \
65 if (IS_ERR(inp)) { return PTR_ERR(inp); }\
66 outp = (union outputArgs *)(inp); \
70 static inline int max(int a
, int b
)
78 #define INSIZE(tag) sizeof(struct coda_ ## tag ## _in)
79 #define OUTSIZE(tag) sizeof(struct coda_ ## tag ## _out)
80 #define SIZE(tag) max(INSIZE(tag), OUTSIZE(tag))
84 int venus_rootfid(struct super_block
*sb
, ViceFid
*fidp
)
87 union outputArgs
*outp
;
88 int insize
, outsize
, error
;
94 error
= coda_upcall(coda_sbp(sb
), insize
, &outsize
, inp
);
97 printk("coda_get_rootfid: error %d\n", error
);
99 *fidp
= (ViceFid
) outp
->coda_root
.VFid
;
100 CDEBUG(D_SUPER
, "VolumeId: %lx, VnodeId: %lx.\n",
101 fidp
->Volume
, fidp
->Vnode
);
104 CODA_FREE(inp
, insize
);
109 int venus_getattr(struct super_block
*sb
, struct ViceFid
*fid
,
110 struct coda_vattr
*attr
)
112 union inputArgs
*inp
;
113 union outputArgs
*outp
;
114 int insize
, outsize
, error
;
117 insize
= SIZE(getattr
);
119 inp
->coda_getattr
.VFid
= *fid
;
121 error
= coda_upcall(coda_sbp(sb
), insize
, &outsize
, inp
);
123 *attr
= outp
->coda_getattr
.attr
;
125 CODA_FREE(inp
, insize
);
130 int venus_setattr(struct super_block
*sb
, struct ViceFid
*fid
,
131 struct coda_vattr
*vattr
)
133 union inputArgs
*inp
;
134 union outputArgs
*outp
;
135 int insize
, outsize
, error
;
137 insize
= SIZE(setattr
);
140 inp
->coda_setattr
.VFid
= *fid
;
141 inp
->coda_setattr
.attr
= *vattr
;
143 error
= coda_upcall(coda_sbp(sb
), insize
, &outsize
, inp
);
145 CDEBUG(D_SUPER
, " result %d\n", error
);
146 CODA_FREE(inp
, insize
);
150 int venus_lookup(struct super_block
*sb
, struct ViceFid
*fid
,
151 const char *name
, int length
, int * type
,
152 struct ViceFid
*resfid
)
154 union inputArgs
*inp
;
155 union outputArgs
*outp
;
156 int insize
, outsize
, error
;
159 offset
= INSIZE(lookup
);
160 insize
= max(offset
+ length
+1, OUTSIZE(lookup
));
163 inp
->coda_lookup
.VFid
= *fid
;
164 inp
->coda_lookup
.name
= offset
;
165 inp
->coda_lookup
.flags
= CLU_CASE_SENSITIVE
;
166 /* send Venus a null terminated string */
167 memcpy((char *)(inp
) + offset
, name
, length
);
168 *((char *)inp
+ offset
+ length
) = '\0';
170 error
= coda_upcall(coda_sbp(sb
), insize
, &outsize
, inp
);
172 *resfid
= outp
->coda_lookup
.VFid
;
173 *type
= outp
->coda_lookup
.vtype
;
175 CODA_FREE(inp
, insize
);
180 int venus_release(struct super_block
*sb
, struct ViceFid
*fid
, int flags
,
181 struct coda_cred
*cred
)
183 union inputArgs
*inp
;
184 union outputArgs
*outp
;
185 int insize
, outsize
, error
;
187 insize
= SIZE(close
);
191 memcpy(&(inp
->ih
.cred
), cred
, sizeof(*cred
));
193 printk("CODA: close without valid file creds.\n");
195 inp
->coda_close
.VFid
= *fid
;
196 inp
->coda_close
.flags
= flags
;
198 error
= coda_upcall(coda_sbp(sb
), insize
, &outsize
, inp
);
200 CODA_FREE(inp
, insize
);
204 int venus_open(struct super_block
*sb
, struct ViceFid
*fid
,
205 int flags
, ino_t
*ino
, dev_t
*dev
)
207 union inputArgs
*inp
;
208 union outputArgs
*outp
;
209 int insize
, outsize
, error
;
214 inp
->coda_open
.VFid
= *fid
;
215 inp
->coda_open
.flags
= flags
;
217 error
= coda_upcall(coda_sbp(sb
), insize
, &outsize
, inp
);
219 *ino
= outp
->coda_open
.inode
;
220 *dev
= outp
->coda_open
.dev
;
222 CODA_FREE(inp
, insize
);
226 int venus_mkdir(struct super_block
*sb
, struct ViceFid
*dirfid
,
227 const char *name
, int length
,
228 struct ViceFid
*newfid
, struct coda_vattr
*attrs
)
230 union inputArgs
*inp
;
231 union outputArgs
*outp
;
232 int insize
, outsize
, error
;
235 offset
= INSIZE(mkdir
);
236 insize
= max(offset
+ length
+ 1, OUTSIZE(mkdir
));
239 inp
->coda_mkdir
.VFid
= *dirfid
;
240 inp
->coda_mkdir
.attr
= *attrs
;
241 inp
->coda_mkdir
.name
= offset
;
242 /* Venus must get null terminated string */
243 memcpy((char *)(inp
) + offset
, name
, length
);
244 *((char *)inp
+ offset
+ length
) = '\0';
246 error
= coda_upcall(coda_sbp(sb
), insize
, &outsize
, inp
);
248 *attrs
= outp
->coda_mkdir
.attr
;
249 *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 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
;
324 CODA_FREE(inp
, insize
);
328 int venus_rmdir(struct super_block
*sb
, struct ViceFid
*dirfid
,
329 const char *name
, int length
)
331 union inputArgs
*inp
;
332 union outputArgs
*outp
;
333 int insize
, outsize
, error
;
336 offset
= INSIZE(rmdir
);
337 insize
= max(offset
+ length
+ 1, OUTSIZE(rmdir
));
340 inp
->coda_rmdir
.VFid
= *dirfid
;
341 inp
->coda_rmdir
.name
= offset
;
342 memcpy((char *)(inp
) + offset
, name
, length
);
343 *((char *)inp
+ offset
+ length
) = '\0';
345 error
= coda_upcall(coda_sbp(sb
), insize
, &outsize
, inp
);
347 CODA_FREE(inp
, insize
);
351 int venus_remove(struct super_block
*sb
, struct ViceFid
*dirfid
,
352 const char *name
, int length
)
354 union inputArgs
*inp
;
355 union outputArgs
*outp
;
356 int error
=0, insize
, outsize
, offset
;
358 offset
= INSIZE(remove
);
359 insize
= max(offset
+ length
+ 1, OUTSIZE(remove
));
362 inp
->coda_remove
.VFid
= *dirfid
;
363 inp
->coda_remove
.name
= offset
;
364 memcpy((char *)(inp
) + offset
, name
, length
);
365 *((char *)inp
+ offset
+ length
) = '\0';
367 error
= coda_upcall(coda_sbp(sb
), insize
, &outsize
, inp
);
369 CODA_FREE(inp
, insize
);
373 int venus_readlink(struct super_block
*sb
, struct ViceFid
*fid
,
374 char *buffer
, int *length
)
376 union inputArgs
*inp
;
377 union outputArgs
*outp
;
378 int insize
, outsize
, error
;
382 insize
= max(INSIZE(readlink
), OUTSIZE(readlink
)+ *length
+ 1);
383 UPARG(CODA_READLINK
);
385 inp
->coda_readlink
.VFid
= *fid
;
387 error
= coda_upcall(coda_sbp(sb
), insize
, &outsize
, inp
);
390 retlen
= outp
->coda_readlink
.count
;
391 if ( retlen
> *length
)
394 result
= (char *)outp
+ (long)outp
->coda_readlink
.data
;
395 memcpy(buffer
, result
, retlen
);
396 *(buffer
+ retlen
) = '\0';
399 CDEBUG(D_INODE
, " result %d\n",error
);
401 CODA_FREE(inp
, insize
);
407 int venus_link(struct super_block
*sb
, struct ViceFid
*fid
,
408 struct ViceFid
*dirfid
, const char *name
, int len
)
410 union inputArgs
*inp
;
411 union outputArgs
*outp
;
412 int insize
, outsize
, error
;
415 offset
= INSIZE(link
);
416 insize
= max(offset
+ len
+ 1, OUTSIZE(link
));
419 inp
->coda_link
.sourceFid
= *fid
;
420 inp
->coda_link
.destFid
= *dirfid
;
421 inp
->coda_link
.tname
= offset
;
423 /* make sure strings are null terminated */
424 memcpy((char *)(inp
) + offset
, name
, len
);
425 *((char *)inp
+ offset
+ len
) = '\0';
427 error
= coda_upcall(coda_sbp(sb
), insize
, &outsize
, inp
);
429 CDEBUG(D_INODE
, " result %d\n",error
);
431 CODA_FREE(inp
, insize
);
435 int venus_symlink(struct super_block
*sb
, struct ViceFid
*fid
,
436 const char *name
, int len
,
437 const char *symname
, int symlen
)
439 union inputArgs
*inp
;
440 union outputArgs
*outp
;
441 int insize
, outsize
, error
;
444 offset
= INSIZE(symlink
);
445 insize
= max(offset
+ len
+ symlen
+ 8, OUTSIZE(symlink
));
448 /* inp->coda_symlink.attr = *tva; XXXXXX */
449 inp
->coda_symlink
.VFid
= *fid
;
451 /* Round up to word boundary and null terminate */
452 inp
->coda_symlink
.srcname
= offset
;
453 s
= ( symlen
& ~0x3 ) + 4;
454 memcpy((char *)(inp
) + offset
, symname
, symlen
);
455 *((char *)inp
+ offset
+ symlen
) = '\0';
457 /* Round up to word boundary and null terminate */
459 inp
->coda_symlink
.tname
= offset
;
460 s
= (len
& ~0x3) + 4;
461 memcpy((char *)(inp
) + offset
, name
, len
);
462 *((char *)inp
+ offset
+ len
) = '\0';
464 error
= coda_upcall(coda_sbp(sb
), insize
, &outsize
, inp
);
466 CDEBUG(D_INODE
, " result %d\n",error
);
468 CODA_FREE(inp
, insize
);
472 int venus_fsync(struct super_block
*sb
, struct ViceFid
*fid
)
474 union inputArgs
*inp
;
475 union outputArgs
*outp
;
476 int insize
, outsize
, error
;
481 inp
->coda_fsync
.VFid
= *fid
;
482 error
= coda_upcall(coda_sbp(sb
), sizeof(union inputArgs
),
485 CODA_FREE(inp
, insize
);
489 int venus_access(struct super_block
*sb
, struct ViceFid
*fid
, int mask
)
491 union inputArgs
*inp
;
492 union outputArgs
*outp
;
493 int insize
, outsize
, error
;
495 insize
= SIZE(access
);
498 inp
->coda_access
.VFid
= *fid
;
499 inp
->coda_access
.flags
= mask
;
501 error
= coda_upcall(coda_sbp(sb
), insize
, &outsize
, inp
);
503 CODA_FREE(inp
, insize
);
509 int venus_pioctl(struct super_block
*sb
, struct ViceFid
*fid
,
510 unsigned int cmd
, struct PioctlData
*data
)
512 union inputArgs
*inp
;
513 union outputArgs
*outp
;
514 int insize
, outsize
, error
;
517 insize
= VC_MAXMSGSIZE
;
520 /* build packet for Venus */
521 if (data
->vi
.in_size
> VC_MAXDATASIZE
) {
526 inp
->coda_ioctl
.VFid
= *fid
;
528 /* the cmd field was mutated by increasing its size field to
529 * reflect the path and follow args. We need to subtract that
530 * out before sending the command to Venus. */
531 inp
->coda_ioctl
.cmd
= (cmd
& ~(PIOCPARM_MASK
<< 16));
532 iocsize
= ((cmd
>> 16) & PIOCPARM_MASK
) - sizeof(char *) - sizeof(int);
533 inp
->coda_ioctl
.cmd
|= (iocsize
& PIOCPARM_MASK
) << 16;
535 /* in->coda_ioctl.rwflag = flag; */
536 inp
->coda_ioctl
.len
= data
->vi
.in_size
;
537 inp
->coda_ioctl
.data
= (char *)(INSIZE(ioctl
));
539 /* get the data out of user space */
540 if ( copy_from_user((char*)inp
+ (long)inp
->coda_ioctl
.data
,
541 data
->vi
.in
, data
->vi
.in_size
) ) {
546 error
= coda_upcall(coda_sbp(sb
), insize
, &outsize
, inp
);
549 printk("coda_pioctl: Venus returns: %d for %s\n",
550 error
, coda_f2s(fid
));
554 /* Copy out the OUT buffer. */
555 if (outp
->coda_ioctl
.len
> data
->vi
.out_size
) {
556 CDEBUG(D_FILE
, "return len %d <= request len %d\n",
557 outp
->coda_ioctl
.len
,
561 error
= verify_area(VERIFY_WRITE
, data
->vi
.out
,
563 if ( error
) goto exit
;
565 if (copy_to_user(data
->vi
.out
,
566 (char *)outp
+ (long)outp
->coda_ioctl
.data
,
567 data
->vi
.out_size
)) {
574 CODA_FREE(inp
, insize
);
578 int venus_statfs(struct super_block
*sb
, struct statfs
*sfs
)
580 union inputArgs
*inp
;
581 union outputArgs
*outp
;
582 int insize
, outsize
, error
;
584 insize
= max(INSIZE(statfs
), OUTSIZE(statfs
));
587 error
= coda_upcall(coda_sbp(sb
), insize
, &outsize
, inp
);
590 sfs
->f_blocks
= outp
->coda_statfs
.stat
.f_blocks
;
591 sfs
->f_bfree
= outp
->coda_statfs
.stat
.f_bfree
;
592 sfs
->f_bavail
= outp
->coda_statfs
.stat
.f_bavail
;
593 sfs
->f_files
= outp
->coda_statfs
.stat
.f_files
;
594 sfs
->f_ffree
= outp
->coda_statfs
.stat
.f_ffree
;
596 printk("coda_statfs: Venus returns: %d\n", error
);
599 CDEBUG(D_INODE
, " result %d\n",error
);
601 CODA_FREE(inp
, insize
);
606 * coda_upcall and coda_downcall routines.
610 static inline unsigned long coda_waitfor_upcall(struct upc_req
*vmp
)
612 DECLARE_WAITQUEUE(wait
, current
);
613 struct timeval begin
= { 0, 0 }, end
= { 0, 0 };
615 vmp
->uc_posttime
= jiffies
;
617 if (coda_upcall_timestamping
)
618 do_gettimeofday(&begin
);
620 add_wait_queue(&vmp
->uc_sleep
, &wait
);
622 if ( !coda_hard
&& vmp
->uc_opcode
!= CODA_CLOSE
)
623 set_current_state(TASK_INTERRUPTIBLE
);
625 set_current_state(TASK_UNINTERRUPTIBLE
);
628 if ( !coda_upc_comm
.vc_inuse
)
632 if ( vmp
->uc_flags
& ( REQ_WRITE
| REQ_ABORT
) )
635 if ( !coda_hard
&& vmp
->uc_opcode
!= CODA_CLOSE
&& signal_pending(current
) ) {
636 /* if this process really wants to die, let it go */
637 if ( sigismember(&(current
->signal
), SIGKILL
) ||
638 sigismember(&(current
->signal
), SIGINT
) )
640 /* signal is present: after timeout always return
641 really smart idea, probably useless ... */
642 if ( jiffies
- vmp
->uc_posttime
> coda_timeout
* HZ
)
647 remove_wait_queue(&vmp
->uc_sleep
, &wait
);
648 current
->state
= TASK_RUNNING
;
650 if (coda_upcall_timestamping
&& begin
.tv_sec
!= 0) {
651 do_gettimeofday(&end
);
653 if (end
.tv_usec
< begin
.tv_usec
) {
654 end
.tv_usec
+= 1000000; end
.tv_sec
--;
656 end
.tv_sec
-= begin
.tv_sec
;
657 end
.tv_usec
-= begin
.tv_usec
;
660 CDEBUG(D_SPECIAL
, "begin: %ld.%06ld, elapsed: %ld.%06ld\n",
661 begin
.tv_sec
, (unsigned long)begin
.tv_usec
,
662 end
.tv_sec
, (unsigned long)end
.tv_usec
);
664 return ((end
.tv_sec
* 1000000) + end
.tv_usec
);
669 * coda_upcall will return an error in the case of
670 * failed communication with Venus _or_ will peek at Venus
671 * reply and return Venus' error.
673 * As venus has 2 types of errors, normal errors (positive) and internal
674 * errors (negative), normal errors are negated, while internal errors
675 * are all mapped to -EINTR, while showing a nice warning message. (jh)
678 static int coda_upcall(struct coda_sb_info
*sbi
,
679 int inSize
, int *outSize
,
680 union inputArgs
*buffer
)
682 unsigned long runtime
;
683 struct venus_comm
*vcommp
;
684 union outputArgs
*out
;
690 vcommp
= &coda_upc_comm
;
691 if ( !vcommp
->vc_inuse
) {
692 printk("No pseudo device in upcall comms at %p\n", vcommp
);
696 /* Format the request message. */
697 CODA_ALLOC(req
,struct upc_req
*,sizeof(struct upc_req
));
698 req
->uc_data
= (void *)buffer
;
700 req
->uc_inSize
= inSize
;
701 req
->uc_outSize
= *outSize
? *outSize
: inSize
;
702 req
->uc_opcode
= ((union inputArgs
*)buffer
)->ih
.opcode
;
703 req
->uc_unique
= ++vcommp
->vc_seq
;
704 init_waitqueue_head(&req
->uc_sleep
);
706 /* Fill in the common input args. */
707 ((union inputArgs
*)buffer
)->ih
.unique
= req
->uc_unique
;
709 /* Append msg to pending queue and poke Venus. */
710 list_add(&(req
->uc_chain
), vcommp
->vc_pending
.prev
);
713 "Proc %d wake Venus for(opc,uniq) =(%d,%d) msg at %p.zzz.\n",
714 current
->pid
, req
->uc_opcode
, req
->uc_unique
, 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
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
);
734 "..process %d woken up by Venus for req at %p, data at %p\n",
735 current
->pid
, req
, req
->uc_data
);
736 if (vcommp
->vc_inuse
) { /* 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
;
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
;
753 if ( !(req
->uc_flags
& REQ_READ
) && signal_pending(current
)) {
754 /* Interrupted before venus read it. */
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
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
;
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
));
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
);
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
);
795 printk("Coda: Strange interruption..\n");
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
);
805 CODA_FREE(req
, sizeof(struct upc_req
));
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
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
)
847 /* Handle invalidation requests. */
848 if ( !sb
|| !sb
->s_root
|| !sb
->s_root
->d_inode
) {
849 CDEBUG(D_DOWNCALL
, "coda_downcall: opcode %d, no sb!\n", opcode
);
857 CDEBUG(D_DOWNCALL
, "CODA_FLUSH\n");
858 coda_cache_clear_all(sb
);
859 shrink_dcache_sb(sb
);
860 coda_flag_inode(sb
->s_root
->d_inode
, C_FLUSH
);
864 case CODA_PURGEUSER
: {
865 struct coda_cred
*cred
= &out
->coda_purgeuser
.cred
;
866 CDEBUG(D_DOWNCALL
, "CODA_PURGEUSER\n");
868 printk("PURGEUSER: null cred!\n");
871 clstats(CODA_PURGEUSER
);
872 coda_cache_clear_cred(sb
, cred
);
878 ViceFid
*fid
= &out
->coda_zapdir
.CodaFid
;
879 CDEBUG(D_DOWNCALL
, "zapdir: fid = %s...\n", coda_f2s(fid
));
880 clstats(CODA_ZAPDIR
);
882 inode
= coda_fid_to_inode(fid
, sb
);
884 CDEBUG(D_DOWNCALL
, "zapdir: inode = %ld children flagged\n",
886 coda_flag_inode_children(inode
, C_PURGE
);
887 CDEBUG(D_DOWNCALL
, "zapdir: inode = %ld cache cleared\n", inode
->i_ino
);
888 coda_flag_inode(inode
, C_VATTR
);
891 CDEBUG(D_DOWNCALL
, "zapdir: no inode\n");
896 case CODA_ZAPFILE
: {
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
);
903 CDEBUG(D_DOWNCALL
, "zapfile: inode = %ld\n",
905 coda_flag_inode(inode
, C_VATTR
);
908 CDEBUG(D_DOWNCALL
, "zapfile: no inode\n");
912 case CODA_PURGEFID
: {
914 ViceFid
*fid
= &out
->coda_purgefid
.CodaFid
;
915 CDEBUG(D_DOWNCALL
, "purgefid: fid = %s\n", coda_f2s(fid
));
916 clstats(CODA_PURGEFID
);
917 inode
= coda_fid_to_inode(fid
, sb
);
919 CDEBUG(D_DOWNCALL
, "purgefid: inode = %ld\n",
921 coda_flag_inode_children(inode
, C_PURGE
);
922 coda_purge_dentries(inode
);
925 CDEBUG(D_DOWNCALL
, "purgefid: no inode\n");
929 case CODA_REPLACE
: {
931 ViceFid
*oldfid
= &out
->coda_replace
.OldFid
;
932 ViceFid
*newfid
= &out
->coda_replace
.NewFid
;
933 clstats(CODA_REPLACE
);
934 CDEBUG(D_DOWNCALL
, "CODA_REPLACE\n");
935 inode
= coda_fid_to_inode(oldfid
, sb
);
937 CDEBUG(D_DOWNCALL
, "replacefid: inode = %ld\n",
939 coda_replace_fid(inode
, oldfid
, newfid
);
942 CDEBUG(D_DOWNCALL
, "purgefid: no inode\n");