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