The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/coda/upcall.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 1d918b9ffc8acc5ad714b9e9d88449c0


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.