coda: ignore returned values when upcalls return errors
[linux-2.6/verdex.git] / fs / coda / upcall.c
blob097dbb2fd6f5a9c5ef6cc93fad681f44442c231d
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 <linux/signal.h>
19 #include <linux/sched.h>
20 #include <linux/types.h>
21 #include <linux/kernel.h>
22 #include <linux/mm.h>
23 #include <linux/time.h>
24 #include <linux/fs.h>
25 #include <linux/file.h>
26 #include <linux/stat.h>
27 #include <linux/errno.h>
28 #include <linux/string.h>
29 #include <asm/uaccess.h>
30 #include <linux/vmalloc.h>
31 #include <linux/vfs.h>
33 #include <linux/coda.h>
34 #include <linux/coda_linux.h>
35 #include <linux/coda_psdev.h>
36 #include <linux/coda_fs_i.h>
37 #include <linux/coda_cache.h>
38 #include <linux/coda_proc.h>
40 static int coda_upcall(struct coda_sb_info *mntinfo, int inSize, int *outSize,
41 union inputArgs *buffer);
43 static void *alloc_upcall(int opcode, int size)
45 union inputArgs *inp;
47 CODA_ALLOC(inp, union inputArgs *, size);
48 if (!inp)
49 return ERR_PTR(-ENOMEM);
51 inp->ih.opcode = opcode;
52 inp->ih.pid = current->pid;
53 inp->ih.pgid = process_group(current);
54 #ifdef CONFIG_CODA_FS_OLD_API
55 memset(&inp->ih.cred, 0, sizeof(struct coda_cred));
56 inp->ih.cred.cr_fsuid = current->fsuid;
57 #else
58 inp->ih.uid = current->fsuid;
59 #endif
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, struct CodaFid *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);
87 if (!error)
88 *fidp = outp->coda_root.VFid;
90 CODA_FREE(inp, insize);
91 return error;
94 int venus_getattr(struct super_block *sb, struct CodaFid *fid,
95 struct coda_vattr *attr)
97 union inputArgs *inp;
98 union outputArgs *outp;
99 int insize, outsize, error;
101 insize = SIZE(getattr);
102 UPARG(CODA_GETATTR);
103 inp->coda_getattr.VFid = *fid;
105 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
106 if (!error)
107 *attr = outp->coda_getattr.attr;
109 CODA_FREE(inp, insize);
110 return error;
113 int venus_setattr(struct super_block *sb, struct CodaFid *fid,
114 struct coda_vattr *vattr)
116 union inputArgs *inp;
117 union outputArgs *outp;
118 int insize, outsize, error;
120 insize = SIZE(setattr);
121 UPARG(CODA_SETATTR);
123 inp->coda_setattr.VFid = *fid;
124 inp->coda_setattr.attr = *vattr;
126 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
128 CODA_FREE(inp, insize);
129 return error;
132 int venus_lookup(struct super_block *sb, struct CodaFid *fid,
133 const char *name, int length, int * type,
134 struct CodaFid *resfid)
136 union inputArgs *inp;
137 union outputArgs *outp;
138 int insize, outsize, error;
139 int offset;
141 offset = INSIZE(lookup);
142 insize = max_t(unsigned int, offset + length +1, OUTSIZE(lookup));
143 UPARG(CODA_LOOKUP);
145 inp->coda_lookup.VFid = *fid;
146 inp->coda_lookup.name = offset;
147 inp->coda_lookup.flags = CLU_CASE_SENSITIVE;
148 /* send Venus a null terminated string */
149 memcpy((char *)(inp) + offset, name, length);
150 *((char *)inp + offset + length) = '\0';
152 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
153 if (!error) {
154 *resfid = outp->coda_lookup.VFid;
155 *type = outp->coda_lookup.vtype;
158 CODA_FREE(inp, insize);
159 return error;
162 int venus_store(struct super_block *sb, struct CodaFid *fid, int flags,
163 vuid_t uid)
165 union inputArgs *inp;
166 union outputArgs *outp;
167 int insize, outsize, error;
168 #ifdef CONFIG_CODA_FS_OLD_API
169 struct coda_cred cred = { 0, };
170 cred.cr_fsuid = uid;
171 #endif
173 insize = SIZE(store);
174 UPARG(CODA_STORE);
176 #ifdef CONFIG_CODA_FS_OLD_API
177 memcpy(&(inp->ih.cred), &cred, sizeof(cred));
178 #else
179 inp->ih.uid = uid;
180 #endif
182 inp->coda_store.VFid = *fid;
183 inp->coda_store.flags = flags;
185 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
187 CODA_FREE(inp, insize);
188 return error;
191 int venus_release(struct super_block *sb, struct CodaFid *fid, int flags)
193 union inputArgs *inp;
194 union outputArgs *outp;
195 int insize, outsize, error;
197 insize = SIZE(release);
198 UPARG(CODA_RELEASE);
200 inp->coda_release.VFid = *fid;
201 inp->coda_release.flags = flags;
203 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
205 CODA_FREE(inp, insize);
206 return error;
209 int venus_close(struct super_block *sb, struct CodaFid *fid, int flags,
210 vuid_t uid)
212 union inputArgs *inp;
213 union outputArgs *outp;
214 int insize, outsize, error;
215 #ifdef CONFIG_CODA_FS_OLD_API
216 struct coda_cred cred = { 0, };
217 cred.cr_fsuid = uid;
218 #endif
220 insize = SIZE(release);
221 UPARG(CODA_CLOSE);
223 #ifdef CONFIG_CODA_FS_OLD_API
224 memcpy(&(inp->ih.cred), &cred, sizeof(cred));
225 #else
226 inp->ih.uid = uid;
227 #endif
229 inp->coda_close.VFid = *fid;
230 inp->coda_close.flags = flags;
232 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
234 CODA_FREE(inp, insize);
235 return error;
238 int venus_open(struct super_block *sb, struct CodaFid *fid,
239 int flags, struct file **fh)
241 union inputArgs *inp;
242 union outputArgs *outp;
243 int insize, outsize, error;
245 insize = SIZE(open_by_fd);
246 UPARG(CODA_OPEN_BY_FD);
248 inp->coda_open_by_fd.VFid = *fid;
249 inp->coda_open_by_fd.flags = flags;
251 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
252 if (!error)
253 *fh = outp->coda_open_by_fd.fh;
255 CODA_FREE(inp, insize);
256 return error;
259 int venus_mkdir(struct super_block *sb, struct CodaFid *dirfid,
260 const char *name, int length,
261 struct CodaFid *newfid, struct coda_vattr *attrs)
263 union inputArgs *inp;
264 union outputArgs *outp;
265 int insize, outsize, error;
266 int offset;
268 offset = INSIZE(mkdir);
269 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(mkdir));
270 UPARG(CODA_MKDIR);
272 inp->coda_mkdir.VFid = *dirfid;
273 inp->coda_mkdir.attr = *attrs;
274 inp->coda_mkdir.name = offset;
275 /* Venus must get null terminated string */
276 memcpy((char *)(inp) + offset, name, length);
277 *((char *)inp + offset + length) = '\0';
279 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
280 if (!error) {
281 *attrs = outp->coda_mkdir.attr;
282 *newfid = outp->coda_mkdir.VFid;
285 CODA_FREE(inp, insize);
286 return error;
290 int venus_rename(struct super_block *sb, struct CodaFid *old_fid,
291 struct CodaFid *new_fid, size_t old_length,
292 size_t new_length, const char *old_name,
293 const char *new_name)
295 union inputArgs *inp;
296 union outputArgs *outp;
297 int insize, outsize, error;
298 int offset, s;
300 offset = INSIZE(rename);
301 insize = max_t(unsigned int, offset + new_length + old_length + 8,
302 OUTSIZE(rename));
303 UPARG(CODA_RENAME);
305 inp->coda_rename.sourceFid = *old_fid;
306 inp->coda_rename.destFid = *new_fid;
307 inp->coda_rename.srcname = offset;
309 /* Venus must receive an null terminated string */
310 s = ( old_length & ~0x3) +4; /* round up to word boundary */
311 memcpy((char *)(inp) + offset, old_name, old_length);
312 *((char *)inp + offset + old_length) = '\0';
314 /* another null terminated string for Venus */
315 offset += s;
316 inp->coda_rename.destname = offset;
317 s = ( new_length & ~0x3) +4; /* round up to word boundary */
318 memcpy((char *)(inp) + offset, new_name, new_length);
319 *((char *)inp + offset + new_length) = '\0';
321 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
323 CODA_FREE(inp, insize);
324 return error;
327 int venus_create(struct super_block *sb, struct CodaFid *dirfid,
328 const char *name, int length, int excl, int mode,
329 struct CodaFid *newfid, struct coda_vattr *attrs)
331 union inputArgs *inp;
332 union outputArgs *outp;
333 int insize, outsize, error;
334 int offset;
336 offset = INSIZE(create);
337 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(create));
338 UPARG(CODA_CREATE);
340 inp->coda_create.VFid = *dirfid;
341 inp->coda_create.attr.va_mode = mode;
342 inp->coda_create.excl = excl;
343 inp->coda_create.mode = mode;
344 inp->coda_create.name = offset;
346 /* Venus must get null terminated string */
347 memcpy((char *)(inp) + offset, name, length);
348 *((char *)inp + offset + length) = '\0';
350 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
351 if (!error) {
352 *attrs = outp->coda_create.attr;
353 *newfid = outp->coda_create.VFid;
356 CODA_FREE(inp, insize);
357 return error;
360 int venus_rmdir(struct super_block *sb, struct CodaFid *dirfid,
361 const char *name, int length)
363 union inputArgs *inp;
364 union outputArgs *outp;
365 int insize, outsize, error;
366 int offset;
368 offset = INSIZE(rmdir);
369 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(rmdir));
370 UPARG(CODA_RMDIR);
372 inp->coda_rmdir.VFid = *dirfid;
373 inp->coda_rmdir.name = offset;
374 memcpy((char *)(inp) + offset, name, length);
375 *((char *)inp + offset + length) = '\0';
377 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
379 CODA_FREE(inp, insize);
380 return error;
383 int venus_remove(struct super_block *sb, struct CodaFid *dirfid,
384 const char *name, int length)
386 union inputArgs *inp;
387 union outputArgs *outp;
388 int error=0, insize, outsize, offset;
390 offset = INSIZE(remove);
391 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(remove));
392 UPARG(CODA_REMOVE);
394 inp->coda_remove.VFid = *dirfid;
395 inp->coda_remove.name = offset;
396 memcpy((char *)(inp) + offset, name, length);
397 *((char *)inp + offset + length) = '\0';
399 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
401 CODA_FREE(inp, insize);
402 return error;
405 int venus_readlink(struct super_block *sb, struct CodaFid *fid,
406 char *buffer, int *length)
408 union inputArgs *inp;
409 union outputArgs *outp;
410 int insize, outsize, error;
411 int retlen;
412 char *result;
414 insize = max_t(unsigned int,
415 INSIZE(readlink), OUTSIZE(readlink)+ *length + 1);
416 UPARG(CODA_READLINK);
418 inp->coda_readlink.VFid = *fid;
420 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
421 if (!error) {
422 retlen = outp->coda_readlink.count;
423 if ( retlen > *length )
424 retlen = *length;
425 *length = retlen;
426 result = (char *)outp + (long)outp->coda_readlink.data;
427 memcpy(buffer, result, retlen);
428 *(buffer + retlen) = '\0';
431 CODA_FREE(inp, insize);
432 return error;
437 int venus_link(struct super_block *sb, struct CodaFid *fid,
438 struct CodaFid *dirfid, const char *name, int len )
440 union inputArgs *inp;
441 union outputArgs *outp;
442 int insize, outsize, error;
443 int offset;
445 offset = INSIZE(link);
446 insize = max_t(unsigned int, offset + len + 1, OUTSIZE(link));
447 UPARG(CODA_LINK);
449 inp->coda_link.sourceFid = *fid;
450 inp->coda_link.destFid = *dirfid;
451 inp->coda_link.tname = offset;
453 /* make sure strings are null terminated */
454 memcpy((char *)(inp) + offset, name, len);
455 *((char *)inp + offset + len) = '\0';
457 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
459 CODA_FREE(inp, insize);
460 return error;
463 int venus_symlink(struct super_block *sb, struct CodaFid *fid,
464 const char *name, int len,
465 const char *symname, int symlen)
467 union inputArgs *inp;
468 union outputArgs *outp;
469 int insize, outsize, error;
470 int offset, s;
472 offset = INSIZE(symlink);
473 insize = max_t(unsigned int, offset + len + symlen + 8, OUTSIZE(symlink));
474 UPARG(CODA_SYMLINK);
476 /* inp->coda_symlink.attr = *tva; XXXXXX */
477 inp->coda_symlink.VFid = *fid;
479 /* Round up to word boundary and null terminate */
480 inp->coda_symlink.srcname = offset;
481 s = ( symlen & ~0x3 ) + 4;
482 memcpy((char *)(inp) + offset, symname, symlen);
483 *((char *)inp + offset + symlen) = '\0';
485 /* Round up to word boundary and null terminate */
486 offset += s;
487 inp->coda_symlink.tname = offset;
488 s = (len & ~0x3) + 4;
489 memcpy((char *)(inp) + offset, name, len);
490 *((char *)inp + offset + len) = '\0';
492 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
494 CODA_FREE(inp, insize);
495 return error;
498 int venus_fsync(struct super_block *sb, struct CodaFid *fid)
500 union inputArgs *inp;
501 union outputArgs *outp;
502 int insize, outsize, error;
504 insize=SIZE(fsync);
505 UPARG(CODA_FSYNC);
507 inp->coda_fsync.VFid = *fid;
508 error = coda_upcall(coda_sbp(sb), sizeof(union inputArgs),
509 &outsize, inp);
511 CODA_FREE(inp, insize);
512 return error;
515 int venus_access(struct super_block *sb, struct CodaFid *fid, int mask)
517 union inputArgs *inp;
518 union outputArgs *outp;
519 int insize, outsize, error;
521 insize = SIZE(access);
522 UPARG(CODA_ACCESS);
524 inp->coda_access.VFid = *fid;
525 inp->coda_access.flags = mask;
527 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
529 CODA_FREE(inp, insize);
530 return error;
534 int venus_pioctl(struct super_block *sb, struct CodaFid *fid,
535 unsigned int cmd, struct PioctlData *data)
537 union inputArgs *inp;
538 union outputArgs *outp;
539 int insize, outsize, error;
540 int iocsize;
542 insize = VC_MAXMSGSIZE;
543 UPARG(CODA_IOCTL);
545 /* build packet for Venus */
546 if (data->vi.in_size > VC_MAXDATASIZE) {
547 error = -EINVAL;
548 goto exit;
551 if (data->vi.out_size > VC_MAXDATASIZE) {
552 error = -EINVAL;
553 goto exit;
556 inp->coda_ioctl.VFid = *fid;
558 /* the cmd field was mutated by increasing its size field to
559 * reflect the path and follow args. We need to subtract that
560 * out before sending the command to Venus. */
561 inp->coda_ioctl.cmd = (cmd & ~(PIOCPARM_MASK << 16));
562 iocsize = ((cmd >> 16) & PIOCPARM_MASK) - sizeof(char *) - sizeof(int);
563 inp->coda_ioctl.cmd |= (iocsize & PIOCPARM_MASK) << 16;
565 /* in->coda_ioctl.rwflag = flag; */
566 inp->coda_ioctl.len = data->vi.in_size;
567 inp->coda_ioctl.data = (char *)(INSIZE(ioctl));
569 /* get the data out of user space */
570 if ( copy_from_user((char*)inp + (long)inp->coda_ioctl.data,
571 data->vi.in, data->vi.in_size) ) {
572 error = -EINVAL;
573 goto exit;
576 error = coda_upcall(coda_sbp(sb), SIZE(ioctl) + data->vi.in_size,
577 &outsize, inp);
579 if (error) {
580 printk("coda_pioctl: Venus returns: %d for %s\n",
581 error, coda_f2s(fid));
582 goto exit;
585 if (outsize < (long)outp->coda_ioctl.data + outp->coda_ioctl.len) {
586 error = -EINVAL;
587 goto exit;
590 /* Copy out the OUT buffer. */
591 if (outp->coda_ioctl.len > data->vi.out_size) {
592 error = -EINVAL;
593 goto exit;
596 /* Copy out the OUT buffer. */
597 if (copy_to_user(data->vi.out,
598 (char *)outp + (long)outp->coda_ioctl.data,
599 outp->coda_ioctl.len)) {
600 error = -EFAULT;
601 goto exit;
604 exit:
605 CODA_FREE(inp, insize);
606 return error;
609 int venus_statfs(struct dentry *dentry, struct kstatfs *sfs)
611 union inputArgs *inp;
612 union outputArgs *outp;
613 int insize, outsize, error;
615 insize = max_t(unsigned int, INSIZE(statfs), OUTSIZE(statfs));
616 UPARG(CODA_STATFS);
618 error = coda_upcall(coda_sbp(dentry->d_sb), insize, &outsize, inp);
619 if (!error) {
620 sfs->f_blocks = outp->coda_statfs.stat.f_blocks;
621 sfs->f_bfree = outp->coda_statfs.stat.f_bfree;
622 sfs->f_bavail = outp->coda_statfs.stat.f_bavail;
623 sfs->f_files = outp->coda_statfs.stat.f_files;
624 sfs->f_ffree = outp->coda_statfs.stat.f_ffree;
627 CODA_FREE(inp, insize);
628 return error;
632 * coda_upcall and coda_downcall routines.
634 static void block_signals(sigset_t *old)
636 spin_lock_irq(&current->sighand->siglock);
637 *old = current->blocked;
639 sigfillset(&current->blocked);
640 sigdelset(&current->blocked, SIGKILL);
641 sigdelset(&current->blocked, SIGSTOP);
642 sigdelset(&current->blocked, SIGINT);
644 recalc_sigpending();
645 spin_unlock_irq(&current->sighand->siglock);
648 static void unblock_signals(sigset_t *old)
650 spin_lock_irq(&current->sighand->siglock);
651 current->blocked = *old;
652 recalc_sigpending();
653 spin_unlock_irq(&current->sighand->siglock);
656 /* Don't allow signals to interrupt the following upcalls before venus
657 * has seen them,
658 * - CODA_CLOSE or CODA_RELEASE upcall (to avoid reference count problems)
659 * - CODA_STORE (to avoid data loss)
661 #define CODA_INTERRUPTIBLE(r) (!coda_hard && \
662 (((r)->uc_opcode != CODA_CLOSE && \
663 (r)->uc_opcode != CODA_STORE && \
664 (r)->uc_opcode != CODA_RELEASE) || \
665 (r)->uc_flags & REQ_READ))
667 static inline void coda_waitfor_upcall(struct upc_req *req)
669 DECLARE_WAITQUEUE(wait, current);
670 unsigned long timeout = jiffies + coda_timeout * HZ;
671 sigset_t old;
672 int blocked;
674 block_signals(&old);
675 blocked = 1;
677 add_wait_queue(&req->uc_sleep, &wait);
678 for (;;) {
679 if (CODA_INTERRUPTIBLE(req))
680 set_current_state(TASK_INTERRUPTIBLE);
681 else
682 set_current_state(TASK_UNINTERRUPTIBLE);
684 /* got a reply */
685 if (req->uc_flags & (REQ_WRITE | REQ_ABORT))
686 break;
688 if (blocked && time_after(jiffies, timeout) &&
689 CODA_INTERRUPTIBLE(req))
691 unblock_signals(&old);
692 blocked = 0;
695 if (signal_pending(current)) {
696 list_del(&req->uc_chain);
697 break;
700 if (blocked)
701 schedule_timeout(HZ);
702 else
703 schedule();
705 if (blocked)
706 unblock_signals(&old);
708 remove_wait_queue(&req->uc_sleep, &wait);
709 set_current_state(TASK_RUNNING);
714 * coda_upcall will return an error in the case of
715 * failed communication with Venus _or_ will peek at Venus
716 * reply and return Venus' error.
718 * As venus has 2 types of errors, normal errors (positive) and internal
719 * errors (negative), normal errors are negated, while internal errors
720 * are all mapped to -EINTR, while showing a nice warning message. (jh)
723 static int coda_upcall(struct coda_sb_info *sbi,
724 int inSize, int *outSize,
725 union inputArgs *buffer)
727 struct venus_comm *vcommp;
728 union outputArgs *out;
729 union inputArgs *sig_inputArgs;
730 struct upc_req *req, *sig_req;
731 int error = 0;
733 vcommp = sbi->sbi_vcomm;
734 if (!vcommp->vc_inuse) {
735 printk(KERN_NOTICE "coda: Venus dead, not sending upcall\n");
736 return -ENXIO;
739 /* Format the request message. */
740 req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
741 if (!req)
742 return -ENOMEM;
744 req->uc_data = (void *)buffer;
745 req->uc_flags = 0;
746 req->uc_inSize = inSize;
747 req->uc_outSize = *outSize ? *outSize : inSize;
748 req->uc_opcode = ((union inputArgs *)buffer)->ih.opcode;
749 req->uc_unique = ++vcommp->vc_seq;
750 init_waitqueue_head(&req->uc_sleep);
752 /* Fill in the common input args. */
753 ((union inputArgs *)buffer)->ih.unique = req->uc_unique;
755 /* Append msg to pending queue and poke Venus. */
756 list_add_tail(&req->uc_chain, &vcommp->vc_pending);
758 wake_up_interruptible(&vcommp->vc_waitq);
759 /* We can be interrupted while we wait for Venus to process
760 * our request. If the interrupt occurs before Venus has read
761 * the request, we dequeue and return. If it occurs after the
762 * read but before the reply, we dequeue, send a signal
763 * message, and return. If it occurs after the reply we ignore
764 * it. In no case do we want to restart the syscall. If it
765 * was interrupted by a venus shutdown (psdev_close), return
766 * ENODEV. */
768 /* Go to sleep. Wake up on signals only after the timeout. */
769 coda_waitfor_upcall(req);
771 /* Op went through, interrupt or not... */
772 if (req->uc_flags & REQ_WRITE) {
773 out = (union outputArgs *)req->uc_data;
774 /* here we map positive Venus errors to kernel errors */
775 error = -out->oh.result;
776 *outSize = req->uc_outSize;
777 goto exit;
780 error = -EINTR;
781 if ((req->uc_flags & REQ_ABORT) || !signal_pending(current)) {
782 printk(KERN_WARNING "coda: Unexpected interruption.\n");
783 goto exit;
786 /* Interrupted before venus read it. */
787 if (!(req->uc_flags & REQ_READ))
788 goto exit;
790 /* Venus saw the upcall, make sure we can send interrupt signal */
791 if (!vcommp->vc_inuse) {
792 printk(KERN_INFO "coda: Venus dead, not sending signal.\n");
793 goto exit;
796 error = -ENOMEM;
797 sig_req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
798 if (!sig_req) goto exit;
800 CODA_ALLOC((sig_req->uc_data), char *, sizeof(struct coda_in_hdr));
801 if (!sig_req->uc_data) {
802 kfree(sig_req);
803 goto exit;
806 error = -EINTR;
807 sig_inputArgs = (union inputArgs *)sig_req->uc_data;
808 sig_inputArgs->ih.opcode = CODA_SIGNAL;
809 sig_inputArgs->ih.unique = req->uc_unique;
811 sig_req->uc_flags = REQ_ASYNC;
812 sig_req->uc_opcode = sig_inputArgs->ih.opcode;
813 sig_req->uc_unique = sig_inputArgs->ih.unique;
814 sig_req->uc_inSize = sizeof(struct coda_in_hdr);
815 sig_req->uc_outSize = sizeof(struct coda_in_hdr);
817 /* insert at head of queue! */
818 list_add(&(sig_req->uc_chain), &vcommp->vc_pending);
819 wake_up_interruptible(&vcommp->vc_waitq);
821 exit:
822 kfree(req);
823 return error;
827 The statements below are part of the Coda opportunistic
828 programming -- taken from the Mach/BSD kernel code for Coda.
829 You don't get correct semantics by stating what needs to be
830 done without guaranteeing the invariants needed for it to happen.
831 When will be have time to find out what exactly is going on? (pjb)
836 * There are 7 cases where cache invalidations occur. The semantics
837 * of each is listed here:
839 * CODA_FLUSH -- flush all entries from the name cache and the cnode cache.
840 * CODA_PURGEUSER -- flush all entries from the name cache for a specific user
841 * This call is a result of token expiration.
843 * The next arise as the result of callbacks on a file or directory.
844 * CODA_ZAPFILE -- flush the cached attributes for a file.
846 * CODA_ZAPDIR -- flush the attributes for the dir and
847 * force a new lookup for all the children
848 of this dir.
851 * The next is a result of Venus detecting an inconsistent file.
852 * CODA_PURGEFID -- flush the attribute for the file
853 * purge it and its children from the dcache
855 * The last allows Venus to replace local fids with global ones
856 * during reintegration.
858 * CODA_REPLACE -- replace one CodaFid with another throughout the name cache */
860 int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
862 /* Handle invalidation requests. */
863 if ( !sb || !sb->s_root || !sb->s_root->d_inode)
864 return 0;
866 switch (opcode) {
868 case CODA_FLUSH : {
869 coda_cache_clear_all(sb);
870 shrink_dcache_sb(sb);
871 coda_flag_inode(sb->s_root->d_inode, C_FLUSH);
872 return(0);
875 case CODA_PURGEUSER : {
876 coda_cache_clear_all(sb);
877 return(0);
880 case CODA_ZAPDIR : {
881 struct inode *inode;
882 struct CodaFid *fid = &out->coda_zapdir.CodaFid;
884 inode = coda_fid_to_inode(fid, sb);
885 if (inode) {
886 coda_flag_inode_children(inode, C_PURGE);
887 coda_flag_inode(inode, C_VATTR);
888 iput(inode);
891 return(0);
894 case CODA_ZAPFILE : {
895 struct inode *inode;
896 struct CodaFid *fid = &out->coda_zapfile.CodaFid;
897 inode = coda_fid_to_inode(fid, sb);
898 if ( inode ) {
899 coda_flag_inode(inode, C_VATTR);
900 iput(inode);
902 return 0;
905 case CODA_PURGEFID : {
906 struct inode *inode;
907 struct CodaFid *fid = &out->coda_purgefid.CodaFid;
908 inode = coda_fid_to_inode(fid, sb);
909 if ( inode ) {
910 coda_flag_inode_children(inode, C_PURGE);
912 /* catch the dentries later if some are still busy */
913 coda_flag_inode(inode, C_PURGE);
914 d_prune_aliases(inode);
916 iput(inode);
918 return 0;
921 case CODA_REPLACE : {
922 struct inode *inode;
923 struct CodaFid *oldfid = &out->coda_replace.OldFid;
924 struct CodaFid *newfid = &out->coda_replace.NewFid;
925 inode = coda_fid_to_inode(oldfid, sb);
926 if ( inode ) {
927 coda_replace_fid(inode, oldfid, newfid);
928 iput(inode);
930 return 0;
933 return 0;