coda: cleanup coda_lookup, use dsplice_alias
[deliverable/linux.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);
970648eb 87 if (!error)
1da177e4 88 *fidp = outp->coda_root.VFid;
1da177e4
LT
89
90 CODA_FREE(inp, insize);
91 return error;
92}
93
94int venus_getattr(struct super_block *sb, struct CodaFid *fid,
95 struct coda_vattr *attr)
96{
97 union inputArgs *inp;
98 union outputArgs *outp;
99 int insize, outsize, error;
100
101 insize = SIZE(getattr);
102 UPARG(CODA_GETATTR);
103 inp->coda_getattr.VFid = *fid;
104
970648eb
JH
105 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
106 if (!error)
107 *attr = outp->coda_getattr.attr;
1da177e4
LT
108
109 CODA_FREE(inp, insize);
110 return error;
111}
112
113int venus_setattr(struct super_block *sb, struct CodaFid *fid,
114 struct coda_vattr *vattr)
115{
116 union inputArgs *inp;
117 union outputArgs *outp;
118 int insize, outsize, error;
119
120 insize = SIZE(setattr);
121 UPARG(CODA_SETATTR);
122
123 inp->coda_setattr.VFid = *fid;
124 inp->coda_setattr.attr = *vattr;
125
126 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
127
128 CODA_FREE(inp, insize);
129 return error;
130}
131
132int venus_lookup(struct super_block *sb, struct CodaFid *fid,
133 const char *name, int length, int * type,
134 struct CodaFid *resfid)
135{
136 union inputArgs *inp;
137 union outputArgs *outp;
138 int insize, outsize, error;
139 int offset;
140
141 offset = INSIZE(lookup);
142 insize = max_t(unsigned int, offset + length +1, OUTSIZE(lookup));
143 UPARG(CODA_LOOKUP);
144
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';
151
970648eb
JH
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;
156 }
1da177e4
LT
157
158 CODA_FREE(inp, insize);
159 return error;
160}
161
162int venus_store(struct super_block *sb, struct CodaFid *fid, int flags,
163 vuid_t uid)
164{
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
172
173 insize = SIZE(store);
174 UPARG(CODA_STORE);
175
176#ifdef CONFIG_CODA_FS_OLD_API
177 memcpy(&(inp->ih.cred), &cred, sizeof(cred));
178#else
179 inp->ih.uid = uid;
180#endif
181
182 inp->coda_store.VFid = *fid;
183 inp->coda_store.flags = flags;
184
185 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
186
187 CODA_FREE(inp, insize);
188 return error;
189}
190
191int venus_release(struct super_block *sb, struct CodaFid *fid, int flags)
192{
193 union inputArgs *inp;
194 union outputArgs *outp;
195 int insize, outsize, error;
196
197 insize = SIZE(release);
198 UPARG(CODA_RELEASE);
199
200 inp->coda_release.VFid = *fid;
201 inp->coda_release.flags = flags;
202
203 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
204
205 CODA_FREE(inp, insize);
206 return error;
207}
208
209int venus_close(struct super_block *sb, struct CodaFid *fid, int flags,
210 vuid_t uid)
211{
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
219
220 insize = SIZE(release);
221 UPARG(CODA_CLOSE);
222
223#ifdef CONFIG_CODA_FS_OLD_API
224 memcpy(&(inp->ih.cred), &cred, sizeof(cred));
225#else
226 inp->ih.uid = uid;
227#endif
228
229 inp->coda_close.VFid = *fid;
230 inp->coda_close.flags = flags;
231
232 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
233
234 CODA_FREE(inp, insize);
235 return error;
236}
237
238int venus_open(struct super_block *sb, struct CodaFid *fid,
239 int flags, struct file **fh)
240{
241 union inputArgs *inp;
242 union outputArgs *outp;
243 int insize, outsize, error;
244
245 insize = SIZE(open_by_fd);
246 UPARG(CODA_OPEN_BY_FD);
247
38c2e437
JH
248 inp->coda_open_by_fd.VFid = *fid;
249 inp->coda_open_by_fd.flags = flags;
1da177e4 250
38c2e437
JH
251 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
252 if (!error)
253 *fh = outp->coda_open_by_fd.fh;
1da177e4
LT
254
255 CODA_FREE(inp, insize);
256 return error;
257}
258
259int venus_mkdir(struct super_block *sb, struct CodaFid *dirfid,
260 const char *name, int length,
261 struct CodaFid *newfid, struct coda_vattr *attrs)
262{
263 union inputArgs *inp;
264 union outputArgs *outp;
265 int insize, outsize, error;
266 int offset;
267
268 offset = INSIZE(mkdir);
269 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(mkdir));
270 UPARG(CODA_MKDIR);
271
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';
1da177e4 278
970648eb
JH
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;
283 }
1da177e4
LT
284
285 CODA_FREE(inp, insize);
286 return error;
287}
288
289
290int 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)
294{
295 union inputArgs *inp;
296 union outputArgs *outp;
297 int insize, outsize, error;
298 int offset, s;
299
300 offset = INSIZE(rename);
301 insize = max_t(unsigned int, offset + new_length + old_length + 8,
302 OUTSIZE(rename));
303 UPARG(CODA_RENAME);
304
305 inp->coda_rename.sourceFid = *old_fid;
306 inp->coda_rename.destFid = *new_fid;
307 inp->coda_rename.srcname = offset;
308
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';
313
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';
320
321 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
322
323 CODA_FREE(inp, insize);
324 return error;
325}
326
327int 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)
330{
331 union inputArgs *inp;
332 union outputArgs *outp;
333 int insize, outsize, error;
334 int offset;
335
336 offset = INSIZE(create);
337 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(create));
338 UPARG(CODA_CREATE);
339
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;
345
346 /* Venus must get null terminated string */
347 memcpy((char *)(inp) + offset, name, length);
348 *((char *)inp + offset + length) = '\0';
1da177e4 349
970648eb
JH
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;
354 }
1da177e4
LT
355
356 CODA_FREE(inp, insize);
357 return error;
358}
359
360int venus_rmdir(struct super_block *sb, struct CodaFid *dirfid,
361 const char *name, int length)
362{
363 union inputArgs *inp;
364 union outputArgs *outp;
365 int insize, outsize, error;
366 int offset;
367
368 offset = INSIZE(rmdir);
369 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(rmdir));
370 UPARG(CODA_RMDIR);
371
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';
376
377 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
378
379 CODA_FREE(inp, insize);
380 return error;
381}
382
383int venus_remove(struct super_block *sb, struct CodaFid *dirfid,
384 const char *name, int length)
385{
386 union inputArgs *inp;
387 union outputArgs *outp;
388 int error=0, insize, outsize, offset;
389
390 offset = INSIZE(remove);
391 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(remove));
392 UPARG(CODA_REMOVE);
393
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';
398
399 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
400
401 CODA_FREE(inp, insize);
402 return error;
403}
404
405int venus_readlink(struct super_block *sb, struct CodaFid *fid,
406 char *buffer, int *length)
407{
408 union inputArgs *inp;
409 union outputArgs *outp;
410 int insize, outsize, error;
411 int retlen;
412 char *result;
413
414 insize = max_t(unsigned int,
415 INSIZE(readlink), OUTSIZE(readlink)+ *length + 1);
416 UPARG(CODA_READLINK);
417
418 inp->coda_readlink.VFid = *fid;
970648eb
JH
419
420 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
421 if (!error) {
422 retlen = outp->coda_readlink.count;
1da177e4 423 if ( retlen > *length )
970648eb 424 retlen = *length;
1da177e4
LT
425 *length = retlen;
426 result = (char *)outp + (long)outp->coda_readlink.data;
427 memcpy(buffer, result, retlen);
428 *(buffer + retlen) = '\0';
429 }
970648eb 430
1da177e4
LT
431 CODA_FREE(inp, insize);
432 return error;
433}
434
435
436
437int venus_link(struct super_block *sb, struct CodaFid *fid,
438 struct CodaFid *dirfid, const char *name, int len )
439{
440 union inputArgs *inp;
441 union outputArgs *outp;
442 int insize, outsize, error;
443 int offset;
444
445 offset = INSIZE(link);
446 insize = max_t(unsigned int, offset + len + 1, OUTSIZE(link));
447 UPARG(CODA_LINK);
448
449 inp->coda_link.sourceFid = *fid;
450 inp->coda_link.destFid = *dirfid;
451 inp->coda_link.tname = offset;
452
453 /* make sure strings are null terminated */
454 memcpy((char *)(inp) + offset, name, len);
455 *((char *)inp + offset + len) = '\0';
456
457 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
458
459 CODA_FREE(inp, insize);
460 return error;
461}
462
463int venus_symlink(struct super_block *sb, struct CodaFid *fid,
464 const char *name, int len,
465 const char *symname, int symlen)
466{
467 union inputArgs *inp;
468 union outputArgs *outp;
469 int insize, outsize, error;
470 int offset, s;
471
472 offset = INSIZE(symlink);
473 insize = max_t(unsigned int, offset + len + symlen + 8, OUTSIZE(symlink));
474 UPARG(CODA_SYMLINK);
475
476 /* inp->coda_symlink.attr = *tva; XXXXXX */
477 inp->coda_symlink.VFid = *fid;
478
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';
484
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';
491
492 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
493
494 CODA_FREE(inp, insize);
495 return error;
496}
497
498int venus_fsync(struct super_block *sb, struct CodaFid *fid)
499{
500 union inputArgs *inp;
501 union outputArgs *outp;
502 int insize, outsize, error;
503
504 insize=SIZE(fsync);
505 UPARG(CODA_FSYNC);
506
507 inp->coda_fsync.VFid = *fid;
508 error = coda_upcall(coda_sbp(sb), sizeof(union inputArgs),
509 &outsize, inp);
510
511 CODA_FREE(inp, insize);
512 return error;
513}
514
515int venus_access(struct super_block *sb, struct CodaFid *fid, int mask)
516{
517 union inputArgs *inp;
518 union outputArgs *outp;
519 int insize, outsize, error;
520
521 insize = SIZE(access);
522 UPARG(CODA_ACCESS);
523
524 inp->coda_access.VFid = *fid;
525 inp->coda_access.flags = mask;
526
527 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
528
529 CODA_FREE(inp, insize);
530 return error;
531}
532
533
534int venus_pioctl(struct super_block *sb, struct CodaFid *fid,
535 unsigned int cmd, struct PioctlData *data)
536{
537 union inputArgs *inp;
538 union outputArgs *outp;
539 int insize, outsize, error;
540 int iocsize;
541
542 insize = VC_MAXMSGSIZE;
543 UPARG(CODA_IOCTL);
544
545 /* build packet for Venus */
546 if (data->vi.in_size > VC_MAXDATASIZE) {
547 error = -EINVAL;
548 goto exit;
549 }
550
551 if (data->vi.out_size > VC_MAXDATASIZE) {
552 error = -EINVAL;
553 goto exit;
554 }
555
556 inp->coda_ioctl.VFid = *fid;
557
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;
564
565 /* in->coda_ioctl.rwflag = flag; */
566 inp->coda_ioctl.len = data->vi.in_size;
567 inp->coda_ioctl.data = (char *)(INSIZE(ioctl));
568
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;
574 }
575
576 error = coda_upcall(coda_sbp(sb), SIZE(ioctl) + data->vi.in_size,
577 &outsize, inp);
578
579 if (error) {
580 printk("coda_pioctl: Venus returns: %d for %s\n",
581 error, coda_f2s(fid));
582 goto exit;
583 }
584
585 if (outsize < (long)outp->coda_ioctl.data + outp->coda_ioctl.len) {
586 error = -EINVAL;
587 goto exit;
588 }
589
590 /* Copy out the OUT buffer. */
591 if (outp->coda_ioctl.len > data->vi.out_size) {
592 error = -EINVAL;
593 goto exit;
594 }
595
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;
602 }
603
604 exit:
605 CODA_FREE(inp, insize);
606 return error;
607}
608
726c3342 609int venus_statfs(struct dentry *dentry, struct kstatfs *sfs)
1da177e4
LT
610{
611 union inputArgs *inp;
612 union outputArgs *outp;
613 int insize, outsize, error;
614
615 insize = max_t(unsigned int, INSIZE(statfs), OUTSIZE(statfs));
616 UPARG(CODA_STATFS);
617
970648eb
JH
618 error = coda_upcall(coda_sbp(dentry->d_sb), insize, &outsize, inp);
619 if (!error) {
1da177e4
LT
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;
1da177e4
LT
625 }
626
627 CODA_FREE(inp, insize);
628 return error;
629}
630
631/*
632 * coda_upcall and coda_downcall routines.
1da177e4 633 */
d9664c95
JH
634static void block_signals(sigset_t *old)
635{
636 spin_lock_irq(&current->sighand->siglock);
637 *old = current->blocked;
638
639 sigfillset(&current->blocked);
640 sigdelset(&current->blocked, SIGKILL);
641 sigdelset(&current->blocked, SIGSTOP);
642 sigdelset(&current->blocked, SIGINT);
643
644 recalc_sigpending();
645 spin_unlock_irq(&current->sighand->siglock);
646}
647
648static void unblock_signals(sigset_t *old)
649{
650 spin_lock_irq(&current->sighand->siglock);
651 current->blocked = *old;
652 recalc_sigpending();
653 spin_unlock_irq(&current->sighand->siglock);
654}
655
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)
660 */
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))
1da177e4 666
d9664c95 667static inline void coda_waitfor_upcall(struct upc_req *req)
1da177e4
LT
668{
669 DECLARE_WAITQUEUE(wait, current);
d9664c95
JH
670 unsigned long timeout = jiffies + coda_timeout * HZ;
671 sigset_t old;
672 int blocked;
1da177e4 673
d9664c95
JH
674 block_signals(&old);
675 blocked = 1;
1da177e4 676
d9664c95 677 add_wait_queue(&req->uc_sleep, &wait);
1da177e4 678 for (;;) {
d9664c95 679 if (CODA_INTERRUPTIBLE(req))
1da177e4
LT
680 set_current_state(TASK_INTERRUPTIBLE);
681 else
682 set_current_state(TASK_UNINTERRUPTIBLE);
683
1da177e4 684 /* got a reply */
d9664c95 685 if (req->uc_flags & (REQ_WRITE | REQ_ABORT))
1da177e4
LT
686 break;
687
d9664c95
JH
688 if (blocked && time_after(jiffies, timeout) &&
689 CODA_INTERRUPTIBLE(req))
690 {
691 unblock_signals(&old);
692 blocked = 0;
1da177e4 693 }
d9664c95
JH
694
695 if (signal_pending(current)) {
696 list_del(&req->uc_chain);
697 break;
698 }
699
700 if (blocked)
701 schedule_timeout(HZ);
702 else
703 schedule();
1da177e4 704 }
d9664c95
JH
705 if (blocked)
706 unblock_signals(&old);
1da177e4 707
d9664c95
JH
708 remove_wait_queue(&req->uc_sleep, &wait);
709 set_current_state(TASK_RUNNING);
1da177e4
LT
710}
711
712
713/*
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.
717 *
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)
721 *
722 */
fe71b5f3
JH
723static int coda_upcall(struct coda_sb_info *sbi,
724 int inSize, int *outSize,
725 union inputArgs *buffer)
1da177e4
LT
726{
727 struct venus_comm *vcommp;
728 union outputArgs *out;
fe71b5f3
JH
729 union inputArgs *sig_inputArgs;
730 struct upc_req *req, *sig_req;
1da177e4
LT
731 int error = 0;
732
733 vcommp = sbi->sbi_vcomm;
fe71b5f3
JH
734 if (!vcommp->vc_inuse) {
735 printk(KERN_NOTICE "coda: Venus dead, not sending upcall\n");
736 return -ENXIO;
1da177e4
LT
737 }
738
739 /* Format the request message. */
37461e19 740 req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
fe71b5f3 741 if (!req)
1da177e4 742 return -ENOMEM;
fe71b5f3 743
1da177e4
LT
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);
fe71b5f3 751
1da177e4
LT
752 /* Fill in the common input args. */
753 ((union inputArgs *)buffer)->ih.unique = req->uc_unique;
754
755 /* Append msg to pending queue and poke Venus. */
fe71b5f3
JH
756 list_add_tail(&req->uc_chain, &vcommp->vc_pending);
757
1da177e4
LT
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. */
767
768 /* Go to sleep. Wake up on signals only after the timeout. */
87065519 769 coda_waitfor_upcall(req);
1da177e4 770
fe71b5f3
JH
771 /* Op went through, interrupt or not... */
772 if (req->uc_flags & REQ_WRITE) {
1da177e4
LT
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;
fe71b5f3
JH
778 }
779
780 error = -EINTR;
781 if ((req->uc_flags & REQ_ABORT) || !signal_pending(current)) {
782 printk(KERN_WARNING "coda: Unexpected interruption.\n");
1da177e4 783 goto exit;
1da177e4
LT
784 }
785
fe71b5f3
JH
786 /* Interrupted before venus read it. */
787 if (!(req->uc_flags & REQ_READ))
788 goto exit;
789
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;
794 }
795
796 error = -ENOMEM;
37461e19 797 sig_req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
fe71b5f3
JH
798 if (!sig_req) goto exit;
799
800 CODA_ALLOC((sig_req->uc_data), char *, sizeof(struct coda_in_hdr));
801 if (!sig_req->uc_data) {
37461e19 802 kfree(sig_req);
fe71b5f3
JH
803 goto exit;
804 }
805
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;
810
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);
816
817 /* insert at head of queue! */
818 list_add(&(sig_req->uc_chain), &vcommp->vc_pending);
819 wake_up_interruptible(&vcommp->vc_waitq);
820
821exit:
37461e19 822 kfree(req);
1da177e4
LT
823 return error;
824}
825
826/*
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)
832*/
833
834
835/*
836 * There are 7 cases where cache invalidations occur. The semantics
837 * of each is listed here:
838 *
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.
842 *
843 * The next arise as the result of callbacks on a file or directory.
844 * CODA_ZAPFILE -- flush the cached attributes for a file.
845
846 * CODA_ZAPDIR -- flush the attributes for the dir and
847 * force a new lookup for all the children
848 of this dir.
849
850 *
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
854 *
855 * The last allows Venus to replace local fids with global ones
856 * during reintegration.
857 *
858 * CODA_REPLACE -- replace one CodaFid with another throughout the name cache */
859
860int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
861{
862 /* Handle invalidation requests. */
863 if ( !sb || !sb->s_root || !sb->s_root->d_inode)
864 return 0;
865
866 switch (opcode) {
867
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);
873 }
874
875 case CODA_PURGEUSER : {
876 coda_cache_clear_all(sb);
877 return(0);
878 }
879
880 case CODA_ZAPDIR : {
881 struct inode *inode;
882 struct CodaFid *fid = &out->coda_zapdir.CodaFid;
883
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);
889 }
890
891 return(0);
892 }
893
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);
901 }
902 return 0;
903 }
904
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);
911
912 /* catch the dentries later if some are still busy */
913 coda_flag_inode(inode, C_PURGE);
914 d_prune_aliases(inode);
915
916 iput(inode);
917 }
918 return 0;
919 }
920
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);
929 }
930 return 0;
931 }
932 }
933 return 0;
934}
935
This page took 0.561495 seconds and 5 git commands to generate.