This source file includes following definitions.
- alloc_upcall
- venus_rootfid
- venus_getattr
- venus_setattr
- venus_lookup
- venus_close
- venus_open
- venus_mkdir
- venus_rename
- venus_create
- venus_rmdir
- venus_remove
- venus_readlink
- venus_link
- venus_symlink
- venus_fsync
- venus_access
- venus_pioctl
- venus_statfs
- venus_access_intent
- coda_block_signals
- coda_unblock_signals
- coda_waitfor_upcall
- coda_upcall
- coda_downcall
   1 
   2 
   3 
   4 
   5 
   6 
   7 
   8 
   9 
  10 
  11 
  12 
  13 
  14 
  15 
  16 
  17 
  18 #include <linux/signal.h>
  19 #include <linux/sched/signal.h>
  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 <linux/slab.h>
  30 #include <linux/mutex.h>
  31 #include <linux/uaccess.h>
  32 #include <linux/vmalloc.h>
  33 #include <linux/vfs.h>
  34 
  35 #include <linux/coda.h>
  36 #include "coda_psdev.h"
  37 #include "coda_linux.h"
  38 #include "coda_cache.h"
  39 
  40 #include "coda_int.h"
  41 
  42 static int coda_upcall(struct venus_comm *vc, int inSize, int *outSize,
  43                        union inputArgs *buffer);
  44 
  45 static void *alloc_upcall(int opcode, int size)
  46 {
  47         union inputArgs *inp;
  48 
  49         inp = kvzalloc(size, GFP_KERNEL);
  50         if (!inp)
  51                 return ERR_PTR(-ENOMEM);
  52 
  53         inp->ih.opcode = opcode;
  54         inp->ih.pid = task_pid_nr_ns(current, &init_pid_ns);
  55         inp->ih.pgid = task_pgrp_nr_ns(current, &init_pid_ns);
  56         inp->ih.uid = from_kuid(&init_user_ns, current_fsuid());
  57 
  58         return (void*)inp;
  59 }
  60 
  61 #define UPARG(op)\
  62 do {\
  63         inp = (union inputArgs *)alloc_upcall(op, insize); \
  64         if (IS_ERR(inp)) { return PTR_ERR(inp); }\
  65         outp = (union outputArgs *)(inp); \
  66         outsize = insize; \
  67 } while (0)
  68 
  69 #define INSIZE(tag) sizeof(struct coda_ ## tag ## _in)
  70 #define OUTSIZE(tag) sizeof(struct coda_ ## tag ## _out)
  71 #define SIZE(tag)  max_t(unsigned int, INSIZE(tag), OUTSIZE(tag))
  72 
  73 
  74 
  75 int venus_rootfid(struct super_block *sb, struct CodaFid *fidp)
  76 {
  77         union inputArgs *inp;
  78         union outputArgs *outp;
  79         int insize, outsize, error;
  80 
  81         insize = SIZE(root);
  82         UPARG(CODA_ROOT);
  83 
  84         error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
  85         if (!error)
  86                 *fidp = outp->coda_root.VFid;
  87 
  88         kvfree(inp);
  89         return error;
  90 }
  91 
  92 int venus_getattr(struct super_block *sb, struct CodaFid *fid, 
  93                      struct coda_vattr *attr) 
  94 {
  95         union inputArgs *inp;
  96         union outputArgs *outp;
  97         int insize, outsize, error;
  98 
  99         insize = SIZE(getattr); 
 100         UPARG(CODA_GETATTR);
 101         inp->coda_getattr.VFid = *fid;
 102 
 103         error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 104         if (!error)
 105                 *attr = outp->coda_getattr.attr;
 106 
 107         kvfree(inp);
 108         return error;
 109 }
 110 
 111 int venus_setattr(struct super_block *sb, struct CodaFid *fid, 
 112                   struct coda_vattr *vattr)
 113 {
 114         union inputArgs *inp;
 115         union outputArgs *outp;
 116         int insize, outsize, error;
 117         
 118         insize = SIZE(setattr);
 119         UPARG(CODA_SETATTR);
 120 
 121         inp->coda_setattr.VFid = *fid;
 122         inp->coda_setattr.attr = *vattr;
 123 
 124         error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 125 
 126         kvfree(inp);
 127         return error;
 128 }
 129 
 130 int venus_lookup(struct super_block *sb, struct CodaFid *fid, 
 131                     const char *name, int length, int * type, 
 132                     struct CodaFid *resfid)
 133 {
 134         union inputArgs *inp;
 135         union outputArgs *outp;
 136         int insize, outsize, error;
 137         int offset;
 138 
 139         offset = INSIZE(lookup);
 140         insize = max_t(unsigned int, offset + length +1, OUTSIZE(lookup));
 141         UPARG(CODA_LOOKUP);
 142 
 143         inp->coda_lookup.VFid = *fid;
 144         inp->coda_lookup.name = offset;
 145         inp->coda_lookup.flags = CLU_CASE_SENSITIVE;
 146         
 147         memcpy((char *)(inp) + offset, name, length);
 148         *((char *)inp + offset + length) = '\0';
 149 
 150         error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 151         if (!error) {
 152                 *resfid = outp->coda_lookup.VFid;
 153                 *type = outp->coda_lookup.vtype;
 154         }
 155 
 156         kvfree(inp);
 157         return error;
 158 }
 159 
 160 int venus_close(struct super_block *sb, struct CodaFid *fid, int flags,
 161                 kuid_t uid)
 162 {
 163         union inputArgs *inp;
 164         union outputArgs *outp;
 165         int insize, outsize, error;
 166         
 167         insize = SIZE(release);
 168         UPARG(CODA_CLOSE);
 169         
 170         inp->ih.uid = from_kuid(&init_user_ns, uid);
 171         inp->coda_close.VFid = *fid;
 172         inp->coda_close.flags = flags;
 173 
 174         error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 175 
 176         kvfree(inp);
 177         return error;
 178 }
 179 
 180 int venus_open(struct super_block *sb, struct CodaFid *fid,
 181                   int flags, struct file **fh)
 182 {
 183         union inputArgs *inp;
 184         union outputArgs *outp;
 185         int insize, outsize, error;
 186        
 187         insize = SIZE(open_by_fd);
 188         UPARG(CODA_OPEN_BY_FD);
 189 
 190         inp->coda_open_by_fd.VFid = *fid;
 191         inp->coda_open_by_fd.flags = flags;
 192 
 193         error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 194         if (!error)
 195                 *fh = outp->coda_open_by_fd.fh;
 196 
 197         kvfree(inp);
 198         return error;
 199 }       
 200 
 201 int venus_mkdir(struct super_block *sb, struct CodaFid *dirfid, 
 202                    const char *name, int length, 
 203                    struct CodaFid *newfid, struct coda_vattr *attrs)
 204 {
 205         union inputArgs *inp;
 206         union outputArgs *outp;
 207         int insize, outsize, error;
 208         int offset;
 209 
 210         offset = INSIZE(mkdir);
 211         insize = max_t(unsigned int, offset + length + 1, OUTSIZE(mkdir));
 212         UPARG(CODA_MKDIR);
 213 
 214         inp->coda_mkdir.VFid = *dirfid;
 215         inp->coda_mkdir.attr = *attrs;
 216         inp->coda_mkdir.name = offset;
 217         
 218         memcpy((char *)(inp) + offset, name, length);
 219         *((char *)inp + offset + length) = '\0';
 220 
 221         error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 222         if (!error) {
 223                 *attrs = outp->coda_mkdir.attr;
 224                 *newfid = outp->coda_mkdir.VFid;
 225         }
 226 
 227         kvfree(inp);
 228         return error;        
 229 }
 230 
 231 
 232 int venus_rename(struct super_block *sb, struct CodaFid *old_fid, 
 233                  struct CodaFid *new_fid, size_t old_length, 
 234                  size_t new_length, const char *old_name, 
 235                  const char *new_name)
 236 {
 237         union inputArgs *inp;
 238         union outputArgs *outp;
 239         int insize, outsize, error; 
 240         int offset, s;
 241         
 242         offset = INSIZE(rename);
 243         insize = max_t(unsigned int, offset + new_length + old_length + 8,
 244                      OUTSIZE(rename)); 
 245         UPARG(CODA_RENAME);
 246 
 247         inp->coda_rename.sourceFid = *old_fid;
 248         inp->coda_rename.destFid =  *new_fid;
 249         inp->coda_rename.srcname = offset;
 250 
 251         
 252         s = ( old_length & ~0x3) +4; 
 253         memcpy((char *)(inp) + offset, old_name, old_length);
 254         *((char *)inp + offset + old_length) = '\0';
 255 
 256         
 257         offset += s;
 258         inp->coda_rename.destname = offset;
 259         s = ( new_length & ~0x3) +4; 
 260         memcpy((char *)(inp) + offset, new_name, new_length);
 261         *((char *)inp + offset + new_length) = '\0';
 262 
 263         error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 264 
 265         kvfree(inp);
 266         return error;
 267 }
 268 
 269 int venus_create(struct super_block *sb, struct CodaFid *dirfid, 
 270                  const char *name, int length, int excl, int mode,
 271                  struct CodaFid *newfid, struct coda_vattr *attrs) 
 272 {
 273         union inputArgs *inp;
 274         union outputArgs *outp;
 275         int insize, outsize, error;
 276         int offset;
 277 
 278         offset = INSIZE(create);
 279         insize = max_t(unsigned int, offset + length + 1, OUTSIZE(create));
 280         UPARG(CODA_CREATE);
 281 
 282         inp->coda_create.VFid = *dirfid;
 283         inp->coda_create.attr.va_mode = mode;
 284         inp->coda_create.excl = excl;
 285         inp->coda_create.mode = mode;
 286         inp->coda_create.name = offset;
 287 
 288         
 289         memcpy((char *)(inp) + offset, name, length);
 290         *((char *)inp + offset + length) = '\0';
 291 
 292         error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 293         if (!error) {
 294                 *attrs = outp->coda_create.attr;
 295                 *newfid = outp->coda_create.VFid;
 296         }
 297 
 298         kvfree(inp);
 299         return error;        
 300 }
 301 
 302 int venus_rmdir(struct super_block *sb, struct CodaFid *dirfid, 
 303                     const char *name, int length)
 304 {
 305         union inputArgs *inp;
 306         union outputArgs *outp;
 307         int insize, outsize, error;
 308         int offset;
 309 
 310         offset = INSIZE(rmdir);
 311         insize = max_t(unsigned int, offset + length + 1, OUTSIZE(rmdir));
 312         UPARG(CODA_RMDIR);
 313 
 314         inp->coda_rmdir.VFid = *dirfid;
 315         inp->coda_rmdir.name = offset;
 316         memcpy((char *)(inp) + offset, name, length);
 317         *((char *)inp + offset + length) = '\0';
 318 
 319         error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 320 
 321         kvfree(inp);
 322         return error;
 323 }
 324 
 325 int venus_remove(struct super_block *sb, struct CodaFid *dirfid, 
 326                     const char *name, int length)
 327 {
 328         union inputArgs *inp;
 329         union outputArgs *outp;
 330         int error=0, insize, outsize, offset;
 331 
 332         offset = INSIZE(remove);
 333         insize = max_t(unsigned int, offset + length + 1, OUTSIZE(remove));
 334         UPARG(CODA_REMOVE);
 335 
 336         inp->coda_remove.VFid = *dirfid;
 337         inp->coda_remove.name = offset;
 338         memcpy((char *)(inp) + offset, name, length);
 339         *((char *)inp + offset + length) = '\0';
 340 
 341         error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 342 
 343         kvfree(inp);
 344         return error;
 345 }
 346 
 347 int venus_readlink(struct super_block *sb, struct CodaFid *fid, 
 348                       char *buffer, int *length)
 349 { 
 350         union inputArgs *inp;
 351         union outputArgs *outp;
 352         int insize, outsize, error;
 353         int retlen;
 354         char *result;
 355         
 356         insize = max_t(unsigned int,
 357                      INSIZE(readlink), OUTSIZE(readlink)+ *length);
 358         UPARG(CODA_READLINK);
 359 
 360         inp->coda_readlink.VFid = *fid;
 361 
 362         error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 363         if (!error) {
 364                 retlen = outp->coda_readlink.count;
 365                 if (retlen >= *length)
 366                         retlen = *length - 1;
 367                 *length = retlen;
 368                 result =  (char *)outp + (long)outp->coda_readlink.data;
 369                 memcpy(buffer, result, retlen);
 370                 *(buffer + retlen) = '\0';
 371         }
 372 
 373         kvfree(inp);
 374         return error;
 375 }
 376 
 377 
 378 
 379 int venus_link(struct super_block *sb, struct CodaFid *fid, 
 380                   struct CodaFid *dirfid, const char *name, int len )
 381 {
 382         union inputArgs *inp;
 383         union outputArgs *outp;
 384         int insize, outsize, error;
 385         int offset;
 386 
 387         offset = INSIZE(link);
 388         insize = max_t(unsigned int, offset  + len + 1, OUTSIZE(link));
 389         UPARG(CODA_LINK);
 390 
 391         inp->coda_link.sourceFid = *fid;
 392         inp->coda_link.destFid = *dirfid;
 393         inp->coda_link.tname = offset;
 394 
 395         
 396         memcpy((char *)(inp) + offset, name, len);
 397         *((char *)inp + offset + len) = '\0';
 398 
 399         error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 400 
 401         kvfree(inp);
 402         return error;
 403 }
 404 
 405 int venus_symlink(struct super_block *sb, struct CodaFid *fid,
 406                      const char *name, int len,
 407                      const char *symname, int symlen)
 408 {
 409         union inputArgs *inp;
 410         union outputArgs *outp;
 411         int insize, outsize, error;
 412         int offset, s;
 413 
 414         offset = INSIZE(symlink);
 415         insize = max_t(unsigned int, offset + len + symlen + 8, OUTSIZE(symlink));
 416         UPARG(CODA_SYMLINK);
 417         
 418          
 419         inp->coda_symlink.VFid = *fid;
 420 
 421         
 422         inp->coda_symlink.srcname = offset;
 423         s = ( symlen  & ~0x3 ) + 4; 
 424         memcpy((char *)(inp) + offset, symname, symlen);
 425         *((char *)inp + offset + symlen) = '\0';
 426         
 427         
 428         offset += s;
 429         inp->coda_symlink.tname = offset;
 430         s = (len & ~0x3) + 4;
 431         memcpy((char *)(inp) + offset, name, len);
 432         *((char *)inp + offset + len) = '\0';
 433 
 434         error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 435 
 436         kvfree(inp);
 437         return error;
 438 }
 439 
 440 int venus_fsync(struct super_block *sb, struct CodaFid *fid)
 441 {
 442         union inputArgs *inp;
 443         union outputArgs *outp; 
 444         int insize, outsize, error;
 445         
 446         insize=SIZE(fsync);
 447         UPARG(CODA_FSYNC);
 448 
 449         inp->coda_fsync.VFid = *fid;
 450         error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 451 
 452         kvfree(inp);
 453         return error;
 454 }
 455 
 456 int venus_access(struct super_block *sb, struct CodaFid *fid, int mask)
 457 {
 458         union inputArgs *inp;
 459         union outputArgs *outp; 
 460         int insize, outsize, error;
 461 
 462         insize = SIZE(access);
 463         UPARG(CODA_ACCESS);
 464 
 465         inp->coda_access.VFid = *fid;
 466         inp->coda_access.flags = mask;
 467 
 468         error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 469 
 470         kvfree(inp);
 471         return error;
 472 }
 473 
 474 
 475 int venus_pioctl(struct super_block *sb, struct CodaFid *fid,
 476                  unsigned int cmd, struct PioctlData *data)
 477 {
 478         union inputArgs *inp;
 479         union outputArgs *outp;  
 480         int insize, outsize, error;
 481         int iocsize;
 482 
 483         insize = VC_MAXMSGSIZE;
 484         UPARG(CODA_IOCTL);
 485 
 486         
 487         if (data->vi.in_size > VC_MAXDATASIZE) {
 488                 error = -EINVAL;
 489                 goto exit;
 490         }
 491 
 492         if (data->vi.out_size > VC_MAXDATASIZE) {
 493                 error = -EINVAL;
 494                 goto exit;
 495         }
 496 
 497         inp->coda_ioctl.VFid = *fid;
 498     
 499         
 500 
 501 
 502         inp->coda_ioctl.cmd = (cmd & ~(PIOCPARM_MASK << 16));   
 503         iocsize = ((cmd >> 16) & PIOCPARM_MASK) - sizeof(char *) - sizeof(int);
 504         inp->coda_ioctl.cmd |= (iocsize & PIOCPARM_MASK) <<     16;     
 505     
 506         
 507         inp->coda_ioctl.len = data->vi.in_size;
 508         inp->coda_ioctl.data = (char *)(INSIZE(ioctl));
 509      
 510         
 511         if (copy_from_user((char *)inp + (long)inp->coda_ioctl.data,
 512                            data->vi.in, data->vi.in_size)) {
 513                 error = -EINVAL;
 514                 goto exit;
 515         }
 516 
 517         error = coda_upcall(coda_vcp(sb), SIZE(ioctl) + data->vi.in_size,
 518                             &outsize, inp);
 519 
 520         if (error) {
 521                 pr_warn("%s: Venus returns: %d for %s\n",
 522                         __func__, error, coda_f2s(fid));
 523                 goto exit; 
 524         }
 525 
 526         if (outsize < (long)outp->coda_ioctl.data + outp->coda_ioctl.len) {
 527                 error = -EINVAL;
 528                 goto exit;
 529         }
 530         
 531         
 532         if (outp->coda_ioctl.len > data->vi.out_size) {
 533                 error = -EINVAL;
 534                 goto exit;
 535         }
 536 
 537         
 538         if (copy_to_user(data->vi.out,
 539                          (char *)outp + (long)outp->coda_ioctl.data,
 540                          outp->coda_ioctl.len)) {
 541                 error = -EFAULT;
 542                 goto exit;
 543         }
 544 
 545  exit:
 546         kvfree(inp);
 547         return error;
 548 }
 549 
 550 int venus_statfs(struct dentry *dentry, struct kstatfs *sfs)
 551 { 
 552         union inputArgs *inp;
 553         union outputArgs *outp;
 554         int insize, outsize, error;
 555         
 556         insize = SIZE(statfs);
 557         UPARG(CODA_STATFS);
 558 
 559         error = coda_upcall(coda_vcp(dentry->d_sb), insize, &outsize, inp);
 560         if (!error) {
 561                 sfs->f_blocks = outp->coda_statfs.stat.f_blocks;
 562                 sfs->f_bfree  = outp->coda_statfs.stat.f_bfree;
 563                 sfs->f_bavail = outp->coda_statfs.stat.f_bavail;
 564                 sfs->f_files  = outp->coda_statfs.stat.f_files;
 565                 sfs->f_ffree  = outp->coda_statfs.stat.f_ffree;
 566         }
 567 
 568         kvfree(inp);
 569         return error;
 570 }
 571 
 572 int venus_access_intent(struct super_block *sb, struct CodaFid *fid,
 573                         bool *access_intent_supported,
 574                         size_t count, loff_t ppos, int type)
 575 {
 576         union inputArgs *inp;
 577         union outputArgs *outp;
 578         int insize, outsize, error;
 579         bool finalizer =
 580                 type == CODA_ACCESS_TYPE_READ_FINISH ||
 581                 type == CODA_ACCESS_TYPE_WRITE_FINISH;
 582 
 583         if (!*access_intent_supported && !finalizer)
 584                 return 0;
 585 
 586         insize = SIZE(access_intent);
 587         UPARG(CODA_ACCESS_INTENT);
 588 
 589         inp->coda_access_intent.VFid = *fid;
 590         inp->coda_access_intent.count = count;
 591         inp->coda_access_intent.pos = ppos;
 592         inp->coda_access_intent.type = type;
 593 
 594         error = coda_upcall(coda_vcp(sb), insize,
 595                             finalizer ? NULL : &outsize, inp);
 596 
 597         
 598 
 599 
 600 
 601 
 602         if (!finalizer || error)
 603                 kvfree(inp);
 604 
 605         
 606         if (error == -EOPNOTSUPP) {
 607                 *access_intent_supported = false;
 608                 error = 0;
 609         }
 610         return error;
 611 }
 612 
 613 
 614 
 615 
 616 static void coda_block_signals(sigset_t *old)
 617 {
 618         spin_lock_irq(¤t->sighand->siglock);
 619         *old = current->blocked;
 620 
 621         sigfillset(¤t->blocked);
 622         sigdelset(¤t->blocked, SIGKILL);
 623         sigdelset(¤t->blocked, SIGSTOP);
 624         sigdelset(¤t->blocked, SIGINT);
 625 
 626         recalc_sigpending();
 627         spin_unlock_irq(¤t->sighand->siglock);
 628 }
 629 
 630 static void coda_unblock_signals(sigset_t *old)
 631 {
 632         spin_lock_irq(¤t->sighand->siglock);
 633         current->blocked = *old;
 634         recalc_sigpending();
 635         spin_unlock_irq(¤t->sighand->siglock);
 636 }
 637 
 638 
 639 
 640 
 641 
 642 
 643 
 644 #define CODA_INTERRUPTIBLE(r) (!coda_hard && \
 645                                (((r)->uc_opcode != CODA_CLOSE && \
 646                                  (r)->uc_opcode != CODA_STORE && \
 647                                  (r)->uc_opcode != CODA_ACCESS_INTENT && \
 648                                  (r)->uc_opcode != CODA_RELEASE) || \
 649                                 (r)->uc_flags & CODA_REQ_READ))
 650 
 651 static inline void coda_waitfor_upcall(struct venus_comm *vcp,
 652                                        struct upc_req *req)
 653 {
 654         DECLARE_WAITQUEUE(wait, current);
 655         unsigned long timeout = jiffies + coda_timeout * HZ;
 656         sigset_t old;
 657         int blocked;
 658 
 659         coda_block_signals(&old);
 660         blocked = 1;
 661 
 662         add_wait_queue(&req->uc_sleep, &wait);
 663         for (;;) {
 664                 if (CODA_INTERRUPTIBLE(req))
 665                         set_current_state(TASK_INTERRUPTIBLE);
 666                 else
 667                         set_current_state(TASK_UNINTERRUPTIBLE);
 668 
 669                 
 670                 if (req->uc_flags & (CODA_REQ_WRITE | CODA_REQ_ABORT))
 671                         break;
 672 
 673                 if (blocked && time_after(jiffies, timeout) &&
 674                     CODA_INTERRUPTIBLE(req))
 675                 {
 676                         coda_unblock_signals(&old);
 677                         blocked = 0;
 678                 }
 679 
 680                 if (signal_pending(current)) {
 681                         list_del(&req->uc_chain);
 682                         break;
 683                 }
 684 
 685                 mutex_unlock(&vcp->vc_mutex);
 686                 if (blocked)
 687                         schedule_timeout(HZ);
 688                 else
 689                         schedule();
 690                 mutex_lock(&vcp->vc_mutex);
 691         }
 692         if (blocked)
 693                 coda_unblock_signals(&old);
 694 
 695         remove_wait_queue(&req->uc_sleep, &wait);
 696         set_current_state(TASK_RUNNING);
 697 }
 698 
 699 
 700 
 701 
 702 
 703 
 704 
 705 
 706 
 707 
 708 
 709 static int coda_upcall(struct venus_comm *vcp,
 710                        int inSize, int *outSize,
 711                        union inputArgs *buffer)
 712 {
 713         union outputArgs *out;
 714         union inputArgs *sig_inputArgs;
 715         struct upc_req *req = NULL, *sig_req;
 716         int error;
 717 
 718         mutex_lock(&vcp->vc_mutex);
 719 
 720         if (!vcp->vc_inuse) {
 721                 pr_notice("Venus dead, not sending upcall\n");
 722                 error = -ENXIO;
 723                 goto exit;
 724         }
 725 
 726         
 727         req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
 728         if (!req) {
 729                 error = -ENOMEM;
 730                 goto exit;
 731         }
 732 
 733         buffer->ih.unique = ++vcp->vc_seq;
 734 
 735         req->uc_data = (void *)buffer;
 736         req->uc_flags = outSize ? 0 : CODA_REQ_ASYNC;
 737         req->uc_inSize = inSize;
 738         req->uc_outSize = (outSize && *outSize) ? *outSize : inSize;
 739         req->uc_opcode = buffer->ih.opcode;
 740         req->uc_unique = buffer->ih.unique;
 741         init_waitqueue_head(&req->uc_sleep);
 742 
 743         
 744         list_add_tail(&req->uc_chain, &vcp->vc_pending);
 745         wake_up_interruptible(&vcp->vc_waitq);
 746 
 747         if (req->uc_flags & CODA_REQ_ASYNC) {
 748                 mutex_unlock(&vcp->vc_mutex);
 749                 return 0;
 750         }
 751 
 752         
 753 
 754 
 755 
 756 
 757 
 758 
 759 
 760 
 761         
 762         coda_waitfor_upcall(vcp, req);
 763 
 764         
 765         if (req->uc_flags & CODA_REQ_WRITE) {
 766                 out = (union outputArgs *)req->uc_data;
 767                 
 768                 error = -out->oh.result;
 769                 *outSize = req->uc_outSize;
 770                 goto exit;
 771         }
 772 
 773         error = -EINTR;
 774         if ((req->uc_flags & CODA_REQ_ABORT) || !signal_pending(current)) {
 775                 pr_warn("Unexpected interruption.\n");
 776                 goto exit;
 777         }
 778 
 779         
 780         if (!(req->uc_flags & CODA_REQ_READ))
 781                 goto exit;
 782 
 783         
 784         if (!vcp->vc_inuse) {
 785                 pr_info("Venus dead, not sending signal.\n");
 786                 goto exit;
 787         }
 788 
 789         error = -ENOMEM;
 790         sig_req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
 791         if (!sig_req) goto exit;
 792 
 793         sig_inputArgs = kvzalloc(sizeof(struct coda_in_hdr), GFP_KERNEL);
 794         if (!sig_inputArgs) {
 795                 kfree(sig_req);
 796                 goto exit;
 797         }
 798 
 799         error = -EINTR;
 800         sig_inputArgs->ih.opcode = CODA_SIGNAL;
 801         sig_inputArgs->ih.unique = req->uc_unique;
 802 
 803         sig_req->uc_flags = CODA_REQ_ASYNC;
 804         sig_req->uc_opcode = sig_inputArgs->ih.opcode;
 805         sig_req->uc_unique = sig_inputArgs->ih.unique;
 806         sig_req->uc_data = (void *)sig_inputArgs;
 807         sig_req->uc_inSize = sizeof(struct coda_in_hdr);
 808         sig_req->uc_outSize = sizeof(struct coda_in_hdr);
 809 
 810         
 811         list_add(&(sig_req->uc_chain), &vcp->vc_pending);
 812         wake_up_interruptible(&vcp->vc_waitq);
 813 
 814 exit:
 815         kfree(req);
 816         mutex_unlock(&vcp->vc_mutex);
 817         return error;
 818 }
 819 
 820 
 821 
 822 
 823 
 824 
 825 
 826 
 827 
 828 
 829 
 830 
 831 
 832 
 833 
 834 
 835 
 836 
 837 
 838 
 839 
 840 
 841 
 842 
 843 
 844 
 845 
 846 
 847 
 848 
 849 
 850 
 851 
 852 
 853 
 854 int coda_downcall(struct venus_comm *vcp, int opcode, union outputArgs *out,
 855                   size_t nbytes)
 856 {
 857         struct inode *inode = NULL;
 858         struct CodaFid *fid = NULL, *newfid;
 859         struct super_block *sb;
 860 
 861         
 862 
 863 
 864 
 865         switch (opcode) {
 866         case CODA_PURGEUSER:
 867                 if (nbytes < sizeof(struct coda_purgeuser_out))
 868                         return -EINVAL;
 869                 break;
 870 
 871         case CODA_ZAPDIR:
 872                 if (nbytes < sizeof(struct coda_zapdir_out))
 873                         return -EINVAL;
 874                 break;
 875 
 876         case CODA_ZAPFILE:
 877                 if (nbytes < sizeof(struct coda_zapfile_out))
 878                         return -EINVAL;
 879                 break;
 880 
 881         case CODA_PURGEFID:
 882                 if (nbytes < sizeof(struct coda_purgefid_out))
 883                         return -EINVAL;
 884                 break;
 885 
 886         case CODA_REPLACE:
 887                 if (nbytes < sizeof(struct coda_replace_out))
 888                         return -EINVAL;
 889                 break;
 890         }
 891 
 892         
 893         mutex_lock(&vcp->vc_mutex);
 894         sb = vcp->vc_sb;
 895         if (!sb || !sb->s_root)
 896                 goto unlock_out;
 897 
 898         switch (opcode) {
 899         case CODA_FLUSH:
 900                 coda_cache_clear_all(sb);
 901                 shrink_dcache_sb(sb);
 902                 if (d_really_is_positive(sb->s_root))
 903                         coda_flag_inode(d_inode(sb->s_root), C_FLUSH);
 904                 break;
 905 
 906         case CODA_PURGEUSER:
 907                 coda_cache_clear_all(sb);
 908                 break;
 909 
 910         case CODA_ZAPDIR:
 911                 fid = &out->coda_zapdir.CodaFid;
 912                 break;
 913 
 914         case CODA_ZAPFILE:
 915                 fid = &out->coda_zapfile.CodaFid;
 916                 break;
 917 
 918         case CODA_PURGEFID:
 919                 fid = &out->coda_purgefid.CodaFid;
 920                 break;
 921 
 922         case CODA_REPLACE:
 923                 fid = &out->coda_replace.OldFid;
 924                 break;
 925         }
 926         if (fid)
 927                 inode = coda_fid_to_inode(fid, sb);
 928 
 929 unlock_out:
 930         mutex_unlock(&vcp->vc_mutex);
 931 
 932         if (!inode)
 933                 return 0;
 934 
 935         switch (opcode) {
 936         case CODA_ZAPDIR:
 937                 coda_flag_inode_children(inode, C_PURGE);
 938                 coda_flag_inode(inode, C_VATTR);
 939                 break;
 940 
 941         case CODA_ZAPFILE:
 942                 coda_flag_inode(inode, C_VATTR);
 943                 break;
 944 
 945         case CODA_PURGEFID:
 946                 coda_flag_inode_children(inode, C_PURGE);
 947 
 948                 
 949                 coda_flag_inode(inode, C_PURGE);
 950                 d_prune_aliases(inode);
 951                 break;
 952 
 953         case CODA_REPLACE:
 954                 newfid = &out->coda_replace.NewFid;
 955                 coda_replace_fid(inode, fid, newfid);
 956                 break;
 957         }
 958         iput(inode);
 959         return 0;
 960 }