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 44static int coda_upcall(struct coda_sb_info *mntinfo, int inSize, int *outSize, 45 union inputArgs *buffer); 46 47static 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)\ 64do {\ 65 inp = (union inputArgs *)alloc_upcall(op, insize); \ 66 if (IS_ERR(inp)) { return PTR_ERR(inp); }\ 67 outp = (union outputArgs *)(inp); \ 68 outsize = insize; \ 69} while (0) 70 71#define INSIZE(tag) sizeof(struct coda_ ## tag ## _in) 72#define OUTSIZE(tag) sizeof(struct coda_ ## tag ## _out) 73#define SIZE(tag) max_t(unsigned int, INSIZE(tag), OUTSIZE(tag)) 74 75 76/* the upcalls */ 77int venus_rootfid(struct super_block *sb, 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 100int 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 119int 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 139int 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 168int 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 189int 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 207int 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 228int 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 249int 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 279int 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 318int 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 351int 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 374int 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 396int 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 430int 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 457int 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 493int 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 510int 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 529int 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 599int 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 630static 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 */ 699static 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 870int 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 979