linux/fs/coda/upcall.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Mostly platform independent upcall operations to Venus:
   4 *  -- upcalls
   5 *  -- upcall routines
   6 *
   7 * Linux 2.0 version
   8 * Copyright (C) 1996 Peter J. Braam <braam@maths.ox.ac.uk>, 
   9 * Michael Callahan <callahan@maths.ox.ac.uk> 
  10 * 
  11 * Redone for Linux 2.1
  12 * Copyright (C) 1997 Carnegie Mellon University
  13 *
  14 * Carnegie Mellon University encourages users of this code to contribute
  15 * improvements to the Coda project. Contact Peter Braam <coda@cs.cmu.edu>.
  16 */
  17
  18#include <linux/signal.h>
  19#include <linux/sched/signal.h>
  20#include <linux/types.h>
  21#include <linux/kernel.h>
  22#include <linux/mm.h>
  23#include <linux/time.h>
  24#include <linux/fs.h>
  25#include <linux/file.h>
  26#include <linux/stat.h>
  27#include <linux/errno.h>
  28#include <linux/string.h>
  29#include <linux/slab.h>
  30#include <linux/mutex.h>
  31#include <linux/uaccess.h>
  32#include <linux/vmalloc.h>
  33#include <linux/vfs.h>
  34
  35#include <linux/coda.h>
  36#include "coda_psdev.h"
  37#include "coda_linux.h"
  38#include "coda_cache.h"
  39
  40#include "coda_int.h"
  41
  42static int coda_upcall(struct venus_comm *vc, int inSize, int *outSize,
  43                       union inputArgs *buffer);
  44
  45static void *alloc_upcall(int opcode, int size)
  46{
  47        union inputArgs *inp;
  48
  49        inp = kvzalloc(size, GFP_KERNEL);
  50        if (!inp)
  51                return ERR_PTR(-ENOMEM);
  52
  53        inp->ih.opcode = opcode;
  54        inp->ih.pid = task_pid_nr_ns(current, &init_pid_ns);
  55        inp->ih.pgid = task_pgrp_nr_ns(current, &init_pid_ns);
  56        inp->ih.uid = from_kuid(&init_user_ns, current_fsuid());
  57
  58        return (void*)inp;
  59}
  60
  61#define UPARG(op)\
  62do {\
  63        inp = (union inputArgs *)alloc_upcall(op, insize); \
  64        if (IS_ERR(inp)) { return PTR_ERR(inp); }\
  65        outp = (union outputArgs *)(inp); \
  66        outsize = insize; \
  67} while (0)
  68
  69#define INSIZE(tag) sizeof(struct coda_ ## tag ## _in)
  70#define OUTSIZE(tag) sizeof(struct coda_ ## tag ## _out)
  71#define SIZE(tag)  max_t(unsigned int, INSIZE(tag), OUTSIZE(tag))
  72
  73
  74/* the upcalls */
  75int venus_rootfid(struct super_block *sb, struct CodaFid *fidp)
  76{
  77        union inputArgs *inp;
  78        union outputArgs *outp;
  79        int insize, outsize, error;
  80
  81        insize = SIZE(root);
  82        UPARG(CODA_ROOT);
  83
  84        error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
  85        if (!error)
  86                *fidp = outp->coda_root.VFid;
  87
  88        kvfree(inp);
  89        return error;
  90}
  91
  92int venus_getattr(struct super_block *sb, struct CodaFid *fid, 
  93                     struct coda_vattr *attr) 
  94{
  95        union inputArgs *inp;
  96        union outputArgs *outp;
  97        int insize, outsize, error;
  98
  99        insize = SIZE(getattr); 
 100        UPARG(CODA_GETATTR);
 101        inp->coda_getattr.VFid = *fid;
 102
 103        error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 104        if (!error)
 105                *attr = outp->coda_getattr.attr;
 106
 107        kvfree(inp);
 108        return error;
 109}
 110
 111int venus_setattr(struct super_block *sb, struct CodaFid *fid, 
 112                  struct coda_vattr *vattr)
 113{
 114        union inputArgs *inp;
 115        union outputArgs *outp;
 116        int insize, outsize, error;
 117        
 118        insize = SIZE(setattr);
 119        UPARG(CODA_SETATTR);
 120
 121        inp->coda_setattr.VFid = *fid;
 122        inp->coda_setattr.attr = *vattr;
 123
 124        error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 125
 126        kvfree(inp);
 127        return error;
 128}
 129
 130int venus_lookup(struct super_block *sb, struct CodaFid *fid, 
 131                    const char *name, int length, int * type, 
 132                    struct CodaFid *resfid)
 133{
 134        union inputArgs *inp;
 135        union outputArgs *outp;
 136        int insize, outsize, error;
 137        int offset;
 138
 139        offset = INSIZE(lookup);
 140        insize = max_t(unsigned int, offset + length +1, OUTSIZE(lookup));
 141        UPARG(CODA_LOOKUP);
 142
 143        inp->coda_lookup.VFid = *fid;
 144        inp->coda_lookup.name = offset;
 145        inp->coda_lookup.flags = CLU_CASE_SENSITIVE;
 146        /* send Venus a null terminated string */
 147        memcpy((char *)(inp) + offset, name, length);
 148        *((char *)inp + offset + length) = '\0';
 149
 150        error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 151        if (!error) {
 152                *resfid = outp->coda_lookup.VFid;
 153                *type = outp->coda_lookup.vtype;
 154        }
 155
 156        kvfree(inp);
 157        return error;
 158}
 159
 160int venus_close(struct super_block *sb, struct CodaFid *fid, int flags,
 161                kuid_t uid)
 162{
 163        union inputArgs *inp;
 164        union outputArgs *outp;
 165        int insize, outsize, error;
 166        
 167        insize = SIZE(release);
 168        UPARG(CODA_CLOSE);
 169        
 170        inp->ih.uid = from_kuid(&init_user_ns, uid);
 171        inp->coda_close.VFid = *fid;
 172        inp->coda_close.flags = flags;
 173
 174        error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 175
 176        kvfree(inp);
 177        return error;
 178}
 179
 180int venus_open(struct super_block *sb, struct CodaFid *fid,
 181                  int flags, struct file **fh)
 182{
 183        union inputArgs *inp;
 184        union outputArgs *outp;
 185        int insize, outsize, error;
 186       
 187        insize = SIZE(open_by_fd);
 188        UPARG(CODA_OPEN_BY_FD);
 189
 190        inp->coda_open_by_fd.VFid = *fid;
 191        inp->coda_open_by_fd.flags = flags;
 192
 193        error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 194        if (!error)
 195                *fh = outp->coda_open_by_fd.fh;
 196
 197        kvfree(inp);
 198        return error;
 199}       
 200
 201int venus_mkdir(struct super_block *sb, struct CodaFid *dirfid, 
 202                   const char *name, int length, 
 203                   struct CodaFid *newfid, struct coda_vattr *attrs)
 204{
 205        union inputArgs *inp;
 206        union outputArgs *outp;
 207        int insize, outsize, error;
 208        int offset;
 209
 210        offset = INSIZE(mkdir);
 211        insize = max_t(unsigned int, offset + length + 1, OUTSIZE(mkdir));
 212        UPARG(CODA_MKDIR);
 213
 214        inp->coda_mkdir.VFid = *dirfid;
 215        inp->coda_mkdir.attr = *attrs;
 216        inp->coda_mkdir.name = offset;
 217        /* Venus must get null terminated string */
 218        memcpy((char *)(inp) + offset, name, length);
 219        *((char *)inp + offset + length) = '\0';
 220
 221        error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 222        if (!error) {
 223                *attrs = outp->coda_mkdir.attr;
 224                *newfid = outp->coda_mkdir.VFid;
 225        }
 226
 227        kvfree(inp);
 228        return error;        
 229}
 230
 231
 232int venus_rename(struct super_block *sb, struct CodaFid *old_fid, 
 233                 struct CodaFid *new_fid, size_t old_length, 
 234                 size_t new_length, const char *old_name, 
 235                 const char *new_name)
 236{
 237        union inputArgs *inp;
 238        union outputArgs *outp;
 239        int insize, outsize, error; 
 240        int offset, s;
 241        
 242        offset = INSIZE(rename);
 243        insize = max_t(unsigned int, offset + new_length + old_length + 8,
 244                     OUTSIZE(rename)); 
 245        UPARG(CODA_RENAME);
 246
 247        inp->coda_rename.sourceFid = *old_fid;
 248        inp->coda_rename.destFid =  *new_fid;
 249        inp->coda_rename.srcname = offset;
 250
 251        /* Venus must receive an null terminated string */
 252        s = ( old_length & ~0x3) +4; /* round up to word boundary */
 253        memcpy((char *)(inp) + offset, old_name, old_length);
 254        *((char *)inp + offset + old_length) = '\0';
 255
 256        /* another null terminated string for Venus */
 257        offset += s;
 258        inp->coda_rename.destname = offset;
 259        s = ( new_length & ~0x3) +4; /* round up to word boundary */
 260        memcpy((char *)(inp) + offset, new_name, new_length);
 261        *((char *)inp + offset + new_length) = '\0';
 262
 263        error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 264
 265        kvfree(inp);
 266        return error;
 267}
 268
 269int venus_create(struct super_block *sb, struct CodaFid *dirfid, 
 270                 const char *name, int length, int excl, int mode,
 271                 struct CodaFid *newfid, struct coda_vattr *attrs) 
 272{
 273        union inputArgs *inp;
 274        union outputArgs *outp;
 275        int insize, outsize, error;
 276        int offset;
 277
 278        offset = INSIZE(create);
 279        insize = max_t(unsigned int, offset + length + 1, OUTSIZE(create));
 280        UPARG(CODA_CREATE);
 281
 282        inp->coda_create.VFid = *dirfid;
 283        inp->coda_create.attr.va_mode = mode;
 284        inp->coda_create.excl = excl;
 285        inp->coda_create.mode = mode;
 286        inp->coda_create.name = offset;
 287
 288        /* Venus must get null terminated string */
 289        memcpy((char *)(inp) + offset, name, length);
 290        *((char *)inp + offset + length) = '\0';
 291
 292        error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 293        if (!error) {
 294                *attrs = outp->coda_create.attr;
 295                *newfid = outp->coda_create.VFid;
 296        }
 297
 298        kvfree(inp);
 299        return error;        
 300}
 301
 302int venus_rmdir(struct super_block *sb, struct CodaFid *dirfid, 
 303                    const char *name, int length)
 304{
 305        union inputArgs *inp;
 306        union outputArgs *outp;
 307        int insize, outsize, error;
 308        int offset;
 309
 310        offset = INSIZE(rmdir);
 311        insize = max_t(unsigned int, offset + length + 1, OUTSIZE(rmdir));
 312        UPARG(CODA_RMDIR);
 313
 314        inp->coda_rmdir.VFid = *dirfid;
 315        inp->coda_rmdir.name = offset;
 316        memcpy((char *)(inp) + offset, name, length);
 317        *((char *)inp + offset + length) = '\0';
 318
 319        error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 320
 321        kvfree(inp);
 322        return error;
 323}
 324
 325int venus_remove(struct super_block *sb, struct CodaFid *dirfid, 
 326                    const char *name, int length)
 327{
 328        union inputArgs *inp;
 329        union outputArgs *outp;
 330        int error=0, insize, outsize, offset;
 331
 332        offset = INSIZE(remove);
 333        insize = max_t(unsigned int, offset + length + 1, OUTSIZE(remove));
 334        UPARG(CODA_REMOVE);
 335
 336        inp->coda_remove.VFid = *dirfid;
 337        inp->coda_remove.name = offset;
 338        memcpy((char *)(inp) + offset, name, length);
 339        *((char *)inp + offset + length) = '\0';
 340
 341        error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 342
 343        kvfree(inp);
 344        return error;
 345}
 346
 347int venus_readlink(struct super_block *sb, struct CodaFid *fid, 
 348                      char *buffer, int *length)
 349{ 
 350        union inputArgs *inp;
 351        union outputArgs *outp;
 352        int insize, outsize, error;
 353        int retlen;
 354        char *result;
 355        
 356        insize = max_t(unsigned int,
 357                     INSIZE(readlink), OUTSIZE(readlink)+ *length);
 358        UPARG(CODA_READLINK);
 359
 360        inp->coda_readlink.VFid = *fid;
 361
 362        error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 363        if (!error) {
 364                retlen = outp->coda_readlink.count;
 365                if (retlen >= *length)
 366                        retlen = *length - 1;
 367                *length = retlen;
 368                result =  (char *)outp + (long)outp->coda_readlink.data;
 369                memcpy(buffer, result, retlen);
 370                *(buffer + retlen) = '\0';
 371        }
 372
 373        kvfree(inp);
 374        return error;
 375}
 376
 377
 378
 379int venus_link(struct super_block *sb, struct CodaFid *fid, 
 380                  struct CodaFid *dirfid, const char *name, int len )
 381{
 382        union inputArgs *inp;
 383        union outputArgs *outp;
 384        int insize, outsize, error;
 385        int offset;
 386
 387        offset = INSIZE(link);
 388        insize = max_t(unsigned int, offset  + len + 1, OUTSIZE(link));
 389        UPARG(CODA_LINK);
 390
 391        inp->coda_link.sourceFid = *fid;
 392        inp->coda_link.destFid = *dirfid;
 393        inp->coda_link.tname = offset;
 394
 395        /* make sure strings are null terminated */
 396        memcpy((char *)(inp) + offset, name, len);
 397        *((char *)inp + offset + len) = '\0';
 398
 399        error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 400
 401        kvfree(inp);
 402        return error;
 403}
 404
 405int venus_symlink(struct super_block *sb, struct CodaFid *fid,
 406                     const char *name, int len,
 407                     const char *symname, int symlen)
 408{
 409        union inputArgs *inp;
 410        union outputArgs *outp;
 411        int insize, outsize, error;
 412        int offset, s;
 413
 414        offset = INSIZE(symlink);
 415        insize = max_t(unsigned int, offset + len + symlen + 8, OUTSIZE(symlink));
 416        UPARG(CODA_SYMLINK);
 417        
 418        /*        inp->coda_symlink.attr = *tva; XXXXXX */ 
 419        inp->coda_symlink.VFid = *fid;
 420
 421        /* Round up to word boundary and null terminate */
 422        inp->coda_symlink.srcname = offset;
 423        s = ( symlen  & ~0x3 ) + 4; 
 424        memcpy((char *)(inp) + offset, symname, symlen);
 425        *((char *)inp + offset + symlen) = '\0';
 426        
 427        /* Round up to word boundary and null terminate */
 428        offset += s;
 429        inp->coda_symlink.tname = offset;
 430        s = (len & ~0x3) + 4;
 431        memcpy((char *)(inp) + offset, name, len);
 432        *((char *)inp + offset + len) = '\0';
 433
 434        error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 435
 436        kvfree(inp);
 437        return error;
 438}
 439
 440int venus_fsync(struct super_block *sb, struct CodaFid *fid)
 441{
 442        union inputArgs *inp;
 443        union outputArgs *outp; 
 444        int insize, outsize, error;
 445        
 446        insize=SIZE(fsync);
 447        UPARG(CODA_FSYNC);
 448
 449        inp->coda_fsync.VFid = *fid;
 450        error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 451
 452        kvfree(inp);
 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        kvfree(inp);
 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                pr_warn("%s: Venus returns: %d for %s\n",
 522                        __func__, 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        kvfree(inp);
 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 = SIZE(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        kvfree(inp);
 569        return error;
 570}
 571
 572int venus_access_intent(struct super_block *sb, struct CodaFid *fid,
 573                        bool *access_intent_supported,
 574                        size_t count, loff_t ppos, int type)
 575{
 576        union inputArgs *inp;
 577        union outputArgs *outp;
 578        int insize, outsize, error;
 579        bool finalizer =
 580                type == CODA_ACCESS_TYPE_READ_FINISH ||
 581                type == CODA_ACCESS_TYPE_WRITE_FINISH;
 582
 583        if (!*access_intent_supported && !finalizer)
 584                return 0;
 585
 586        insize = SIZE(access_intent);
 587        UPARG(CODA_ACCESS_INTENT);
 588
 589        inp->coda_access_intent.VFid = *fid;
 590        inp->coda_access_intent.count = count;
 591        inp->coda_access_intent.pos = ppos;
 592        inp->coda_access_intent.type = type;
 593
 594        error = coda_upcall(coda_vcp(sb), insize,
 595                            finalizer ? NULL : &outsize, inp);
 596
 597        /*
 598         * we have to free the request buffer for synchronous upcalls
 599         * or when asynchronous upcalls fail, but not when asynchronous
 600         * upcalls succeed
 601         */
 602        if (!finalizer || error)
 603                kvfree(inp);
 604
 605        /* Chunked access is not supported or an old Coda client */
 606        if (error == -EOPNOTSUPP) {
 607                *access_intent_supported = false;
 608                error = 0;
 609        }
 610        return error;
 611}
 612
 613/*
 614 * coda_upcall and coda_downcall routines.
 615 */
 616static void coda_block_signals(sigset_t *old)
 617{
 618        spin_lock_irq(&current->sighand->siglock);
 619        *old = current->blocked;
 620
 621        sigfillset(&current->blocked);
 622        sigdelset(&current->blocked, SIGKILL);
 623        sigdelset(&current->blocked, SIGSTOP);
 624        sigdelset(&current->blocked, SIGINT);
 625
 626        recalc_sigpending();
 627        spin_unlock_irq(&current->sighand->siglock);
 628}
 629
 630static void coda_unblock_signals(sigset_t *old)
 631{
 632        spin_lock_irq(&current->sighand->siglock);
 633        current->blocked = *old;
 634        recalc_sigpending();
 635        spin_unlock_irq(&current->sighand->siglock);
 636}
 637
 638/* Don't allow signals to interrupt the following upcalls before venus
 639 * has seen them,
 640 * - CODA_CLOSE or CODA_RELEASE upcall  (to avoid reference count problems)
 641 * - CODA_STORE                         (to avoid data loss)
 642 * - CODA_ACCESS_INTENT                 (to avoid reference count problems)
 643 */
 644#define CODA_INTERRUPTIBLE(r) (!coda_hard && \
 645                               (((r)->uc_opcode != CODA_CLOSE && \
 646                                 (r)->uc_opcode != CODA_STORE && \
 647                                 (r)->uc_opcode != CODA_ACCESS_INTENT && \
 648                                 (r)->uc_opcode != CODA_RELEASE) || \
 649                                (r)->uc_flags & CODA_REQ_READ))
 650
 651static inline void coda_waitfor_upcall(struct venus_comm *vcp,
 652                                       struct upc_req *req)
 653{
 654        DECLARE_WAITQUEUE(wait, current);
 655        unsigned long timeout = jiffies + coda_timeout * HZ;
 656        sigset_t old;
 657        int blocked;
 658
 659        coda_block_signals(&old);
 660        blocked = 1;
 661
 662        add_wait_queue(&req->uc_sleep, &wait);
 663        for (;;) {
 664                if (CODA_INTERRUPTIBLE(req))
 665                        set_current_state(TASK_INTERRUPTIBLE);
 666                else
 667                        set_current_state(TASK_UNINTERRUPTIBLE);
 668
 669                /* got a reply */
 670                if (req->uc_flags & (CODA_REQ_WRITE | CODA_REQ_ABORT))
 671                        break;
 672
 673                if (blocked && time_after(jiffies, timeout) &&
 674                    CODA_INTERRUPTIBLE(req))
 675                {
 676                        coda_unblock_signals(&old);
 677                        blocked = 0;
 678                }
 679
 680                if (signal_pending(current)) {
 681                        list_del(&req->uc_chain);
 682                        break;
 683                }
 684
 685                mutex_unlock(&vcp->vc_mutex);
 686                if (blocked)
 687                        schedule_timeout(HZ);
 688                else
 689                        schedule();
 690                mutex_lock(&vcp->vc_mutex);
 691        }
 692        if (blocked)
 693                coda_unblock_signals(&old);
 694
 695        remove_wait_queue(&req->uc_sleep, &wait);
 696        set_current_state(TASK_RUNNING);
 697}
 698
 699
 700/*
 701 * coda_upcall will return an error in the case of
 702 * failed communication with Venus _or_ will peek at Venus
 703 * reply and return Venus' error.
 704 *
 705 * As venus has 2 types of errors, normal errors (positive) and internal
 706 * errors (negative), normal errors are negated, while internal errors
 707 * are all mapped to -EINTR, while showing a nice warning message. (jh)
 708 */
 709static int coda_upcall(struct venus_comm *vcp,
 710                       int inSize, int *outSize,
 711                       union inputArgs *buffer)
 712{
 713        union outputArgs *out;
 714        union inputArgs *sig_inputArgs;
 715        struct upc_req *req = NULL, *sig_req;
 716        int error;
 717
 718        mutex_lock(&vcp->vc_mutex);
 719
 720        if (!vcp->vc_inuse) {
 721                pr_notice("Venus dead, not sending upcall\n");
 722                error = -ENXIO;
 723                goto exit;
 724        }
 725
 726        /* Format the request message. */
 727        req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
 728        if (!req) {
 729                error = -ENOMEM;
 730                goto exit;
 731        }
 732
 733        buffer->ih.unique = ++vcp->vc_seq;
 734
 735        req->uc_data = (void *)buffer;
 736        req->uc_flags = outSize ? 0 : CODA_REQ_ASYNC;
 737        req->uc_inSize = inSize;
 738        req->uc_outSize = (outSize && *outSize) ? *outSize : inSize;
 739        req->uc_opcode = buffer->ih.opcode;
 740        req->uc_unique = buffer->ih.unique;
 741        init_waitqueue_head(&req->uc_sleep);
 742
 743        /* Append msg to pending queue and poke Venus. */
 744        list_add_tail(&req->uc_chain, &vcp->vc_pending);
 745        wake_up_interruptible(&vcp->vc_waitq);
 746
 747        if (req->uc_flags & CODA_REQ_ASYNC) {
 748                mutex_unlock(&vcp->vc_mutex);
 749                return 0;
 750        }
 751
 752        /* We can be interrupted while we wait for Venus to process
 753         * our request.  If the interrupt occurs before Venus has read
 754         * the request, we dequeue and return. If it occurs after the
 755         * read but before the reply, we dequeue, send a signal
 756         * message, and return. If it occurs after the reply we ignore
 757         * it. In no case do we want to restart the syscall.  If it
 758         * was interrupted by a venus shutdown (psdev_close), return
 759         * ENODEV.  */
 760
 761        /* Go to sleep.  Wake up on signals only after the timeout. */
 762        coda_waitfor_upcall(vcp, req);
 763
 764        /* Op went through, interrupt or not... */
 765        if (req->uc_flags & CODA_REQ_WRITE) {
 766                out = (union outputArgs *)req->uc_data;
 767                /* here we map positive Venus errors to kernel errors */
 768                error = -out->oh.result;
 769                *outSize = req->uc_outSize;
 770                goto exit;
 771        }
 772
 773        error = -EINTR;
 774        if ((req->uc_flags & CODA_REQ_ABORT) || !signal_pending(current)) {
 775                pr_warn("Unexpected interruption.\n");
 776                goto exit;
 777        }
 778
 779        /* Interrupted before venus read it. */
 780        if (!(req->uc_flags & CODA_REQ_READ))
 781                goto exit;
 782
 783        /* Venus saw the upcall, make sure we can send interrupt signal */
 784        if (!vcp->vc_inuse) {
 785                pr_info("Venus dead, not sending signal.\n");
 786                goto exit;
 787        }
 788
 789        error = -ENOMEM;
 790        sig_req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
 791        if (!sig_req) goto exit;
 792
 793        sig_inputArgs = kvzalloc(sizeof(struct coda_in_hdr), GFP_KERNEL);
 794        if (!sig_inputArgs) {
 795                kfree(sig_req);
 796                goto exit;
 797        }
 798
 799        error = -EINTR;
 800        sig_inputArgs->ih.opcode = CODA_SIGNAL;
 801        sig_inputArgs->ih.unique = req->uc_unique;
 802
 803        sig_req->uc_flags = CODA_REQ_ASYNC;
 804        sig_req->uc_opcode = sig_inputArgs->ih.opcode;
 805        sig_req->uc_unique = sig_inputArgs->ih.unique;
 806        sig_req->uc_data = (void *)sig_inputArgs;
 807        sig_req->uc_inSize = sizeof(struct coda_in_hdr);
 808        sig_req->uc_outSize = sizeof(struct coda_in_hdr);
 809
 810        /* insert at head of queue! */
 811        list_add(&(sig_req->uc_chain), &vcp->vc_pending);
 812        wake_up_interruptible(&vcp->vc_waitq);
 813
 814exit:
 815        kfree(req);
 816        mutex_unlock(&vcp->vc_mutex);
 817        return error;
 818}
 819
 820/*  
 821    The statements below are part of the Coda opportunistic
 822    programming -- taken from the Mach/BSD kernel code for Coda. 
 823    You don't get correct semantics by stating what needs to be
 824    done without guaranteeing the invariants needed for it to happen.
 825    When will be have time to find out what exactly is going on?  (pjb)
 826*/
 827
 828
 829/* 
 830 * There are 7 cases where cache invalidations occur.  The semantics
 831 *  of each is listed here:
 832 *
 833 * CODA_FLUSH     -- flush all entries from the name cache and the cnode cache.
 834 * CODA_PURGEUSER -- flush all entries from the name cache for a specific user
 835 *                  This call is a result of token expiration.
 836 *
 837 * The next arise as the result of callbacks on a file or directory.
 838 * CODA_ZAPFILE   -- flush the cached attributes for a file.
 839
 840 * CODA_ZAPDIR    -- flush the attributes for the dir and
 841 *                  force a new lookup for all the children
 842                    of this dir.
 843
 844 *
 845 * The next is a result of Venus detecting an inconsistent file.
 846 * CODA_PURGEFID  -- flush the attribute for the file
 847 *                  purge it and its children from the dcache
 848 *
 849 * The last  allows Venus to replace local fids with global ones
 850 * during reintegration.
 851 *
 852 * CODA_REPLACE -- replace one CodaFid with another throughout the name cache */
 853
 854int coda_downcall(struct venus_comm *vcp, int opcode, union outputArgs *out,
 855                  size_t nbytes)
 856{
 857        struct inode *inode = NULL;
 858        struct CodaFid *fid = NULL, *newfid;
 859        struct super_block *sb;
 860
 861        /*
 862         * Make sure we have received enough data from the cache
 863         * manager to populate the necessary fields in the buffer
 864         */
 865        switch (opcode) {
 866        case CODA_PURGEUSER:
 867                if (nbytes < sizeof(struct coda_purgeuser_out))
 868                        return -EINVAL;
 869                break;
 870
 871        case CODA_ZAPDIR:
 872                if (nbytes < sizeof(struct coda_zapdir_out))
 873                        return -EINVAL;
 874                break;
 875
 876        case CODA_ZAPFILE:
 877                if (nbytes < sizeof(struct coda_zapfile_out))
 878                        return -EINVAL;
 879                break;
 880
 881        case CODA_PURGEFID:
 882                if (nbytes < sizeof(struct coda_purgefid_out))
 883                        return -EINVAL;
 884                break;
 885
 886        case CODA_REPLACE:
 887                if (nbytes < sizeof(struct coda_replace_out))
 888                        return -EINVAL;
 889                break;
 890        }
 891
 892        /* Handle invalidation requests. */
 893        mutex_lock(&vcp->vc_mutex);
 894        sb = vcp->vc_sb;
 895        if (!sb || !sb->s_root)
 896                goto unlock_out;
 897
 898        switch (opcode) {
 899        case CODA_FLUSH:
 900                coda_cache_clear_all(sb);
 901                shrink_dcache_sb(sb);
 902                if (d_really_is_positive(sb->s_root))
 903                        coda_flag_inode(d_inode(sb->s_root), C_FLUSH);
 904                break;
 905
 906        case CODA_PURGEUSER:
 907                coda_cache_clear_all(sb);
 908                break;
 909
 910        case CODA_ZAPDIR:
 911                fid = &out->coda_zapdir.CodaFid;
 912                break;
 913
 914        case CODA_ZAPFILE:
 915                fid = &out->coda_zapfile.CodaFid;
 916                break;
 917
 918        case CODA_PURGEFID:
 919                fid = &out->coda_purgefid.CodaFid;
 920                break;
 921
 922        case CODA_REPLACE:
 923                fid = &out->coda_replace.OldFid;
 924                break;
 925        }
 926        if (fid)
 927                inode = coda_fid_to_inode(fid, sb);
 928
 929unlock_out:
 930        mutex_unlock(&vcp->vc_mutex);
 931
 932        if (!inode)
 933                return 0;
 934
 935        switch (opcode) {
 936        case CODA_ZAPDIR:
 937                coda_flag_inode_children(inode, C_PURGE);
 938                coda_flag_inode(inode, C_VATTR);
 939                break;
 940
 941        case CODA_ZAPFILE:
 942                coda_flag_inode(inode, C_VATTR);
 943                break;
 944
 945        case CODA_PURGEFID:
 946                coda_flag_inode_children(inode, C_PURGE);
 947
 948                /* catch the dentries later if some are still busy */
 949                coda_flag_inode(inode, C_PURGE);
 950                d_prune_aliases(inode);
 951                break;
 952
 953        case CODA_REPLACE:
 954                newfid = &out->coda_replace.NewFid;
 955                coda_replace_fid(inode, fid, newfid);
 956                break;
 957        }
 958        iput(inode);
 959        return 0;
 960}
 961