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 <linux/signal.h>
  18#include <linux/sched.h>
  19#include <linux/types.h>
  20#include <linux/kernel.h>
  21#include <linux/mm.h>
  22#include <linux/time.h>
  23#include <linux/fs.h>
  24#include <linux/file.h>
  25#include <linux/stat.h>
  26#include <linux/errno.h>
  27#include <linux/string.h>
  28#include <linux/slab.h>
  29#include <linux/mutex.h>
  30#include <asm/uaccess.h>
  31#include <linux/vmalloc.h>
  32#include <linux/vfs.h>
  33
  34#include <linux/coda.h>
  35#include <linux/coda_psdev.h>
  36#include "coda_linux.h"
  37#include "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 = task_pid_nr_ns(current, &init_pid_ns);
  54        inp->ih.pgid = task_pgrp_nr_ns(current, &init_pid_ns);
  55        inp->ih.uid = from_kuid(&init_user_ns, 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                kuid_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 = from_kuid(&init_user_ns, 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 & CODA_REQ_READ))
 607
 608static inline void coda_waitfor_upcall(struct venus_comm *vcp,
 609                                       struct upc_req *req)
 610{
 611        DECLARE_WAITQUEUE(wait, current);
 612        unsigned long timeout = jiffies + coda_timeout * HZ;
 613        sigset_t old;
 614        int blocked;
 615
 616        coda_block_signals(&old);
 617        blocked = 1;
 618
 619        add_wait_queue(&req->uc_sleep, &wait);
 620        for (;;) {
 621                if (CODA_INTERRUPTIBLE(req))
 622                        set_current_state(TASK_INTERRUPTIBLE);
 623                else
 624                        set_current_state(TASK_UNINTERRUPTIBLE);
 625
 626                /* got a reply */
 627                if (req->uc_flags & (CODA_REQ_WRITE | CODA_REQ_ABORT))
 628                        break;
 629
 630                if (blocked && time_after(jiffies, timeout) &&
 631                    CODA_INTERRUPTIBLE(req))
 632                {
 633                        coda_unblock_signals(&old);
 634                        blocked = 0;
 635                }
 636
 637                if (signal_pending(current)) {
 638                        list_del(&req->uc_chain);
 639                        break;
 640                }
 641
 642                mutex_unlock(&vcp->vc_mutex);
 643                if (blocked)
 644                        schedule_timeout(HZ);
 645                else
 646                        schedule();
 647                mutex_lock(&vcp->vc_mutex);
 648        }
 649        if (blocked)
 650                coda_unblock_signals(&old);
 651
 652        remove_wait_queue(&req->uc_sleep, &wait);
 653        set_current_state(TASK_RUNNING);
 654}
 655
 656
 657/*
 658 * coda_upcall will return an error in the case of
 659 * failed communication with Venus _or_ will peek at Venus
 660 * reply and return Venus' error.
 661 *
 662 * As venus has 2 types of errors, normal errors (positive) and internal
 663 * errors (negative), normal errors are negated, while internal errors
 664 * are all mapped to -EINTR, while showing a nice warning message. (jh)
 665 */
 666static int coda_upcall(struct venus_comm *vcp,
 667                       int inSize, int *outSize,
 668                       union inputArgs *buffer)
 669{
 670        union outputArgs *out;
 671        union inputArgs *sig_inputArgs;
 672        struct upc_req *req = NULL, *sig_req;
 673        int error;
 674
 675        mutex_lock(&vcp->vc_mutex);
 676
 677        if (!vcp->vc_inuse) {
 678                printk(KERN_NOTICE "coda: Venus dead, not sending upcall\n");
 679                error = -ENXIO;
 680                goto exit;
 681        }
 682
 683        /* Format the request message. */
 684        req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
 685        if (!req) {
 686                error = -ENOMEM;
 687                goto exit;
 688        }
 689
 690        req->uc_data = (void *)buffer;
 691        req->uc_flags = 0;
 692        req->uc_inSize = inSize;
 693        req->uc_outSize = *outSize ? *outSize : inSize;
 694        req->uc_opcode = ((union inputArgs *)buffer)->ih.opcode;
 695        req->uc_unique = ++vcp->vc_seq;
 696        init_waitqueue_head(&req->uc_sleep);
 697
 698        /* Fill in the common input args. */
 699        ((union inputArgs *)buffer)->ih.unique = req->uc_unique;
 700
 701        /* Append msg to pending queue and poke Venus. */
 702        list_add_tail(&req->uc_chain, &vcp->vc_pending);
 703
 704        wake_up_interruptible(&vcp->vc_waitq);
 705        /* We can be interrupted while we wait for Venus to process
 706         * our request.  If the interrupt occurs before Venus has read
 707         * the request, we dequeue and return. If it occurs after the
 708         * read but before the reply, we dequeue, send a signal
 709         * message, and return. If it occurs after the reply we ignore
 710         * it. In no case do we want to restart the syscall.  If it
 711         * was interrupted by a venus shutdown (psdev_close), return
 712         * ENODEV.  */
 713
 714        /* Go to sleep.  Wake up on signals only after the timeout. */
 715        coda_waitfor_upcall(vcp, req);
 716
 717        /* Op went through, interrupt or not... */
 718        if (req->uc_flags & CODA_REQ_WRITE) {
 719                out = (union outputArgs *)req->uc_data;
 720                /* here we map positive Venus errors to kernel errors */
 721                error = -out->oh.result;
 722                *outSize = req->uc_outSize;
 723                goto exit;
 724        }
 725
 726        error = -EINTR;
 727        if ((req->uc_flags & CODA_REQ_ABORT) || !signal_pending(current)) {
 728                printk(KERN_WARNING "coda: Unexpected interruption.\n");
 729                goto exit;
 730        }
 731
 732        /* Interrupted before venus read it. */
 733        if (!(req->uc_flags & CODA_REQ_READ))
 734                goto exit;
 735
 736        /* Venus saw the upcall, make sure we can send interrupt signal */
 737        if (!vcp->vc_inuse) {
 738                printk(KERN_INFO "coda: Venus dead, not sending signal.\n");
 739                goto exit;
 740        }
 741
 742        error = -ENOMEM;
 743        sig_req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
 744        if (!sig_req) goto exit;
 745
 746        CODA_ALLOC((sig_req->uc_data), char *, sizeof(struct coda_in_hdr));
 747        if (!sig_req->uc_data) {
 748                kfree(sig_req);
 749                goto exit;
 750        }
 751
 752        error = -EINTR;
 753        sig_inputArgs = (union inputArgs *)sig_req->uc_data;
 754        sig_inputArgs->ih.opcode = CODA_SIGNAL;
 755        sig_inputArgs->ih.unique = req->uc_unique;
 756
 757        sig_req->uc_flags = CODA_REQ_ASYNC;
 758        sig_req->uc_opcode = sig_inputArgs->ih.opcode;
 759        sig_req->uc_unique = sig_inputArgs->ih.unique;
 760        sig_req->uc_inSize = sizeof(struct coda_in_hdr);
 761        sig_req->uc_outSize = sizeof(struct coda_in_hdr);
 762
 763        /* insert at head of queue! */
 764        list_add(&(sig_req->uc_chain), &vcp->vc_pending);
 765        wake_up_interruptible(&vcp->vc_waitq);
 766
 767exit:
 768        kfree(req);
 769        mutex_unlock(&vcp->vc_mutex);
 770        return error;
 771}
 772
 773/*  
 774    The statements below are part of the Coda opportunistic
 775    programming -- taken from the Mach/BSD kernel code for Coda. 
 776    You don't get correct semantics by stating what needs to be
 777    done without guaranteeing the invariants needed for it to happen.
 778    When will be have time to find out what exactly is going on?  (pjb)
 779*/
 780
 781
 782/* 
 783 * There are 7 cases where cache invalidations occur.  The semantics
 784 *  of each is listed here:
 785 *
 786 * CODA_FLUSH     -- flush all entries from the name cache and the cnode cache.
 787 * CODA_PURGEUSER -- flush all entries from the name cache for a specific user
 788 *                  This call is a result of token expiration.
 789 *
 790 * The next arise as the result of callbacks on a file or directory.
 791 * CODA_ZAPFILE   -- flush the cached attributes for a file.
 792
 793 * CODA_ZAPDIR    -- flush the attributes for the dir and
 794 *                  force a new lookup for all the children
 795                    of this dir.
 796
 797 *
 798 * The next is a result of Venus detecting an inconsistent file.
 799 * CODA_PURGEFID  -- flush the attribute for the file
 800 *                  purge it and its children from the dcache
 801 *
 802 * The last  allows Venus to replace local fids with global ones
 803 * during reintegration.
 804 *
 805 * CODA_REPLACE -- replace one CodaFid with another throughout the name cache */
 806
 807int coda_downcall(struct venus_comm *vcp, int opcode, union outputArgs *out)
 808{
 809        struct inode *inode = NULL;
 810        struct CodaFid *fid = NULL, *newfid;
 811        struct super_block *sb;
 812
 813        /* Handle invalidation requests. */
 814        mutex_lock(&vcp->vc_mutex);
 815        sb = vcp->vc_sb;
 816        if (!sb || !sb->s_root)
 817                goto unlock_out;
 818
 819        switch (opcode) {
 820        case CODA_FLUSH:
 821                coda_cache_clear_all(sb);
 822                shrink_dcache_sb(sb);
 823                if (sb->s_root->d_inode)
 824                        coda_flag_inode(sb->s_root->d_inode, C_FLUSH);
 825                break;
 826
 827        case CODA_PURGEUSER:
 828                coda_cache_clear_all(sb);
 829                break;
 830
 831        case CODA_ZAPDIR:
 832                fid = &out->coda_zapdir.CodaFid;
 833                break;
 834
 835        case CODA_ZAPFILE:
 836                fid = &out->coda_zapfile.CodaFid;
 837                break;
 838
 839        case CODA_PURGEFID:
 840                fid = &out->coda_purgefid.CodaFid;
 841                break;
 842
 843        case CODA_REPLACE:
 844                fid = &out->coda_replace.OldFid;
 845                break;
 846        }
 847        if (fid)
 848                inode = coda_fid_to_inode(fid, sb);
 849
 850unlock_out:
 851        mutex_unlock(&vcp->vc_mutex);
 852
 853        if (!inode)
 854                return 0;
 855
 856        switch (opcode) {
 857        case CODA_ZAPDIR:
 858                coda_flag_inode_children(inode, C_PURGE);
 859                coda_flag_inode(inode, C_VATTR);
 860                break;
 861
 862        case CODA_ZAPFILE:
 863                coda_flag_inode(inode, C_VATTR);
 864                break;
 865
 866        case CODA_PURGEFID:
 867                coda_flag_inode_children(inode, C_PURGE);
 868
 869                /* catch the dentries later if some are still busy */
 870                coda_flag_inode(inode, C_PURGE);
 871                d_prune_aliases(inode);
 872                break;
 873
 874        case CODA_REPLACE:
 875                newfid = &out->coda_replace.NewFid;
 876                coda_replace_fid(inode, fid, newfid);
 877                break;
 878        }
 879        iput(inode);
 880        return 0;
 881}
 882
 883