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