linux-old/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 <asm/signal.h>
  19#include <linux/signal.h>
  20
  21#include <linux/types.h>
  22#include <linux/kernel.h>
  23#include <linux/mm.h>
  24#include <linux/sched.h>
  25#include <linux/fs.h>
  26#include <linux/file.h>
  27#include <linux/stat.h>
  28#include <linux/errno.h>
  29#include <linux/locks.h>
  30#include <linux/string.h>
  31#include <asm/uaccess.h>
  32#include <linux/vmalloc.h>
  33
  34#include <linux/coda.h>
  35#include <linux/coda_linux.h>
  36#include <linux/coda_psdev.h>
  37#include <linux/coda_fs_i.h>
  38#include <linux/coda_cache.h>
  39#include <linux/coda_proc.h> 
  40
  41#define upc_alloc() kmalloc(sizeof(struct upc_req), GFP_KERNEL)
  42#define upc_free(r) kfree(r)
  43
  44static int coda_upcall(struct coda_sb_info *mntinfo, int inSize, int *outSize, 
  45                       union inputArgs *buffer);
  46
  47static void *alloc_upcall(int opcode, int size)
  48{
  49        union inputArgs *inp;
  50
  51        CODA_ALLOC(inp, union inputArgs *, size);
  52        if (!inp)
  53                return ERR_PTR(-ENOMEM);
  54
  55        inp->ih.opcode = opcode;
  56        inp->ih.pid = current->pid;
  57        inp->ih.pgid = current->pgrp;
  58        coda_load_creds(&(inp->ih.cred));
  59
  60        return (void*)inp;
  61}
  62
  63#define UPARG(op)\
  64do {\
  65        inp = (union inputArgs *)alloc_upcall(op, insize); \
  66        if (IS_ERR(inp)) { return PTR_ERR(inp); }\
  67        outp = (union outputArgs *)(inp); \
  68        outsize = insize; \
  69} while (0)
  70
  71#define INSIZE(tag) sizeof(struct coda_ ## tag ## _in)
  72#define OUTSIZE(tag) sizeof(struct coda_ ## tag ## _out)
  73#define SIZE(tag)  max_t(unsigned int, INSIZE(tag), OUTSIZE(tag))
  74
  75
  76/* the upcalls */
  77int venus_rootfid(struct super_block *sb, ViceFid *fidp)
  78{
  79        union inputArgs *inp;
  80        union outputArgs *outp;
  81        int insize, outsize, error;
  82
  83        insize = SIZE(root);
  84        UPARG(CODA_ROOT);
  85
  86        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
  87        
  88        if (error) {
  89                printk("coda_get_rootfid: error %d\n", error);
  90        } else {
  91                *fidp = (ViceFid) outp->coda_root.VFid;
  92                CDEBUG(D_SUPER, "VolumeId: %lx, VnodeId: %lx.\n",
  93                       fidp->Volume, fidp->Vnode);
  94        }
  95
  96        CODA_FREE(inp, insize);
  97        return error;
  98}
  99
 100int venus_getattr(struct super_block *sb, struct ViceFid *fid, 
 101                     struct coda_vattr *attr) 
 102{
 103        union inputArgs *inp;
 104        union outputArgs *outp;
 105        int insize, outsize, error;
 106
 107        insize = SIZE(getattr); 
 108        UPARG(CODA_GETATTR);
 109        inp->coda_getattr.VFid = *fid;
 110
 111        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 112        
 113        *attr = outp->coda_getattr.attr;
 114
 115        CODA_FREE(inp, insize);
 116        return error;
 117}
 118
 119int venus_setattr(struct super_block *sb, struct ViceFid *fid, 
 120                  struct coda_vattr *vattr)
 121{
 122        union inputArgs *inp;
 123        union outputArgs *outp;
 124        int insize, outsize, error;
 125        
 126        insize = SIZE(setattr);
 127        UPARG(CODA_SETATTR);
 128
 129        inp->coda_setattr.VFid = *fid;
 130        inp->coda_setattr.attr = *vattr;
 131
 132        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 133
 134        CDEBUG(D_SUPER, " result %d\n", error); 
 135        CODA_FREE(inp, insize);
 136        return error;
 137}
 138
 139int venus_lookup(struct super_block *sb, struct ViceFid *fid, 
 140                    const char *name, int length, int * type, 
 141                    struct ViceFid *resfid)
 142{
 143        union inputArgs *inp;
 144        union outputArgs *outp;
 145        int insize, outsize, error;
 146        int offset;
 147
 148        offset = INSIZE(lookup);
 149        insize = max_t(unsigned int, offset + length +1, OUTSIZE(lookup));
 150        UPARG(CODA_LOOKUP);
 151
 152        inp->coda_lookup.VFid = *fid;
 153        inp->coda_lookup.name = offset;
 154        inp->coda_lookup.flags = CLU_CASE_SENSITIVE;
 155        /* send Venus a null terminated string */
 156        memcpy((char *)(inp) + offset, name, length);
 157        *((char *)inp + offset + length) = '\0';
 158
 159        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 160
 161        *resfid = outp->coda_lookup.VFid;
 162        *type = outp->coda_lookup.vtype;
 163
 164        CODA_FREE(inp, insize);
 165        return error;
 166}
 167
 168int venus_store(struct super_block *sb, struct ViceFid *fid, int flags,
 169                struct coda_cred *cred)
 170{
 171        union inputArgs *inp;
 172        union outputArgs *outp;
 173        int insize, outsize, error;
 174        
 175        insize = SIZE(store);
 176        UPARG(CODA_STORE);
 177        
 178        memcpy(&(inp->ih.cred), cred, sizeof(*cred));
 179        
 180        inp->coda_store.VFid = *fid;
 181        inp->coda_store.flags = flags;
 182
 183        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 184
 185        CODA_FREE(inp, insize);
 186        return error;
 187}
 188
 189int venus_release(struct super_block *sb, struct ViceFid *fid, int flags)
 190{
 191        union inputArgs *inp;
 192        union outputArgs *outp;
 193        int insize, outsize, error;
 194        
 195        insize = SIZE(release);
 196        UPARG(CODA_RELEASE);
 197        
 198        inp->coda_release.VFid = *fid;
 199        inp->coda_release.flags = flags;
 200
 201        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 202
 203        CODA_FREE(inp, insize);
 204        return error;
 205}
 206
 207int venus_close(struct super_block *sb, struct ViceFid *fid, int flags,
 208                struct coda_cred *cred)
 209{
 210        union inputArgs *inp;
 211        union outputArgs *outp;
 212        int insize, outsize, error;
 213        
 214        insize = SIZE(release);
 215        UPARG(CODA_CLOSE);
 216        
 217        memcpy(&(inp->ih.cred), cred, sizeof(*cred));
 218        
 219        inp->coda_close.VFid = *fid;
 220        inp->coda_close.flags = flags;
 221
 222        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 223
 224        CODA_FREE(inp, insize);
 225        return error;
 226}
 227
 228int venus_open(struct super_block *sb, struct ViceFid *fid,
 229                  int flags, struct file **fh)
 230{
 231        union inputArgs *inp;
 232        union outputArgs *outp;
 233        int insize, outsize, error;
 234       
 235        insize = SIZE(open_by_fd);
 236        UPARG(CODA_OPEN_BY_FD);
 237
 238        inp->coda_open.VFid = *fid;
 239        inp->coda_open.flags = flags;
 240
 241        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 242
 243        *fh = outp->coda_open_by_fd.fh;
 244
 245        CODA_FREE(inp, insize);
 246        return error;
 247}       
 248
 249int venus_mkdir(struct super_block *sb, struct ViceFid *dirfid, 
 250                   const char *name, int length, 
 251                   struct ViceFid *newfid, struct coda_vattr *attrs)
 252{
 253        union inputArgs *inp;
 254        union outputArgs *outp;
 255        int insize, outsize, error;
 256        int offset;
 257
 258        offset = INSIZE(mkdir);
 259        insize = max_t(unsigned int, offset + length + 1, OUTSIZE(mkdir));
 260        UPARG(CODA_MKDIR);
 261
 262        inp->coda_mkdir.VFid = *dirfid;
 263        inp->coda_mkdir.attr = *attrs;
 264        inp->coda_mkdir.name = offset;
 265        /* Venus must get null terminated string */
 266        memcpy((char *)(inp) + offset, name, length);
 267        *((char *)inp + offset + length) = '\0';
 268        
 269        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 270
 271        *attrs = outp->coda_mkdir.attr;
 272        *newfid = outp->coda_mkdir.VFid;
 273
 274        CODA_FREE(inp, insize);
 275        return error;        
 276}
 277
 278
 279int venus_rename(struct super_block *sb, struct ViceFid *old_fid, 
 280                 struct ViceFid *new_fid, size_t old_length, 
 281                 size_t new_length, const char *old_name, 
 282                 const char *new_name)
 283{
 284        union inputArgs *inp;
 285        union outputArgs *outp;
 286        int insize, outsize, error; 
 287        int offset, s;
 288        
 289        offset = INSIZE(rename);
 290        insize = max_t(unsigned int, offset + new_length + old_length + 8,
 291                     OUTSIZE(rename)); 
 292        UPARG(CODA_RENAME);
 293
 294        inp->coda_rename.sourceFid = *old_fid;
 295        inp->coda_rename.destFid =  *new_fid;
 296        inp->coda_rename.srcname = offset;
 297
 298        /* Venus must receive an null terminated string */
 299        s = ( old_length & ~0x3) +4; /* round up to word boundary */
 300        memcpy((char *)(inp) + offset, old_name, old_length);
 301        *((char *)inp + offset + old_length) = '\0';
 302
 303        /* another null terminated string for Venus */
 304        offset += s;
 305        inp->coda_rename.destname = offset;
 306        s = ( new_length & ~0x3) +4; /* round up to word boundary */
 307        memcpy((char *)(inp) + offset, new_name, new_length);
 308        *((char *)inp + offset + new_length) = '\0';
 309
 310        CDEBUG(D_INODE, "destname in packet: %s\n", 
 311              (char *)inp + (int) inp->coda_rename.destname);
 312        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 313
 314        CODA_FREE(inp, insize);
 315        return error;
 316}
 317
 318int venus_create(struct super_block *sb, struct ViceFid *dirfid, 
 319                    const char *name, int length, int excl, int mode, int rdev,
 320                    struct ViceFid *newfid, struct coda_vattr *attrs) 
 321{
 322        union inputArgs *inp;
 323        union outputArgs *outp;
 324        int insize, outsize, error;
 325        int offset;
 326
 327        offset = INSIZE(create);
 328        insize = max_t(unsigned int, offset + length + 1, OUTSIZE(create));
 329        UPARG(CODA_CREATE);
 330
 331        inp->coda_create.VFid = *dirfid;
 332        inp->coda_create.attr.va_mode = mode;
 333        inp->coda_create.attr.va_rdev = rdev;
 334        inp->coda_create.excl = excl;
 335        inp->coda_create.mode = mode;
 336        inp->coda_create.name = offset;
 337
 338        /* Venus must get null terminated string */
 339        memcpy((char *)(inp) + offset, name, length);
 340        *((char *)inp + offset + length) = '\0';
 341                
 342        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 343
 344        *attrs = outp->coda_create.attr;
 345        *newfid = outp->coda_create.VFid;
 346
 347        CODA_FREE(inp, insize);
 348        return error;        
 349}
 350
 351int venus_rmdir(struct super_block *sb, struct ViceFid *dirfid, 
 352                    const char *name, int length)
 353{
 354        union inputArgs *inp;
 355        union outputArgs *outp;
 356        int insize, outsize, error;
 357        int offset;
 358
 359        offset = INSIZE(rmdir);
 360        insize = max_t(unsigned int, offset + length + 1, OUTSIZE(rmdir));
 361        UPARG(CODA_RMDIR);
 362
 363        inp->coda_rmdir.VFid = *dirfid;
 364        inp->coda_rmdir.name = offset;
 365        memcpy((char *)(inp) + offset, name, length);
 366        *((char *)inp + offset + length) = '\0';
 367        
 368        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 369
 370        CODA_FREE(inp, insize);
 371        return error;
 372}
 373
 374int venus_remove(struct super_block *sb, struct ViceFid *dirfid, 
 375                    const char *name, int length)
 376{
 377        union inputArgs *inp;
 378        union outputArgs *outp;
 379        int error=0, insize, outsize, offset;
 380
 381        offset = INSIZE(remove);
 382        insize = max_t(unsigned int, offset + length + 1, OUTSIZE(remove));
 383        UPARG(CODA_REMOVE);
 384
 385        inp->coda_remove.VFid = *dirfid;
 386        inp->coda_remove.name = offset;
 387        memcpy((char *)(inp) + offset, name, length);
 388        *((char *)inp + offset + length) = '\0';
 389        
 390        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 391
 392        CODA_FREE(inp, insize);
 393        return error;
 394}
 395
 396int venus_readlink(struct super_block *sb, struct ViceFid *fid, 
 397                      char *buffer, int *length)
 398{ 
 399        union inputArgs *inp;
 400        union outputArgs *outp;
 401        int insize, outsize, error;
 402        int retlen;
 403        char *result;
 404        
 405        insize = max_t(unsigned int,
 406                     INSIZE(readlink), OUTSIZE(readlink)+ *length + 1);
 407        UPARG(CODA_READLINK);
 408
 409        inp->coda_readlink.VFid = *fid;
 410    
 411        error =  coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 412        
 413        if (! error) {
 414                retlen = outp->coda_readlink.count;
 415                if ( retlen > *length )
 416                        retlen = *length;
 417                *length = retlen;
 418                result =  (char *)outp + (long)outp->coda_readlink.data;
 419                memcpy(buffer, result, retlen);
 420                *(buffer + retlen) = '\0';
 421        }
 422        
 423        CDEBUG(D_INODE, " result %d\n",error);
 424        CODA_FREE(inp, insize);
 425        return error;
 426}
 427
 428
 429
 430int venus_link(struct super_block *sb, struct ViceFid *fid, 
 431                  struct ViceFid *dirfid, const char *name, int len )
 432{
 433        union inputArgs *inp;
 434        union outputArgs *outp;
 435        int insize, outsize, error;
 436        int offset;
 437
 438        offset = INSIZE(link);
 439        insize = max_t(unsigned int, offset  + len + 1, OUTSIZE(link));
 440        UPARG(CODA_LINK);
 441
 442        inp->coda_link.sourceFid = *fid;
 443        inp->coda_link.destFid = *dirfid;
 444        inp->coda_link.tname = offset;
 445
 446        /* make sure strings are null terminated */
 447        memcpy((char *)(inp) + offset, name, len);
 448        *((char *)inp + offset + len) = '\0';
 449        
 450        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 451
 452        CDEBUG(D_INODE, " result %d\n",error);
 453        CODA_FREE(inp, insize);
 454        return error;
 455}
 456
 457int venus_symlink(struct super_block *sb, struct ViceFid *fid,
 458                     const char *name, int len,
 459                     const char *symname, int symlen)
 460{
 461        union inputArgs *inp;
 462        union outputArgs *outp;
 463        int insize, outsize, error;
 464        int offset, s;
 465
 466        offset = INSIZE(symlink);
 467        insize = max_t(unsigned int, offset + len + symlen + 8, OUTSIZE(symlink));
 468        UPARG(CODA_SYMLINK);
 469        
 470        /*        inp->coda_symlink.attr = *tva; XXXXXX */ 
 471        inp->coda_symlink.VFid = *fid;
 472
 473        /* Round up to word boundary and null terminate */
 474        inp->coda_symlink.srcname = offset;
 475        s = ( symlen  & ~0x3 ) + 4; 
 476        memcpy((char *)(inp) + offset, symname, symlen);
 477        *((char *)inp + offset + symlen) = '\0';
 478        
 479        /* Round up to word boundary and null terminate */
 480        offset += s;
 481        inp->coda_symlink.tname = offset;
 482        s = (len & ~0x3) + 4;
 483        memcpy((char *)(inp) + offset, name, len);
 484        *((char *)inp + offset + len) = '\0';
 485
 486        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 487
 488        CDEBUG(D_INODE, " result %d\n",error);
 489        CODA_FREE(inp, insize);
 490        return error;
 491}
 492
 493int venus_fsync(struct super_block *sb, struct ViceFid *fid)
 494{
 495        union inputArgs *inp;
 496        union outputArgs *outp; 
 497        int insize, outsize, error;
 498        
 499        insize=SIZE(fsync);
 500        UPARG(CODA_FSYNC);
 501
 502        inp->coda_fsync.VFid = *fid;
 503        error = coda_upcall(coda_sbp(sb), sizeof(union inputArgs), 
 504                            &outsize, inp);
 505
 506        CODA_FREE(inp, insize);
 507        return error;
 508}
 509
 510int venus_access(struct super_block *sb, struct ViceFid *fid, int mask)
 511{
 512        union inputArgs *inp;
 513        union outputArgs *outp; 
 514        int insize, outsize, error;
 515
 516        insize = SIZE(access);
 517        UPARG(CODA_ACCESS);
 518
 519        inp->coda_access.VFid = *fid;
 520        inp->coda_access.flags = mask;
 521
 522        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 523
 524        CODA_FREE(inp, insize);
 525        return error;
 526}
 527
 528
 529int venus_pioctl(struct super_block *sb, struct ViceFid *fid,
 530                 unsigned int cmd, struct PioctlData *data)
 531{
 532        union inputArgs *inp;
 533        union outputArgs *outp;  
 534        int insize, outsize, error;
 535        int iocsize;
 536
 537        insize = VC_MAXMSGSIZE;
 538        UPARG(CODA_IOCTL);
 539
 540        /* build packet for Venus */
 541        if (data->vi.in_size > VC_MAXDATASIZE) {
 542                error = -EINVAL;
 543                goto exit;
 544        }
 545
 546        if (data->vi.out_size > VC_MAXDATASIZE) {
 547                error = -EINVAL;
 548                goto exit;
 549        }
 550
 551        inp->coda_ioctl.VFid = *fid;
 552    
 553        /* the cmd field was mutated by increasing its size field to
 554         * reflect the path and follow args. We need to subtract that
 555         * out before sending the command to Venus.  */
 556        inp->coda_ioctl.cmd = (cmd & ~(PIOCPARM_MASK << 16));   
 557        iocsize = ((cmd >> 16) & PIOCPARM_MASK) - sizeof(char *) - sizeof(int);
 558        inp->coda_ioctl.cmd |= (iocsize & PIOCPARM_MASK) <<     16;     
 559    
 560        /* in->coda_ioctl.rwflag = flag; */
 561        inp->coda_ioctl.len = data->vi.in_size;
 562        inp->coda_ioctl.data = (char *)(INSIZE(ioctl));
 563     
 564        /* get the data out of user space */
 565        if ( copy_from_user((char*)inp + (long)inp->coda_ioctl.data,
 566                            data->vi.in, data->vi.in_size) ) {
 567                error = -EINVAL;
 568                goto exit;
 569        }
 570
 571        error = coda_upcall(coda_sbp(sb), SIZE(ioctl) + data->vi.in_size,
 572                            &outsize, inp);
 573        
 574        if (error) {
 575                printk("coda_pioctl: Venus returns: %d for %s\n", 
 576                       error, coda_f2s(fid));
 577                goto exit; 
 578        }
 579
 580        if (outsize < (long)outp->coda_ioctl.data + outp->coda_ioctl.len) {
 581                CDEBUG(D_FILE, "reply size %d < reply len %ld\n", outsize,
 582                       (long)outp->coda_ioctl.data + outp->coda_ioctl.len);
 583                error = -EINVAL;
 584                goto exit;
 585        }
 586
 587        if (outp->coda_ioctl.len > data->vi.out_size) {
 588                CDEBUG(D_FILE, "return len %d > request len %d\n",
 589                       outp->coda_ioctl.len, data->vi.out_size);
 590                error = -EINVAL;
 591                goto exit;
 592        }
 593
 594        /* Copy out the OUT buffer. */
 595        error = verify_area(VERIFY_WRITE, data->vi.out, outp->coda_ioctl.len);
 596        if ( error ) goto exit;
 597
 598        if (copy_to_user(data->vi.out, 
 599                         (char *)outp + (long)outp->coda_ioctl.data, 
 600                         outp->coda_ioctl.len)) {
 601            error = -EINVAL;
 602        }
 603 exit:
 604        CODA_FREE(inp, insize);
 605        return error;
 606}
 607
 608int venus_statfs(struct super_block *sb, struct statfs *sfs) 
 609{ 
 610        union inputArgs *inp;
 611        union outputArgs *outp;
 612        int insize, outsize, error;
 613        
 614        insize = max_t(unsigned int, INSIZE(statfs), OUTSIZE(statfs));
 615        UPARG(CODA_STATFS);
 616
 617        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 618        
 619        if (!error) {
 620                sfs->f_blocks = outp->coda_statfs.stat.f_blocks;
 621                sfs->f_bfree  = outp->coda_statfs.stat.f_bfree;
 622                sfs->f_bavail = outp->coda_statfs.stat.f_bavail;
 623                sfs->f_files  = outp->coda_statfs.stat.f_files;
 624                sfs->f_ffree  = outp->coda_statfs.stat.f_ffree;
 625        } else {
 626                printk("coda_statfs: Venus returns: %d\n", error);
 627        }
 628
 629        CDEBUG(D_INODE, " result %d\n",error);
 630        CODA_FREE(inp, insize);
 631        return error;
 632}
 633
 634/*
 635 * coda_upcall and coda_downcall routines.
 636 * 
 637 */
 638
 639static inline unsigned long coda_waitfor_upcall(struct upc_req *vmp,
 640                                                struct venus_comm *vcommp)
 641{
 642        DECLARE_WAITQUEUE(wait, current);
 643        struct timeval begin = { 0, 0 }, end = { 0, 0 };
 644
 645        vmp->uc_posttime = jiffies;
 646
 647        if (coda_upcall_timestamping)
 648                do_gettimeofday(&begin);
 649
 650        add_wait_queue(&vmp->uc_sleep, &wait);
 651        for (;;) {
 652                if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE ) 
 653                        set_current_state(TASK_INTERRUPTIBLE);
 654                else
 655                        set_current_state(TASK_UNINTERRUPTIBLE);
 656
 657                /* venus died */
 658                if ( !vcommp->vc_inuse )
 659                        break;
 660
 661                /* got a reply */
 662                if ( vmp->uc_flags & ( REQ_WRITE | REQ_ABORT ) )
 663                        break;
 664
 665                if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE && signal_pending(current) ) {
 666                        /* if this process really wants to die, let it go */
 667                        if ( sigismember(&(current->pending.signal), SIGKILL) ||
 668                             sigismember(&(current->pending.signal), SIGINT) )
 669                                break;
 670                        /* signal is present: after timeout always return 
 671                           really smart idea, probably useless ... */
 672                        if ( jiffies - vmp->uc_posttime > coda_timeout * HZ )
 673                                break; 
 674                }
 675                schedule();
 676        }
 677        remove_wait_queue(&vmp->uc_sleep, &wait);
 678        set_current_state(TASK_RUNNING);
 679
 680        if (coda_upcall_timestamping && begin.tv_sec != 0) {
 681                do_gettimeofday(&end);
 682
 683                if (end.tv_usec < begin.tv_usec) {
 684                        end.tv_usec += 1000000; end.tv_sec--;
 685                }
 686                end.tv_sec  -= begin.tv_sec;
 687                end.tv_usec -= begin.tv_usec;
 688        }
 689
 690        CDEBUG(D_SPECIAL, "begin: %ld.%06ld, elapsed: %ld.%06ld\n",
 691                begin.tv_sec, (unsigned long)begin.tv_usec,
 692                end.tv_sec, (unsigned long)end.tv_usec);
 693
 694        return  ((end.tv_sec * 1000000) + end.tv_usec);
 695}
 696
 697
 698/* 
 699 * coda_upcall will return an error in the case of 
 700 * failed communication with Venus _or_ will peek at Venus
 701 * reply and return Venus' error.
 702 *
 703 * As venus has 2 types of errors, normal errors (positive) and internal
 704 * errors (negative), normal errors are negated, while internal errors
 705 * are all mapped to -EINTR, while showing a nice warning message. (jh)
 706 * 
 707 */
 708static int coda_upcall(struct coda_sb_info *sbi, 
 709                int inSize, int *outSize, 
 710                union inputArgs *buffer) 
 711{
 712        unsigned long runtime; 
 713        struct venus_comm *vcommp;
 714        union outputArgs *out;
 715        struct upc_req *req;
 716        int error = 0;
 717
 718        vcommp = sbi->sbi_vcomm;
 719        if ( !vcommp->vc_inuse ) {
 720                printk("No pseudo device in upcall comms at %p\n", vcommp);
 721                return -ENXIO;
 722        }
 723
 724        /* Format the request message. */
 725        req = upc_alloc();
 726        if (!req) {
 727                printk("Failed to allocate upc_req structure\n");
 728                return -ENOMEM;
 729        }
 730        req->uc_data = (void *)buffer;
 731        req->uc_flags = 0;
 732        req->uc_inSize = inSize;
 733        req->uc_outSize = *outSize ? *outSize : inSize;
 734        req->uc_opcode = ((union inputArgs *)buffer)->ih.opcode;
 735        req->uc_unique = ++vcommp->vc_seq;
 736        init_waitqueue_head(&req->uc_sleep);
 737        
 738        /* Fill in the common input args. */
 739        ((union inputArgs *)buffer)->ih.unique = req->uc_unique;
 740
 741        /* Append msg to pending queue and poke Venus. */
 742        list_add(&(req->uc_chain), vcommp->vc_pending.prev);
 743        
 744        CDEBUG(D_UPCALL, 
 745               "Proc %d wake Venus for(opc,uniq) =(%d,%d) msg at %p.zzz.\n",
 746               current->pid, req->uc_opcode, req->uc_unique, req);
 747
 748        wake_up_interruptible(&vcommp->vc_waitq);
 749        /* We can be interrupted while we wait for Venus to process
 750         * our request.  If the interrupt occurs before Venus has read
 751         * the request, we dequeue and return. If it occurs after the
 752         * read but before the reply, we dequeue, send a signal
 753         * message, and return. If it occurs after the reply we ignore
 754         * it. In no case do we want to restart the syscall.  If it
 755         * was interrupted by a venus shutdown (psdev_close), return
 756         * ENODEV.  */
 757
 758        /* Go to sleep.  Wake up on signals only after the timeout. */
 759        runtime = coda_waitfor_upcall(req, vcommp);
 760        coda_upcall_stats(((union inputArgs *)buffer)->ih.opcode, runtime);
 761
 762        CDEBUG(D_TIMING, "opc: %d time: %ld uniq: %d size: %d\n",
 763               req->uc_opcode, jiffies - req->uc_posttime, 
 764               req->uc_unique, req->uc_outSize);
 765        CDEBUG(D_UPCALL, 
 766               "..process %d woken up by Venus for req at %p, data at %p\n", 
 767               current->pid, req, req->uc_data);
 768        if (vcommp->vc_inuse) {      /* i.e. Venus is still alive */
 769            /* Op went through, interrupt or not... */
 770            if (req->uc_flags & REQ_WRITE) {
 771                out = (union outputArgs *)req->uc_data;
 772                /* here we map positive Venus errors to kernel errors */
 773                error = -out->oh.result;
 774                CDEBUG(D_UPCALL, 
 775                       "upcall: (u,o,r) (%ld, %ld, %ld) out at %p\n", 
 776                       out->oh.unique, out->oh.opcode, out->oh.result, out);
 777                *outSize = req->uc_outSize;
 778                goto exit;
 779            }
 780            if ( !(req->uc_flags & REQ_READ) && signal_pending(current)) { 
 781                /* Interrupted before venus read it. */
 782                CDEBUG(D_UPCALL, 
 783                       "Interrupted before read:(op,un) (%d.%d), flags = %x\n",
 784                       req->uc_opcode, req->uc_unique, req->uc_flags);
 785                list_del(&(req->uc_chain));
 786                /* perhaps the best way to convince the app to
 787                   give up? */
 788                error = -EINTR;
 789                goto exit;
 790            } 
 791            if ( (req->uc_flags & REQ_READ) && signal_pending(current) ) {
 792                    /* interrupted after Venus did its read, send signal */
 793                    union inputArgs *sig_inputArgs;
 794                    struct upc_req *sig_req;
 795                    
 796                    CDEBUG(D_UPCALL, 
 797                           "Sending Venus a signal: op = %d.%d, flags = %x\n",
 798                           req->uc_opcode, req->uc_unique, req->uc_flags);
 799                    
 800                    list_del(&(req->uc_chain));
 801                    error = -ENOMEM;
 802                    sig_req = upc_alloc();
 803                    if (!sig_req) goto exit;
 804
 805                    CODA_ALLOC((sig_req->uc_data), char *, sizeof(struct coda_in_hdr));
 806                    if (!sig_req->uc_data) {
 807                        upc_free(sig_req);
 808                        goto exit;
 809                    }
 810                    
 811                    error = -EINTR;
 812                    sig_inputArgs = (union inputArgs *)sig_req->uc_data;
 813                    sig_inputArgs->ih.opcode = CODA_SIGNAL;
 814                    sig_inputArgs->ih.unique = req->uc_unique;
 815                    
 816                    sig_req->uc_flags = REQ_ASYNC;
 817                    sig_req->uc_opcode = sig_inputArgs->ih.opcode;
 818                    sig_req->uc_unique = sig_inputArgs->ih.unique;
 819                    sig_req->uc_inSize = sizeof(struct coda_in_hdr);
 820                    sig_req->uc_outSize = sizeof(struct coda_in_hdr);
 821                    CDEBUG(D_UPCALL, 
 822                           "coda_upcall: enqueing signal msg (%d, %d)\n",
 823                           sig_req->uc_opcode, sig_req->uc_unique);
 824                    
 825                    /* insert at head of queue! */
 826                    list_add(&(sig_req->uc_chain), &vcommp->vc_pending);
 827                    wake_up_interruptible(&vcommp->vc_waitq);
 828            } else {
 829                    printk("Coda: Strange interruption..\n");
 830                    error = -EINTR;
 831            }
 832        } else {        /* If venus died i.e. !VC_OPEN(vcommp) */
 833                printk("coda_upcall: Venus dead on (op,un) (%d.%d) flags %d\n",
 834                       req->uc_opcode, req->uc_unique, req->uc_flags);
 835                error = -ENODEV;
 836        }
 837
 838 exit:
 839        upc_free(req);
 840        if (error) 
 841                badclstats();
 842        return error;
 843}
 844
 845/*  
 846    The statements below are part of the Coda opportunistic
 847    programming -- taken from the Mach/BSD kernel code for Coda. 
 848    You don't get correct semantics by stating what needs to be
 849    done without guaranteeing the invariants needed for it to happen.
 850    When will be have time to find out what exactly is going on?  (pjb)
 851*/
 852
 853
 854/* 
 855 * There are 7 cases where cache invalidations occur.  The semantics
 856 *  of each is listed here:
 857 *
 858 * CODA_FLUSH     -- flush all entries from the name cache and the cnode cache.
 859 * CODA_PURGEUSER -- flush all entries from the name cache for a specific user
 860 *                  This call is a result of token expiration.
 861 *
 862 * The next arise as the result of callbacks on a file or directory.
 863 * CODA_ZAPFILE   -- flush the cached attributes for a file.
 864
 865 * CODA_ZAPDIR    -- flush the attributes for the dir and
 866 *                  force a new lookup for all the children
 867                    of this dir.
 868
 869 *
 870 * The next is a result of Venus detecting an inconsistent file.
 871 * CODA_PURGEFID  -- flush the attribute for the file
 872 *                  purge it and its children from the dcache
 873 *
 874 * The last  allows Venus to replace local fids with global ones
 875 * during reintegration.
 876 *
 877 * CODA_REPLACE -- replace one ViceFid with another throughout the name cache */
 878
 879int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
 880{
 881        /* Handle invalidation requests. */
 882          if ( !sb || !sb->s_root || !sb->s_root->d_inode) { 
 883                  CDEBUG(D_DOWNCALL, "coda_downcall: opcode %d, no sb!\n", opcode);
 884                  return 0; 
 885          }
 886
 887          switch (opcode) {
 888
 889          case CODA_FLUSH : {
 890                   clstats(CODA_FLUSH);
 891                   CDEBUG(D_DOWNCALL, "CODA_FLUSH\n");
 892                   coda_cache_clear_all(sb, NULL);
 893                   shrink_dcache_sb(sb);
 894                   coda_flag_inode(sb->s_root->d_inode, C_FLUSH);
 895                   return(0);
 896          }
 897
 898          case CODA_PURGEUSER : {
 899                   struct coda_cred *cred = &out->coda_purgeuser.cred;
 900                   CDEBUG(D_DOWNCALL, "CODA_PURGEUSER\n");
 901                   if ( !cred ) {
 902                           printk("PURGEUSER: null cred!\n");
 903                           return 0;
 904                   }
 905                   clstats(CODA_PURGEUSER);
 906                   coda_cache_clear_all(sb, cred);
 907                   return(0);
 908          }
 909
 910          case CODA_ZAPDIR : {
 911                  struct inode *inode;
 912                  ViceFid *fid = &out->coda_zapdir.CodaFid;
 913                  CDEBUG(D_DOWNCALL, "zapdir: fid = %s...\n", coda_f2s(fid));
 914                  clstats(CODA_ZAPDIR);
 915
 916                  inode = coda_fid_to_inode(fid, sb);
 917                  if (inode) {
 918                          CDEBUG(D_DOWNCALL, "zapdir: inode = %ld children flagged\n", 
 919                                 inode->i_ino);
 920                          coda_flag_inode_children(inode, C_PURGE);
 921                          CDEBUG(D_DOWNCALL, "zapdir: inode = %ld cache cleared\n", inode->i_ino);
 922                          coda_flag_inode(inode, C_VATTR);
 923                          iput(inode);
 924                  } else 
 925                          CDEBUG(D_DOWNCALL, "zapdir: no inode\n");
 926                  
 927                  return(0);
 928          }
 929
 930          case CODA_ZAPFILE : {
 931                  struct inode *inode;
 932                  struct ViceFid *fid = &out->coda_zapfile.CodaFid;
 933                  clstats(CODA_ZAPFILE);
 934                  CDEBUG(D_DOWNCALL, "zapfile: fid = %s\n", coda_f2s(fid));
 935                  inode = coda_fid_to_inode(fid, sb);
 936                  if ( inode ) {
 937                          CDEBUG(D_DOWNCALL, "zapfile: inode = %ld\n",
 938                                 inode->i_ino);
 939                          coda_flag_inode(inode, C_VATTR);
 940                          iput(inode);
 941                  } else 
 942                          CDEBUG(D_DOWNCALL, "zapfile: no inode\n");
 943                  return 0;
 944          }
 945
 946          case CODA_PURGEFID : {
 947                  struct inode *inode;
 948                  ViceFid *fid = &out->coda_purgefid.CodaFid;
 949                  CDEBUG(D_DOWNCALL, "purgefid: fid = %s\n", coda_f2s(fid));
 950                  clstats(CODA_PURGEFID);
 951                  inode = coda_fid_to_inode(fid, sb);
 952                  if ( inode ) { 
 953                        CDEBUG(D_DOWNCALL, "purgefid: inode = %ld\n",
 954                               inode->i_ino);
 955                        coda_flag_inode_children(inode, C_PURGE);
 956
 957                        /* catch the dentries later if some are still busy */
 958                        coda_flag_inode(inode, C_PURGE);
 959                        d_prune_aliases(inode);
 960
 961                        iput(inode);
 962                  } else 
 963                        CDEBUG(D_DOWNCALL, "purgefid: no inode\n");
 964                  return 0;
 965          }
 966
 967          case CODA_REPLACE : {
 968                  struct inode *inode;
 969                  ViceFid *oldfid = &out->coda_replace.OldFid;
 970                  ViceFid *newfid = &out->coda_replace.NewFid;
 971                  clstats(CODA_REPLACE);
 972                  CDEBUG(D_DOWNCALL, "CODA_REPLACE\n");
 973                  inode = coda_fid_to_inode(oldfid, sb);
 974                  if ( inode ) { 
 975                          CDEBUG(D_DOWNCALL, "replacefid: inode = %ld\n",
 976                                 inode->i_ino);
 977                          coda_replace_fid(inode, oldfid, newfid);
 978                          iput(inode);
 979                  }else 
 980                          CDEBUG(D_DOWNCALL, "purgefid: no inode\n");
 981                  
 982                  return 0;
 983          }
 984          }
 985          return 0;
 986}
 987
 988
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.