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