IB/mlx4: Fix error path in create_qp_common()
[linux-2.6/zen-sources.git] / fs / coda / upcall.c
blobcd561d2e90b05723dfd611ae6604ca2a895695cf
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>
39 #include "coda_int.h"
41 static int coda_upcall(struct venus_comm *vc, int inSize, int *outSize,
42 union inputArgs *buffer);
44 static void *alloc_upcall(int opcode, int size)
46 union inputArgs *inp;
48 CODA_ALLOC(inp, union inputArgs *, size);
49 if (!inp)
50 return ERR_PTR(-ENOMEM);
52 inp->ih.opcode = opcode;
53 inp->ih.pid = current->pid;
54 inp->ih.pgid = process_group(current);
55 #ifdef CONFIG_CODA_FS_OLD_API
56 memset(&inp->ih.cred, 0, sizeof(struct coda_cred));
57 inp->ih.cred.cr_fsuid = current->fsuid;
58 #else
59 inp->ih.uid = current->fsuid;
60 #endif
61 return (void*)inp;
64 #define UPARG(op)\
65 do {\
66 inp = (union inputArgs *)alloc_upcall(op, insize); \
67 if (IS_ERR(inp)) { return PTR_ERR(inp); }\
68 outp = (union outputArgs *)(inp); \
69 outsize = insize; \
70 } while (0)
72 #define INSIZE(tag) sizeof(struct coda_ ## tag ## _in)
73 #define OUTSIZE(tag) sizeof(struct coda_ ## tag ## _out)
74 #define SIZE(tag) max_t(unsigned int, INSIZE(tag), OUTSIZE(tag))
77 /* the upcalls */
78 int venus_rootfid(struct super_block *sb, struct CodaFid *fidp)
80 union inputArgs *inp;
81 union outputArgs *outp;
82 int insize, outsize, error;
84 insize = SIZE(root);
85 UPARG(CODA_ROOT);
87 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
88 if (!error)
89 *fidp = outp->coda_root.VFid;
91 CODA_FREE(inp, insize);
92 return error;
95 int venus_getattr(struct super_block *sb, struct CodaFid *fid,
96 struct coda_vattr *attr)
98 union inputArgs *inp;
99 union outputArgs *outp;
100 int insize, outsize, error;
102 insize = SIZE(getattr);
103 UPARG(CODA_GETATTR);
104 inp->coda_getattr.VFid = *fid;
106 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
107 if (!error)
108 *attr = outp->coda_getattr.attr;
110 CODA_FREE(inp, insize);
111 return error;
114 int venus_setattr(struct super_block *sb, struct CodaFid *fid,
115 struct coda_vattr *vattr)
117 union inputArgs *inp;
118 union outputArgs *outp;
119 int insize, outsize, error;
121 insize = SIZE(setattr);
122 UPARG(CODA_SETATTR);
124 inp->coda_setattr.VFid = *fid;
125 inp->coda_setattr.attr = *vattr;
127 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
129 CODA_FREE(inp, insize);
130 return error;
133 int venus_lookup(struct super_block *sb, struct CodaFid *fid,
134 const char *name, int length, int * type,
135 struct CodaFid *resfid)
137 union inputArgs *inp;
138 union outputArgs *outp;
139 int insize, outsize, error;
140 int offset;
142 offset = INSIZE(lookup);
143 insize = max_t(unsigned int, offset + length +1, OUTSIZE(lookup));
144 UPARG(CODA_LOOKUP);
146 inp->coda_lookup.VFid = *fid;
147 inp->coda_lookup.name = offset;
148 inp->coda_lookup.flags = CLU_CASE_SENSITIVE;
149 /* send Venus a null terminated string */
150 memcpy((char *)(inp) + offset, name, length);
151 *((char *)inp + offset + length) = '\0';
153 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
154 if (!error) {
155 *resfid = outp->coda_lookup.VFid;
156 *type = outp->coda_lookup.vtype;
159 CODA_FREE(inp, insize);
160 return error;
163 int venus_store(struct super_block *sb, struct CodaFid *fid, int flags,
164 vuid_t uid)
166 union inputArgs *inp;
167 union outputArgs *outp;
168 int insize, outsize, error;
169 #ifdef CONFIG_CODA_FS_OLD_API
170 struct coda_cred cred = { 0, };
171 cred.cr_fsuid = uid;
172 #endif
174 insize = SIZE(store);
175 UPARG(CODA_STORE);
177 #ifdef CONFIG_CODA_FS_OLD_API
178 memcpy(&(inp->ih.cred), &cred, sizeof(cred));
179 #else
180 inp->ih.uid = uid;
181 #endif
183 inp->coda_store.VFid = *fid;
184 inp->coda_store.flags = flags;
186 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
188 CODA_FREE(inp, insize);
189 return error;
192 int venus_release(struct super_block *sb, struct CodaFid *fid, int flags)
194 union inputArgs *inp;
195 union outputArgs *outp;
196 int insize, outsize, error;
198 insize = SIZE(release);
199 UPARG(CODA_RELEASE);
201 inp->coda_release.VFid = *fid;
202 inp->coda_release.flags = flags;
204 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
206 CODA_FREE(inp, insize);
207 return error;
210 int venus_close(struct super_block *sb, struct CodaFid *fid, int flags,
211 vuid_t uid)
213 union inputArgs *inp;
214 union outputArgs *outp;
215 int insize, outsize, error;
216 #ifdef CONFIG_CODA_FS_OLD_API
217 struct coda_cred cred = { 0, };
218 cred.cr_fsuid = uid;
219 #endif
221 insize = SIZE(release);
222 UPARG(CODA_CLOSE);
224 #ifdef CONFIG_CODA_FS_OLD_API
225 memcpy(&(inp->ih.cred), &cred, sizeof(cred));
226 #else
227 inp->ih.uid = uid;
228 #endif
230 inp->coda_close.VFid = *fid;
231 inp->coda_close.flags = flags;
233 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
235 CODA_FREE(inp, insize);
236 return error;
239 int venus_open(struct super_block *sb, struct CodaFid *fid,
240 int flags, struct file **fh)
242 union inputArgs *inp;
243 union outputArgs *outp;
244 int insize, outsize, error;
246 insize = SIZE(open_by_fd);
247 UPARG(CODA_OPEN_BY_FD);
249 inp->coda_open_by_fd.VFid = *fid;
250 inp->coda_open_by_fd.flags = flags;
252 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
253 if (!error)
254 *fh = outp->coda_open_by_fd.fh;
256 CODA_FREE(inp, insize);
257 return error;
260 int venus_mkdir(struct super_block *sb, struct CodaFid *dirfid,
261 const char *name, int length,
262 struct CodaFid *newfid, struct coda_vattr *attrs)
264 union inputArgs *inp;
265 union outputArgs *outp;
266 int insize, outsize, error;
267 int offset;
269 offset = INSIZE(mkdir);
270 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(mkdir));
271 UPARG(CODA_MKDIR);
273 inp->coda_mkdir.VFid = *dirfid;
274 inp->coda_mkdir.attr = *attrs;
275 inp->coda_mkdir.name = offset;
276 /* Venus must get null terminated string */
277 memcpy((char *)(inp) + offset, name, length);
278 *((char *)inp + offset + length) = '\0';
280 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
281 if (!error) {
282 *attrs = outp->coda_mkdir.attr;
283 *newfid = outp->coda_mkdir.VFid;
286 CODA_FREE(inp, insize);
287 return error;
291 int venus_rename(struct super_block *sb, struct CodaFid *old_fid,
292 struct CodaFid *new_fid, size_t old_length,
293 size_t new_length, const char *old_name,
294 const char *new_name)
296 union inputArgs *inp;
297 union outputArgs *outp;
298 int insize, outsize, error;
299 int offset, s;
301 offset = INSIZE(rename);
302 insize = max_t(unsigned int, offset + new_length + old_length + 8,
303 OUTSIZE(rename));
304 UPARG(CODA_RENAME);
306 inp->coda_rename.sourceFid = *old_fid;
307 inp->coda_rename.destFid = *new_fid;
308 inp->coda_rename.srcname = offset;
310 /* Venus must receive an null terminated string */
311 s = ( old_length & ~0x3) +4; /* round up to word boundary */
312 memcpy((char *)(inp) + offset, old_name, old_length);
313 *((char *)inp + offset + old_length) = '\0';
315 /* another null terminated string for Venus */
316 offset += s;
317 inp->coda_rename.destname = offset;
318 s = ( new_length & ~0x3) +4; /* round up to word boundary */
319 memcpy((char *)(inp) + offset, new_name, new_length);
320 *((char *)inp + offset + new_length) = '\0';
322 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
324 CODA_FREE(inp, insize);
325 return error;
328 int venus_create(struct super_block *sb, struct CodaFid *dirfid,
329 const char *name, int length, int excl, int mode,
330 struct CodaFid *newfid, struct coda_vattr *attrs)
332 union inputArgs *inp;
333 union outputArgs *outp;
334 int insize, outsize, error;
335 int offset;
337 offset = INSIZE(create);
338 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(create));
339 UPARG(CODA_CREATE);
341 inp->coda_create.VFid = *dirfid;
342 inp->coda_create.attr.va_mode = mode;
343 inp->coda_create.excl = excl;
344 inp->coda_create.mode = mode;
345 inp->coda_create.name = offset;
347 /* Venus must get null terminated string */
348 memcpy((char *)(inp) + offset, name, length);
349 *((char *)inp + offset + length) = '\0';
351 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
352 if (!error) {
353 *attrs = outp->coda_create.attr;
354 *newfid = outp->coda_create.VFid;
357 CODA_FREE(inp, insize);
358 return error;
361 int venus_rmdir(struct super_block *sb, struct CodaFid *dirfid,
362 const char *name, int length)
364 union inputArgs *inp;
365 union outputArgs *outp;
366 int insize, outsize, error;
367 int offset;
369 offset = INSIZE(rmdir);
370 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(rmdir));
371 UPARG(CODA_RMDIR);
373 inp->coda_rmdir.VFid = *dirfid;
374 inp->coda_rmdir.name = offset;
375 memcpy((char *)(inp) + offset, name, length);
376 *((char *)inp + offset + length) = '\0';
378 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
380 CODA_FREE(inp, insize);
381 return error;
384 int venus_remove(struct super_block *sb, struct CodaFid *dirfid,
385 const char *name, int length)
387 union inputArgs *inp;
388 union outputArgs *outp;
389 int error=0, insize, outsize, offset;
391 offset = INSIZE(remove);
392 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(remove));
393 UPARG(CODA_REMOVE);
395 inp->coda_remove.VFid = *dirfid;
396 inp->coda_remove.name = offset;
397 memcpy((char *)(inp) + offset, name, length);
398 *((char *)inp + offset + length) = '\0';
400 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
402 CODA_FREE(inp, insize);
403 return error;
406 int venus_readlink(struct super_block *sb, struct CodaFid *fid,
407 char *buffer, int *length)
409 union inputArgs *inp;
410 union outputArgs *outp;
411 int insize, outsize, error;
412 int retlen;
413 char *result;
415 insize = max_t(unsigned int,
416 INSIZE(readlink), OUTSIZE(readlink)+ *length + 1);
417 UPARG(CODA_READLINK);
419 inp->coda_readlink.VFid = *fid;
421 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
422 if (!error) {
423 retlen = outp->coda_readlink.count;
424 if ( retlen > *length )
425 retlen = *length;
426 *length = retlen;
427 result = (char *)outp + (long)outp->coda_readlink.data;
428 memcpy(buffer, result, retlen);
429 *(buffer + retlen) = '\0';
432 CODA_FREE(inp, insize);
433 return error;
438 int venus_link(struct super_block *sb, struct CodaFid *fid,
439 struct CodaFid *dirfid, const char *name, int len )
441 union inputArgs *inp;
442 union outputArgs *outp;
443 int insize, outsize, error;
444 int offset;
446 offset = INSIZE(link);
447 insize = max_t(unsigned int, offset + len + 1, OUTSIZE(link));
448 UPARG(CODA_LINK);
450 inp->coda_link.sourceFid = *fid;
451 inp->coda_link.destFid = *dirfid;
452 inp->coda_link.tname = offset;
454 /* make sure strings are null terminated */
455 memcpy((char *)(inp) + offset, name, len);
456 *((char *)inp + offset + len) = '\0';
458 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
460 CODA_FREE(inp, insize);
461 return error;
464 int venus_symlink(struct super_block *sb, struct CodaFid *fid,
465 const char *name, int len,
466 const char *symname, int symlen)
468 union inputArgs *inp;
469 union outputArgs *outp;
470 int insize, outsize, error;
471 int offset, s;
473 offset = INSIZE(symlink);
474 insize = max_t(unsigned int, offset + len + symlen + 8, OUTSIZE(symlink));
475 UPARG(CODA_SYMLINK);
477 /* inp->coda_symlink.attr = *tva; XXXXXX */
478 inp->coda_symlink.VFid = *fid;
480 /* Round up to word boundary and null terminate */
481 inp->coda_symlink.srcname = offset;
482 s = ( symlen & ~0x3 ) + 4;
483 memcpy((char *)(inp) + offset, symname, symlen);
484 *((char *)inp + offset + symlen) = '\0';
486 /* Round up to word boundary and null terminate */
487 offset += s;
488 inp->coda_symlink.tname = offset;
489 s = (len & ~0x3) + 4;
490 memcpy((char *)(inp) + offset, name, len);
491 *((char *)inp + offset + len) = '\0';
493 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
495 CODA_FREE(inp, insize);
496 return error;
499 int venus_fsync(struct super_block *sb, struct CodaFid *fid)
501 union inputArgs *inp;
502 union outputArgs *outp;
503 int insize, outsize, error;
505 insize=SIZE(fsync);
506 UPARG(CODA_FSYNC);
508 inp->coda_fsync.VFid = *fid;
509 error = coda_upcall(coda_vcp(sb), sizeof(union inputArgs),
510 &outsize, inp);
512 CODA_FREE(inp, insize);
513 return error;
516 int venus_access(struct super_block *sb, struct CodaFid *fid, int mask)
518 union inputArgs *inp;
519 union outputArgs *outp;
520 int insize, outsize, error;
522 insize = SIZE(access);
523 UPARG(CODA_ACCESS);
525 inp->coda_access.VFid = *fid;
526 inp->coda_access.flags = mask;
528 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
530 CODA_FREE(inp, insize);
531 return error;
535 int venus_pioctl(struct super_block *sb, struct CodaFid *fid,
536 unsigned int cmd, struct PioctlData *data)
538 union inputArgs *inp;
539 union outputArgs *outp;
540 int insize, outsize, error;
541 int iocsize;
543 insize = VC_MAXMSGSIZE;
544 UPARG(CODA_IOCTL);
546 /* build packet for Venus */
547 if (data->vi.in_size > VC_MAXDATASIZE) {
548 error = -EINVAL;
549 goto exit;
552 if (data->vi.out_size > VC_MAXDATASIZE) {
553 error = -EINVAL;
554 goto exit;
557 inp->coda_ioctl.VFid = *fid;
559 /* the cmd field was mutated by increasing its size field to
560 * reflect the path and follow args. We need to subtract that
561 * out before sending the command to Venus. */
562 inp->coda_ioctl.cmd = (cmd & ~(PIOCPARM_MASK << 16));
563 iocsize = ((cmd >> 16) & PIOCPARM_MASK) - sizeof(char *) - sizeof(int);
564 inp->coda_ioctl.cmd |= (iocsize & PIOCPARM_MASK) << 16;
566 /* in->coda_ioctl.rwflag = flag; */
567 inp->coda_ioctl.len = data->vi.in_size;
568 inp->coda_ioctl.data = (char *)(INSIZE(ioctl));
570 /* get the data out of user space */
571 if ( copy_from_user((char*)inp + (long)inp->coda_ioctl.data,
572 data->vi.in, data->vi.in_size) ) {
573 error = -EINVAL;
574 goto exit;
577 error = coda_upcall(coda_vcp(sb), SIZE(ioctl) + data->vi.in_size,
578 &outsize, inp);
580 if (error) {
581 printk("coda_pioctl: Venus returns: %d for %s\n",
582 error, coda_f2s(fid));
583 goto exit;
586 if (outsize < (long)outp->coda_ioctl.data + outp->coda_ioctl.len) {
587 error = -EINVAL;
588 goto exit;
591 /* Copy out the OUT buffer. */
592 if (outp->coda_ioctl.len > data->vi.out_size) {
593 error = -EINVAL;
594 goto exit;
597 /* Copy out the OUT buffer. */
598 if (copy_to_user(data->vi.out,
599 (char *)outp + (long)outp->coda_ioctl.data,
600 outp->coda_ioctl.len)) {
601 error = -EFAULT;
602 goto exit;
605 exit:
606 CODA_FREE(inp, insize);
607 return error;
610 int venus_statfs(struct dentry *dentry, struct kstatfs *sfs)
612 union inputArgs *inp;
613 union outputArgs *outp;
614 int insize, outsize, error;
616 insize = max_t(unsigned int, INSIZE(statfs), OUTSIZE(statfs));
617 UPARG(CODA_STATFS);
619 error = coda_upcall(coda_vcp(dentry->d_sb), insize, &outsize, inp);
620 if (!error) {
621 sfs->f_blocks = outp->coda_statfs.stat.f_blocks;
622 sfs->f_bfree = outp->coda_statfs.stat.f_bfree;
623 sfs->f_bavail = outp->coda_statfs.stat.f_bavail;
624 sfs->f_files = outp->coda_statfs.stat.f_files;
625 sfs->f_ffree = outp->coda_statfs.stat.f_ffree;
628 CODA_FREE(inp, insize);
629 return error;
633 * coda_upcall and coda_downcall routines.
635 static void coda_block_signals(sigset_t *old)
637 spin_lock_irq(&current->sighand->siglock);
638 *old = current->blocked;
640 sigfillset(&current->blocked);
641 sigdelset(&current->blocked, SIGKILL);
642 sigdelset(&current->blocked, SIGSTOP);
643 sigdelset(&current->blocked, SIGINT);
645 recalc_sigpending();
646 spin_unlock_irq(&current->sighand->siglock);
649 static void coda_unblock_signals(sigset_t *old)
651 spin_lock_irq(&current->sighand->siglock);
652 current->blocked = *old;
653 recalc_sigpending();
654 spin_unlock_irq(&current->sighand->siglock);
657 /* Don't allow signals to interrupt the following upcalls before venus
658 * has seen them,
659 * - CODA_CLOSE or CODA_RELEASE upcall (to avoid reference count problems)
660 * - CODA_STORE (to avoid data loss)
662 #define CODA_INTERRUPTIBLE(r) (!coda_hard && \
663 (((r)->uc_opcode != CODA_CLOSE && \
664 (r)->uc_opcode != CODA_STORE && \
665 (r)->uc_opcode != CODA_RELEASE) || \
666 (r)->uc_flags & REQ_READ))
668 static inline void coda_waitfor_upcall(struct upc_req *req)
670 DECLARE_WAITQUEUE(wait, current);
671 unsigned long timeout = jiffies + coda_timeout * HZ;
672 sigset_t old;
673 int blocked;
675 coda_block_signals(&old);
676 blocked = 1;
678 add_wait_queue(&req->uc_sleep, &wait);
679 for (;;) {
680 if (CODA_INTERRUPTIBLE(req))
681 set_current_state(TASK_INTERRUPTIBLE);
682 else
683 set_current_state(TASK_UNINTERRUPTIBLE);
685 /* got a reply */
686 if (req->uc_flags & (REQ_WRITE | REQ_ABORT))
687 break;
689 if (blocked && time_after(jiffies, timeout) &&
690 CODA_INTERRUPTIBLE(req))
692 coda_unblock_signals(&old);
693 blocked = 0;
696 if (signal_pending(current)) {
697 list_del(&req->uc_chain);
698 break;
701 if (blocked)
702 schedule_timeout(HZ);
703 else
704 schedule();
706 if (blocked)
707 coda_unblock_signals(&old);
709 remove_wait_queue(&req->uc_sleep, &wait);
710 set_current_state(TASK_RUNNING);
715 * coda_upcall will return an error in the case of
716 * failed communication with Venus _or_ will peek at Venus
717 * reply and return Venus' error.
719 * As venus has 2 types of errors, normal errors (positive) and internal
720 * errors (negative), normal errors are negated, while internal errors
721 * are all mapped to -EINTR, while showing a nice warning message. (jh)
723 static int coda_upcall(struct venus_comm *vcp,
724 int inSize, int *outSize,
725 union inputArgs *buffer)
727 union outputArgs *out;
728 union inputArgs *sig_inputArgs;
729 struct upc_req *req, *sig_req;
730 int error = 0;
732 if (!vcp->vc_inuse) {
733 printk(KERN_NOTICE "coda: Venus dead, not sending upcall\n");
734 return -ENXIO;
737 /* Format the request message. */
738 req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
739 if (!req)
740 return -ENOMEM;
742 req->uc_data = (void *)buffer;
743 req->uc_flags = 0;
744 req->uc_inSize = inSize;
745 req->uc_outSize = *outSize ? *outSize : inSize;
746 req->uc_opcode = ((union inputArgs *)buffer)->ih.opcode;
747 req->uc_unique = ++vcp->vc_seq;
748 init_waitqueue_head(&req->uc_sleep);
750 /* Fill in the common input args. */
751 ((union inputArgs *)buffer)->ih.unique = req->uc_unique;
753 /* Append msg to pending queue and poke Venus. */
754 list_add_tail(&req->uc_chain, &vcp->vc_pending);
756 wake_up_interruptible(&vcp->vc_waitq);
757 /* We can be interrupted while we wait for Venus to process
758 * our request. If the interrupt occurs before Venus has read
759 * the request, we dequeue and return. If it occurs after the
760 * read but before the reply, we dequeue, send a signal
761 * message, and return. If it occurs after the reply we ignore
762 * it. In no case do we want to restart the syscall. If it
763 * was interrupted by a venus shutdown (psdev_close), return
764 * ENODEV. */
766 /* Go to sleep. Wake up on signals only after the timeout. */
767 coda_waitfor_upcall(req);
769 /* Op went through, interrupt or not... */
770 if (req->uc_flags & REQ_WRITE) {
771 out = (union outputArgs *)req->uc_data;
772 /* here we map positive Venus errors to kernel errors */
773 error = -out->oh.result;
774 *outSize = req->uc_outSize;
775 goto exit;
778 error = -EINTR;
779 if ((req->uc_flags & REQ_ABORT) || !signal_pending(current)) {
780 printk(KERN_WARNING "coda: Unexpected interruption.\n");
781 goto exit;
784 /* Interrupted before venus read it. */
785 if (!(req->uc_flags & REQ_READ))
786 goto exit;
788 /* Venus saw the upcall, make sure we can send interrupt signal */
789 if (!vcp->vc_inuse) {
790 printk(KERN_INFO "coda: Venus dead, not sending signal.\n");
791 goto exit;
794 error = -ENOMEM;
795 sig_req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
796 if (!sig_req) goto exit;
798 CODA_ALLOC((sig_req->uc_data), char *, sizeof(struct coda_in_hdr));
799 if (!sig_req->uc_data) {
800 kfree(sig_req);
801 goto exit;
804 error = -EINTR;
805 sig_inputArgs = (union inputArgs *)sig_req->uc_data;
806 sig_inputArgs->ih.opcode = CODA_SIGNAL;
807 sig_inputArgs->ih.unique = req->uc_unique;
809 sig_req->uc_flags = REQ_ASYNC;
810 sig_req->uc_opcode = sig_inputArgs->ih.opcode;
811 sig_req->uc_unique = sig_inputArgs->ih.unique;
812 sig_req->uc_inSize = sizeof(struct coda_in_hdr);
813 sig_req->uc_outSize = sizeof(struct coda_in_hdr);
815 /* insert at head of queue! */
816 list_add(&(sig_req->uc_chain), &vcp->vc_pending);
817 wake_up_interruptible(&vcp->vc_waitq);
819 exit:
820 kfree(req);
821 return error;
825 The statements below are part of the Coda opportunistic
826 programming -- taken from the Mach/BSD kernel code for Coda.
827 You don't get correct semantics by stating what needs to be
828 done without guaranteeing the invariants needed for it to happen.
829 When will be have time to find out what exactly is going on? (pjb)
834 * There are 7 cases where cache invalidations occur. The semantics
835 * of each is listed here:
837 * CODA_FLUSH -- flush all entries from the name cache and the cnode cache.
838 * CODA_PURGEUSER -- flush all entries from the name cache for a specific user
839 * This call is a result of token expiration.
841 * The next arise as the result of callbacks on a file or directory.
842 * CODA_ZAPFILE -- flush the cached attributes for a file.
844 * CODA_ZAPDIR -- flush the attributes for the dir and
845 * force a new lookup for all the children
846 of this dir.
849 * The next is a result of Venus detecting an inconsistent file.
850 * CODA_PURGEFID -- flush the attribute for the file
851 * purge it and its children from the dcache
853 * The last allows Venus to replace local fids with global ones
854 * during reintegration.
856 * CODA_REPLACE -- replace one CodaFid with another throughout the name cache */
858 int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
860 struct inode *inode = NULL;
861 struct CodaFid *fid, *newfid;
863 /* Handle invalidation requests. */
864 if ( !sb || !sb->s_root)
865 return 0;
867 switch (opcode) {
868 case CODA_FLUSH:
869 coda_cache_clear_all(sb);
870 shrink_dcache_sb(sb);
871 if (sb->s_root->d_inode)
872 coda_flag_inode(sb->s_root->d_inode, C_FLUSH);
873 break;
875 case CODA_PURGEUSER:
876 coda_cache_clear_all(sb);
877 break;
879 case CODA_ZAPDIR:
880 fid = &out->coda_zapdir.CodaFid;
881 inode = coda_fid_to_inode(fid, sb);
882 if (inode) {
883 coda_flag_inode_children(inode, C_PURGE);
884 coda_flag_inode(inode, C_VATTR);
886 break;
888 case CODA_ZAPFILE:
889 fid = &out->coda_zapfile.CodaFid;
890 inode = coda_fid_to_inode(fid, sb);
891 if (inode)
892 coda_flag_inode(inode, C_VATTR);
893 break;
895 case CODA_PURGEFID:
896 fid = &out->coda_purgefid.CodaFid;
897 inode = coda_fid_to_inode(fid, sb);
898 if (inode) {
899 coda_flag_inode_children(inode, C_PURGE);
901 /* catch the dentries later if some are still busy */
902 coda_flag_inode(inode, C_PURGE);
903 d_prune_aliases(inode);
906 break;
908 case CODA_REPLACE:
909 fid = &out->coda_replace.OldFid;
910 newfid = &out->coda_replace.NewFid;
911 inode = coda_fid_to_inode(fid, sb);
912 if (inode)
913 coda_replace_fid(inode, fid, newfid);
914 break;
917 if (inode)
918 iput(inode);
920 return 0;