coda: replace upc_alloc/upc_free with kmalloc/kfree
[linux-block.git] / fs / coda / upcall.c
CommitLineData
1da177e4
LT
1/*
2 * Mostly platform independent upcall operations to Venus:
3 * -- upcalls
4 * -- upcall routines
5 *
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
12 *
13 * Carnegie Mellon University encourages users of this code to contribute
14 * improvements to the Coda project. Contact Peter Braam <coda@cs.cmu.edu>.
15 */
16
17#include <asm/system.h>
18#include <linux/signal.h>
e8edc6e0 19#include <linux/sched.h>
1da177e4
LT
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>
32
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>
39
1da177e4
LT
40static int coda_upcall(struct coda_sb_info *mntinfo, int inSize, int *outSize,
41 union inputArgs *buffer);
42
43static void *alloc_upcall(int opcode, int size)
44{
45 union inputArgs *inp;
46
47 CODA_ALLOC(inp, union inputArgs *, size);
48 if (!inp)
49 return ERR_PTR(-ENOMEM);
50
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;
61}
62
63#define UPARG(op)\
64do {\
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)
70
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))
74
75
76/* the upcalls */
77int venus_rootfid(struct super_block *sb, struct CodaFid *fidp)
78{
79 union inputArgs *inp;
80 union outputArgs *outp;
81 int insize, outsize, error;
82
83 insize = SIZE(root);
84 UPARG(CODA_ROOT);
85
86 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
87
88 if (error) {
89 printk("coda_get_rootfid: error %d\n", error);
90 } else {
91 *fidp = outp->coda_root.VFid;
92 }
93
94 CODA_FREE(inp, insize);
95 return error;
96}
97
98int venus_getattr(struct super_block *sb, struct CodaFid *fid,
99 struct coda_vattr *attr)
100{
101 union inputArgs *inp;
102 union outputArgs *outp;
103 int insize, outsize, error;
104
105 insize = SIZE(getattr);
106 UPARG(CODA_GETATTR);
107 inp->coda_getattr.VFid = *fid;
108
109 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
110
111 *attr = outp->coda_getattr.attr;
112
113 CODA_FREE(inp, insize);
114 return error;
115}
116
117int venus_setattr(struct super_block *sb, struct CodaFid *fid,
118 struct coda_vattr *vattr)
119{
120 union inputArgs *inp;
121 union outputArgs *outp;
122 int insize, outsize, error;
123
124 insize = SIZE(setattr);
125 UPARG(CODA_SETATTR);
126
127 inp->coda_setattr.VFid = *fid;
128 inp->coda_setattr.attr = *vattr;
129
130 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
131
132 CODA_FREE(inp, insize);
133 return error;
134}
135
136int venus_lookup(struct super_block *sb, struct CodaFid *fid,
137 const char *name, int length, int * type,
138 struct CodaFid *resfid)
139{
140 union inputArgs *inp;
141 union outputArgs *outp;
142 int insize, outsize, error;
143 int offset;
144
145 offset = INSIZE(lookup);
146 insize = max_t(unsigned int, offset + length +1, OUTSIZE(lookup));
147 UPARG(CODA_LOOKUP);
148
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';
155
156 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
157
158 *resfid = outp->coda_lookup.VFid;
159 *type = outp->coda_lookup.vtype;
160
161 CODA_FREE(inp, insize);
162 return error;
163}
164
165int venus_store(struct super_block *sb, struct CodaFid *fid, int flags,
166 vuid_t uid)
167{
168 union inputArgs *inp;
169 union outputArgs *outp;
170 int insize, outsize, error;
171#ifdef CONFIG_CODA_FS_OLD_API
172 struct coda_cred cred = { 0, };
173 cred.cr_fsuid = uid;
174#endif
175
176 insize = SIZE(store);
177 UPARG(CODA_STORE);
178
179#ifdef CONFIG_CODA_FS_OLD_API
180 memcpy(&(inp->ih.cred), &cred, sizeof(cred));
181#else
182 inp->ih.uid = uid;
183#endif
184
185 inp->coda_store.VFid = *fid;
186 inp->coda_store.flags = flags;
187
188 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
189
190 CODA_FREE(inp, insize);
191 return error;
192}
193
194int venus_release(struct super_block *sb, struct CodaFid *fid, int flags)
195{
196 union inputArgs *inp;
197 union outputArgs *outp;
198 int insize, outsize, error;
199
200 insize = SIZE(release);
201 UPARG(CODA_RELEASE);
202
203 inp->coda_release.VFid = *fid;
204 inp->coda_release.flags = flags;
205
206 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
207
208 CODA_FREE(inp, insize);
209 return error;
210}
211
212int venus_close(struct super_block *sb, struct CodaFid *fid, int flags,
213 vuid_t uid)
214{
215 union inputArgs *inp;
216 union outputArgs *outp;
217 int insize, outsize, error;
218#ifdef CONFIG_CODA_FS_OLD_API
219 struct coda_cred cred = { 0, };
220 cred.cr_fsuid = uid;
221#endif
222
223 insize = SIZE(release);
224 UPARG(CODA_CLOSE);
225
226#ifdef CONFIG_CODA_FS_OLD_API
227 memcpy(&(inp->ih.cred), &cred, sizeof(cred));
228#else
229 inp->ih.uid = uid;
230#endif
231
232 inp->coda_close.VFid = *fid;
233 inp->coda_close.flags = flags;
234
235 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
236
237 CODA_FREE(inp, insize);
238 return error;
239}
240
241int venus_open(struct super_block *sb, struct CodaFid *fid,
242 int flags, struct file **fh)
243{
244 union inputArgs *inp;
245 union outputArgs *outp;
246 int insize, outsize, error;
247
248 insize = SIZE(open_by_fd);
249 UPARG(CODA_OPEN_BY_FD);
250
38c2e437
JH
251 inp->coda_open_by_fd.VFid = *fid;
252 inp->coda_open_by_fd.flags = flags;
1da177e4 253
38c2e437
JH
254 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
255 if (!error)
256 *fh = outp->coda_open_by_fd.fh;
1da177e4
LT
257
258 CODA_FREE(inp, insize);
259 return error;
260}
261
262int venus_mkdir(struct super_block *sb, struct CodaFid *dirfid,
263 const char *name, int length,
264 struct CodaFid *newfid, struct coda_vattr *attrs)
265{
266 union inputArgs *inp;
267 union outputArgs *outp;
268 int insize, outsize, error;
269 int offset;
270
271 offset = INSIZE(mkdir);
272 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(mkdir));
273 UPARG(CODA_MKDIR);
274
275 inp->coda_mkdir.VFid = *dirfid;
276 inp->coda_mkdir.attr = *attrs;
277 inp->coda_mkdir.name = offset;
278 /* Venus must get null terminated string */
279 memcpy((char *)(inp) + offset, name, length);
280 *((char *)inp + offset + length) = '\0';
281
282 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
283
284 *attrs = outp->coda_mkdir.attr;
285 *newfid = outp->coda_mkdir.VFid;
286
287 CODA_FREE(inp, insize);
288 return error;
289}
290
291
292int venus_rename(struct super_block *sb, struct CodaFid *old_fid,
293 struct CodaFid *new_fid, size_t old_length,
294 size_t new_length, const char *old_name,
295 const char *new_name)
296{
297 union inputArgs *inp;
298 union outputArgs *outp;
299 int insize, outsize, error;
300 int offset, s;
301
302 offset = INSIZE(rename);
303 insize = max_t(unsigned int, offset + new_length + old_length + 8,
304 OUTSIZE(rename));
305 UPARG(CODA_RENAME);
306
307 inp->coda_rename.sourceFid = *old_fid;
308 inp->coda_rename.destFid = *new_fid;
309 inp->coda_rename.srcname = offset;
310
311 /* Venus must receive an null terminated string */
312 s = ( old_length & ~0x3) +4; /* round up to word boundary */
313 memcpy((char *)(inp) + offset, old_name, old_length);
314 *((char *)inp + offset + old_length) = '\0';
315
316 /* another null terminated string for Venus */
317 offset += s;
318 inp->coda_rename.destname = offset;
319 s = ( new_length & ~0x3) +4; /* round up to word boundary */
320 memcpy((char *)(inp) + offset, new_name, new_length);
321 *((char *)inp + offset + new_length) = '\0';
322
323 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
324
325 CODA_FREE(inp, insize);
326 return error;
327}
328
329int venus_create(struct super_block *sb, struct CodaFid *dirfid,
330 const char *name, int length, int excl, int mode,
331 struct CodaFid *newfid, struct coda_vattr *attrs)
332{
333 union inputArgs *inp;
334 union outputArgs *outp;
335 int insize, outsize, error;
336 int offset;
337
338 offset = INSIZE(create);
339 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(create));
340 UPARG(CODA_CREATE);
341
342 inp->coda_create.VFid = *dirfid;
343 inp->coda_create.attr.va_mode = mode;
344 inp->coda_create.excl = excl;
345 inp->coda_create.mode = mode;
346 inp->coda_create.name = offset;
347
348 /* Venus must get null terminated string */
349 memcpy((char *)(inp) + offset, name, length);
350 *((char *)inp + offset + length) = '\0';
351
352 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
353
354 *attrs = outp->coda_create.attr;
355 *newfid = outp->coda_create.VFid;
356
357 CODA_FREE(inp, insize);
358 return error;
359}
360
361int venus_rmdir(struct super_block *sb, struct CodaFid *dirfid,
362 const char *name, int length)
363{
364 union inputArgs *inp;
365 union outputArgs *outp;
366 int insize, outsize, error;
367 int offset;
368
369 offset = INSIZE(rmdir);
370 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(rmdir));
371 UPARG(CODA_RMDIR);
372
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';
377
378 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
379
380 CODA_FREE(inp, insize);
381 return error;
382}
383
384int venus_remove(struct super_block *sb, struct CodaFid *dirfid,
385 const char *name, int length)
386{
387 union inputArgs *inp;
388 union outputArgs *outp;
389 int error=0, insize, outsize, offset;
390
391 offset = INSIZE(remove);
392 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(remove));
393 UPARG(CODA_REMOVE);
394
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';
399
400 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
401
402 CODA_FREE(inp, insize);
403 return error;
404}
405
406int venus_readlink(struct super_block *sb, struct CodaFid *fid,
407 char *buffer, int *length)
408{
409 union inputArgs *inp;
410 union outputArgs *outp;
411 int insize, outsize, error;
412 int retlen;
413 char *result;
414
415 insize = max_t(unsigned int,
416 INSIZE(readlink), OUTSIZE(readlink)+ *length + 1);
417 UPARG(CODA_READLINK);
418
419 inp->coda_readlink.VFid = *fid;
420
421 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
422
423 if (! error) {
424 retlen = outp->coda_readlink.count;
425 if ( retlen > *length )
426 retlen = *length;
427 *length = retlen;
428 result = (char *)outp + (long)outp->coda_readlink.data;
429 memcpy(buffer, result, retlen);
430 *(buffer + retlen) = '\0';
431 }
432
433 CODA_FREE(inp, insize);
434 return error;
435}
436
437
438
439int venus_link(struct super_block *sb, struct CodaFid *fid,
440 struct CodaFid *dirfid, const char *name, int len )
441{
442 union inputArgs *inp;
443 union outputArgs *outp;
444 int insize, outsize, error;
445 int offset;
446
447 offset = INSIZE(link);
448 insize = max_t(unsigned int, offset + len + 1, OUTSIZE(link));
449 UPARG(CODA_LINK);
450
451 inp->coda_link.sourceFid = *fid;
452 inp->coda_link.destFid = *dirfid;
453 inp->coda_link.tname = offset;
454
455 /* make sure strings are null terminated */
456 memcpy((char *)(inp) + offset, name, len);
457 *((char *)inp + offset + len) = '\0';
458
459 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
460
461 CODA_FREE(inp, insize);
462 return error;
463}
464
465int venus_symlink(struct super_block *sb, struct CodaFid *fid,
466 const char *name, int len,
467 const char *symname, int symlen)
468{
469 union inputArgs *inp;
470 union outputArgs *outp;
471 int insize, outsize, error;
472 int offset, s;
473
474 offset = INSIZE(symlink);
475 insize = max_t(unsigned int, offset + len + symlen + 8, OUTSIZE(symlink));
476 UPARG(CODA_SYMLINK);
477
478 /* inp->coda_symlink.attr = *tva; XXXXXX */
479 inp->coda_symlink.VFid = *fid;
480
481 /* Round up to word boundary and null terminate */
482 inp->coda_symlink.srcname = offset;
483 s = ( symlen & ~0x3 ) + 4;
484 memcpy((char *)(inp) + offset, symname, symlen);
485 *((char *)inp + offset + symlen) = '\0';
486
487 /* Round up to word boundary and null terminate */
488 offset += s;
489 inp->coda_symlink.tname = offset;
490 s = (len & ~0x3) + 4;
491 memcpy((char *)(inp) + offset, name, len);
492 *((char *)inp + offset + len) = '\0';
493
494 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
495
496 CODA_FREE(inp, insize);
497 return error;
498}
499
500int venus_fsync(struct super_block *sb, struct CodaFid *fid)
501{
502 union inputArgs *inp;
503 union outputArgs *outp;
504 int insize, outsize, error;
505
506 insize=SIZE(fsync);
507 UPARG(CODA_FSYNC);
508
509 inp->coda_fsync.VFid = *fid;
510 error = coda_upcall(coda_sbp(sb), sizeof(union inputArgs),
511 &outsize, inp);
512
513 CODA_FREE(inp, insize);
514 return error;
515}
516
517int venus_access(struct super_block *sb, struct CodaFid *fid, int mask)
518{
519 union inputArgs *inp;
520 union outputArgs *outp;
521 int insize, outsize, error;
522
523 insize = SIZE(access);
524 UPARG(CODA_ACCESS);
525
526 inp->coda_access.VFid = *fid;
527 inp->coda_access.flags = mask;
528
529 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
530
531 CODA_FREE(inp, insize);
532 return error;
533}
534
535
536int venus_pioctl(struct super_block *sb, struct CodaFid *fid,
537 unsigned int cmd, struct PioctlData *data)
538{
539 union inputArgs *inp;
540 union outputArgs *outp;
541 int insize, outsize, error;
542 int iocsize;
543
544 insize = VC_MAXMSGSIZE;
545 UPARG(CODA_IOCTL);
546
547 /* build packet for Venus */
548 if (data->vi.in_size > VC_MAXDATASIZE) {
549 error = -EINVAL;
550 goto exit;
551 }
552
553 if (data->vi.out_size > VC_MAXDATASIZE) {
554 error = -EINVAL;
555 goto exit;
556 }
557
558 inp->coda_ioctl.VFid = *fid;
559
560 /* the cmd field was mutated by increasing its size field to
561 * reflect the path and follow args. We need to subtract that
562 * out before sending the command to Venus. */
563 inp->coda_ioctl.cmd = (cmd & ~(PIOCPARM_MASK << 16));
564 iocsize = ((cmd >> 16) & PIOCPARM_MASK) - sizeof(char *) - sizeof(int);
565 inp->coda_ioctl.cmd |= (iocsize & PIOCPARM_MASK) << 16;
566
567 /* in->coda_ioctl.rwflag = flag; */
568 inp->coda_ioctl.len = data->vi.in_size;
569 inp->coda_ioctl.data = (char *)(INSIZE(ioctl));
570
571 /* get the data out of user space */
572 if ( copy_from_user((char*)inp + (long)inp->coda_ioctl.data,
573 data->vi.in, data->vi.in_size) ) {
574 error = -EINVAL;
575 goto exit;
576 }
577
578 error = coda_upcall(coda_sbp(sb), SIZE(ioctl) + data->vi.in_size,
579 &outsize, inp);
580
581 if (error) {
582 printk("coda_pioctl: Venus returns: %d for %s\n",
583 error, coda_f2s(fid));
584 goto exit;
585 }
586
587 if (outsize < (long)outp->coda_ioctl.data + outp->coda_ioctl.len) {
588 error = -EINVAL;
589 goto exit;
590 }
591
592 /* Copy out the OUT buffer. */
593 if (outp->coda_ioctl.len > data->vi.out_size) {
594 error = -EINVAL;
595 goto exit;
596 }
597
598 /* Copy out the OUT buffer. */
599 if (copy_to_user(data->vi.out,
600 (char *)outp + (long)outp->coda_ioctl.data,
601 outp->coda_ioctl.len)) {
602 error = -EFAULT;
603 goto exit;
604 }
605
606 exit:
607 CODA_FREE(inp, insize);
608 return error;
609}
610
726c3342 611int venus_statfs(struct dentry *dentry, struct kstatfs *sfs)
1da177e4
LT
612{
613 union inputArgs *inp;
614 union outputArgs *outp;
615 int insize, outsize, error;
616
617 insize = max_t(unsigned int, INSIZE(statfs), OUTSIZE(statfs));
618 UPARG(CODA_STATFS);
619
726c3342 620 error = coda_upcall(coda_sbp(dentry->d_sb), insize, &outsize, inp);
1da177e4
LT
621
622 if (!error) {
623 sfs->f_blocks = outp->coda_statfs.stat.f_blocks;
624 sfs->f_bfree = outp->coda_statfs.stat.f_bfree;
625 sfs->f_bavail = outp->coda_statfs.stat.f_bavail;
626 sfs->f_files = outp->coda_statfs.stat.f_files;
627 sfs->f_ffree = outp->coda_statfs.stat.f_ffree;
628 } else {
629 printk("coda_statfs: Venus returns: %d\n", error);
630 }
631
632 CODA_FREE(inp, insize);
633 return error;
634}
635
636/*
637 * coda_upcall and coda_downcall routines.
1da177e4 638 */
d9664c95
JH
639static void block_signals(sigset_t *old)
640{
641 spin_lock_irq(&current->sighand->siglock);
642 *old = current->blocked;
643
644 sigfillset(&current->blocked);
645 sigdelset(&current->blocked, SIGKILL);
646 sigdelset(&current->blocked, SIGSTOP);
647 sigdelset(&current->blocked, SIGINT);
648
649 recalc_sigpending();
650 spin_unlock_irq(&current->sighand->siglock);
651}
652
653static void unblock_signals(sigset_t *old)
654{
655 spin_lock_irq(&current->sighand->siglock);
656 current->blocked = *old;
657 recalc_sigpending();
658 spin_unlock_irq(&current->sighand->siglock);
659}
660
661/* Don't allow signals to interrupt the following upcalls before venus
662 * has seen them,
663 * - CODA_CLOSE or CODA_RELEASE upcall (to avoid reference count problems)
664 * - CODA_STORE (to avoid data loss)
665 */
666#define CODA_INTERRUPTIBLE(r) (!coda_hard && \
667 (((r)->uc_opcode != CODA_CLOSE && \
668 (r)->uc_opcode != CODA_STORE && \
669 (r)->uc_opcode != CODA_RELEASE) || \
670 (r)->uc_flags & REQ_READ))
1da177e4 671
d9664c95 672static inline void coda_waitfor_upcall(struct upc_req *req)
1da177e4
LT
673{
674 DECLARE_WAITQUEUE(wait, current);
d9664c95
JH
675 unsigned long timeout = jiffies + coda_timeout * HZ;
676 sigset_t old;
677 int blocked;
1da177e4 678
d9664c95
JH
679 block_signals(&old);
680 blocked = 1;
1da177e4 681
d9664c95 682 add_wait_queue(&req->uc_sleep, &wait);
1da177e4 683 for (;;) {
d9664c95 684 if (CODA_INTERRUPTIBLE(req))
1da177e4
LT
685 set_current_state(TASK_INTERRUPTIBLE);
686 else
687 set_current_state(TASK_UNINTERRUPTIBLE);
688
1da177e4 689 /* got a reply */
d9664c95 690 if (req->uc_flags & (REQ_WRITE | REQ_ABORT))
1da177e4
LT
691 break;
692
d9664c95
JH
693 if (blocked && time_after(jiffies, timeout) &&
694 CODA_INTERRUPTIBLE(req))
695 {
696 unblock_signals(&old);
697 blocked = 0;
1da177e4 698 }
d9664c95
JH
699
700 if (signal_pending(current)) {
701 list_del(&req->uc_chain);
702 break;
703 }
704
705 if (blocked)
706 schedule_timeout(HZ);
707 else
708 schedule();
1da177e4 709 }
d9664c95
JH
710 if (blocked)
711 unblock_signals(&old);
1da177e4 712
d9664c95
JH
713 remove_wait_queue(&req->uc_sleep, &wait);
714 set_current_state(TASK_RUNNING);
1da177e4
LT
715}
716
717
718/*
719 * coda_upcall will return an error in the case of
720 * failed communication with Venus _or_ will peek at Venus
721 * reply and return Venus' error.
722 *
723 * As venus has 2 types of errors, normal errors (positive) and internal
724 * errors (negative), normal errors are negated, while internal errors
725 * are all mapped to -EINTR, while showing a nice warning message. (jh)
726 *
727 */
fe71b5f3
JH
728static int coda_upcall(struct coda_sb_info *sbi,
729 int inSize, int *outSize,
730 union inputArgs *buffer)
1da177e4
LT
731{
732 struct venus_comm *vcommp;
733 union outputArgs *out;
fe71b5f3
JH
734 union inputArgs *sig_inputArgs;
735 struct upc_req *req, *sig_req;
1da177e4
LT
736 int error = 0;
737
738 vcommp = sbi->sbi_vcomm;
fe71b5f3
JH
739 if (!vcommp->vc_inuse) {
740 printk(KERN_NOTICE "coda: Venus dead, not sending upcall\n");
741 return -ENXIO;
1da177e4
LT
742 }
743
744 /* Format the request message. */
37461e19 745 req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
fe71b5f3 746 if (!req)
1da177e4 747 return -ENOMEM;
fe71b5f3 748
1da177e4
LT
749 req->uc_data = (void *)buffer;
750 req->uc_flags = 0;
751 req->uc_inSize = inSize;
752 req->uc_outSize = *outSize ? *outSize : inSize;
753 req->uc_opcode = ((union inputArgs *)buffer)->ih.opcode;
754 req->uc_unique = ++vcommp->vc_seq;
755 init_waitqueue_head(&req->uc_sleep);
fe71b5f3 756
1da177e4
LT
757 /* Fill in the common input args. */
758 ((union inputArgs *)buffer)->ih.unique = req->uc_unique;
759
760 /* Append msg to pending queue and poke Venus. */
fe71b5f3
JH
761 list_add_tail(&req->uc_chain, &vcommp->vc_pending);
762
1da177e4
LT
763 wake_up_interruptible(&vcommp->vc_waitq);
764 /* We can be interrupted while we wait for Venus to process
765 * our request. If the interrupt occurs before Venus has read
766 * the request, we dequeue and return. If it occurs after the
767 * read but before the reply, we dequeue, send a signal
768 * message, and return. If it occurs after the reply we ignore
769 * it. In no case do we want to restart the syscall. If it
770 * was interrupted by a venus shutdown (psdev_close), return
771 * ENODEV. */
772
773 /* Go to sleep. Wake up on signals only after the timeout. */
87065519 774 coda_waitfor_upcall(req);
1da177e4 775
fe71b5f3
JH
776 /* Op went through, interrupt or not... */
777 if (req->uc_flags & REQ_WRITE) {
1da177e4
LT
778 out = (union outputArgs *)req->uc_data;
779 /* here we map positive Venus errors to kernel errors */
780 error = -out->oh.result;
781 *outSize = req->uc_outSize;
782 goto exit;
fe71b5f3
JH
783 }
784
785 error = -EINTR;
786 if ((req->uc_flags & REQ_ABORT) || !signal_pending(current)) {
787 printk(KERN_WARNING "coda: Unexpected interruption.\n");
1da177e4 788 goto exit;
1da177e4
LT
789 }
790
fe71b5f3
JH
791 /* Interrupted before venus read it. */
792 if (!(req->uc_flags & REQ_READ))
793 goto exit;
794
795 /* Venus saw the upcall, make sure we can send interrupt signal */
796 if (!vcommp->vc_inuse) {
797 printk(KERN_INFO "coda: Venus dead, not sending signal.\n");
798 goto exit;
799 }
800
801 error = -ENOMEM;
37461e19 802 sig_req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
fe71b5f3
JH
803 if (!sig_req) goto exit;
804
805 CODA_ALLOC((sig_req->uc_data), char *, sizeof(struct coda_in_hdr));
806 if (!sig_req->uc_data) {
37461e19 807 kfree(sig_req);
fe71b5f3
JH
808 goto exit;
809 }
810
811 error = -EINTR;
812 sig_inputArgs = (union inputArgs *)sig_req->uc_data;
813 sig_inputArgs->ih.opcode = CODA_SIGNAL;
814 sig_inputArgs->ih.unique = req->uc_unique;
815
816 sig_req->uc_flags = REQ_ASYNC;
817 sig_req->uc_opcode = sig_inputArgs->ih.opcode;
818 sig_req->uc_unique = sig_inputArgs->ih.unique;
819 sig_req->uc_inSize = sizeof(struct coda_in_hdr);
820 sig_req->uc_outSize = sizeof(struct coda_in_hdr);
821
822 /* insert at head of queue! */
823 list_add(&(sig_req->uc_chain), &vcommp->vc_pending);
824 wake_up_interruptible(&vcommp->vc_waitq);
825
826exit:
37461e19 827 kfree(req);
1da177e4
LT
828 return error;
829}
830
831/*
832 The statements below are part of the Coda opportunistic
833 programming -- taken from the Mach/BSD kernel code for Coda.
834 You don't get correct semantics by stating what needs to be
835 done without guaranteeing the invariants needed for it to happen.
836 When will be have time to find out what exactly is going on? (pjb)
837*/
838
839
840/*
841 * There are 7 cases where cache invalidations occur. The semantics
842 * of each is listed here:
843 *
844 * CODA_FLUSH -- flush all entries from the name cache and the cnode cache.
845 * CODA_PURGEUSER -- flush all entries from the name cache for a specific user
846 * This call is a result of token expiration.
847 *
848 * The next arise as the result of callbacks on a file or directory.
849 * CODA_ZAPFILE -- flush the cached attributes for a file.
850
851 * CODA_ZAPDIR -- flush the attributes for the dir and
852 * force a new lookup for all the children
853 of this dir.
854
855 *
856 * The next is a result of Venus detecting an inconsistent file.
857 * CODA_PURGEFID -- flush the attribute for the file
858 * purge it and its children from the dcache
859 *
860 * The last allows Venus to replace local fids with global ones
861 * during reintegration.
862 *
863 * CODA_REPLACE -- replace one CodaFid with another throughout the name cache */
864
865int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
866{
867 /* Handle invalidation requests. */
868 if ( !sb || !sb->s_root || !sb->s_root->d_inode)
869 return 0;
870
871 switch (opcode) {
872
873 case CODA_FLUSH : {
874 coda_cache_clear_all(sb);
875 shrink_dcache_sb(sb);
876 coda_flag_inode(sb->s_root->d_inode, C_FLUSH);
877 return(0);
878 }
879
880 case CODA_PURGEUSER : {
881 coda_cache_clear_all(sb);
882 return(0);
883 }
884
885 case CODA_ZAPDIR : {
886 struct inode *inode;
887 struct CodaFid *fid = &out->coda_zapdir.CodaFid;
888
889 inode = coda_fid_to_inode(fid, sb);
890 if (inode) {
891 coda_flag_inode_children(inode, C_PURGE);
892 coda_flag_inode(inode, C_VATTR);
893 iput(inode);
894 }
895
896 return(0);
897 }
898
899 case CODA_ZAPFILE : {
900 struct inode *inode;
901 struct CodaFid *fid = &out->coda_zapfile.CodaFid;
902 inode = coda_fid_to_inode(fid, sb);
903 if ( inode ) {
904 coda_flag_inode(inode, C_VATTR);
905 iput(inode);
906 }
907 return 0;
908 }
909
910 case CODA_PURGEFID : {
911 struct inode *inode;
912 struct CodaFid *fid = &out->coda_purgefid.CodaFid;
913 inode = coda_fid_to_inode(fid, sb);
914 if ( inode ) {
915 coda_flag_inode_children(inode, C_PURGE);
916
917 /* catch the dentries later if some are still busy */
918 coda_flag_inode(inode, C_PURGE);
919 d_prune_aliases(inode);
920
921 iput(inode);
922 }
923 return 0;
924 }
925
926 case CODA_REPLACE : {
927 struct inode *inode;
928 struct CodaFid *oldfid = &out->coda_replace.OldFid;
929 struct CodaFid *newfid = &out->coda_replace.NewFid;
930 inode = coda_fid_to_inode(oldfid, sb);
931 if ( inode ) {
932 coda_replace_fid(inode, oldfid, newfid);
933 iput(inode);
934 }
935 return 0;
936 }
937 }
938 return 0;
939}
940