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
alloc_upcall(int opcode,int size)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 */
venus_rootfid(struct super_block * sb,ViceFid * fidp)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
venus_getattr(struct super_block * sb,struct ViceFid * fid,struct coda_vattr * attr)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
venus_setattr(struct super_block * sb,struct ViceFid * fid,struct coda_vattr * vattr)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
venus_lookup(struct super_block * sb,struct ViceFid * fid,const char * name,int length,int * type,struct ViceFid * resfid)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
venus_store(struct super_block * sb,struct ViceFid * fid,int flags,struct coda_cred * cred)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
venus_release(struct super_block * sb,struct ViceFid * fid,int flags)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
venus_close(struct super_block * sb,struct ViceFid * fid,int flags,struct coda_cred * cred)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
venus_open(struct super_block * sb,struct ViceFid * fid,int flags,struct file ** fh)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
venus_mkdir(struct super_block * sb,struct ViceFid * dirfid,const char * name,int length,struct ViceFid * newfid,struct coda_vattr * attrs)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
venus_rename(struct super_block * sb,struct ViceFid * old_fid,struct ViceFid * new_fid,size_t old_length,size_t new_length,const char * old_name,const char * new_name)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
venus_create(struct super_block * sb,struct ViceFid * dirfid,const char * name,int length,int excl,int mode,int rdev,struct ViceFid * newfid,struct coda_vattr * attrs)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
venus_rmdir(struct super_block * sb,struct ViceFid * dirfid,const char * name,int length)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
venus_remove(struct super_block * sb,struct ViceFid * dirfid,const char * name,int length)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
venus_readlink(struct super_block * sb,struct ViceFid * fid,char * buffer,int * length)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
venus_link(struct super_block * sb,struct ViceFid * fid,struct ViceFid * dirfid,const char * name,int len)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
venus_symlink(struct super_block * sb,struct ViceFid * fid,const char * name,int len,const char * symname,int symlen)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
venus_fsync(struct super_block * sb,struct ViceFid * fid)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
venus_access(struct super_block * sb,struct ViceFid * fid,int mask)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
venus_pioctl(struct super_block * sb,struct ViceFid * fid,unsigned int cmd,struct PioctlData * data)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 if (data->vi.out_size > VC_MAXDATASIZE) {
547 error = -EINVAL;
548 goto exit;
549 }
550
551 inp->coda_ioctl.VFid = *fid;
552
553 /* the cmd field was mutated by increasing its size field to
554 * reflect the path and follow args. We need to subtract that
555 * out before sending the command to Venus. */
556 inp->coda_ioctl.cmd = (cmd & ~(PIOCPARM_MASK << 16));
557 iocsize = ((cmd >> 16) & PIOCPARM_MASK) - sizeof(char *) - sizeof(int);
558 inp->coda_ioctl.cmd |= (iocsize & PIOCPARM_MASK) << 16;
559
560 /* in->coda_ioctl.rwflag = flag; */
561 inp->coda_ioctl.len = data->vi.in_size;
562 inp->coda_ioctl.data = (char *)(INSIZE(ioctl));
563
564 /* get the data out of user space */
565 if ( copy_from_user((char*)inp + (long)inp->coda_ioctl.data,
566 data->vi.in, data->vi.in_size) ) {
567 error = -EINVAL;
568 goto exit;
569 }
570
571 error = coda_upcall(coda_sbp(sb), SIZE(ioctl) + data->vi.in_size,
572 &outsize, inp);
573
574 if (error) {
575 printk("coda_pioctl: Venus returns: %d for %s\n",
576 error, coda_f2s(fid));
577 goto exit;
578 }
579
580 if (outsize < (long)outp->coda_ioctl.data + outp->coda_ioctl.len) {
581 CDEBUG(D_FILE, "reply size %d < reply len %ld\n", outsize,
582 (long)outp->coda_ioctl.data + outp->coda_ioctl.len);
583 error = -EINVAL;
584 goto exit;
585 }
586
587 if (outp->coda_ioctl.len > data->vi.out_size) {
588 CDEBUG(D_FILE, "return len %d > request len %d\n",
589 outp->coda_ioctl.len, data->vi.out_size);
590 error = -EINVAL;
591 goto exit;
592 }
593
594 /* Copy out the OUT buffer. */
595 error = verify_area(VERIFY_WRITE, data->vi.out, outp->coda_ioctl.len);
596 if ( error ) goto exit;
597
598 if (copy_to_user(data->vi.out,
599 (char *)outp + (long)outp->coda_ioctl.data,
600 outp->coda_ioctl.len)) {
601 error = -EINVAL;
602 }
603 exit:
604 CODA_FREE(inp, insize);
605 return error;
606 }
607
venus_statfs(struct super_block * sb,struct statfs * sfs)608 int venus_statfs(struct super_block *sb, struct statfs *sfs)
609 {
610 union inputArgs *inp;
611 union outputArgs *outp;
612 int insize, outsize, error;
613
614 insize = max_t(unsigned int, INSIZE(statfs), OUTSIZE(statfs));
615 UPARG(CODA_STATFS);
616
617 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
618
619 if (!error) {
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;
625 } else {
626 printk("coda_statfs: Venus returns: %d\n", error);
627 }
628
629 CDEBUG(D_INODE, " result %d\n",error);
630 CODA_FREE(inp, insize);
631 return error;
632 }
633
634 /*
635 * coda_upcall and coda_downcall routines.
636 *
637 */
638
coda_waitfor_upcall(struct upc_req * vmp,struct venus_comm * vcommp)639 static inline unsigned long coda_waitfor_upcall(struct upc_req *vmp,
640 struct venus_comm *vcommp)
641 {
642 DECLARE_WAITQUEUE(wait, current);
643 struct timeval begin = { 0, 0 }, end = { 0, 0 };
644
645 vmp->uc_posttime = jiffies;
646
647 if (coda_upcall_timestamping)
648 do_gettimeofday(&begin);
649
650 add_wait_queue(&vmp->uc_sleep, &wait);
651 for (;;) {
652 if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE )
653 set_current_state(TASK_INTERRUPTIBLE);
654 else
655 set_current_state(TASK_UNINTERRUPTIBLE);
656
657 /* venus died */
658 if ( !vcommp->vc_inuse )
659 break;
660
661 /* got a reply */
662 if ( vmp->uc_flags & ( REQ_WRITE | REQ_ABORT ) )
663 break;
664
665 if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE && signal_pending(current) ) {
666 /* if this process really wants to die, let it go */
667 if ( sigismember(&(current->pending.signal), SIGKILL) ||
668 sigismember(&(current->pending.signal), SIGINT) )
669 break;
670 /* signal is present: after timeout always return
671 really smart idea, probably useless ... */
672 if ( jiffies - vmp->uc_posttime > coda_timeout * HZ )
673 break;
674 }
675 schedule();
676 }
677 remove_wait_queue(&vmp->uc_sleep, &wait);
678 set_current_state(TASK_RUNNING);
679
680 if (coda_upcall_timestamping && begin.tv_sec != 0) {
681 do_gettimeofday(&end);
682
683 if (end.tv_usec < begin.tv_usec) {
684 end.tv_usec += 1000000; end.tv_sec--;
685 }
686 end.tv_sec -= begin.tv_sec;
687 end.tv_usec -= begin.tv_usec;
688 }
689
690 CDEBUG(D_SPECIAL, "begin: %ld.%06ld, elapsed: %ld.%06ld\n",
691 begin.tv_sec, (unsigned long)begin.tv_usec,
692 end.tv_sec, (unsigned long)end.tv_usec);
693
694 return ((end.tv_sec * 1000000) + end.tv_usec);
695 }
696
697
698 /*
699 * coda_upcall will return an error in the case of
700 * failed communication with Venus _or_ will peek at Venus
701 * reply and return Venus' error.
702 *
703 * As venus has 2 types of errors, normal errors (positive) and internal
704 * errors (negative), normal errors are negated, while internal errors
705 * are all mapped to -EINTR, while showing a nice warning message. (jh)
706 *
707 */
coda_upcall(struct coda_sb_info * sbi,int inSize,int * outSize,union inputArgs * buffer)708 static int coda_upcall(struct coda_sb_info *sbi,
709 int inSize, int *outSize,
710 union inputArgs *buffer)
711 {
712 unsigned long runtime;
713 struct venus_comm *vcommp;
714 union outputArgs *out;
715 struct upc_req *req;
716 int error = 0;
717
718 vcommp = sbi->sbi_vcomm;
719 if ( !vcommp->vc_inuse ) {
720 printk("No pseudo device in upcall comms at %p\n", vcommp);
721 return -ENXIO;
722 }
723
724 /* Format the request message. */
725 req = upc_alloc();
726 if (!req) {
727 printk("Failed to allocate upc_req structure\n");
728 return -ENOMEM;
729 }
730 req->uc_data = (void *)buffer;
731 req->uc_flags = 0;
732 req->uc_inSize = inSize;
733 req->uc_outSize = *outSize ? *outSize : inSize;
734 req->uc_opcode = ((union inputArgs *)buffer)->ih.opcode;
735 req->uc_unique = ++vcommp->vc_seq;
736 init_waitqueue_head(&req->uc_sleep);
737
738 /* Fill in the common input args. */
739 ((union inputArgs *)buffer)->ih.unique = req->uc_unique;
740
741 /* Append msg to pending queue and poke Venus. */
742 list_add(&(req->uc_chain), vcommp->vc_pending.prev);
743
744 CDEBUG(D_UPCALL,
745 "Proc %d wake Venus for(opc,uniq) =(%d,%d) msg at %p.zzz.\n",
746 current->pid, req->uc_opcode, req->uc_unique, req);
747
748 wake_up_interruptible(&vcommp->vc_waitq);
749 /* We can be interrupted while we wait for Venus to process
750 * our request. If the interrupt occurs before Venus has read
751 * the request, we dequeue and return. If it occurs after the
752 * read but before the reply, we dequeue, send a signal
753 * message, and return. If it occurs after the reply we ignore
754 * it. In no case do we want to restart the syscall. If it
755 * was interrupted by a venus shutdown (psdev_close), return
756 * ENODEV. */
757
758 /* Go to sleep. Wake up on signals only after the timeout. */
759 runtime = coda_waitfor_upcall(req, vcommp);
760 coda_upcall_stats(((union inputArgs *)buffer)->ih.opcode, runtime);
761
762 CDEBUG(D_TIMING, "opc: %d time: %ld uniq: %d size: %d\n",
763 req->uc_opcode, jiffies - req->uc_posttime,
764 req->uc_unique, req->uc_outSize);
765 CDEBUG(D_UPCALL,
766 "..process %d woken up by Venus for req at %p, data at %p\n",
767 current->pid, req, req->uc_data);
768 if (vcommp->vc_inuse) { /* i.e. Venus is still alive */
769 /* Op went through, interrupt or not... */
770 if (req->uc_flags & REQ_WRITE) {
771 out = (union outputArgs *)req->uc_data;
772 /* here we map positive Venus errors to kernel errors */
773 error = -out->oh.result;
774 CDEBUG(D_UPCALL,
775 "upcall: (u,o,r) (%ld, %ld, %ld) out at %p\n",
776 out->oh.unique, out->oh.opcode, out->oh.result, out);
777 *outSize = req->uc_outSize;
778 goto exit;
779 }
780 if ( !(req->uc_flags & REQ_READ) && signal_pending(current)) {
781 /* Interrupted before venus read it. */
782 CDEBUG(D_UPCALL,
783 "Interrupted before read:(op,un) (%d.%d), flags = %x\n",
784 req->uc_opcode, req->uc_unique, req->uc_flags);
785 list_del(&(req->uc_chain));
786 /* perhaps the best way to convince the app to
787 give up? */
788 error = -EINTR;
789 goto exit;
790 }
791 if ( (req->uc_flags & REQ_READ) && signal_pending(current) ) {
792 /* interrupted after Venus did its read, send signal */
793 union inputArgs *sig_inputArgs;
794 struct upc_req *sig_req;
795
796 CDEBUG(D_UPCALL,
797 "Sending Venus a signal: op = %d.%d, flags = %x\n",
798 req->uc_opcode, req->uc_unique, req->uc_flags);
799
800 list_del(&(req->uc_chain));
801 error = -ENOMEM;
802 sig_req = upc_alloc();
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) {
807 upc_free(sig_req);
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 CDEBUG(D_UPCALL,
822 "coda_upcall: enqueing signal msg (%d, %d)\n",
823 sig_req->uc_opcode, sig_req->uc_unique);
824
825 /* insert at head of queue! */
826 list_add(&(sig_req->uc_chain), &vcommp->vc_pending);
827 wake_up_interruptible(&vcommp->vc_waitq);
828 } else {
829 printk("Coda: Strange interruption..\n");
830 error = -EINTR;
831 }
832 } else { /* If venus died i.e. !VC_OPEN(vcommp) */
833 printk("coda_upcall: Venus dead on (op,un) (%d.%d) flags %d\n",
834 req->uc_opcode, req->uc_unique, req->uc_flags);
835 error = -ENODEV;
836 }
837
838 exit:
839 upc_free(req);
840 if (error)
841 badclstats();
842 return error;
843 }
844
845 /*
846 The statements below are part of the Coda opportunistic
847 programming -- taken from the Mach/BSD kernel code for Coda.
848 You don't get correct semantics by stating what needs to be
849 done without guaranteeing the invariants needed for it to happen.
850 When will be have time to find out what exactly is going on? (pjb)
851 */
852
853
854 /*
855 * There are 7 cases where cache invalidations occur. The semantics
856 * of each is listed here:
857 *
858 * CODA_FLUSH -- flush all entries from the name cache and the cnode cache.
859 * CODA_PURGEUSER -- flush all entries from the name cache for a specific user
860 * This call is a result of token expiration.
861 *
862 * The next arise as the result of callbacks on a file or directory.
863 * CODA_ZAPFILE -- flush the cached attributes for a file.
864
865 * CODA_ZAPDIR -- flush the attributes for the dir and
866 * force a new lookup for all the children
867 of this dir.
868
869 *
870 * The next is a result of Venus detecting an inconsistent file.
871 * CODA_PURGEFID -- flush the attribute for the file
872 * purge it and its children from the dcache
873 *
874 * The last allows Venus to replace local fids with global ones
875 * during reintegration.
876 *
877 * CODA_REPLACE -- replace one ViceFid with another throughout the name cache */
878
coda_downcall(int opcode,union outputArgs * out,struct super_block * sb)879 int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
880 {
881 /* Handle invalidation requests. */
882 if ( !sb || !sb->s_root || !sb->s_root->d_inode) {
883 CDEBUG(D_DOWNCALL, "coda_downcall: opcode %d, no sb!\n", opcode);
884 return 0;
885 }
886
887 switch (opcode) {
888
889 case CODA_FLUSH : {
890 clstats(CODA_FLUSH);
891 CDEBUG(D_DOWNCALL, "CODA_FLUSH\n");
892 coda_cache_clear_all(sb, NULL);
893 shrink_dcache_sb(sb);
894 coda_flag_inode(sb->s_root->d_inode, C_FLUSH);
895 return(0);
896 }
897
898 case CODA_PURGEUSER : {
899 struct coda_cred *cred = &out->coda_purgeuser.cred;
900 CDEBUG(D_DOWNCALL, "CODA_PURGEUSER\n");
901 if ( !cred ) {
902 printk("PURGEUSER: null cred!\n");
903 return 0;
904 }
905 clstats(CODA_PURGEUSER);
906 coda_cache_clear_all(sb, cred);
907 return(0);
908 }
909
910 case CODA_ZAPDIR : {
911 struct inode *inode;
912 ViceFid *fid = &out->coda_zapdir.CodaFid;
913 CDEBUG(D_DOWNCALL, "zapdir: fid = %s...\n", coda_f2s(fid));
914 clstats(CODA_ZAPDIR);
915
916 inode = coda_fid_to_inode(fid, sb);
917 if (inode) {
918 CDEBUG(D_DOWNCALL, "zapdir: inode = %ld children flagged\n",
919 inode->i_ino);
920 coda_flag_inode_children(inode, C_PURGE);
921 CDEBUG(D_DOWNCALL, "zapdir: inode = %ld cache cleared\n", inode->i_ino);
922 coda_flag_inode(inode, C_VATTR);
923 iput(inode);
924 } else
925 CDEBUG(D_DOWNCALL, "zapdir: no inode\n");
926
927 return(0);
928 }
929
930 case CODA_ZAPFILE : {
931 struct inode *inode;
932 struct ViceFid *fid = &out->coda_zapfile.CodaFid;
933 clstats(CODA_ZAPFILE);
934 CDEBUG(D_DOWNCALL, "zapfile: fid = %s\n", coda_f2s(fid));
935 inode = coda_fid_to_inode(fid, sb);
936 if ( inode ) {
937 CDEBUG(D_DOWNCALL, "zapfile: inode = %ld\n",
938 inode->i_ino);
939 coda_flag_inode(inode, C_VATTR);
940 iput(inode);
941 } else
942 CDEBUG(D_DOWNCALL, "zapfile: no inode\n");
943 return 0;
944 }
945
946 case CODA_PURGEFID : {
947 struct inode *inode;
948 ViceFid *fid = &out->coda_purgefid.CodaFid;
949 CDEBUG(D_DOWNCALL, "purgefid: fid = %s\n", coda_f2s(fid));
950 clstats(CODA_PURGEFID);
951 inode = coda_fid_to_inode(fid, sb);
952 if ( inode ) {
953 CDEBUG(D_DOWNCALL, "purgefid: inode = %ld\n",
954 inode->i_ino);
955 coda_flag_inode_children(inode, C_PURGE);
956
957 /* catch the dentries later if some are still busy */
958 coda_flag_inode(inode, C_PURGE);
959 d_prune_aliases(inode);
960
961 iput(inode);
962 } else
963 CDEBUG(D_DOWNCALL, "purgefid: no inode\n");
964 return 0;
965 }
966
967 case CODA_REPLACE : {
968 struct inode *inode;
969 ViceFid *oldfid = &out->coda_replace.OldFid;
970 ViceFid *newfid = &out->coda_replace.NewFid;
971 clstats(CODA_REPLACE);
972 CDEBUG(D_DOWNCALL, "CODA_REPLACE\n");
973 inode = coda_fid_to_inode(oldfid, sb);
974 if ( inode ) {
975 CDEBUG(D_DOWNCALL, "replacefid: inode = %ld\n",
976 inode->i_ino);
977 coda_replace_fid(inode, oldfid, newfid);
978 iput(inode);
979 }else
980 CDEBUG(D_DOWNCALL, "purgefid: no inode\n");
981
982 return 0;
983 }
984 }
985 return 0;
986 }
987
988