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 <linux/slab.h>
  30#include <linux/mutex.h>
  31#include <asm/uaccess.h>
  32#include <linux/vmalloc.h>
  33#include <linux/vfs.h>
  34
  35#include <linux/coda.h>
  36#include <linux/coda_psdev.h>
  37#include "coda_linux.h"
  38#include "coda_cache.h"
  39
  40#include "coda_int.h"
  41
  42static int coda_upcall(struct venus_comm *vc, int inSize, int *outSize,
  43                       union inputArgs *buffer);
  44
  45static void *alloc_upcall(int opcode, int size)
  46{
  47        union inputArgs *inp;
  48
  49        CODA_ALLOC(inp, union inputArgs *, size);
  50        if (!inp)
  51                return ERR_PTR(-ENOMEM);
  52
  53        inp->ih.opcode = opcode;
  54        inp->ih.pid = current->pid;
  55        inp->ih.pgid = task_pgrp_nr(current);
  56        inp->ih.uid = current_fsuid();
  57
  58        return (void*)inp;
  59}
  60
  61#define UPARG(op)\
  62do {\
  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/* the upcalls */
  75int 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        CODA_FREE(inp, insize);
  89        return error;
  90}
  91
  92int 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        CODA_FREE(inp, insize);
 108        return error;
 109}
 110
 111int 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        CODA_FREE(inp, insize);
 127        return error;
 128}
 129
 130int 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        /* send Venus a null terminated string */
 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        CODA_FREE(inp, insize);
 157        return error;
 158}
 159
 160int venus_close(struct super_block *sb, struct CodaFid *fid, int flags,
 161                vuid_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 = 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        CODA_FREE(inp, insize);
 177        return error;
 178}
 179
 180int 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        CODA_FREE(inp, insize);
 198        return error;
 199}       
 200
 201int 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        /* Venus must get null terminated string */
 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        CODA_FREE(inp, insize);
 228        return error;        
 229}
 230
 231
 232int 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        /* Venus must receive an null terminated string */
 252        s = ( old_length & ~0x3) +4; /* round up to word boundary */
 253        memcpy((char *)(inp) + offset, old_name, old_length);
 254        *((char *)inp + offset + old_length) = '\0';
 255
 256        /* another null terminated string for Venus */
 257        offset += s;
 258        inp->coda_rename.destname = offset;
 259        s = ( new_length & ~0x3) +4; /* round up to word boundary */
 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        CODA_FREE(inp, insize);
 266        return error;
 267}
 268
 269int 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        /* Venus must get null terminated string */
 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        CODA_FREE(inp, insize);
 299        return error;        
 300}
 301
 302int 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        CODA_FREE(inp, insize);
 322        return error;
 323}
 324
 325int 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        CODA_FREE(inp, insize);
 344        return error;
 345}
 346
 347int 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 + 1);
 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;
 367                *length = retlen;
 368                result =  (char *)outp + (long)outp->coda_readlink.data;
 369                memcpy(buffer, result, retlen);
 370                *(buffer + retlen) = '\0';
 371        }
 372
 373        CODA_FREE(inp, insize);
 374        return error;
 375}
 376
 377
 378
 379int 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        /* make sure strings are null terminated */
 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        CODA_FREE(inp, insize);
 402        return error;
 403}
 404
 405int 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        /*        inp->coda_symlink.attr = *tva; XXXXXX */ 
 419        inp->coda_symlink.VFid = *fid;
 420
 421        /* Round up to word boundary and null terminate */
 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        /* Round up to word boundary and null terminate */
 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        CODA_FREE(inp, insize);
 437        return error;
 438}
 439
 440int 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), sizeof(union inputArgs),
 451                            &outsize, inp);
 452
 453        CODA_FREE(inp, insize);
 454        return error;
 455}
 456
 457int venus_access(struct super_block *sb, struct CodaFid *fid, int mask)
 458{
 459        union inputArgs *inp;
 460        union outputArgs *outp; 
 461        int insize, outsize, error;
 462
 463        insize = SIZE(access);
 464        UPARG(CODA_ACCESS);
 465
 466        inp->coda_access.VFid = *fid;
 467        inp->coda_access.flags = mask;
 468
 469        error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 470
 471        CODA_FREE(inp, insize);
 472        return error;
 473}
 474
 475
 476int venus_pioctl(struct super_block *sb, struct CodaFid *fid,
 477                 unsigned int cmd, struct PioctlData *data)
 478{
 479        union inputArgs *inp;
 480        union outputArgs *outp;  
 481        int insize, outsize, error;
 482        int iocsize;
 483
 484        insize = VC_MAXMSGSIZE;
 485        UPARG(CODA_IOCTL);
 486
 487        /* build packet for Venus */
 488        if (data->vi.in_size > VC_MAXDATASIZE) {
 489                error = -EINVAL;
 490                goto exit;
 491        }
 492
 493        if (data->vi.out_size > VC_MAXDATASIZE) {
 494                error = -EINVAL;
 495                goto exit;
 496        }
 497
 498        inp->coda_ioctl.VFid = *fid;
 499    
 500        /* the cmd field was mutated by increasing its size field to
 501         * reflect the path and follow args. We need to subtract that
 502         * out before sending the command to Venus.  */
 503        inp->coda_ioctl.cmd = (cmd & ~(PIOCPARM_MASK << 16));   
 504        iocsize = ((cmd >> 16) & PIOCPARM_MASK) - sizeof(char *) - sizeof(int);
 505        inp->coda_ioctl.cmd |= (iocsize & PIOCPARM_MASK) <<     16;     
 506    
 507        /* in->coda_ioctl.rwflag = flag; */
 508        inp->coda_ioctl.len = data->vi.in_size;
 509        inp->coda_ioctl.data = (char *)(INSIZE(ioctl));
 510     
 511        /* get the data out of user space */
 512        if ( copy_from_user((char*)inp + (long)inp->coda_ioctl.data,
 513                            data->vi.in, data->vi.in_size) ) {
 514                error = -EINVAL;
 515                goto exit;
 516        }
 517
 518        error = coda_upcall(coda_vcp(sb), SIZE(ioctl) + data->vi.in_size,
 519                            &outsize, inp);
 520
 521        if (error) {
 522                printk("coda_pioctl: Venus returns: %d for %s\n", 
 523                       error, coda_f2s(fid));
 524                goto exit; 
 525        }
 526
 527        if (outsize < (long)outp->coda_ioctl.data + outp->coda_ioctl.len) {
 528                error = -EINVAL;
 529                goto exit;
 530        }
 531        
 532        /* Copy out the OUT buffer. */
 533        if (outp->coda_ioctl.len > data->vi.out_size) {
 534                error = -EINVAL;
 535                goto exit;
 536        }
 537
 538        /* Copy out the OUT buffer. */
 539        if (copy_to_user(data->vi.out,
 540                         (char *)outp + (long)outp->coda_ioctl.data,
 541                         outp->coda_ioctl.len)) {
 542                error = -EFAULT;
 543                goto exit;
 544        }
 545
 546 exit:
 547        CODA_FREE(inp, insize);
 548        return error;
 549}
 550
 551int venus_statfs(struct dentry *dentry, struct kstatfs *sfs)
 552{ 
 553        union inputArgs *inp;
 554        union outputArgs *outp;
 555        int insize, outsize, error;
 556        
 557        insize = max_t(unsigned int, INSIZE(statfs), OUTSIZE(statfs));
 558        UPARG(CODA_STATFS);
 559
 560        error = coda_upcall(coda_vcp(dentry->d_sb), insize, &outsize, inp);
 561        if (!error) {
 562                sfs->f_blocks = outp->coda_statfs.stat.f_blocks;
 563                sfs->f_bfree  = outp->coda_statfs.stat.f_bfree;
 564                sfs->f_bavail = outp->coda_statfs.stat.f_bavail;
 565                sfs->f_files  = outp->coda_statfs.stat.f_files;
 566                sfs->f_ffree  = outp->coda_statfs.stat.f_ffree;
 567        }
 568
 569        CODA_FREE(inp, insize);
 570        return error;
 571}
 572
 573/*
 574 * coda_upcall and coda_downcall routines.
 575 */
 576static void coda_block_signals(sigset_t *old)
 577{
 578        spin_lock_irq(&current->sighand->siglock);
 579        *old = current->blocked;
 580
 581        sigfillset(&current->blocked);
 582        sigdelset(&current->blocked, SIGKILL);
 583        sigdelset(&current->blocked, SIGSTOP);
 584        sigdelset(&current->blocked, SIGINT);
 585
 586        recalc_sigpending();
 587        spin_unlock_irq(&current->sighand->siglock);
 588}
 589
 590static void coda_unblock_signals(sigset_t *old)
 591{
 592        spin_lock_irq(&current->sighand->siglock);
 593        current->blocked = *old;
 594        recalc_sigpending();
 595        spin_unlock_irq(&current->sighand->siglock);
 596}
 597
 598/* Don't allow signals to interrupt the following upcalls before venus
 599 * has seen them,
 600 * - CODA_CLOSE or CODA_RELEASE upcall  (to avoid reference count problems)
 601 * - CODA_STORE                         (to avoid data loss)
 602 */
 603#define CODA_INTERRUPTIBLE(r) (!coda_hard && \
 604                               (((r)->uc_opcode != CODA_CLOSE && \
 605                                 (r)->uc_opcode != CODA_STORE && \
 606                                 (r)->uc_opcode != CODA_RELEASE) || \
 607                                (r)->uc_flags & CODA_REQ_READ))
 608
 609static inline void coda_waitfor_upcall(struct venus_comm *vcp,
 610                                       struct upc_req *req)
 611{
 612        DECLARE_WAITQUEUE(wait, current);
 613        unsigned long timeout = jiffies + coda_timeout * HZ;
 614        sigset_t old;
 615        int blocked;
 616
 617        coda_block_signals(&old);
 618        blocked = 1;
 619
 620        add_wait_queue(&req->uc_sleep, &wait);
 621        for (;;) {
 622                if (CODA_INTERRUPTIBLE(req))
 623                        set_current_state(TASK_INTERRUPTIBLE);
 624                else
 625                        set_current_state(TASK_UNINTERRUPTIBLE);
 626
 627                /* got a reply */
 628                if (req->uc_flags & (CODA_REQ_WRITE | CODA_REQ_ABORT))
 629                        break;
 630
 631                if (blocked && time_after(jiffies, timeout) &&
 632                    CODA_INTERRUPTIBLE(req))
 633                {
 634                        coda_unblock_signals(&old);
 635                        blocked = 0;
 636                }
 637
 638                if (signal_pending(current)) {
 639                        list_del(&req->uc_chain);
 640                        break;
 641                }
 642
 643                mutex_unlock(&vcp->vc_mutex);
 644                if (blocked)
 645                        schedule_timeout(HZ);
 646                else
 647                        schedule();
 648                mutex_lock(&vcp->vc_mutex);
 649        }
 650        if (blocked)
 651                coda_unblock_signals(&old);
 652
 653        remove_wait_queue(&req->uc_sleep, &wait);
 654        set_current_state(TASK_RUNNING);
 655}
 656
 657
 658/*
 659 * coda_upcall will return an error in the case of
 660 * failed communication with Venus _or_ will peek at Venus
 661 * reply and return Venus' error.
 662 *
 663 * As venus has 2 types of errors, normal errors (positive) and internal
 664 * errors (negative), normal errors are negated, while internal errors
 665 * are all mapped to -EINTR, while showing a nice warning message. (jh)
 666 */
 667static int coda_upcall(struct venus_comm *vcp,
 668                       int inSize, int *outSize,
 669                       union inputArgs *buffer)
 670{
 671        union outputArgs *out;
 672        union inputArgs *sig_inputArgs;
 673        struct upc_req *req = NULL, *sig_req;
 674        int error;
 675
 676        mutex_lock(&vcp->vc_mutex);
 677
 678        if (!vcp->vc_inuse) {
 679                printk(KERN_NOTICE "coda: Venus dead, not sending upcall\n");
 680                error = -ENXIO;
 681                goto exit;
 682        }
 683
 684        /* Format the request message. */
 685        req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
 686        if (!req) {
 687                error = -ENOMEM;
 688                goto exit;
 689        }
 690
 691        req->uc_data = (void *)buffer;
 692        req->uc_flags = 0;
 693        req->uc_inSize = inSize;
 694        req->uc_outSize = *outSize ? *outSize : inSize;
 695        req->uc_opcode = ((union inputArgs *)buffer)->ih.opcode;
 696        req->uc_unique = ++vcp->vc_seq;
 697        init_waitqueue_head(&req->uc_sleep);
 698
 699        /* Fill in the common input args. */
 700        ((union inputArgs *)buffer)->ih.unique = req->uc_unique;
 701
 702        /* Append msg to pending queue and poke Venus. */
 703        list_add_tail(&req->uc_chain, &vcp->vc_pending);
 704
 705        wake_up_interruptible(&vcp->vc_waitq);
 706        /* We can be interrupted while we wait for Venus to process
 707         * our request.  If the interrupt occurs before Venus has read
 708         * the request, we dequeue and return. If it occurs after the
 709         * read but before the reply, we dequeue, send a signal
 710         * message, and return. If it occurs after the reply we ignore
 711         * it. In no case do we want to restart the syscall.  If it
 712         * was interrupted by a venus shutdown (psdev_close), return
 713         * ENODEV.  */
 714
 715        /* Go to sleep.  Wake up on signals only after the timeout. */
 716        coda_waitfor_upcall(vcp, req);
 717
 718        /* Op went through, interrupt or not... */
 719        if (req->uc_flags & CODA_REQ_WRITE) {
 720                out = (union outputArgs *)req->uc_data;
 721                /* here we map positive Venus errors to kernel errors */
 722                error = -out->oh.result;
 723                *outSize = req->uc_outSize;
 724                goto exit;
 725        }
 726
 727        error = -EINTR;
 728        if ((req->uc_flags & CODA_REQ_ABORT) || !signal_pending(current)) {
 729                printk(KERN_WARNING "coda: Unexpected interruption.\n");
 730                goto exit;
 731        }
 732
 733        /* Interrupted before venus read it. */
 734        if (!(req->uc_flags & CODA_REQ_READ))
 735                goto exit;
 736
 737        /* Venus saw the upcall, make sure we can send interrupt signal */
 738        if (!vcp->vc_inuse) {
 739                printk(KERN_INFO "coda: Venus dead, not sending signal.\n");
 740                goto exit;
 741        }
 742
 743        error = -ENOMEM;
 744        sig_req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
 745        if (!sig_req) goto exit;
 746
 747        CODA_ALLOC((sig_req->uc_data), char *, sizeof(struct coda_in_hdr));
 748        if (!sig_req->uc_data) {
 749                kfree(sig_req);
 750                goto exit;
 751        }
 752
 753        error = -EINTR;
 754        sig_inputArgs = (union inputArgs *)sig_req->uc_data;
 755        sig_inputArgs->ih.opcode = CODA_SIGNAL;
 756        sig_inputArgs->ih.unique = req->uc_unique;
 757
 758        sig_req->uc_flags = CODA_REQ_ASYNC;
 759        sig_req->uc_opcode = sig_inputArgs->ih.opcode;
 760        sig_req->uc_unique = sig_inputArgs->ih.unique;
 761        sig_req->uc_inSize = sizeof(struct coda_in_hdr);
 762        sig_req->uc_outSize = sizeof(struct coda_in_hdr);
 763
 764        /* insert at head of queue! */
 765        list_add(&(sig_req->uc_chain), &vcp->vc_pending);
 766        wake_up_interruptible(&vcp->vc_waitq);
 767
 768exit:
 769        kfree(req);
 770        mutex_unlock(&vcp->vc_mutex);
 771        return error;
 772}
 773
 774/*  
 775    The statements below are part of the Coda opportunistic
 776    programming -- taken from the Mach/BSD kernel code for Coda. 
 777    You don't get correct semantics by stating what needs to be
 778    done without guaranteeing the invariants needed for it to happen.
 779    When will be have time to find out what exactly is going on?  (pjb)
 780*/
 781
 782
 783/* 
 784 * There are 7 cases where cache invalidations occur.  The semantics
 785 *  of each is listed here:
 786 *
 787 * CODA_FLUSH     -- flush all entries from the name cache and the cnode cache.
 788 * CODA_PURGEUSER -- flush all entries from the name cache for a specific user
 789 *                  This call is a result of token expiration.
 790 *
 791 * The next arise as the result of callbacks on a file or directory.
 792 * CODA_ZAPFILE   -- flush the cached attributes for a file.
 793
 794 * CODA_ZAPDIR    -- flush the attributes for the dir and
 795 *                  force a new lookup for all the children
 796                    of this dir.
 797
 798 *
 799 * The next is a result of Venus detecting an inconsistent file.
 800 * CODA_PURGEFID  -- flush the attribute for the file
 801 *                  purge it and its children from the dcache
 802 *
 803 * The last  allows Venus to replace local fids with global ones
 804 * during reintegration.
 805 *
 806 * CODA_REPLACE -- replace one CodaFid with another throughout the name cache */
 807
 808int coda_downcall(struct venus_comm *vcp, int opcode, union outputArgs *out)
 809{
 810        struct inode *inode = NULL;
 811        struct CodaFid *fid = NULL, *newfid;
 812        struct super_block *sb;
 813
 814        /* Handle invalidation requests. */
 815        mutex_lock(&vcp->vc_mutex);
 816        sb = vcp->vc_sb;
 817        if (!sb || !sb->s_root)
 818                goto unlock_out;
 819
 820        switch (opcode) {
 821        case CODA_FLUSH:
 822                coda_cache_clear_all(sb);
 823                shrink_dcache_sb(sb);
 824                if (sb->s_root->d_inode)
 825                        coda_flag_inode(sb->s_root->d_inode, C_FLUSH);
 826                break;
 827
 828        case CODA_PURGEUSER:
 829                coda_cache_clear_all(sb);
 830                break;
 831
 832        case CODA_ZAPDIR:
 833                fid = &out->coda_zapdir.CodaFid;
 834                break;
 835
 836        case CODA_ZAPFILE:
 837                fid = &out->coda_zapfile.CodaFid;
 838                break;
 839
 840        case CODA_PURGEFID:
 841                fid = &out->coda_purgefid.CodaFid;
 842                break;
 843
 844        case CODA_REPLACE:
 845                fid = &out->coda_replace.OldFid;
 846                break;
 847        }
 848        if (fid)
 849                inode = coda_fid_to_inode(fid, sb);
 850
 851unlock_out:
 852        mutex_unlock(&vcp->vc_mutex);
 853
 854        if (!inode)
 855                return 0;
 856
 857        switch (opcode) {
 858        case CODA_ZAPDIR:
 859                coda_flag_inode_children(inode, C_PURGE);
 860                coda_flag_inode(inode, C_VATTR);
 861                break;
 862
 863        case CODA_ZAPFILE:
 864                coda_flag_inode(inode, C_VATTR);
 865                break;
 866
 867        case CODA_PURGEFID:
 868                coda_flag_inode_children(inode, C_PURGE);
 869
 870                /* catch the dentries later if some are still busy */
 871                coda_flag_inode(inode, C_PURGE);
 872                d_prune_aliases(inode);
 873                break;
 874
 875        case CODA_REPLACE:
 876                newfid = &out->coda_replace.NewFid;
 877                coda_replace_fid(inode, fid, newfid);
 878                break;
 879        }
 880        iput(inode);
 881        return 0;
 882}
 883
 884