Replace extern inline with static inline.
[linux-2.6/linux-mips.git] / fs / coda / upcall.c
blob6ab4f181513e7009f0f51ed5478a1f5cb65525c8
1 /*
2 * Mostly platform independent upcall operations to Venus:
3 * -- upcalls
4 * -- upcall routines
6 * Linux 2.0 version
7 * Copyright (C) 1996 Peter J. Braam <braam@maths.ox.ac.uk>,
8 * Michael Callahan <callahan@maths.ox.ac.uk>
9 *
10 * Redone for Linux 2.1
11 * Copyright (C) 1997 Carnegie Mellon University
13 * Carnegie Mellon University encourages users of this code to contribute
14 * improvements to the Coda project. Contact Peter Braam <coda@cs.cmu.edu>.
17 #include <asm/system.h>
18 #include <asm/signal.h>
19 #include <linux/signal.h>
21 #include <linux/types.h>
22 #include <linux/kernel.h>
23 #include <linux/mm.h>
24 #include <linux/time.h>
25 #include <linux/fs.h>
26 #include <linux/file.h>
27 #include <linux/stat.h>
28 #include <linux/errno.h>
29 #include <linux/string.h>
30 #include <asm/uaccess.h>
31 #include <linux/vmalloc.h>
32 #include <linux/vfs.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)
49 union inputArgs *inp;
51 CODA_ALLOC(inp, union inputArgs *, size);
52 if (!inp)
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));
60 return (void*)inp;
63 #define UPARG(op)\
64 do {\
65 inp = (union inputArgs *)alloc_upcall(op, insize); \
66 if (IS_ERR(inp)) { return PTR_ERR(inp); }\
67 outp = (union outputArgs *)(inp); \
68 outsize = insize; \
69 } while (0)
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))
76 /* the upcalls */
77 int venus_rootfid(struct super_block *sb, ViceFid *fidp)
79 union inputArgs *inp;
80 union outputArgs *outp;
81 int insize, outsize, error;
83 insize = SIZE(root);
84 UPARG(CODA_ROOT);
86 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
88 if (error) {
89 printk("coda_get_rootfid: error %d\n", error);
90 } else {
91 *fidp = (ViceFid) outp->coda_root.VFid;
94 CODA_FREE(inp, insize);
95 return error;
98 int venus_getattr(struct super_block *sb, struct ViceFid *fid,
99 struct coda_vattr *attr)
101 union inputArgs *inp;
102 union outputArgs *outp;
103 int insize, outsize, error;
105 insize = SIZE(getattr);
106 UPARG(CODA_GETATTR);
107 inp->coda_getattr.VFid = *fid;
109 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
111 *attr = outp->coda_getattr.attr;
113 CODA_FREE(inp, insize);
114 return error;
117 int venus_setattr(struct super_block *sb, struct ViceFid *fid,
118 struct coda_vattr *vattr)
120 union inputArgs *inp;
121 union outputArgs *outp;
122 int insize, outsize, error;
124 insize = SIZE(setattr);
125 UPARG(CODA_SETATTR);
127 inp->coda_setattr.VFid = *fid;
128 inp->coda_setattr.attr = *vattr;
130 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
132 CODA_FREE(inp, insize);
133 return error;
136 int venus_lookup(struct super_block *sb, struct ViceFid *fid,
137 const char *name, int length, int * type,
138 struct ViceFid *resfid)
140 union inputArgs *inp;
141 union outputArgs *outp;
142 int insize, outsize, error;
143 int offset;
145 offset = INSIZE(lookup);
146 insize = max_t(unsigned int, offset + length +1, OUTSIZE(lookup));
147 UPARG(CODA_LOOKUP);
149 inp->coda_lookup.VFid = *fid;
150 inp->coda_lookup.name = offset;
151 inp->coda_lookup.flags = CLU_CASE_SENSITIVE;
152 /* send Venus a null terminated string */
153 memcpy((char *)(inp) + offset, name, length);
154 *((char *)inp + offset + length) = '\0';
156 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
158 *resfid = outp->coda_lookup.VFid;
159 *type = outp->coda_lookup.vtype;
161 CODA_FREE(inp, insize);
162 return error;
165 int venus_store(struct super_block *sb, struct ViceFid *fid, int flags,
166 struct coda_cred *cred)
168 union inputArgs *inp;
169 union outputArgs *outp;
170 int insize, outsize, error;
172 insize = SIZE(store);
173 UPARG(CODA_STORE);
175 memcpy(&(inp->ih.cred), cred, sizeof(*cred));
177 inp->coda_store.VFid = *fid;
178 inp->coda_store.flags = flags;
180 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
182 CODA_FREE(inp, insize);
183 return error;
186 int venus_release(struct super_block *sb, struct ViceFid *fid, int flags)
188 union inputArgs *inp;
189 union outputArgs *outp;
190 int insize, outsize, error;
192 insize = SIZE(release);
193 UPARG(CODA_RELEASE);
195 inp->coda_release.VFid = *fid;
196 inp->coda_release.flags = flags;
198 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
200 CODA_FREE(inp, insize);
201 return error;
204 int venus_close(struct super_block *sb, struct ViceFid *fid, int flags,
205 struct coda_cred *cred)
207 union inputArgs *inp;
208 union outputArgs *outp;
209 int insize, outsize, error;
211 insize = SIZE(release);
212 UPARG(CODA_CLOSE);
214 memcpy(&(inp->ih.cred), cred, sizeof(*cred));
216 inp->coda_close.VFid = *fid;
217 inp->coda_close.flags = flags;
219 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
221 CODA_FREE(inp, insize);
222 return error;
225 int venus_open(struct super_block *sb, struct ViceFid *fid,
226 int flags, struct file **fh)
228 union inputArgs *inp;
229 union outputArgs *outp;
230 int insize, outsize, error;
232 insize = SIZE(open_by_fd);
233 UPARG(CODA_OPEN_BY_FD);
235 inp->coda_open.VFid = *fid;
236 inp->coda_open.flags = flags;
238 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
240 *fh = outp->coda_open_by_fd.fh;
242 CODA_FREE(inp, insize);
243 return error;
246 int venus_mkdir(struct super_block *sb, struct ViceFid *dirfid,
247 const char *name, int length,
248 struct ViceFid *newfid, struct coda_vattr *attrs)
250 union inputArgs *inp;
251 union outputArgs *outp;
252 int insize, outsize, error;
253 int offset;
255 offset = INSIZE(mkdir);
256 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(mkdir));
257 UPARG(CODA_MKDIR);
259 inp->coda_mkdir.VFid = *dirfid;
260 inp->coda_mkdir.attr = *attrs;
261 inp->coda_mkdir.name = offset;
262 /* Venus must get null terminated string */
263 memcpy((char *)(inp) + offset, name, length);
264 *((char *)inp + offset + length) = '\0';
266 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
268 *attrs = outp->coda_mkdir.attr;
269 *newfid = outp->coda_mkdir.VFid;
271 CODA_FREE(inp, insize);
272 return error;
276 int venus_rename(struct super_block *sb, struct ViceFid *old_fid,
277 struct ViceFid *new_fid, size_t old_length,
278 size_t new_length, const char *old_name,
279 const char *new_name)
281 union inputArgs *inp;
282 union outputArgs *outp;
283 int insize, outsize, error;
284 int offset, s;
286 offset = INSIZE(rename);
287 insize = max_t(unsigned int, offset + new_length + old_length + 8,
288 OUTSIZE(rename));
289 UPARG(CODA_RENAME);
291 inp->coda_rename.sourceFid = *old_fid;
292 inp->coda_rename.destFid = *new_fid;
293 inp->coda_rename.srcname = offset;
295 /* Venus must receive an null terminated string */
296 s = ( old_length & ~0x3) +4; /* round up to word boundary */
297 memcpy((char *)(inp) + offset, old_name, old_length);
298 *((char *)inp + offset + old_length) = '\0';
300 /* another null terminated string for Venus */
301 offset += s;
302 inp->coda_rename.destname = offset;
303 s = ( new_length & ~0x3) +4; /* round up to word boundary */
304 memcpy((char *)(inp) + offset, new_name, new_length);
305 *((char *)inp + offset + new_length) = '\0';
307 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
309 CODA_FREE(inp, insize);
310 return error;
313 int venus_create(struct super_block *sb, struct ViceFid *dirfid,
314 const char *name, int length, int excl, int mode, dev_t rdev,
315 struct ViceFid *newfid, struct coda_vattr *attrs)
317 union inputArgs *inp;
318 union outputArgs *outp;
319 int insize, outsize, error;
320 int offset;
322 offset = INSIZE(create);
323 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(create));
324 UPARG(CODA_CREATE);
326 inp->coda_create.VFid = *dirfid;
327 inp->coda_create.attr.va_mode = mode;
328 inp->coda_create.attr.va_rdev = rdev;
329 inp->coda_create.excl = excl;
330 inp->coda_create.mode = mode;
331 inp->coda_create.name = offset;
333 /* Venus must get null terminated string */
334 memcpy((char *)(inp) + offset, name, length);
335 *((char *)inp + offset + length) = '\0';
337 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
339 *attrs = outp->coda_create.attr;
340 *newfid = outp->coda_create.VFid;
342 CODA_FREE(inp, insize);
343 return error;
346 int venus_rmdir(struct super_block *sb, struct ViceFid *dirfid,
347 const char *name, int length)
349 union inputArgs *inp;
350 union outputArgs *outp;
351 int insize, outsize, error;
352 int offset;
354 offset = INSIZE(rmdir);
355 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(rmdir));
356 UPARG(CODA_RMDIR);
358 inp->coda_rmdir.VFid = *dirfid;
359 inp->coda_rmdir.name = offset;
360 memcpy((char *)(inp) + offset, name, length);
361 *((char *)inp + offset + length) = '\0';
363 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
365 CODA_FREE(inp, insize);
366 return error;
369 int venus_remove(struct super_block *sb, struct ViceFid *dirfid,
370 const char *name, int length)
372 union inputArgs *inp;
373 union outputArgs *outp;
374 int error=0, insize, outsize, offset;
376 offset = INSIZE(remove);
377 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(remove));
378 UPARG(CODA_REMOVE);
380 inp->coda_remove.VFid = *dirfid;
381 inp->coda_remove.name = offset;
382 memcpy((char *)(inp) + offset, name, length);
383 *((char *)inp + offset + length) = '\0';
385 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
387 CODA_FREE(inp, insize);
388 return error;
391 int venus_readlink(struct super_block *sb, struct ViceFid *fid,
392 char *buffer, int *length)
394 union inputArgs *inp;
395 union outputArgs *outp;
396 int insize, outsize, error;
397 int retlen;
398 char *result;
400 insize = max_t(unsigned int,
401 INSIZE(readlink), OUTSIZE(readlink)+ *length + 1);
402 UPARG(CODA_READLINK);
404 inp->coda_readlink.VFid = *fid;
406 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
408 if (! error) {
409 retlen = outp->coda_readlink.count;
410 if ( retlen > *length )
411 retlen = *length;
412 *length = retlen;
413 result = (char *)outp + (long)outp->coda_readlink.data;
414 memcpy(buffer, result, retlen);
415 *(buffer + retlen) = '\0';
418 CODA_FREE(inp, insize);
419 return error;
424 int venus_link(struct super_block *sb, struct ViceFid *fid,
425 struct ViceFid *dirfid, const char *name, int len )
427 union inputArgs *inp;
428 union outputArgs *outp;
429 int insize, outsize, error;
430 int offset;
432 offset = INSIZE(link);
433 insize = max_t(unsigned int, offset + len + 1, OUTSIZE(link));
434 UPARG(CODA_LINK);
436 inp->coda_link.sourceFid = *fid;
437 inp->coda_link.destFid = *dirfid;
438 inp->coda_link.tname = offset;
440 /* make sure strings are null terminated */
441 memcpy((char *)(inp) + offset, name, len);
442 *((char *)inp + offset + len) = '\0';
444 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
446 CODA_FREE(inp, insize);
447 return error;
450 int venus_symlink(struct super_block *sb, struct ViceFid *fid,
451 const char *name, int len,
452 const char *symname, int symlen)
454 union inputArgs *inp;
455 union outputArgs *outp;
456 int insize, outsize, error;
457 int offset, s;
459 offset = INSIZE(symlink);
460 insize = max_t(unsigned int, offset + len + symlen + 8, OUTSIZE(symlink));
461 UPARG(CODA_SYMLINK);
463 /* inp->coda_symlink.attr = *tva; XXXXXX */
464 inp->coda_symlink.VFid = *fid;
466 /* Round up to word boundary and null terminate */
467 inp->coda_symlink.srcname = offset;
468 s = ( symlen & ~0x3 ) + 4;
469 memcpy((char *)(inp) + offset, symname, symlen);
470 *((char *)inp + offset + symlen) = '\0';
472 /* Round up to word boundary and null terminate */
473 offset += s;
474 inp->coda_symlink.tname = offset;
475 s = (len & ~0x3) + 4;
476 memcpy((char *)(inp) + offset, name, len);
477 *((char *)inp + offset + len) = '\0';
479 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
481 CODA_FREE(inp, insize);
482 return error;
485 int venus_fsync(struct super_block *sb, struct ViceFid *fid)
487 union inputArgs *inp;
488 union outputArgs *outp;
489 int insize, outsize, error;
491 insize=SIZE(fsync);
492 UPARG(CODA_FSYNC);
494 inp->coda_fsync.VFid = *fid;
495 error = coda_upcall(coda_sbp(sb), sizeof(union inputArgs),
496 &outsize, inp);
498 CODA_FREE(inp, insize);
499 return error;
502 int venus_access(struct super_block *sb, struct ViceFid *fid, int mask)
504 union inputArgs *inp;
505 union outputArgs *outp;
506 int insize, outsize, error;
508 insize = SIZE(access);
509 UPARG(CODA_ACCESS);
511 inp->coda_access.VFid = *fid;
512 inp->coda_access.flags = mask;
514 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
516 CODA_FREE(inp, insize);
517 return error;
521 int venus_pioctl(struct super_block *sb, struct ViceFid *fid,
522 unsigned int cmd, struct PioctlData *data)
524 union inputArgs *inp;
525 union outputArgs *outp;
526 int insize, outsize, error;
527 int iocsize;
529 insize = VC_MAXMSGSIZE;
530 UPARG(CODA_IOCTL);
532 /* build packet for Venus */
533 if (data->vi.in_size > VC_MAXDATASIZE) {
534 error = -EINVAL;
535 goto exit;
538 inp->coda_ioctl.VFid = *fid;
540 /* the cmd field was mutated by increasing its size field to
541 * reflect the path and follow args. We need to subtract that
542 * out before sending the command to Venus. */
543 inp->coda_ioctl.cmd = (cmd & ~(PIOCPARM_MASK << 16));
544 iocsize = ((cmd >> 16) & PIOCPARM_MASK) - sizeof(char *) - sizeof(int);
545 inp->coda_ioctl.cmd |= (iocsize & PIOCPARM_MASK) << 16;
547 /* in->coda_ioctl.rwflag = flag; */
548 inp->coda_ioctl.len = data->vi.in_size;
549 inp->coda_ioctl.data = (char *)(INSIZE(ioctl));
551 /* get the data out of user space */
552 if ( copy_from_user((char*)inp + (long)inp->coda_ioctl.data,
553 data->vi.in, data->vi.in_size) ) {
554 error = -EINVAL;
555 goto exit;
558 error = coda_upcall(coda_sbp(sb), SIZE(ioctl) + data->vi.in_size,
559 &outsize, inp);
561 if (error) {
562 printk("coda_pioctl: Venus returns: %d for %s\n",
563 error, coda_f2s(fid));
564 goto exit;
567 /* Copy out the OUT buffer. */
568 if (outp->coda_ioctl.len > data->vi.out_size) {
569 error = -EINVAL;
570 } else {
571 error = verify_area(VERIFY_WRITE, data->vi.out,
572 data->vi.out_size);
573 if ( error ) goto exit;
575 if (copy_to_user(data->vi.out,
576 (char *)outp + (long)outp->coda_ioctl.data,
577 data->vi.out_size)) {
578 error = -EINVAL;
579 goto exit;
583 exit:
584 CODA_FREE(inp, insize);
585 return error;
588 int venus_statfs(struct super_block *sb, struct kstatfs *sfs)
590 union inputArgs *inp;
591 union outputArgs *outp;
592 int insize, outsize, error;
594 insize = max_t(unsigned int, INSIZE(statfs), OUTSIZE(statfs));
595 UPARG(CODA_STATFS);
597 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
599 if (!error) {
600 sfs->f_blocks = outp->coda_statfs.stat.f_blocks;
601 sfs->f_bfree = outp->coda_statfs.stat.f_bfree;
602 sfs->f_bavail = outp->coda_statfs.stat.f_bavail;
603 sfs->f_files = outp->coda_statfs.stat.f_files;
604 sfs->f_ffree = outp->coda_statfs.stat.f_ffree;
605 } else {
606 printk("coda_statfs: Venus returns: %d\n", error);
609 CODA_FREE(inp, insize);
610 return error;
614 * coda_upcall and coda_downcall routines.
618 static inline void coda_waitfor_upcall(struct upc_req *vmp,
619 struct venus_comm *vcommp)
621 DECLARE_WAITQUEUE(wait, current);
623 vmp->uc_posttime = jiffies;
625 add_wait_queue(&vmp->uc_sleep, &wait);
626 for (;;) {
627 if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE )
628 set_current_state(TASK_INTERRUPTIBLE);
629 else
630 set_current_state(TASK_UNINTERRUPTIBLE);
632 /* venus died */
633 if ( !vcommp->vc_inuse )
634 break;
636 /* got a reply */
637 if ( vmp->uc_flags & ( REQ_WRITE | REQ_ABORT ) )
638 break;
640 if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE && signal_pending(current) ) {
641 /* if this process really wants to die, let it go */
642 if ( sigismember(&(current->pending.signal), SIGKILL) ||
643 sigismember(&(current->pending.signal), SIGINT) )
644 break;
645 /* signal is present: after timeout always return
646 really smart idea, probably useless ... */
647 if ( jiffies - vmp->uc_posttime > coda_timeout * HZ )
648 break;
650 schedule();
652 remove_wait_queue(&vmp->uc_sleep, &wait);
653 set_current_state(TASK_RUNNING);
655 return;
660 * coda_upcall will return an error in the case of
661 * failed communication with Venus _or_ will peek at Venus
662 * reply and return Venus' error.
664 * As venus has 2 types of errors, normal errors (positive) and internal
665 * errors (negative), normal errors are negated, while internal errors
666 * are all mapped to -EINTR, while showing a nice warning message. (jh)
669 static int coda_upcall(struct coda_sb_info *sbi,
670 int inSize, int *outSize,
671 union inputArgs *buffer)
673 struct venus_comm *vcommp;
674 union outputArgs *out;
675 struct upc_req *req;
676 int error = 0;
678 vcommp = sbi->sbi_vcomm;
679 if ( !vcommp->vc_inuse ) {
680 printk("No pseudo device in upcall comms at %p\n", vcommp);
681 return -ENXIO;
684 /* Format the request message. */
685 req = upc_alloc();
686 if (!req) {
687 printk("Failed to allocate upc_req structure\n");
688 return -ENOMEM;
690 req->uc_data = (void *)buffer;
691 req->uc_flags = 0;
692 req->uc_inSize = inSize;
693 req->uc_outSize = *outSize ? *outSize : inSize;
694 req->uc_opcode = ((union inputArgs *)buffer)->ih.opcode;
695 req->uc_unique = ++vcommp->vc_seq;
696 init_waitqueue_head(&req->uc_sleep);
698 /* Fill in the common input args. */
699 ((union inputArgs *)buffer)->ih.unique = req->uc_unique;
701 /* Append msg to pending queue and poke Venus. */
702 list_add(&(req->uc_chain), vcommp->vc_pending.prev);
704 wake_up_interruptible(&vcommp->vc_waitq);
705 /* We can be interrupted while we wait for Venus to process
706 * our request. If the interrupt occurs before Venus has read
707 * the request, we dequeue and return. If it occurs after the
708 * read but before the reply, we dequeue, send a signal
709 * message, and return. If it occurs after the reply we ignore
710 * it. In no case do we want to restart the syscall. If it
711 * was interrupted by a venus shutdown (psdev_close), return
712 * ENODEV. */
714 /* Go to sleep. Wake up on signals only after the timeout. */
715 coda_waitfor_upcall(req, vcommp);
717 if (vcommp->vc_inuse) { /* i.e. Venus is still alive */
718 /* Op went through, interrupt or not... */
719 if (req->uc_flags & REQ_WRITE) {
720 out = (union outputArgs *)req->uc_data;
721 /* here we map positive Venus errors to kernel errors */
722 error = -out->oh.result;
723 *outSize = req->uc_outSize;
724 goto exit;
726 if ( !(req->uc_flags & REQ_READ) && signal_pending(current)) {
727 /* Interrupted before venus read it. */
728 list_del(&(req->uc_chain));
729 /* perhaps the best way to convince the app to
730 give up? */
731 error = -EINTR;
732 goto exit;
734 if ( (req->uc_flags & REQ_READ) && signal_pending(current) ) {
735 /* interrupted after Venus did its read, send signal */
736 union inputArgs *sig_inputArgs;
737 struct upc_req *sig_req;
739 list_del(&(req->uc_chain));
740 error = -ENOMEM;
741 sig_req = upc_alloc();
742 if (!sig_req) goto exit;
744 CODA_ALLOC((sig_req->uc_data), char *, sizeof(struct coda_in_hdr));
745 if (!sig_req->uc_data) {
746 upc_free(sig_req);
747 goto exit;
750 error = -EINTR;
751 sig_inputArgs = (union inputArgs *)sig_req->uc_data;
752 sig_inputArgs->ih.opcode = CODA_SIGNAL;
753 sig_inputArgs->ih.unique = req->uc_unique;
755 sig_req->uc_flags = REQ_ASYNC;
756 sig_req->uc_opcode = sig_inputArgs->ih.opcode;
757 sig_req->uc_unique = sig_inputArgs->ih.unique;
758 sig_req->uc_inSize = sizeof(struct coda_in_hdr);
759 sig_req->uc_outSize = sizeof(struct coda_in_hdr);
761 /* insert at head of queue! */
762 list_add(&(sig_req->uc_chain), &vcommp->vc_pending);
763 wake_up_interruptible(&vcommp->vc_waitq);
764 } else {
765 printk("Coda: Strange interruption..\n");
766 error = -EINTR;
768 } else { /* If venus died i.e. !VC_OPEN(vcommp) */
769 printk("coda_upcall: Venus dead on (op,un) (%d.%d) flags %d\n",
770 req->uc_opcode, req->uc_unique, req->uc_flags);
771 error = -ENODEV;
774 exit:
775 upc_free(req);
776 return error;
780 The statements below are part of the Coda opportunistic
781 programming -- taken from the Mach/BSD kernel code for Coda.
782 You don't get correct semantics by stating what needs to be
783 done without guaranteeing the invariants needed for it to happen.
784 When will be have time to find out what exactly is going on? (pjb)
789 * There are 7 cases where cache invalidations occur. The semantics
790 * of each is listed here:
792 * CODA_FLUSH -- flush all entries from the name cache and the cnode cache.
793 * CODA_PURGEUSER -- flush all entries from the name cache for a specific user
794 * This call is a result of token expiration.
796 * The next arise as the result of callbacks on a file or directory.
797 * CODA_ZAPFILE -- flush the cached attributes for a file.
799 * CODA_ZAPDIR -- flush the attributes for the dir and
800 * force a new lookup for all the children
801 of this dir.
804 * The next is a result of Venus detecting an inconsistent file.
805 * CODA_PURGEFID -- flush the attribute for the file
806 * purge it and its children from the dcache
808 * The last allows Venus to replace local fids with global ones
809 * during reintegration.
811 * CODA_REPLACE -- replace one ViceFid with another throughout the name cache */
813 int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
815 /* Handle invalidation requests. */
816 if ( !sb || !sb->s_root || !sb->s_root->d_inode)
817 return 0;
819 switch (opcode) {
821 case CODA_FLUSH : {
822 coda_cache_clear_all(sb, NULL);
823 shrink_dcache_sb(sb);
824 coda_flag_inode(sb->s_root->d_inode, C_FLUSH);
825 return(0);
828 case CODA_PURGEUSER : {
829 struct coda_cred *cred = &out->coda_purgeuser.cred;
830 if ( !cred ) {
831 printk("PURGEUSER: null cred!\n");
832 return 0;
834 coda_cache_clear_all(sb, cred);
835 return(0);
838 case CODA_ZAPDIR : {
839 struct inode *inode;
840 ViceFid *fid = &out->coda_zapdir.CodaFid;
842 inode = coda_fid_to_inode(fid, sb);
843 if (inode) {
844 coda_flag_inode_children(inode, C_PURGE);
845 coda_flag_inode(inode, C_VATTR);
846 iput(inode);
849 return(0);
852 case CODA_ZAPFILE : {
853 struct inode *inode;
854 struct ViceFid *fid = &out->coda_zapfile.CodaFid;
855 inode = coda_fid_to_inode(fid, sb);
856 if ( inode ) {
857 coda_flag_inode(inode, C_VATTR);
858 iput(inode);
860 return 0;
863 case CODA_PURGEFID : {
864 struct inode *inode;
865 ViceFid *fid = &out->coda_purgefid.CodaFid;
866 inode = coda_fid_to_inode(fid, sb);
867 if ( inode ) {
868 coda_flag_inode_children(inode, C_PURGE);
870 /* catch the dentries later if some are still busy */
871 coda_flag_inode(inode, C_PURGE);
872 d_prune_aliases(inode);
874 iput(inode);
876 return 0;
879 case CODA_REPLACE : {
880 struct inode *inode;
881 ViceFid *oldfid = &out->coda_replace.OldFid;
882 ViceFid *newfid = &out->coda_replace.NewFid;
883 inode = coda_fid_to_inode(oldfid, sb);
884 if ( inode ) {
885 coda_replace_fid(inode, oldfid, newfid);
886 iput(inode);
888 return 0;
891 return 0;