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 <linux/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        CODA_ALLOC(inp, union inputArgs *, size);
  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        CODA_FREE(inp, insize);
  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        CODA_FREE(inp, insize);
 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        CODA_FREE(inp, insize);
 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        CODA_FREE(inp, insize);
 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        CODA_FREE(inp, insize);
 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        CODA_FREE(inp, insize);
 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        CODA_FREE(inp, insize);
 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        CODA_FREE(inp, insize);
 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        CODA_FREE(inp, insize);
 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        CODA_FREE(inp, insize);
 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        CODA_FREE(inp, insize);
 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        CODA_FREE(inp, insize);
 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        CODA_FREE(inp, insize);
 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        CODA_FREE(inp, insize);
 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        CODA_FREE(inp, insize);
 453        return error;
 454}
 455
 456int venus_access(struct super_block *sb, struct CodaFid *fid, int mask)
 457{
 458        union inputArgs *inp;
 459        union outputArgs *outp; 
 460        int insize, outsize, error;
 461
 462        insize = SIZE(access);
 463        UPARG(CODA_ACCESS);
 464
 465        inp->coda_access.VFid = *fid;
 466        inp->coda_access.flags = mask;
 467
 468        error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 469
 470        CODA_FREE(inp, insize);
 471        return error;
 472}
 473
 474
 475int venus_pioctl(struct super_block *sb, struct CodaFid *fid,
 476                 unsigned int cmd, struct PioctlData *data)
 477{
 478        union inputArgs *inp;
 479        union outputArgs *outp;  
 480        int insize, outsize, error;
 481        int iocsize;
 482
 483        insize = VC_MAXMSGSIZE;
 484        UPARG(CODA_IOCTL);
 485
 486        /* build packet for Venus */
 487        if (data->vi.in_size > VC_MAXDATASIZE) {
 488                error = -EINVAL;
 489                goto exit;
 490        }
 491
 492        if (data->vi.out_size > VC_MAXDATASIZE) {
 493                error = -EINVAL;
 494                goto exit;
 495        }
 496
 497        inp->coda_ioctl.VFid = *fid;
 498    
 499        /* the cmd field was mutated by increasing its size field to
 500         * reflect the path and follow args. We need to subtract that
 501         * out before sending the command to Venus.  */
 502        inp->coda_ioctl.cmd = (cmd & ~(PIOCPARM_MASK << 16));   
 503        iocsize = ((cmd >> 16) & PIOCPARM_MASK) - sizeof(char *) - sizeof(int);
 504        inp->coda_ioctl.cmd |= (iocsize & PIOCPARM_MASK) <<     16;     
 505    
 506        /* in->coda_ioctl.rwflag = flag; */
 507        inp->coda_ioctl.len = data->vi.in_size;
 508        inp->coda_ioctl.data = (char *)(INSIZE(ioctl));
 509     
 510        /* get the data out of user space */
 511        if (copy_from_user((char *)inp + (long)inp->coda_ioctl.data,
 512                           data->vi.in, data->vi.in_size)) {
 513                error = -EINVAL;
 514                goto exit;
 515        }
 516
 517        error = coda_upcall(coda_vcp(sb), SIZE(ioctl) + data->vi.in_size,
 518                            &outsize, inp);
 519
 520        if (error) {
 521                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        CODA_FREE(inp, insize);
 547        return error;
 548}
 549
 550int venus_statfs(struct dentry *dentry, struct kstatfs *sfs)
 551{ 
 552        union inputArgs *inp;
 553        union outputArgs *outp;
 554        int insize, outsize, error;
 555        
 556        insize = max_t(unsigned int, INSIZE(statfs), OUTSIZE(statfs));
 557        UPARG(CODA_STATFS);
 558
 559        error = coda_upcall(coda_vcp(dentry->d_sb), insize, &outsize, inp);
 560        if (!error) {
 561                sfs->f_blocks = outp->coda_statfs.stat.f_blocks;
 562                sfs->f_bfree  = outp->coda_statfs.stat.f_bfree;
 563                sfs->f_bavail = outp->coda_statfs.stat.f_bavail;
 564                sfs->f_files  = outp->coda_statfs.stat.f_files;
 565                sfs->f_ffree  = outp->coda_statfs.stat.f_ffree;
 566        }
 567
 568        CODA_FREE(inp, insize);
 569        return error;
 570}
 571
 572/*
 573 * coda_upcall and coda_downcall routines.
 574 */
 575static void coda_block_signals(sigset_t *old)
 576{
 577        spin_lock_irq(&current->sighand->siglock);
 578        *old = current->blocked;
 579
 580        sigfillset(&current->blocked);
 581        sigdelset(&current->blocked, SIGKILL);
 582        sigdelset(&current->blocked, SIGSTOP);
 583        sigdelset(&current->blocked, SIGINT);
 584
 585        recalc_sigpending();
 586        spin_unlock_irq(&current->sighand->siglock);
 587}
 588
 589static void coda_unblock_signals(sigset_t *old)
 590{
 591        spin_lock_irq(&current->sighand->siglock);
 592        current->blocked = *old;
 593        recalc_sigpending();
 594        spin_unlock_irq(&current->sighand->siglock);
 595}
 596
 597/* Don't allow signals to interrupt the following upcalls before venus
 598 * has seen them,
 599 * - CODA_CLOSE or CODA_RELEASE upcall  (to avoid reference count problems)
 600 * - CODA_STORE                         (to avoid data loss)
 601 */
 602#define CODA_INTERRUPTIBLE(r) (!coda_hard && \
 603                               (((r)->uc_opcode != CODA_CLOSE && \
 604                                 (r)->uc_opcode != CODA_STORE && \
 605                                 (r)->uc_opcode != CODA_RELEASE) || \
 606                                (r)->uc_flags & CODA_REQ_READ))
 607
 608static inline void coda_waitfor_upcall(struct venus_comm *vcp,
 609                                       struct upc_req *req)
 610{
 611        DECLARE_WAITQUEUE(wait, current);
 612        unsigned long timeout = jiffies + coda_timeout * HZ;
 613        sigset_t old;
 614        int blocked;
 615
 616        coda_block_signals(&old);
 617        blocked = 1;
 618
 619        add_wait_queue(&req->uc_sleep, &wait);
 620        for (;;) {
 621                if (CODA_INTERRUPTIBLE(req))
 622                        set_current_state(TASK_INTERRUPTIBLE);
 623                else
 624                        set_current_state(TASK_UNINTERRUPTIBLE);
 625
 626                /* got a reply */
 627                if (req->uc_flags & (CODA_REQ_WRITE | CODA_REQ_ABORT))
 628                        break;
 629
 630                if (blocked && time_after(jiffies, timeout) &&
 631                    CODA_INTERRUPTIBLE(req))
 632                {
 633                        coda_unblock_signals(&old);
 634                        blocked = 0;
 635                }
 636
 637                if (signal_pending(current)) {
 638                        list_del(&req->uc_chain);
 639                        break;
 640                }
 641
 642                mutex_unlock(&vcp->vc_mutex);
 643                if (blocked)
 644                        schedule_timeout(HZ);
 645                else
 646                        schedule();
 647                mutex_lock(&vcp->vc_mutex);
 648        }
 649        if (blocked)
 650                coda_unblock_signals(&old);
 651
 652        remove_wait_queue(&req->uc_sleep, &wait);
 653        set_current_state(TASK_RUNNING);
 654}
 655
 656
 657/*
 658 * coda_upcall will return an error in the case of
 659 * failed communication with Venus _or_ will peek at Venus
 660 * reply and return Venus' error.
 661 *
 662 * As venus has 2 types of errors, normal errors (positive) and internal
 663 * errors (negative), normal errors are negated, while internal errors
 664 * are all mapped to -EINTR, while showing a nice warning message. (jh)
 665 */
 666static int coda_upcall(struct venus_comm *vcp,
 667                       int inSize, int *outSize,
 668                       union inputArgs *buffer)
 669{
 670        union outputArgs *out;
 671        union inputArgs *sig_inputArgs;
 672        struct upc_req *req = NULL, *sig_req;
 673        int error;
 674
 675        mutex_lock(&vcp->vc_mutex);
 676
 677        if (!vcp->vc_inuse) {
 678                pr_notice("Venus dead, not sending upcall\n");
 679                error = -ENXIO;
 680                goto exit;
 681        }
 682
 683        /* Format the request message. */
 684        req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
 685        if (!req) {
 686                error = -ENOMEM;
 687                goto exit;
 688        }
 689
 690        req->uc_data = (void *)buffer;
 691        req->uc_flags = 0;
 692        req->uc_inSize = inSize;
 693        req->uc_outSize = *outSize ? *outSize : inSize;
 694        req->uc_opcode = ((union inputArgs *)buffer)->ih.opcode;
 695        req->uc_unique = ++vcp->vc_seq;
 696        init_waitqueue_head(&req->uc_sleep);
 697
 698        /* Fill in the common input args. */
 699        ((union inputArgs *)buffer)->ih.unique = req->uc_unique;
 700
 701        /* Append msg to pending queue and poke Venus. */
 702        list_add_tail(&req->uc_chain, &vcp->vc_pending);
 703
 704        wake_up_interruptible(&vcp->vc_waitq);
 705        /* We can be interrupted while we wait for Venus to process
 706         * our request.  If the interrupt occurs before Venus has read
 707         * the request, we dequeue and return. If it occurs after the
 708         * read but before the reply, we dequeue, send a signal
 709         * message, and return. If it occurs after the reply we ignore
 710         * it. In no case do we want to restart the syscall.  If it
 711         * was interrupted by a venus shutdown (psdev_close), return
 712         * ENODEV.  */
 713
 714        /* Go to sleep.  Wake up on signals only after the timeout. */
 715        coda_waitfor_upcall(vcp, req);
 716
 717        /* Op went through, interrupt or not... */
 718        if (req->uc_flags & CODA_REQ_WRITE) {
 719                out = (union outputArgs *)req->uc_data;
 720                /* here we map positive Venus errors to kernel errors */
 721                error = -out->oh.result;
 722                *outSize = req->uc_outSize;
 723                goto exit;
 724        }
 725
 726        error = -EINTR;
 727        if ((req->uc_flags & CODA_REQ_ABORT) || !signal_pending(current)) {
 728                pr_warn("Unexpected interruption.\n");
 729                goto exit;
 730        }
 731
 732        /* Interrupted before venus read it. */
 733        if (!(req->uc_flags & CODA_REQ_READ))
 734                goto exit;
 735
 736        /* Venus saw the upcall, make sure we can send interrupt signal */
 737        if (!vcp->vc_inuse) {
 738                pr_info("Venus dead, not sending signal.\n");
 739                goto exit;
 740        }
 741
 742        error = -ENOMEM;
 743        sig_req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
 744        if (!sig_req) goto exit;
 745
 746        CODA_ALLOC((sig_req->uc_data), char *, sizeof(struct coda_in_hdr));
 747        if (!sig_req->uc_data) {
 748                kfree(sig_req);
 749                goto exit;
 750        }
 751
 752        error = -EINTR;
 753        sig_inputArgs = (union inputArgs *)sig_req->uc_data;
 754        sig_inputArgs->ih.opcode = CODA_SIGNAL;
 755        sig_inputArgs->ih.unique = req->uc_unique;
 756
 757        sig_req->uc_flags = CODA_REQ_ASYNC;
 758        sig_req->uc_opcode = sig_inputArgs->ih.opcode;
 759        sig_req->uc_unique = sig_inputArgs->ih.unique;
 760        sig_req->uc_inSize = sizeof(struct coda_in_hdr);
 761        sig_req->uc_outSize = sizeof(struct coda_in_hdr);
 762
 763        /* insert at head of queue! */
 764        list_add(&(sig_req->uc_chain), &vcp->vc_pending);
 765        wake_up_interruptible(&vcp->vc_waitq);
 766
 767exit:
 768        kfree(req);
 769        mutex_unlock(&vcp->vc_mutex);
 770        return error;
 771}
 772
 773/*  
 774    The statements below are part of the Coda opportunistic
 775    programming -- taken from the Mach/BSD kernel code for Coda. 
 776    You don't get correct semantics by stating what needs to be
 777    done without guaranteeing the invariants needed for it to happen.
 778    When will be have time to find out what exactly is going on?  (pjb)
 779*/
 780
 781
 782/* 
 783 * There are 7 cases where cache invalidations occur.  The semantics
 784 *  of each is listed here:
 785 *
 786 * CODA_FLUSH     -- flush all entries from the name cache and the cnode cache.
 787 * CODA_PURGEUSER -- flush all entries from the name cache for a specific user
 788 *                  This call is a result of token expiration.
 789 *
 790 * The next arise as the result of callbacks on a file or directory.
 791 * CODA_ZAPFILE   -- flush the cached attributes for a file.
 792
 793 * CODA_ZAPDIR    -- flush the attributes for the dir and
 794 *                  force a new lookup for all the children
 795                    of this dir.
 796
 797 *
 798 * The next is a result of Venus detecting an inconsistent file.
 799 * CODA_PURGEFID  -- flush the attribute for the file
 800 *                  purge it and its children from the dcache
 801 *
 802 * The last  allows Venus to replace local fids with global ones
 803 * during reintegration.
 804 *
 805 * CODA_REPLACE -- replace one CodaFid with another throughout the name cache */
 806
 807int coda_downcall(struct venus_comm *vcp, int opcode, union outputArgs *out)
 808{
 809        struct inode *inode = NULL;
 810        struct CodaFid *fid = NULL, *newfid;
 811        struct super_block *sb;
 812
 813        /* Handle invalidation requests. */
 814        mutex_lock(&vcp->vc_mutex);
 815        sb = vcp->vc_sb;
 816        if (!sb || !sb->s_root)
 817                goto unlock_out;
 818
 819        switch (opcode) {
 820        case CODA_FLUSH:
 821                coda_cache_clear_all(sb);
 822                shrink_dcache_sb(sb);
 823                if (d_really_is_positive(sb->s_root))
 824                        coda_flag_inode(d_inode(sb->s_root), C_FLUSH);
 825                break;
 826
 827        case CODA_PURGEUSER:
 828                coda_cache_clear_all(sb);
 829                break;
 830
 831        case CODA_ZAPDIR:
 832                fid = &out->coda_zapdir.CodaFid;
 833                break;
 834
 835        case CODA_ZAPFILE:
 836                fid = &out->coda_zapfile.CodaFid;
 837                break;
 838
 839        case CODA_PURGEFID:
 840                fid = &out->coda_purgefid.CodaFid;
 841                break;
 842
 843        case CODA_REPLACE:
 844                fid = &out->coda_replace.OldFid;
 845                break;
 846        }
 847        if (fid)
 848                inode = coda_fid_to_inode(fid, sb);
 849
 850unlock_out:
 851        mutex_unlock(&vcp->vc_mutex);
 852
 853        if (!inode)
 854                return 0;
 855
 856        switch (opcode) {
 857        case CODA_ZAPDIR:
 858                coda_flag_inode_children(inode, C_PURGE);
 859                coda_flag_inode(inode, C_VATTR);
 860                break;
 861
 862        case CODA_ZAPFILE:
 863                coda_flag_inode(inode, C_VATTR);
 864                break;
 865
 866        case CODA_PURGEFID:
 867                coda_flag_inode_children(inode, C_PURGE);
 868
 869                /* catch the dentries later if some are still busy */
 870                coda_flag_inode(inode, C_PURGE);
 871                d_prune_aliases(inode);
 872                break;
 873
 874        case CODA_REPLACE:
 875                newfid = &out->coda_replace.NewFid;
 876                coda_replace_fid(inode, fid, newfid);
 877                break;
 878        }
 879        iput(inode);
 880        return 0;
 881}
 882
 883