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