Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Mostly platform independent upcall operations to Venus:
0004  *  -- upcalls
0005  *  -- upcall routines
0006  *
0007  * Linux 2.0 version
0008  * Copyright (C) 1996 Peter J. Braam <braam@maths.ox.ac.uk>, 
0009  * Michael Callahan <callahan@maths.ox.ac.uk> 
0010  * 
0011  * Redone for Linux 2.1
0012  * Copyright (C) 1997 Carnegie Mellon University
0013  *
0014  * Carnegie Mellon University encourages users of this code to contribute
0015  * improvements to the Coda project. Contact Peter Braam <coda@cs.cmu.edu>.
0016  */
0017 
0018 #include <linux/signal.h>
0019 #include <linux/sched/signal.h>
0020 #include <linux/types.h>
0021 #include <linux/kernel.h>
0022 #include <linux/mm.h>
0023 #include <linux/time.h>
0024 #include <linux/fs.h>
0025 #include <linux/file.h>
0026 #include <linux/stat.h>
0027 #include <linux/errno.h>
0028 #include <linux/string.h>
0029 #include <linux/slab.h>
0030 #include <linux/mutex.h>
0031 #include <linux/uaccess.h>
0032 #include <linux/vmalloc.h>
0033 #include <linux/vfs.h>
0034 
0035 #include <linux/coda.h>
0036 #include "coda_psdev.h"
0037 #include "coda_linux.h"
0038 #include "coda_cache.h"
0039 
0040 #include "coda_int.h"
0041 
0042 static int coda_upcall(struct venus_comm *vc, int inSize, int *outSize,
0043                union inputArgs *buffer);
0044 
0045 static void *alloc_upcall(int opcode, int size)
0046 {
0047     union inputArgs *inp;
0048 
0049     inp = kvzalloc(size, GFP_KERNEL);
0050         if (!inp)
0051         return ERR_PTR(-ENOMEM);
0052 
0053         inp->ih.opcode = opcode;
0054     inp->ih.pid = task_pid_nr_ns(current, &init_pid_ns);
0055     inp->ih.pgid = task_pgrp_nr_ns(current, &init_pid_ns);
0056     inp->ih.uid = from_kuid(&init_user_ns, current_fsuid());
0057 
0058     return (void*)inp;
0059 }
0060 
0061 #define UPARG(op)\
0062 do {\
0063     inp = (union inputArgs *)alloc_upcall(op, insize); \
0064         if (IS_ERR(inp)) { return PTR_ERR(inp); }\
0065         outp = (union outputArgs *)(inp); \
0066         outsize = insize; \
0067 } while (0)
0068 
0069 #define INSIZE(tag) sizeof(struct coda_ ## tag ## _in)
0070 #define OUTSIZE(tag) sizeof(struct coda_ ## tag ## _out)
0071 #define SIZE(tag)  max_t(unsigned int, INSIZE(tag), OUTSIZE(tag))
0072 
0073 
0074 /* the upcalls */
0075 int venus_rootfid(struct super_block *sb, struct CodaFid *fidp)
0076 {
0077         union inputArgs *inp;
0078         union outputArgs *outp;
0079         int insize, outsize, error;
0080 
0081         insize = SIZE(root);
0082         UPARG(CODA_ROOT);
0083 
0084     error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
0085     if (!error)
0086         *fidp = outp->coda_root.VFid;
0087 
0088     kvfree(inp);
0089     return error;
0090 }
0091 
0092 int venus_getattr(struct super_block *sb, struct CodaFid *fid, 
0093              struct coda_vattr *attr) 
0094 {
0095         union inputArgs *inp;
0096         union outputArgs *outp;
0097         int insize, outsize, error;
0098 
0099         insize = SIZE(getattr); 
0100     UPARG(CODA_GETATTR);
0101         inp->coda_getattr.VFid = *fid;
0102 
0103     error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
0104     if (!error)
0105         *attr = outp->coda_getattr.attr;
0106 
0107     kvfree(inp);
0108         return error;
0109 }
0110 
0111 int venus_setattr(struct super_block *sb, struct CodaFid *fid, 
0112           struct coda_vattr *vattr)
0113 {
0114         union inputArgs *inp;
0115         union outputArgs *outp;
0116         int insize, outsize, error;
0117     
0118     insize = SIZE(setattr);
0119     UPARG(CODA_SETATTR);
0120 
0121         inp->coda_setattr.VFid = *fid;
0122     inp->coda_setattr.attr = *vattr;
0123 
0124     error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
0125 
0126     kvfree(inp);
0127         return error;
0128 }
0129 
0130 int venus_lookup(struct super_block *sb, struct CodaFid *fid, 
0131             const char *name, int length, int * type, 
0132             struct CodaFid *resfid)
0133 {
0134         union inputArgs *inp;
0135         union outputArgs *outp;
0136         int insize, outsize, error;
0137     int offset;
0138 
0139     offset = INSIZE(lookup);
0140         insize = max_t(unsigned int, offset + length +1, OUTSIZE(lookup));
0141     UPARG(CODA_LOOKUP);
0142 
0143         inp->coda_lookup.VFid = *fid;
0144     inp->coda_lookup.name = offset;
0145     inp->coda_lookup.flags = CLU_CASE_SENSITIVE;
0146         /* send Venus a null terminated string */
0147         memcpy((char *)(inp) + offset, name, length);
0148         *((char *)inp + offset + length) = '\0';
0149 
0150     error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
0151     if (!error) {
0152         *resfid = outp->coda_lookup.VFid;
0153         *type = outp->coda_lookup.vtype;
0154     }
0155 
0156     kvfree(inp);
0157     return error;
0158 }
0159 
0160 int venus_close(struct super_block *sb, struct CodaFid *fid, int flags,
0161         kuid_t uid)
0162 {
0163     union inputArgs *inp;
0164     union outputArgs *outp;
0165     int insize, outsize, error;
0166     
0167     insize = SIZE(release);
0168     UPARG(CODA_CLOSE);
0169     
0170     inp->ih.uid = from_kuid(&init_user_ns, uid);
0171         inp->coda_close.VFid = *fid;
0172         inp->coda_close.flags = flags;
0173 
0174     error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
0175 
0176     kvfree(inp);
0177         return error;
0178 }
0179 
0180 int venus_open(struct super_block *sb, struct CodaFid *fid,
0181           int flags, struct file **fh)
0182 {
0183         union inputArgs *inp;
0184         union outputArgs *outp;
0185         int insize, outsize, error;
0186        
0187     insize = SIZE(open_by_fd);
0188     UPARG(CODA_OPEN_BY_FD);
0189 
0190     inp->coda_open_by_fd.VFid = *fid;
0191     inp->coda_open_by_fd.flags = flags;
0192 
0193     error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
0194     if (!error)
0195         *fh = outp->coda_open_by_fd.fh;
0196 
0197     kvfree(inp);
0198     return error;
0199 }   
0200 
0201 int venus_mkdir(struct super_block *sb, struct CodaFid *dirfid, 
0202            const char *name, int length, 
0203            struct CodaFid *newfid, struct coda_vattr *attrs)
0204 {
0205         union inputArgs *inp;
0206         union outputArgs *outp;
0207         int insize, outsize, error;
0208         int offset;
0209 
0210     offset = INSIZE(mkdir);
0211     insize = max_t(unsigned int, offset + length + 1, OUTSIZE(mkdir));
0212     UPARG(CODA_MKDIR);
0213 
0214         inp->coda_mkdir.VFid = *dirfid;
0215         inp->coda_mkdir.attr = *attrs;
0216     inp->coda_mkdir.name = offset;
0217         /* Venus must get null terminated string */
0218         memcpy((char *)(inp) + offset, name, length);
0219         *((char *)inp + offset + length) = '\0';
0220 
0221     error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
0222     if (!error) {
0223         *attrs = outp->coda_mkdir.attr;
0224         *newfid = outp->coda_mkdir.VFid;
0225     }
0226 
0227     kvfree(inp);
0228     return error;        
0229 }
0230 
0231 
0232 int venus_rename(struct super_block *sb, struct CodaFid *old_fid, 
0233          struct CodaFid *new_fid, size_t old_length, 
0234          size_t new_length, const char *old_name, 
0235          const char *new_name)
0236 {
0237     union inputArgs *inp;
0238         union outputArgs *outp;
0239         int insize, outsize, error; 
0240     int offset, s;
0241     
0242     offset = INSIZE(rename);
0243     insize = max_t(unsigned int, offset + new_length + old_length + 8,
0244              OUTSIZE(rename)); 
0245     UPARG(CODA_RENAME);
0246 
0247         inp->coda_rename.sourceFid = *old_fid;
0248         inp->coda_rename.destFid =  *new_fid;
0249         inp->coda_rename.srcname = offset;
0250 
0251         /* Venus must receive an null terminated string */
0252         s = ( old_length & ~0x3) +4; /* round up to word boundary */
0253         memcpy((char *)(inp) + offset, old_name, old_length);
0254         *((char *)inp + offset + old_length) = '\0';
0255 
0256         /* another null terminated string for Venus */
0257         offset += s;
0258         inp->coda_rename.destname = offset;
0259         s = ( new_length & ~0x3) +4; /* round up to word boundary */
0260         memcpy((char *)(inp) + offset, new_name, new_length);
0261         *((char *)inp + offset + new_length) = '\0';
0262 
0263     error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
0264 
0265     kvfree(inp);
0266     return error;
0267 }
0268 
0269 int venus_create(struct super_block *sb, struct CodaFid *dirfid, 
0270          const char *name, int length, int excl, int mode,
0271          struct CodaFid *newfid, struct coda_vattr *attrs) 
0272 {
0273         union inputArgs *inp;
0274         union outputArgs *outp;
0275         int insize, outsize, error;
0276         int offset;
0277 
0278         offset = INSIZE(create);
0279     insize = max_t(unsigned int, offset + length + 1, OUTSIZE(create));
0280     UPARG(CODA_CREATE);
0281 
0282         inp->coda_create.VFid = *dirfid;
0283         inp->coda_create.attr.va_mode = mode;
0284     inp->coda_create.excl = excl;
0285         inp->coda_create.mode = mode;
0286         inp->coda_create.name = offset;
0287 
0288         /* Venus must get null terminated string */
0289         memcpy((char *)(inp) + offset, name, length);
0290         *((char *)inp + offset + length) = '\0';
0291 
0292     error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
0293     if (!error) {
0294         *attrs = outp->coda_create.attr;
0295         *newfid = outp->coda_create.VFid;
0296     }
0297 
0298     kvfree(inp);
0299     return error;        
0300 }
0301 
0302 int venus_rmdir(struct super_block *sb, struct CodaFid *dirfid, 
0303             const char *name, int length)
0304 {
0305         union inputArgs *inp;
0306         union outputArgs *outp;
0307         int insize, outsize, error;
0308         int offset;
0309 
0310         offset = INSIZE(rmdir);
0311     insize = max_t(unsigned int, offset + length + 1, OUTSIZE(rmdir));
0312     UPARG(CODA_RMDIR);
0313 
0314         inp->coda_rmdir.VFid = *dirfid;
0315         inp->coda_rmdir.name = offset;
0316         memcpy((char *)(inp) + offset, name, length);
0317     *((char *)inp + offset + length) = '\0';
0318 
0319     error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
0320 
0321     kvfree(inp);
0322     return error;
0323 }
0324 
0325 int venus_remove(struct super_block *sb, struct CodaFid *dirfid, 
0326             const char *name, int length)
0327 {
0328         union inputArgs *inp;
0329         union outputArgs *outp;
0330         int error=0, insize, outsize, offset;
0331 
0332         offset = INSIZE(remove);
0333     insize = max_t(unsigned int, offset + length + 1, OUTSIZE(remove));
0334     UPARG(CODA_REMOVE);
0335 
0336         inp->coda_remove.VFid = *dirfid;
0337         inp->coda_remove.name = offset;
0338         memcpy((char *)(inp) + offset, name, length);
0339     *((char *)inp + offset + length) = '\0';
0340 
0341     error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
0342 
0343     kvfree(inp);
0344     return error;
0345 }
0346 
0347 int venus_readlink(struct super_block *sb, struct CodaFid *fid, 
0348               char *buffer, int *length)
0349 { 
0350         union inputArgs *inp;
0351         union outputArgs *outp;
0352         int insize, outsize, error;
0353         int retlen;
0354         char *result;
0355         
0356     insize = max_t(unsigned int,
0357              INSIZE(readlink), OUTSIZE(readlink)+ *length);
0358     UPARG(CODA_READLINK);
0359 
0360         inp->coda_readlink.VFid = *fid;
0361 
0362     error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
0363     if (!error) {
0364         retlen = outp->coda_readlink.count;
0365         if (retlen >= *length)
0366             retlen = *length - 1;
0367         *length = retlen;
0368         result =  (char *)outp + (long)outp->coda_readlink.data;
0369         memcpy(buffer, result, retlen);
0370         *(buffer + retlen) = '\0';
0371     }
0372 
0373     kvfree(inp);
0374         return error;
0375 }
0376 
0377 
0378 
0379 int venus_link(struct super_block *sb, struct CodaFid *fid, 
0380           struct CodaFid *dirfid, const char *name, int len )
0381 {
0382         union inputArgs *inp;
0383         union outputArgs *outp;
0384         int insize, outsize, error;
0385         int offset;
0386 
0387     offset = INSIZE(link);
0388     insize = max_t(unsigned int, offset  + len + 1, OUTSIZE(link));
0389         UPARG(CODA_LINK);
0390 
0391         inp->coda_link.sourceFid = *fid;
0392         inp->coda_link.destFid = *dirfid;
0393         inp->coda_link.tname = offset;
0394 
0395         /* make sure strings are null terminated */
0396         memcpy((char *)(inp) + offset, name, len);
0397         *((char *)inp + offset + len) = '\0';
0398 
0399     error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
0400 
0401     kvfree(inp);
0402         return error;
0403 }
0404 
0405 int venus_symlink(struct super_block *sb, struct CodaFid *fid,
0406              const char *name, int len,
0407              const char *symname, int symlen)
0408 {
0409         union inputArgs *inp;
0410         union outputArgs *outp;
0411         int insize, outsize, error;
0412         int offset, s;
0413 
0414         offset = INSIZE(symlink);
0415     insize = max_t(unsigned int, offset + len + symlen + 8, OUTSIZE(symlink));
0416     UPARG(CODA_SYMLINK);
0417         
0418         /*        inp->coda_symlink.attr = *tva; XXXXXX */ 
0419         inp->coda_symlink.VFid = *fid;
0420 
0421     /* Round up to word boundary and null terminate */
0422         inp->coda_symlink.srcname = offset;
0423         s = ( symlen  & ~0x3 ) + 4; 
0424         memcpy((char *)(inp) + offset, symname, symlen);
0425         *((char *)inp + offset + symlen) = '\0';
0426         
0427     /* Round up to word boundary and null terminate */
0428         offset += s;
0429         inp->coda_symlink.tname = offset;
0430         s = (len & ~0x3) + 4;
0431         memcpy((char *)(inp) + offset, name, len);
0432         *((char *)inp + offset + len) = '\0';
0433 
0434     error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
0435 
0436     kvfree(inp);
0437         return error;
0438 }
0439 
0440 int venus_fsync(struct super_block *sb, struct CodaFid *fid)
0441 {
0442         union inputArgs *inp;
0443         union outputArgs *outp; 
0444     int insize, outsize, error;
0445     
0446     insize=SIZE(fsync);
0447     UPARG(CODA_FSYNC);
0448 
0449     inp->coda_fsync.VFid = *fid;
0450     error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
0451 
0452     kvfree(inp);
0453     return error;
0454 }
0455 
0456 int venus_access(struct super_block *sb, struct CodaFid *fid, int mask)
0457 {
0458         union inputArgs *inp;
0459         union outputArgs *outp; 
0460     int insize, outsize, error;
0461 
0462     insize = SIZE(access);
0463     UPARG(CODA_ACCESS);
0464 
0465         inp->coda_access.VFid = *fid;
0466         inp->coda_access.flags = mask;
0467 
0468     error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
0469 
0470     kvfree(inp);
0471     return error;
0472 }
0473 
0474 
0475 int venus_pioctl(struct super_block *sb, struct CodaFid *fid,
0476          unsigned int cmd, struct PioctlData *data)
0477 {
0478         union inputArgs *inp;
0479         union outputArgs *outp;  
0480     int insize, outsize, error;
0481     int iocsize;
0482 
0483     insize = VC_MAXMSGSIZE;
0484     UPARG(CODA_IOCTL);
0485 
0486         /* build packet for Venus */
0487         if (data->vi.in_size > VC_MAXDATASIZE) {
0488         error = -EINVAL;
0489         goto exit;
0490         }
0491 
0492         if (data->vi.out_size > VC_MAXDATASIZE) {
0493         error = -EINVAL;
0494         goto exit;
0495     }
0496 
0497         inp->coda_ioctl.VFid = *fid;
0498     
0499         /* the cmd field was mutated by increasing its size field to
0500          * reflect the path and follow args. We need to subtract that
0501          * out before sending the command to Venus.  */
0502         inp->coda_ioctl.cmd = (cmd & ~(PIOCPARM_MASK << 16));   
0503         iocsize = ((cmd >> 16) & PIOCPARM_MASK) - sizeof(char *) - sizeof(int);
0504         inp->coda_ioctl.cmd |= (iocsize & PIOCPARM_MASK) << 16; 
0505     
0506         /* in->coda_ioctl.rwflag = flag; */
0507         inp->coda_ioctl.len = data->vi.in_size;
0508         inp->coda_ioctl.data = (char *)(INSIZE(ioctl));
0509      
0510         /* get the data out of user space */
0511     if (copy_from_user((char *)inp + (long)inp->coda_ioctl.data,
0512                data->vi.in, data->vi.in_size)) {
0513         error = -EINVAL;
0514             goto exit;
0515     }
0516 
0517     error = coda_upcall(coda_vcp(sb), SIZE(ioctl) + data->vi.in_size,
0518                 &outsize, inp);
0519 
0520         if (error) {
0521         pr_warn("%s: Venus returns: %d for %s\n",
0522             __func__, error, coda_f2s(fid));
0523         goto exit; 
0524     }
0525 
0526     if (outsize < (long)outp->coda_ioctl.data + outp->coda_ioctl.len) {
0527         error = -EINVAL;
0528         goto exit;
0529     }
0530         
0531     /* Copy out the OUT buffer. */
0532         if (outp->coda_ioctl.len > data->vi.out_size) {
0533         error = -EINVAL;
0534         goto exit;
0535         }
0536 
0537     /* Copy out the OUT buffer. */
0538     if (copy_to_user(data->vi.out,
0539              (char *)outp + (long)outp->coda_ioctl.data,
0540              outp->coda_ioctl.len)) {
0541         error = -EFAULT;
0542         goto exit;
0543     }
0544 
0545  exit:
0546     kvfree(inp);
0547     return error;
0548 }
0549 
0550 int venus_statfs(struct dentry *dentry, struct kstatfs *sfs)
0551 { 
0552         union inputArgs *inp;
0553         union outputArgs *outp;
0554         int insize, outsize, error;
0555         
0556     insize = SIZE(statfs);
0557     UPARG(CODA_STATFS);
0558 
0559     error = coda_upcall(coda_vcp(dentry->d_sb), insize, &outsize, inp);
0560     if (!error) {
0561         sfs->f_blocks = outp->coda_statfs.stat.f_blocks;
0562         sfs->f_bfree  = outp->coda_statfs.stat.f_bfree;
0563         sfs->f_bavail = outp->coda_statfs.stat.f_bavail;
0564         sfs->f_files  = outp->coda_statfs.stat.f_files;
0565         sfs->f_ffree  = outp->coda_statfs.stat.f_ffree;
0566     }
0567 
0568     kvfree(inp);
0569         return error;
0570 }
0571 
0572 int venus_access_intent(struct super_block *sb, struct CodaFid *fid,
0573             bool *access_intent_supported,
0574             size_t count, loff_t ppos, int type)
0575 {
0576     union inputArgs *inp;
0577     union outputArgs *outp;
0578     int insize, outsize, error;
0579     bool finalizer =
0580         type == CODA_ACCESS_TYPE_READ_FINISH ||
0581         type == CODA_ACCESS_TYPE_WRITE_FINISH;
0582 
0583     if (!*access_intent_supported && !finalizer)
0584         return 0;
0585 
0586     insize = SIZE(access_intent);
0587     UPARG(CODA_ACCESS_INTENT);
0588 
0589     inp->coda_access_intent.VFid = *fid;
0590     inp->coda_access_intent.count = count;
0591     inp->coda_access_intent.pos = ppos;
0592     inp->coda_access_intent.type = type;
0593 
0594     error = coda_upcall(coda_vcp(sb), insize,
0595                 finalizer ? NULL : &outsize, inp);
0596 
0597     /*
0598      * we have to free the request buffer for synchronous upcalls
0599      * or when asynchronous upcalls fail, but not when asynchronous
0600      * upcalls succeed
0601      */
0602     if (!finalizer || error)
0603         kvfree(inp);
0604 
0605     /* Chunked access is not supported or an old Coda client */
0606     if (error == -EOPNOTSUPP) {
0607         *access_intent_supported = false;
0608         error = 0;
0609     }
0610     return error;
0611 }
0612 
0613 /*
0614  * coda_upcall and coda_downcall routines.
0615  */
0616 static void coda_block_signals(sigset_t *old)
0617 {
0618     spin_lock_irq(&current->sighand->siglock);
0619     *old = current->blocked;
0620 
0621     sigfillset(&current->blocked);
0622     sigdelset(&current->blocked, SIGKILL);
0623     sigdelset(&current->blocked, SIGSTOP);
0624     sigdelset(&current->blocked, SIGINT);
0625 
0626     recalc_sigpending();
0627     spin_unlock_irq(&current->sighand->siglock);
0628 }
0629 
0630 static void coda_unblock_signals(sigset_t *old)
0631 {
0632     spin_lock_irq(&current->sighand->siglock);
0633     current->blocked = *old;
0634     recalc_sigpending();
0635     spin_unlock_irq(&current->sighand->siglock);
0636 }
0637 
0638 /* Don't allow signals to interrupt the following upcalls before venus
0639  * has seen them,
0640  * - CODA_CLOSE or CODA_RELEASE upcall  (to avoid reference count problems)
0641  * - CODA_STORE             (to avoid data loss)
0642  * - CODA_ACCESS_INTENT                 (to avoid reference count problems)
0643  */
0644 #define CODA_INTERRUPTIBLE(r) (!coda_hard && \
0645                    (((r)->uc_opcode != CODA_CLOSE && \
0646                  (r)->uc_opcode != CODA_STORE && \
0647                  (r)->uc_opcode != CODA_ACCESS_INTENT && \
0648                  (r)->uc_opcode != CODA_RELEASE) || \
0649                 (r)->uc_flags & CODA_REQ_READ))
0650 
0651 static inline void coda_waitfor_upcall(struct venus_comm *vcp,
0652                        struct upc_req *req)
0653 {
0654     DECLARE_WAITQUEUE(wait, current);
0655     unsigned long timeout = jiffies + coda_timeout * HZ;
0656     sigset_t old;
0657     int blocked;
0658 
0659     coda_block_signals(&old);
0660     blocked = 1;
0661 
0662     add_wait_queue(&req->uc_sleep, &wait);
0663     for (;;) {
0664         if (CODA_INTERRUPTIBLE(req))
0665             set_current_state(TASK_INTERRUPTIBLE);
0666         else
0667             set_current_state(TASK_UNINTERRUPTIBLE);
0668 
0669         /* got a reply */
0670         if (req->uc_flags & (CODA_REQ_WRITE | CODA_REQ_ABORT))
0671             break;
0672 
0673         if (blocked && time_after(jiffies, timeout) &&
0674             CODA_INTERRUPTIBLE(req))
0675         {
0676             coda_unblock_signals(&old);
0677             blocked = 0;
0678         }
0679 
0680         if (signal_pending(current)) {
0681             list_del(&req->uc_chain);
0682             break;
0683         }
0684 
0685         mutex_unlock(&vcp->vc_mutex);
0686         if (blocked)
0687             schedule_timeout(HZ);
0688         else
0689             schedule();
0690         mutex_lock(&vcp->vc_mutex);
0691     }
0692     if (blocked)
0693         coda_unblock_signals(&old);
0694 
0695     remove_wait_queue(&req->uc_sleep, &wait);
0696     set_current_state(TASK_RUNNING);
0697 }
0698 
0699 
0700 /*
0701  * coda_upcall will return an error in the case of
0702  * failed communication with Venus _or_ will peek at Venus
0703  * reply and return Venus' error.
0704  *
0705  * As venus has 2 types of errors, normal errors (positive) and internal
0706  * errors (negative), normal errors are negated, while internal errors
0707  * are all mapped to -EINTR, while showing a nice warning message. (jh)
0708  */
0709 static int coda_upcall(struct venus_comm *vcp,
0710                int inSize, int *outSize,
0711                union inputArgs *buffer)
0712 {
0713     union outputArgs *out;
0714     union inputArgs *sig_inputArgs;
0715     struct upc_req *req = NULL, *sig_req;
0716     int error;
0717 
0718     mutex_lock(&vcp->vc_mutex);
0719 
0720     if (!vcp->vc_inuse) {
0721         pr_notice("Venus dead, not sending upcall\n");
0722         error = -ENXIO;
0723         goto exit;
0724     }
0725 
0726     /* Format the request message. */
0727     req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
0728     if (!req) {
0729         error = -ENOMEM;
0730         goto exit;
0731     }
0732 
0733     buffer->ih.unique = ++vcp->vc_seq;
0734 
0735     req->uc_data = (void *)buffer;
0736     req->uc_flags = outSize ? 0 : CODA_REQ_ASYNC;
0737     req->uc_inSize = inSize;
0738     req->uc_outSize = (outSize && *outSize) ? *outSize : inSize;
0739     req->uc_opcode = buffer->ih.opcode;
0740     req->uc_unique = buffer->ih.unique;
0741     init_waitqueue_head(&req->uc_sleep);
0742 
0743     /* Append msg to pending queue and poke Venus. */
0744     list_add_tail(&req->uc_chain, &vcp->vc_pending);
0745     wake_up_interruptible(&vcp->vc_waitq);
0746 
0747     /* We can return early on asynchronous requests */
0748     if (outSize == NULL) {
0749         mutex_unlock(&vcp->vc_mutex);
0750         return 0;
0751     }
0752 
0753     /* We can be interrupted while we wait for Venus to process
0754      * our request.  If the interrupt occurs before Venus has read
0755      * the request, we dequeue and return. If it occurs after the
0756      * read but before the reply, we dequeue, send a signal
0757      * message, and return. If it occurs after the reply we ignore
0758      * it. In no case do we want to restart the syscall.  If it
0759      * was interrupted by a venus shutdown (psdev_close), return
0760      * ENODEV.  */
0761 
0762     /* Go to sleep.  Wake up on signals only after the timeout. */
0763     coda_waitfor_upcall(vcp, req);
0764 
0765     /* Op went through, interrupt or not... */
0766     if (req->uc_flags & CODA_REQ_WRITE) {
0767         out = (union outputArgs *)req->uc_data;
0768         /* here we map positive Venus errors to kernel errors */
0769         error = -out->oh.result;
0770         *outSize = req->uc_outSize;
0771         goto exit;
0772     }
0773 
0774     error = -EINTR;
0775     if ((req->uc_flags & CODA_REQ_ABORT) || !signal_pending(current)) {
0776         pr_warn("Unexpected interruption.\n");
0777         goto exit;
0778     }
0779 
0780     /* Interrupted before venus read it. */
0781     if (!(req->uc_flags & CODA_REQ_READ))
0782         goto exit;
0783 
0784     /* Venus saw the upcall, make sure we can send interrupt signal */
0785     if (!vcp->vc_inuse) {
0786         pr_info("Venus dead, not sending signal.\n");
0787         goto exit;
0788     }
0789 
0790     error = -ENOMEM;
0791     sig_req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
0792     if (!sig_req) goto exit;
0793 
0794     sig_inputArgs = kvzalloc(sizeof(struct coda_in_hdr), GFP_KERNEL);
0795     if (!sig_inputArgs) {
0796         kfree(sig_req);
0797         goto exit;
0798     }
0799 
0800     error = -EINTR;
0801     sig_inputArgs->ih.opcode = CODA_SIGNAL;
0802     sig_inputArgs->ih.unique = req->uc_unique;
0803 
0804     sig_req->uc_flags = CODA_REQ_ASYNC;
0805     sig_req->uc_opcode = sig_inputArgs->ih.opcode;
0806     sig_req->uc_unique = sig_inputArgs->ih.unique;
0807     sig_req->uc_data = (void *)sig_inputArgs;
0808     sig_req->uc_inSize = sizeof(struct coda_in_hdr);
0809     sig_req->uc_outSize = sizeof(struct coda_in_hdr);
0810 
0811     /* insert at head of queue! */
0812     list_add(&(sig_req->uc_chain), &vcp->vc_pending);
0813     wake_up_interruptible(&vcp->vc_waitq);
0814 
0815 exit:
0816     kfree(req);
0817     mutex_unlock(&vcp->vc_mutex);
0818     return error;
0819 }
0820 
0821 /*  
0822     The statements below are part of the Coda opportunistic
0823     programming -- taken from the Mach/BSD kernel code for Coda. 
0824     You don't get correct semantics by stating what needs to be
0825     done without guaranteeing the invariants needed for it to happen.
0826     When will be have time to find out what exactly is going on?  (pjb)
0827 */
0828 
0829 
0830 /* 
0831  * There are 7 cases where cache invalidations occur.  The semantics
0832  *  of each is listed here:
0833  *
0834  * CODA_FLUSH     -- flush all entries from the name cache and the cnode cache.
0835  * CODA_PURGEUSER -- flush all entries from the name cache for a specific user
0836  *                  This call is a result of token expiration.
0837  *
0838  * The next arise as the result of callbacks on a file or directory.
0839  * CODA_ZAPFILE   -- flush the cached attributes for a file.
0840 
0841  * CODA_ZAPDIR    -- flush the attributes for the dir and
0842  *                  force a new lookup for all the children
0843                     of this dir.
0844 
0845  *
0846  * The next is a result of Venus detecting an inconsistent file.
0847  * CODA_PURGEFID  -- flush the attribute for the file
0848  *                  purge it and its children from the dcache
0849  *
0850  * The last  allows Venus to replace local fids with global ones
0851  * during reintegration.
0852  *
0853  * CODA_REPLACE -- replace one CodaFid with another throughout the name cache */
0854 
0855 int coda_downcall(struct venus_comm *vcp, int opcode, union outputArgs *out,
0856           size_t nbytes)
0857 {
0858     struct inode *inode = NULL;
0859     struct CodaFid *fid = NULL, *newfid;
0860     struct super_block *sb;
0861 
0862     /*
0863      * Make sure we have received enough data from the cache
0864      * manager to populate the necessary fields in the buffer
0865      */
0866     switch (opcode) {
0867     case CODA_PURGEUSER:
0868         if (nbytes < sizeof(struct coda_purgeuser_out))
0869             return -EINVAL;
0870         break;
0871 
0872     case CODA_ZAPDIR:
0873         if (nbytes < sizeof(struct coda_zapdir_out))
0874             return -EINVAL;
0875         break;
0876 
0877     case CODA_ZAPFILE:
0878         if (nbytes < sizeof(struct coda_zapfile_out))
0879             return -EINVAL;
0880         break;
0881 
0882     case CODA_PURGEFID:
0883         if (nbytes < sizeof(struct coda_purgefid_out))
0884             return -EINVAL;
0885         break;
0886 
0887     case CODA_REPLACE:
0888         if (nbytes < sizeof(struct coda_replace_out))
0889             return -EINVAL;
0890         break;
0891     }
0892 
0893     /* Handle invalidation requests. */
0894     mutex_lock(&vcp->vc_mutex);
0895     sb = vcp->vc_sb;
0896     if (!sb || !sb->s_root)
0897         goto unlock_out;
0898 
0899     switch (opcode) {
0900     case CODA_FLUSH:
0901         coda_cache_clear_all(sb);
0902         shrink_dcache_sb(sb);
0903         if (d_really_is_positive(sb->s_root))
0904             coda_flag_inode(d_inode(sb->s_root), C_FLUSH);
0905         break;
0906 
0907     case CODA_PURGEUSER:
0908         coda_cache_clear_all(sb);
0909         break;
0910 
0911     case CODA_ZAPDIR:
0912         fid = &out->coda_zapdir.CodaFid;
0913         break;
0914 
0915     case CODA_ZAPFILE:
0916         fid = &out->coda_zapfile.CodaFid;
0917         break;
0918 
0919     case CODA_PURGEFID:
0920         fid = &out->coda_purgefid.CodaFid;
0921         break;
0922 
0923     case CODA_REPLACE:
0924         fid = &out->coda_replace.OldFid;
0925         break;
0926     }
0927     if (fid)
0928         inode = coda_fid_to_inode(fid, sb);
0929 
0930 unlock_out:
0931     mutex_unlock(&vcp->vc_mutex);
0932 
0933     if (!inode)
0934         return 0;
0935 
0936     switch (opcode) {
0937     case CODA_ZAPDIR:
0938         coda_flag_inode_children(inode, C_PURGE);
0939         coda_flag_inode(inode, C_VATTR);
0940         break;
0941 
0942     case CODA_ZAPFILE:
0943         coda_flag_inode(inode, C_VATTR);
0944         break;
0945 
0946     case CODA_PURGEFID:
0947         coda_flag_inode_children(inode, C_PURGE);
0948 
0949         /* catch the dentries later if some are still busy */
0950         coda_flag_inode(inode, C_PURGE);
0951         d_prune_aliases(inode);
0952         break;
0953 
0954     case CODA_REPLACE:
0955         newfid = &out->coda_replace.NewFid;
0956         coda_replace_fid(inode, fid, newfid);
0957         break;
0958     }
0959     iput(inode);
0960     return 0;
0961 }