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