linux/fs/coda/upcall.c
<<
>>
Prefs
   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#include <linux/sched.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 <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
  39#include "coda_int.h"
  40
  41static int coda_upcall(struct venus_comm *vc, int inSize, int *outSize,
  42                       union inputArgs *buffer);
  43
  44static void *alloc_upcall(int opcode, int size)
  45{
  46        union inputArgs *inp;
  47
  48        CODA_ALLOC(inp, union inputArgs *, size);
  49        if (!inp)
  50                return ERR_PTR(-ENOMEM);
  51
  52        inp->ih.opcode = opcode;
  53        inp->ih.pid = current->pid;
  54        inp->ih.pgid = task_pgrp_nr(current);
  55        inp->ih.uid = current_fsuid();
  56
  57        return (void*)inp;
  58}
  59
  60#define UPARG(op)\
  61do {\
  62        inp = (union inputArgs *)alloc_upcall(op, insize); \
  63        if (IS_ERR(inp)) { return PTR_ERR(inp); }\
  64        outp = (union outputArgs *)(inp); \
  65        outsize = insize; \
  66} while (0)
  67
  68#define INSIZE(tag) sizeof(struct coda_ ## tag ## _in)
  69#define OUTSIZE(tag) sizeof(struct coda_ ## tag ## _out)
  70#define SIZE(tag)  max_t(unsigned int, INSIZE(tag), OUTSIZE(tag))
  71
  72
  73/* the upcalls */
  74int venus_rootfid(struct super_block *sb, struct CodaFid *fidp)
  75{
  76        union inputArgs *inp;
  77        union outputArgs *outp;
  78        int insize, outsize, error;
  79
  80        insize = SIZE(root);
  81        UPARG(CODA_ROOT);
  82
  83        error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
  84        if (!error)
  85                *fidp = outp->coda_root.VFid;
  86
  87        CODA_FREE(inp, insize);
  88        return error;
  89}
  90
  91int venus_getattr(struct super_block *sb, struct CodaFid *fid, 
  92                     struct coda_vattr *attr) 
  93{
  94        union inputArgs *inp;
  95        union outputArgs *outp;
  96        int insize, outsize, error;
  97
  98        insize = SIZE(getattr); 
  99        UPARG(CODA_GETATTR);
 100        inp->coda_getattr.VFid = *fid;
 101
 102        error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 103        if (!error)
 104                *attr = outp->coda_getattr.attr;
 105
 106        CODA_FREE(inp, insize);
 107        return error;
 108}
 109
 110int venus_setattr(struct super_block *sb, struct CodaFid *fid, 
 111                  struct coda_vattr *vattr)
 112{
 113        union inputArgs *inp;
 114        union outputArgs *outp;
 115        int insize, outsize, error;
 116        
 117        insize = SIZE(setattr);
 118        UPARG(CODA_SETATTR);
 119
 120        inp->coda_setattr.VFid = *fid;
 121        inp->coda_setattr.attr = *vattr;
 122
 123        error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 124
 125        CODA_FREE(inp, insize);
 126        return error;
 127}
 128
 129int venus_lookup(struct super_block *sb, struct CodaFid *fid, 
 130                    const char *name, int length, int * type, 
 131                    struct CodaFid *resfid)
 132{
 133        union inputArgs *inp;
 134        union outputArgs *outp;
 135        int insize, outsize, error;
 136        int offset;
 137
 138        offset = INSIZE(lookup);
 139        insize = max_t(unsigned int, offset + length +1, OUTSIZE(lookup));
 140        UPARG(CODA_LOOKUP);
 141
 142        inp->coda_lookup.VFid = *fid;
 143        inp->coda_lookup.name = offset;
 144        inp->coda_lookup.flags = CLU_CASE_SENSITIVE;
 145        /* send Venus a null terminated string */
 146        memcpy((char *)(inp) + offset, name, length);
 147        *((char *)inp + offset + length) = '\0';
 148
 149        error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 150        if (!error) {
 151                *resfid = outp->coda_lookup.VFid;
 152                *type = outp->coda_lookup.vtype;
 153        }
 154
 155        CODA_FREE(inp, insize);
 156        return error;
 157}
 158
 159int venus_close(struct super_block *sb, struct CodaFid *fid, int flags,
 160                vuid_t uid)
 161{
 162        union inputArgs *inp;
 163        union outputArgs *outp;
 164        int insize, outsize, error;
 165        
 166        insize = SIZE(release);
 167        UPARG(CODA_CLOSE);
 168        
 169        inp->ih.uid = uid;
 170        inp->coda_close.VFid = *fid;
 171        inp->coda_close.flags = flags;
 172
 173        error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 174
 175        CODA_FREE(inp, insize);
 176        return error;
 177}
 178
 179int venus_open(struct super_block *sb, struct CodaFid *fid,
 180                  int flags, struct file **fh)
 181{
 182        union inputArgs *inp;
 183        union outputArgs *outp;
 184        int insize, outsize, error;
 185       
 186        insize = SIZE(open_by_fd);
 187        UPARG(CODA_OPEN_BY_FD);
 188
 189        inp->coda_open_by_fd.VFid = *fid;
 190        inp->coda_open_by_fd.flags = flags;
 191
 192        error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 193        if (!error)
 194                *fh = outp->coda_open_by_fd.fh;
 195
 196        CODA_FREE(inp, insize);
 197        return error;
 198}       
 199
 200int venus_mkdir(struct super_block *sb, struct CodaFid *dirfid, 
 201                   const char *name, int length, 
 202                   struct CodaFid *newfid, struct coda_vattr *attrs)
 203{
 204        union inputArgs *inp;
 205        union outputArgs *outp;
 206        int insize, outsize, error;
 207        int offset;
 208
 209        offset = INSIZE(mkdir);
 210        insize = max_t(unsigned int, offset + length + 1, OUTSIZE(mkdir));
 211        UPARG(CODA_MKDIR);
 212
 213        inp->coda_mkdir.VFid = *dirfid;
 214        inp->coda_mkdir.attr = *attrs;
 215        inp->coda_mkdir.name = offset;
 216        /* Venus must get null terminated string */
 217        memcpy((char *)(inp) + offset, name, length);
 218        *((char *)inp + offset + length) = '\0';
 219
 220        error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 221        if (!error) {
 222                *attrs = outp->coda_mkdir.attr;
 223                *newfid = outp->coda_mkdir.VFid;
 224        }
 225
 226        CODA_FREE(inp, insize);
 227        return error;        
 228}
 229
 230
 231int venus_rename(struct super_block *sb, struct CodaFid *old_fid, 
 232                 struct CodaFid *new_fid, size_t old_length, 
 233                 size_t new_length, const char *old_name, 
 234                 const char *new_name)
 235{
 236        union inputArgs *inp;
 237        union outputArgs *outp;
 238        int insize, outsize, error; 
 239        int offset, s;
 240        
 241        offset = INSIZE(rename);
 242        insize = max_t(unsigned int, offset + new_length + old_length + 8,
 243                     OUTSIZE(rename)); 
 244        UPARG(CODA_RENAME);
 245
 246        inp->coda_rename.sourceFid = *old_fid;
 247        inp->coda_rename.destFid =  *new_fid;
 248        inp->coda_rename.srcname = offset;
 249
 250        /* Venus must receive an null terminated string */
 251        s = ( old_length & ~0x3) +4; /* round up to word boundary */
 252        memcpy((char *)(inp) + offset, old_name, old_length);
 253        *((char *)inp + offset + old_length) = '\0';
 254
 255        /* another null terminated string for Venus */
 256        offset += s;
 257        inp->coda_rename.destname = offset;
 258        s = ( new_length & ~0x3) +4; /* round up to word boundary */
 259        memcpy((char *)(inp) + offset, new_name, new_length);
 260        *((char *)inp + offset + new_length) = '\0';
 261
 262        error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 263
 264        CODA_FREE(inp, insize);
 265        return error;
 266}
 267
 268int venus_create(struct super_block *sb, struct CodaFid *dirfid, 
 269                 const char *name, int length, int excl, int mode,
 270                 struct CodaFid *newfid, struct coda_vattr *attrs) 
 271{
 272        union inputArgs *inp;
 273        union outputArgs *outp;
 274        int insize, outsize, error;
 275        int offset;
 276
 277        offset = INSIZE(create);
 278        insize = max_t(unsigned int, offset + length + 1, OUTSIZE(create));
 279        UPARG(CODA_CREATE);
 280
 281        inp->coda_create.VFid = *dirfid;
 282        inp->coda_create.attr.va_mode = mode;
 283        inp->coda_create.excl = excl;
 284        inp->coda_create.mode = mode;
 285        inp->coda_create.name = offset;
 286
 287        /* Venus must get null terminated string */
 288        memcpy((char *)(inp) + offset, name, length);
 289        *((char *)inp + offset + length) = '\0';
 290
 291        error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 292        if (!error) {
 293                *attrs = outp->coda_create.attr;
 294                *newfid = outp->coda_create.VFid;
 295        }
 296
 297        CODA_FREE(inp, insize);
 298        return error;        
 299}
 300
 301int venus_rmdir(struct super_block *sb, struct CodaFid *dirfid, 
 302                    const char *name, int length)
 303{
 304        union inputArgs *inp;
 305        union outputArgs *outp;
 306        int insize, outsize, error;
 307        int offset;
 308
 309        offset = INSIZE(rmdir);
 310        insize = max_t(unsigned int, offset + length + 1, OUTSIZE(rmdir));
 311        UPARG(CODA_RMDIR);
 312
 313        inp->coda_rmdir.VFid = *dirfid;
 314        inp->coda_rmdir.name = offset;
 315        memcpy((char *)(inp) + offset, name, length);
 316        *((char *)inp + offset + length) = '\0';
 317
 318        error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 319
 320        CODA_FREE(inp, insize);
 321        return error;
 322}
 323
 324int venus_remove(struct super_block *sb, struct CodaFid *dirfid, 
 325                    const char *name, int length)
 326{
 327        union inputArgs *inp;
 328        union outputArgs *outp;
 329        int error=0, insize, outsize, offset;
 330
 331        offset = INSIZE(remove);
 332        insize = max_t(unsigned int, offset + length + 1, OUTSIZE(remove));
 333        UPARG(CODA_REMOVE);
 334
 335        inp->coda_remove.VFid = *dirfid;
 336        inp->coda_remove.name = offset;
 337        memcpy((char *)(inp) + offset, name, length);
 338        *((char *)inp + offset + length) = '\0';
 339
 340        error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 341
 342        CODA_FREE(inp, insize);
 343        return error;
 344}
 345
 346int venus_readlink(struct super_block *sb, struct CodaFid *fid, 
 347                      char *buffer, int *length)
 348{ 
 349        union inputArgs *inp;
 350        union outputArgs *outp;
 351        int insize, outsize, error;
 352        int retlen;
 353        char *result;
 354        
 355        insize = max_t(unsigned int,
 356                     INSIZE(readlink), OUTSIZE(readlink)+ *length + 1);
 357        UPARG(CODA_READLINK);
 358
 359        inp->coda_readlink.VFid = *fid;
 360
 361        error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 362        if (!error) {
 363                retlen = outp->coda_readlink.count;
 364                if ( retlen > *length )
 365                        retlen = *length;
 366                *length = retlen;
 367                result =  (char *)outp + (long)outp->coda_readlink.data;
 368                memcpy(buffer, result, retlen);
 369                *(buffer + retlen) = '\0';
 370        }
 371
 372        CODA_FREE(inp, insize);
 373        return error;
 374}
 375
 376
 377
 378int venus_link(struct super_block *sb, struct CodaFid *fid, 
 379                  struct CodaFid *dirfid, const char *name, int len )
 380{
 381        union inputArgs *inp;
 382        union outputArgs *outp;
 383        int insize, outsize, error;
 384        int offset;
 385
 386        offset = INSIZE(link);
 387        insize = max_t(unsigned int, offset  + len + 1, OUTSIZE(link));
 388        UPARG(CODA_LINK);
 389
 390        inp->coda_link.sourceFid = *fid;
 391        inp->coda_link.destFid = *dirfid;
 392        inp->coda_link.tname = offset;
 393
 394        /* make sure strings are null terminated */
 395        memcpy((char *)(inp) + offset, name, len);
 396        *((char *)inp + offset + len) = '\0';
 397
 398        error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 399
 400        CODA_FREE(inp, insize);
 401        return error;
 402}
 403
 404int venus_symlink(struct super_block *sb, struct CodaFid *fid,
 405                     const char *name, int len,
 406                     const char *symname, int symlen)
 407{
 408        union inputArgs *inp;
 409        union outputArgs *outp;
 410        int insize, outsize, error;
 411        int offset, s;
 412
 413        offset = INSIZE(symlink);
 414        insize = max_t(unsigned int, offset + len + symlen + 8, OUTSIZE(symlink));
 415        UPARG(CODA_SYMLINK);
 416        
 417        /*        inp->coda_symlink.attr = *tva; XXXXXX */ 
 418        inp->coda_symlink.VFid = *fid;
 419
 420        /* Round up to word boundary and null terminate */
 421        inp->coda_symlink.srcname = offset;
 422        s = ( symlen  & ~0x3 ) + 4; 
 423        memcpy((char *)(inp) + offset, symname, symlen);
 424        *((char *)inp + offset + symlen) = '\0';
 425        
 426        /* Round up to word boundary and null terminate */
 427        offset += s;
 428        inp->coda_symlink.tname = offset;
 429        s = (len & ~0x3) + 4;
 430        memcpy((char *)(inp) + offset, name, len);
 431        *((char *)inp + offset + len) = '\0';
 432
 433        error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 434
 435        CODA_FREE(inp, insize);
 436        return error;
 437}
 438
 439int venus_fsync(struct super_block *sb, struct CodaFid *fid)
 440{
 441        union inputArgs *inp;
 442        union outputArgs *outp; 
 443        int insize, outsize, error;
 444        
 445        insize=SIZE(fsync);
 446        UPARG(CODA_FSYNC);
 447
 448        inp->coda_fsync.VFid = *fid;
 449        error = coda_upcall(coda_vcp(sb), sizeof(union inputArgs),
 450                            &outsize, inp);
 451
 452        CODA_FREE(inp, insize);
 453        return error;
 454}
 455
 456int 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        CODA_FREE(inp, insize);
 471        return error;
 472}
 473
 474
 475int 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        /* build packet for Venus */
 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        /* the cmd field was mutated by increasing its size field to
 500         * reflect the path and follow args. We need to subtract that
 501         * out before sending the command to Venus.  */
 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        /* in->coda_ioctl.rwflag = flag; */
 507        inp->coda_ioctl.len = data->vi.in_size;
 508        inp->coda_ioctl.data = (char *)(INSIZE(ioctl));
 509     
 510        /* get the data out of user space */
 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                printk("coda_pioctl: Venus returns: %d for %s\n", 
 522                       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        /* Copy out the OUT buffer. */
 532        if (outp->coda_ioctl.len > data->vi.out_size) {
 533                error = -EINVAL;
 534                goto exit;
 535        }
 536
 537        /* Copy out the OUT buffer. */
 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        CODA_FREE(inp, insize);
 547        return error;
 548}
 549
 550int 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 = max_t(unsigned int, INSIZE(statfs), OUTSIZE(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        CODA_FREE(inp, insize);
 569        return error;
 570}
 571
 572/*
 573 * coda_upcall and coda_downcall routines.
 574 */
 575static void coda_block_signals(sigset_t *old)
 576{
 577        spin_lock_irq(&current->sighand->siglock);
 578        *old = current->blocked;
 579
 580        sigfillset(&current->blocked);
 581        sigdelset(&current->blocked, SIGKILL);
 582        sigdelset(&current->blocked, SIGSTOP);
 583        sigdelset(&current->blocked, SIGINT);
 584
 585        recalc_sigpending();
 586        spin_unlock_irq(&current->sighand->siglock);
 587}
 588
 589static void coda_unblock_signals(sigset_t *old)
 590{
 591        spin_lock_irq(&current->sighand->siglock);
 592        current->blocked = *old;
 593        recalc_sigpending();
 594        spin_unlock_irq(&current->sighand->siglock);
 595}
 596
 597/* Don't allow signals to interrupt the following upcalls before venus
 598 * has seen them,
 599 * - CODA_CLOSE or CODA_RELEASE upcall  (to avoid reference count problems)
 600 * - CODA_STORE                         (to avoid data loss)
 601 */
 602#define CODA_INTERRUPTIBLE(r) (!coda_hard && \
 603                               (((r)->uc_opcode != CODA_CLOSE && \
 604                                 (r)->uc_opcode != CODA_STORE && \
 605                                 (r)->uc_opcode != CODA_RELEASE) || \
 606                                (r)->uc_flags & REQ_READ))
 607
 608static inline void coda_waitfor_upcall(struct upc_req *req)
 609{
 610        DECLARE_WAITQUEUE(wait, current);
 611        unsigned long timeout = jiffies + coda_timeout * HZ;
 612        sigset_t old;
 613        int blocked;
 614
 615        coda_block_signals(&old);
 616        blocked = 1;
 617
 618        add_wait_queue(&req->uc_sleep, &wait);
 619        for (;;) {
 620                if (CODA_INTERRUPTIBLE(req))
 621                        set_current_state(TASK_INTERRUPTIBLE);
 622                else
 623                        set_current_state(TASK_UNINTERRUPTIBLE);
 624
 625                /* got a reply */
 626                if (req->uc_flags & (REQ_WRITE | REQ_ABORT))
 627                        break;
 628
 629                if (blocked && time_after(jiffies, timeout) &&
 630                    CODA_INTERRUPTIBLE(req))
 631                {
 632                        coda_unblock_signals(&old);
 633                        blocked = 0;
 634                }
 635
 636                if (signal_pending(current)) {
 637                        list_del(&req->uc_chain);
 638                        break;
 639                }
 640
 641                if (blocked)
 642                        schedule_timeout(HZ);
 643                else
 644                        schedule();
 645        }
 646        if (blocked)
 647                coda_unblock_signals(&old);
 648
 649        remove_wait_queue(&req->uc_sleep, &wait);
 650        set_current_state(TASK_RUNNING);
 651}
 652
 653
 654/*
 655 * coda_upcall will return an error in the case of
 656 * failed communication with Venus _or_ will peek at Venus
 657 * reply and return Venus' error.
 658 *
 659 * As venus has 2 types of errors, normal errors (positive) and internal
 660 * errors (negative), normal errors are negated, while internal errors
 661 * are all mapped to -EINTR, while showing a nice warning message. (jh)
 662 */
 663static int coda_upcall(struct venus_comm *vcp,
 664                       int inSize, int *outSize,
 665                       union inputArgs *buffer)
 666{
 667        union outputArgs *out;
 668        union inputArgs *sig_inputArgs;
 669        struct upc_req *req, *sig_req;
 670        int error = 0;
 671
 672        if (!vcp->vc_inuse) {
 673                printk(KERN_NOTICE "coda: Venus dead, not sending upcall\n");
 674                return -ENXIO;
 675        }
 676
 677        /* Format the request message. */
 678        req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
 679        if (!req)
 680                return -ENOMEM;
 681
 682        req->uc_data = (void *)buffer;
 683        req->uc_flags = 0;
 684        req->uc_inSize = inSize;
 685        req->uc_outSize = *outSize ? *outSize : inSize;
 686        req->uc_opcode = ((union inputArgs *)buffer)->ih.opcode;
 687        req->uc_unique = ++vcp->vc_seq;
 688        init_waitqueue_head(&req->uc_sleep);
 689
 690        /* Fill in the common input args. */
 691        ((union inputArgs *)buffer)->ih.unique = req->uc_unique;
 692
 693        /* Append msg to pending queue and poke Venus. */
 694        list_add_tail(&req->uc_chain, &vcp->vc_pending);
 695
 696        wake_up_interruptible(&vcp->vc_waitq);
 697        /* We can be interrupted while we wait for Venus to process
 698         * our request.  If the interrupt occurs before Venus has read
 699         * the request, we dequeue and return. If it occurs after the
 700         * read but before the reply, we dequeue, send a signal
 701         * message, and return. If it occurs after the reply we ignore
 702         * it. In no case do we want to restart the syscall.  If it
 703         * was interrupted by a venus shutdown (psdev_close), return
 704         * ENODEV.  */
 705
 706        /* Go to sleep.  Wake up on signals only after the timeout. */
 707        coda_waitfor_upcall(req);
 708
 709        /* Op went through, interrupt or not... */
 710        if (req->uc_flags & REQ_WRITE) {
 711                out = (union outputArgs *)req->uc_data;
 712                /* here we map positive Venus errors to kernel errors */
 713                error = -out->oh.result;
 714                *outSize = req->uc_outSize;
 715                goto exit;
 716        }
 717
 718        error = -EINTR;
 719        if ((req->uc_flags & REQ_ABORT) || !signal_pending(current)) {
 720                printk(KERN_WARNING "coda: Unexpected interruption.\n");
 721                goto exit;
 722        }
 723
 724        /* Interrupted before venus read it. */
 725        if (!(req->uc_flags & REQ_READ))
 726                goto exit;
 727
 728        /* Venus saw the upcall, make sure we can send interrupt signal */
 729        if (!vcp->vc_inuse) {
 730                printk(KERN_INFO "coda: Venus dead, not sending signal.\n");
 731                goto exit;
 732        }
 733
 734        error = -ENOMEM;
 735        sig_req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
 736        if (!sig_req) goto exit;
 737
 738        CODA_ALLOC((sig_req->uc_data), char *, sizeof(struct coda_in_hdr));
 739        if (!sig_req->uc_data) {
 740                kfree(sig_req);
 741                goto exit;
 742        }
 743
 744        error = -EINTR;
 745        sig_inputArgs = (union inputArgs *)sig_req->uc_data;
 746        sig_inputArgs->ih.opcode = CODA_SIGNAL;
 747        sig_inputArgs->ih.unique = req->uc_unique;
 748
 749        sig_req->uc_flags = REQ_ASYNC;
 750        sig_req->uc_opcode = sig_inputArgs->ih.opcode;
 751        sig_req->uc_unique = sig_inputArgs->ih.unique;
 752        sig_req->uc_inSize = sizeof(struct coda_in_hdr);
 753        sig_req->uc_outSize = sizeof(struct coda_in_hdr);
 754
 755        /* insert at head of queue! */
 756        list_add(&(sig_req->uc_chain), &vcp->vc_pending);
 757        wake_up_interruptible(&vcp->vc_waitq);
 758
 759exit:
 760        kfree(req);
 761        return error;
 762}
 763
 764/*  
 765    The statements below are part of the Coda opportunistic
 766    programming -- taken from the Mach/BSD kernel code for Coda. 
 767    You don't get correct semantics by stating what needs to be
 768    done without guaranteeing the invariants needed for it to happen.
 769    When will be have time to find out what exactly is going on?  (pjb)
 770*/
 771
 772
 773/* 
 774 * There are 7 cases where cache invalidations occur.  The semantics
 775 *  of each is listed here:
 776 *
 777 * CODA_FLUSH     -- flush all entries from the name cache and the cnode cache.
 778 * CODA_PURGEUSER -- flush all entries from the name cache for a specific user
 779 *                  This call is a result of token expiration.
 780 *
 781 * The next arise as the result of callbacks on a file or directory.
 782 * CODA_ZAPFILE   -- flush the cached attributes for a file.
 783
 784 * CODA_ZAPDIR    -- flush the attributes for the dir and
 785 *                  force a new lookup for all the children
 786                    of this dir.
 787
 788 *
 789 * The next is a result of Venus detecting an inconsistent file.
 790 * CODA_PURGEFID  -- flush the attribute for the file
 791 *                  purge it and its children from the dcache
 792 *
 793 * The last  allows Venus to replace local fids with global ones
 794 * during reintegration.
 795 *
 796 * CODA_REPLACE -- replace one CodaFid with another throughout the name cache */
 797
 798int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
 799{
 800        struct inode *inode = NULL;
 801        struct CodaFid *fid, *newfid;
 802
 803        /* Handle invalidation requests. */
 804        if ( !sb || !sb->s_root)
 805                return 0;
 806
 807        switch (opcode) {
 808        case CODA_FLUSH:
 809                coda_cache_clear_all(sb);
 810                shrink_dcache_sb(sb);
 811                if (sb->s_root->d_inode)
 812                    coda_flag_inode(sb->s_root->d_inode, C_FLUSH);
 813                break;
 814
 815        case CODA_PURGEUSER:
 816                coda_cache_clear_all(sb);
 817                break;
 818
 819        case CODA_ZAPDIR:
 820                fid = &out->coda_zapdir.CodaFid;
 821                inode = coda_fid_to_inode(fid, sb);
 822                if (inode) {
 823                        coda_flag_inode_children(inode, C_PURGE);
 824                        coda_flag_inode(inode, C_VATTR);
 825                }
 826                break;
 827
 828        case CODA_ZAPFILE:
 829                fid = &out->coda_zapfile.CodaFid;
 830                inode = coda_fid_to_inode(fid, sb);
 831                if (inode)
 832                        coda_flag_inode(inode, C_VATTR);
 833                break;
 834
 835        case CODA_PURGEFID:
 836                fid = &out->coda_purgefid.CodaFid;
 837                inode = coda_fid_to_inode(fid, sb);
 838                if (inode) {
 839                        coda_flag_inode_children(inode, C_PURGE);
 840
 841                        /* catch the dentries later if some are still busy */
 842                        coda_flag_inode(inode, C_PURGE);
 843                        d_prune_aliases(inode);
 844
 845                }
 846                break;
 847
 848        case CODA_REPLACE:
 849                fid = &out->coda_replace.OldFid;
 850                newfid = &out->coda_replace.NewFid;
 851                inode = coda_fid_to_inode(fid, sb);
 852                if (inode)
 853                        coda_replace_fid(inode, fid, newfid);
 854                break;
 855        }
 856
 857        if (inode)
 858                iput(inode);
 859
 860        return 0;
 861}
 862
 863