diff options
Diffstat (limited to 'fs/coda/upcall.c')
-rw-r--r-- | fs/coda/upcall.c | 781 |
1 files changed, 451 insertions, 330 deletions
diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c index 43536f622..ac625ad17 100644 --- a/fs/coda/upcall.c +++ b/fs/coda/upcall.c @@ -16,7 +16,8 @@ #include <asm/system.h> #include <asm/segment.h> - +#include <asm/signal.h> +#include <linux/signal.h> #include <linux/types.h> #include <linux/kernel.h> @@ -34,34 +35,54 @@ #include <linux/coda.h> #include <linux/coda_linux.h> #include <linux/coda_psdev.h> -#include <linux/coda_cnode.h> -#include <linux/coda_namecache.h> +#include <linux/coda_fs_i.h> +#include <linux/coda_cache.h> + +#define UPARG(op)\ +do {\ + CODA_ALLOC(inp, union inputArgs *, insize);\ + outp = (union outputArgs *) (inp);\ + inp->ih.opcode = (op);\ + inp->ih.pid = current->pid;\ + inp->ih.pgid = current->pgrp;\ + coda_load_creds(&(inp->ih.cred));\ + outsize = insize;\ +} while (0) + +static inline int max(int a, int b) +{ + if ( a > b ) + return a; + else + return b; +} +#define INSIZE(tag) sizeof(struct cfs_ ## tag ## _in) +#define OUTSIZE(tag) sizeof(struct cfs_ ## tag ## _out) +#define SIZE(tag) max(INSIZE(tag), OUTSIZE(tag)) -static vcsize = (sizeof(struct inputArgs) > sizeof(struct outputArgs)) ? - sizeof(struct inputArgs): sizeof(struct outputArgs); /* the upcalls */ int venus_rootfid(struct super_block *sb, ViceFid *fidp) { - struct inputArgs *inp; - struct outputArgs *outp; - int error=0; - int size; + union inputArgs *inp; + union outputArgs *outp; + int insize, outsize, error; ENTRY; - UPARG(vcsize, CFS_ROOT); - error = coda_upcall(coda_sbp(sb), VC_IN_NO_DATA, &size, inp); + insize = SIZE(root); + UPARG(CFS_ROOT); + error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); if (error) { printk("coda_get_rootfid: error %d\n", error); } else { - *fidp = (ViceFid) outp->d.cfs_root.VFid; + *fidp = (ViceFid) outp->cfs_root.VFid; CDEBUG(D_SUPER, "VolumeId: %lx, VnodeId: %lx.\n", fidp->Volume, fidp->Vnode); } - if (inp) CODA_FREE(inp, VC_IN_NO_DATA); + if (inp) CODA_FREE(inp, insize); EXIT; return -error; } @@ -69,19 +90,19 @@ ENTRY; int venus_getattr(struct super_block *sb, struct ViceFid *fid, struct coda_vattr *attr) { - struct inputArgs *inp; - struct outputArgs *outp; - int size, error; + union inputArgs *inp; + union outputArgs *outp; + int insize, outsize, error; ENTRY; - - UPARG(vcsize, CFS_GETATTR); - inp->d.cfs_getattr.VFid = *fid; - error = coda_upcall(coda_sbp(sb), vcsize, &size, inp); + insize = SIZE(getattr); + UPARG(CFS_GETATTR); + inp->cfs_getattr.VFid = *fid; + error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); if ( !error ) - *attr = (struct coda_vattr) outp->d.cfs_getattr.attr; + *attr = outp->cfs_getattr.attr; - if (inp) CODA_FREE(inp, sizeof(struct inputArgs)); + if (inp) CODA_FREE(inp, insize); EXIT; return -error; } @@ -89,19 +110,20 @@ ENTRY; int venus_setattr(struct super_block *sb, struct ViceFid *fid, struct coda_vattr *vattr) { - struct inputArgs *inp; - struct outputArgs *outp; - int error, size; + union inputArgs *inp; + union outputArgs *outp; + int insize, outsize, error; - UPARG(vcsize, CFS_SETATTR); + insize= SIZE(setattr); + UPARG(CFS_SETATTR); - inp->d.cfs_setattr.VFid = *fid; - inp->d.cfs_setattr.attr = *vattr; + inp->cfs_setattr.VFid = *fid; + inp->cfs_setattr.attr = *vattr; - error = coda_upcall(coda_sbp(sb), vcsize, &size, inp); + error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); - CDEBUG(D_SUPER, " result %ld\n", outp->result); - if ( inp ) CODA_FREE(inp, vcsize); + CDEBUG(D_SUPER, " result %d\n", error); + if ( inp ) CODA_FREE(inp, insize); return -error; } @@ -109,26 +131,26 @@ int venus_lookup(struct super_block *sb, struct ViceFid *fid, const char *name, int length, int * type, struct ViceFid *resfid) { - struct inputArgs *inp; - struct outputArgs *outp; - int insize, size, error=0, payload_offset; + union inputArgs *inp; + union outputArgs *outp; + int insize, outsize, error; + int offset; - insize = VC_INSIZE(cfs_lookup_in) + CFS_MAXNAMLEN +1; - UPARG(insize, CFS_LOOKUP); + offset = INSIZE(lookup); + insize = max(offset + length +1, OUTSIZE(lookup)); + UPARG(CFS_LOOKUP); - inp->d.cfs_lookup.VFid = *fid; + inp->cfs_lookup.VFid = *fid; + inp->cfs_lookup.name = offset; /* send Venus a null terminated string */ - payload_offset = VC_INSIZE(cfs_lookup_in); - inp->d.cfs_lookup.name = (char *) payload_offset; - memcpy((char *)inp + payload_offset, name, length); - *((char *)inp + payload_offset + length) = '\0'; + memcpy((char *)(inp) + offset, name, length); + *((char *)inp + offset + length) = '\0'; - size = payload_offset + length + 1; - error = coda_upcall(coda_sbp(sb), size, &size, inp); + error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); if ( !error ) { - *resfid = outp->d.cfs_lookup.VFid; - *type = outp->d.cfs_lookup.vtype; + *resfid = outp->cfs_lookup.VFid; + *type = outp->cfs_lookup.vtype; } if (inp) CODA_FREE(inp, insize); @@ -138,53 +160,48 @@ int venus_lookup(struct super_block *sb, struct ViceFid *fid, int venus_release(struct super_block *sb, struct ViceFid *fid, int flags) { - struct inputArgs *inp; - struct outputArgs *outp; - int size = sizeof(struct outputArgs); - int error = 0; - - CODA_ALLOC(inp, struct inputArgs *, sizeof(struct inputArgs)); - outp = (struct outputArgs *)inp; - INIT_IN(inp, CFS_CLOSE); - coda_load_creds(&(inp->cred)); + union inputArgs *inp; + union outputArgs *outp; + int insize, outsize, error; + + insize = SIZE(close); + UPARG(CFS_CLOSE); - inp->d.cfs_close.VFid = *fid; - inp->d.cfs_close.flags = flags; + inp->cfs_close.VFid = *fid; + inp->cfs_close.flags = flags; - error = coda_upcall(coda_sbp(sb), size, &size, inp); + error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); - if (inp) CODA_FREE(inp, sizeof(struct inputArgs)); + if (inp) + CODA_FREE(inp, insize); return -error; } int venus_open(struct super_block *sb, struct ViceFid *fid, int flags, ino_t *ino, dev_t *dev) { - struct inputArgs *inp = NULL; - struct outputArgs *outp = NULL; - int size = sizeof(struct inputArgs); - int error = 0; - - CODA_ALLOC(inp, struct inputArgs *, sizeof(struct inputArgs)); - outp = (struct outputArgs *)inp; - INIT_IN(inp, CFS_OPEN); - coda_load_creds(&(inp->cred)); + union inputArgs *inp; + union outputArgs *outp; + int insize, outsize, error; + + insize = SIZE(open); + UPARG(CFS_OPEN); - inp->d.cfs_open.VFid = *fid; - inp->d.cfs_open.flags = flags; + inp->cfs_open.VFid = *fid; + inp->cfs_open.flags = flags; - error = coda_upcall(coda_sbp(sb), size, &size, inp); + error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); if ( !error ) { - *ino = outp->d.cfs_open.inode; - *dev = outp->d.cfs_open.dev; + *ino = outp->cfs_open.inode; + *dev = outp->cfs_open.dev; } else { *ino = 0; *dev = 0; } if (inp) - CODA_FREE(inp, sizeof(struct inputArgs)); + CODA_FREE(inp, insize); return -error; } @@ -193,69 +210,69 @@ int venus_mkdir(struct super_block *sb, struct ViceFid *dirfid, const char *name, int length, struct ViceFid *newfid, struct coda_vattr *attrs) { - struct inputArgs *inp; - struct outputArgs *outp; - int error=0, size, payload_offset; - - payload_offset = VC_INSIZE(cfs_mkdir_in); - size = CFS_MAXNAMLEN + payload_offset; - UPARG(size, CFS_MKDIR); - - inp->d.cfs_mkdir.VFid = *dirfid; - inp->d.cfs_mkdir.attr = *attrs; - inp->d.cfs_mkdir.name = (char *) payload_offset; - + union inputArgs *inp; + union outputArgs *outp; + int insize, outsize, error; + int offset; + + offset = INSIZE(mkdir); + insize = max(offset + length + 1, OUTSIZE(mkdir)); + UPARG(CFS_MKDIR); + + inp->cfs_mkdir.VFid = *dirfid; + inp->cfs_mkdir.attr = *attrs; + inp->cfs_mkdir.name = offset; /* Venus must get null terminated string */ - memcpy((char *)inp + payload_offset, name, length); - *((char *)inp + payload_offset + length) = '\0'; - size = payload_offset + length + 1; + memcpy((char *)(inp) + offset, name, length); + *((char *)inp + offset + length) = '\0'; - error = coda_upcall(coda_sbp(sb), size, &size, inp); + error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); - *attrs = outp->d.cfs_mkdir.attr; - *newfid = outp->d.cfs_mkdir.VFid; + *attrs = outp->cfs_mkdir.attr; + *newfid = outp->cfs_mkdir.VFid; if (inp) - CODA_FREE(inp, size); + CODA_FREE(inp, insize); return -error; } int venus_rename(struct super_block *sb, struct ViceFid *old_fid, struct ViceFid *new_fid, size_t old_length, - size_t new_length, const char *old_name, const char *new_name) + size_t new_length, const char *old_name, + const char *new_name) { - struct inputArgs *inp; - struct outputArgs *outp; - int error, offset, size, s; + union inputArgs *inp; + union outputArgs *outp; + int insize, outsize, error; + int offset, s; - size = 2*CFS_MAXNAMLEN + VC_INSIZE(cfs_rename_in) +8; - UPARG(size, CFS_RENAME); - - inp->d.cfs_rename.sourceFid = *old_fid; - inp->d.cfs_rename.destFid = *new_fid; + offset = INSIZE(rename); + insize = max(offset + new_length + old_length + 8, + OUTSIZE(rename)); + UPARG(CFS_RENAME); - offset = VC_INSIZE(cfs_rename_in); + inp->cfs_rename.sourceFid = *old_fid; + inp->cfs_rename.destFid = *new_fid; + inp->cfs_rename.srcname = offset; /* Venus must receive an null terminated string */ - inp->d.cfs_rename.srcname = (char *)offset; s = ( old_length & ~0x3) +4; /* round up to word boundary */ - memcpy((char *)inp + offset, old_name, old_length); + memcpy((char *)(inp) + offset, old_name, old_length); *((char *)inp + offset + old_length) = '\0'; /* another null terminated string for Venus */ offset += s; - inp->d.cfs_rename.destname = (char *)offset; + inp->cfs_rename.destname = offset; s = ( new_length & ~0x3) +4; /* round up to word boundary */ - memcpy((char *)inp + offset, new_name, new_length); + memcpy((char *)(inp) + offset, new_name, new_length); *((char *)inp + offset + new_length) = '\0'; - size += s; CDEBUG(D_INODE, "destname in packet: %s\n", - (char *)inp + (int) inp->d.cfs_rename.destname); - error = coda_upcall(coda_sbp(sb), size, &size, inp); + (char *)inp + (int) inp->cfs_rename.destname); + error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); - if (inp) CODA_FREE(inp, size); + if (inp) CODA_FREE(inp, insize); return -error; } @@ -263,131 +280,138 @@ int venus_create(struct super_block *sb, struct ViceFid *dirfid, const char *name, int length, int excl, int mode, struct ViceFid *newfid, struct coda_vattr *attrs) { - struct inputArgs *inp; - struct outputArgs *outp; - int error=0, size, payload_offset; + union inputArgs *inp; + union outputArgs *outp; + int insize, outsize, error; + int offset; - payload_offset = VC_INSIZE(cfs_create_in); - size = CFS_MAXNAMLEN + payload_offset; - UPARG(size, CFS_CREATE); + offset = INSIZE(create); + insize = max(offset + length + 1, OUTSIZE(create)); + UPARG(CFS_CREATE); - inp->d.cfs_create.VFid = *dirfid; - inp->d.cfs_create.attr.va_mode = mode; - inp->d.cfs_create.excl = excl; - inp->d.cfs_create.mode = mode; - inp->d.cfs_create.name = (char *) payload_offset; + inp->cfs_create.VFid = *dirfid; + inp->cfs_create.attr.va_mode = mode; + inp->cfs_create.excl = excl; + inp->cfs_create.mode = mode; + inp->cfs_create.name = offset; /* Venus must get null terminated string */ - memcpy((char *)inp + payload_offset, name, length); - *((char *)inp + payload_offset + length) = '\0'; - size = payload_offset + length + 1; - - error = coda_upcall(coda_sbp(sb), size, &size, inp); + memcpy((char *)(inp) + offset, name, length); + *((char *)inp + offset + length) = '\0'; + + error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); - *attrs = outp->d.cfs_create.attr; - *newfid = outp->d.cfs_create.VFid; + *attrs = outp->cfs_create.attr; + *newfid = outp->cfs_create.VFid; if (inp) - CODA_FREE(inp, size); + CODA_FREE(inp, insize); return -error; } int venus_rmdir(struct super_block *sb, struct ViceFid *dirfid, const char *name, int length) { - struct inputArgs *inp; - struct outputArgs *outp; - int error=0, size, payload_offset; - - payload_offset = VC_INSIZE(cfs_rmdir_in); - size = CFS_MAXNAMLEN + payload_offset; - UPARG(size, CFS_RMDIR); - - inp->d.cfs_rmdir.VFid = *dirfid; - inp->d.cfs_rmdir.name = (char *) payload_offset; - memcpy((char *)inp + payload_offset, name, size); + union inputArgs *inp; + union outputArgs *outp; + int insize, outsize, error; + int offset; + + offset = INSIZE(rmdir); + insize = max(offset + length + 1, OUTSIZE(rmdir)); + UPARG(CFS_RMDIR); + + inp->cfs_rmdir.VFid = *dirfid; + inp->cfs_rmdir.name = offset; + memcpy((char *)(inp) + offset, name, length); + *((char *)inp + offset + length) = '\0'; - error = coda_upcall(coda_sbp(sb), size, &size, inp); + error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); if ( inp ) - CODA_FREE(inp, size); + CODA_FREE(inp, insize); return -error; } int venus_remove(struct super_block *sb, struct ViceFid *dirfid, const char *name, int length) { - struct inputArgs *inp; - struct outputArgs *outp; - int error=0, size, payload_offset; - - payload_offset = VC_INSIZE(cfs_remove_in); - size = CFS_MAXNAMLEN + payload_offset; - UPARG(size, CFS_REMOVE); - - inp->d.cfs_remove.VFid = *dirfid; - inp->d.cfs_remove.name = (char *)payload_offset; - memcpy((char *)inp + payload_offset, name, size); + union inputArgs *inp; + union outputArgs *outp; + int error=0, insize, outsize, offset; + + offset = INSIZE(remove); + insize = max(offset + length + 1, OUTSIZE(remove)); + UPARG(CFS_REMOVE); + + inp->cfs_remove.VFid = *dirfid; + inp->cfs_remove.name = offset; + memcpy((char *)(inp) + offset, name, length); + *((char *)inp + offset + length) = '\0'; - error = coda_upcall(coda_sbp(sb), size, &size, inp); + error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); if ( inp ) - CODA_FREE(inp, size); + CODA_FREE(inp, insize); return -error; } int venus_readlink(struct super_block *sb, struct ViceFid *fid, char *buffer, int *length) { - int error, size, retlen; + union inputArgs *inp; + union outputArgs *outp; + int insize, outsize, error; + int retlen; char *result; - struct inputArgs *inp; - struct outputArgs *outp; - char *buf=NULL; /*[CFS_MAXNAMLEN + VC_INSIZE(cfs_readlink_in)];*/ - size = CFS_MAXPATHLEN + VC_INSIZE(cfs_readlink_in); - UPARG(size, CFS_READLINK); - inp->d.cfs_readlink.VFid = *fid; + insize = max(INSIZE(readlink), OUTSIZE(readlink)+ *length + 1); + UPARG(CFS_READLINK); + + inp->cfs_readlink.VFid = *fid; - error = coda_upcall(coda_sbp(sb), size, &size, inp); + error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); if (! error) { - retlen = outp->d.cfs_readlink.count; + retlen = outp->cfs_readlink.count; if ( retlen > *length ) retlen = *length; *length = retlen; - result = (char *)outp + (int)outp->d.cfs_readlink.data; + result = (char *)outp + (int)outp->cfs_readlink.data; memcpy(buffer, result, retlen); + *(buffer + retlen) = '\0'; } - if (inp) CODA_FREE(buf, size); + if (inp) CODA_FREE(inp, insize); CDEBUG(D_INODE, " result %d\n",error); EXIT; return -error; } + + int venus_link(struct super_block *sb, struct ViceFid *fid, struct ViceFid *dirfid, const char *name, int len ) { - int error, payload_offset, size; - struct inputArgs *inp; - struct outputArgs *outp; + union inputArgs *inp; + union outputArgs *outp; + int insize, outsize, error; + int offset; - size = CFS_MAXNAMLEN + sizeof(struct inputArgs); - UPARG(size, CFS_LINK); + offset = INSIZE(link); + insize = max(offset + len + 1, OUTSIZE(link)); + UPARG(CFS_LINK); - payload_offset = (VC_INSIZE(cfs_link_in)); - inp->d.cfs_link.sourceFid = *fid; - inp->d.cfs_link.destFid = *dirfid; - inp->d.cfs_link.tname = (char *)payload_offset; + inp->cfs_link.sourceFid = *fid; + inp->cfs_link.destFid = *dirfid; + inp->cfs_link.tname = offset; /* make sure strings are null terminated */ - memcpy((char *)inp + payload_offset, name, len); - *((char *)inp + payload_offset + len) = '\0'; - size = payload_offset + len + 1; + memcpy((char *)(inp) + offset, name, len); + *((char *)inp + offset + len) = '\0'; - error = coda_upcall(coda_sbp(sb), size, &size, inp); + error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); if (inp) - CODA_FREE(inp, size); + CODA_FREE(inp, insize); CDEBUG(D_INODE, " result %d\n",error); EXIT; return -error; @@ -397,62 +421,73 @@ int venus_symlink(struct super_block *sb, struct ViceFid *fid, const char *name, int len, const char *symname, int symlen) { - int error, payload_offset, size, s; - struct inputArgs *inp; - struct outputArgs *outp; - - - /* - * allocate space for regular input, - * plus 1 path and 1 name, plus padding - */ - size = sizeof(struct inputArgs) + CFS_MAXNAMLEN + CFS_MAXNAMLEN + 8; - UPARG(size, CFS_SYMLINK); + union inputArgs *inp; + union outputArgs *outp; + int insize, outsize, error; + int offset, s; + + offset = INSIZE(symlink); + insize = max(offset + len + symlen + 8, OUTSIZE(symlink)); + UPARG(CFS_SYMLINK); - /* inp->d.cfs_symlink.attr = *tva; XXXXXX */ - inp->d.cfs_symlink.VFid = *fid; - - payload_offset = VC_INSIZE(cfs_symlink_in); - inp->d.cfs_symlink.srcname =(char*) payload_offset; - - s = ( symlen & ~0x3 ) + 4; /* Round up to word boundary. */ - - /* don't forget to copy out the null termination */ - memcpy((char *)inp + payload_offset, symname, symlen); - *((char *)inp + payload_offset + symlen) = '\0'; + /* inp->cfs_symlink.attr = *tva; XXXXXX */ + inp->cfs_symlink.VFid = *fid; + + /* Round up to word boundary and null terminate */ + inp->cfs_symlink.srcname = offset; + s = ( symlen & ~0x3 ) + 4; + memcpy((char *)(inp) + offset, symname, symlen); + *((char *)inp + offset + symlen) = '\0'; - payload_offset += s; - inp->d.cfs_symlink.tname = (char *) payload_offset; - s = (len & ~0x3) + 4; /* Round up to word boundary. */ - memcpy((char *)inp + payload_offset, name, len); - *((char *)inp + payload_offset + len) = '\0'; + /* Round up to word boundary and null terminate */ + offset += s; + inp->cfs_symlink.tname = offset; + s = (len & ~0x3) + 4; + memcpy((char *)(inp) + offset, name, len); + *((char *)inp + offset + len) = '\0'; - size = payload_offset + s; - error = coda_upcall(coda_sbp(sb), size, &size, inp); + error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); if (inp) - CODA_FREE(inp, size); + CODA_FREE(inp, insize); CDEBUG(D_INODE, " result %d\n",error); EXIT; return -error; } +int venus_fsync(struct super_block *sb, struct ViceFid *fid) +{ + union inputArgs *inp; + union outputArgs *outp; + int insize, outsize, error; + + insize=SIZE(fsync); + UPARG(CFS_FSYNC); + + inp->cfs_fsync.VFid = *fid; + error = coda_upcall(coda_sbp(sb), sizeof(union inputArgs), + &outsize, inp); + + if ( inp ) + CODA_FREE(inp, insize); + return -error; +} + int venus_access(struct super_block *sb, struct ViceFid *fid, int mask) { - struct inputArgs *inp; - struct outputArgs *outp; - int size; - int error; + union inputArgs *inp; + union outputArgs *outp; + int insize, outsize, error; - size = sizeof(struct inputArgs); - UPARG(size, CFS_ACCESS); + insize = SIZE(access); + UPARG(CFS_ACCESS); - inp->d.cfs_access.VFid = *fid; - inp->d.cfs_access.flags = mask << 6; + inp->cfs_access.VFid = *fid; + inp->cfs_access.flags = mask; - error = coda_upcall(coda_sbp(sb), size, &size, inp); + error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); - if (inp) CODA_FREE(inp, sizeof(struct inputArgs)); + if (inp) CODA_FREE(inp, insize); EXIT; return -error; } @@ -461,66 +496,80 @@ int venus_access(struct super_block *sb, struct ViceFid *fid, int mask) int venus_pioctl(struct super_block *sb, struct ViceFid *fid, unsigned int cmd, struct PioctlData *data) { - struct inputArgs *inp; - struct outputArgs *outp; - int size, error = 0; + union inputArgs *inp; + union outputArgs *outp; + int insize, outsize, error; int iocsize; char str[50]; - size = VC_MAXMSGSIZE; - UPARG(size, CFS_IOCTL); + insize = VC_MAXMSGSIZE; + UPARG(CFS_IOCTL); /* build packet for Venus */ - if (data->vi.in_size > VC_DATASIZE) { + if (data->vi.in_size > VC_MAXDATASIZE) { error = EINVAL; goto exit; } - inp->d.cfs_ioctl.VFid = *fid; + inp->cfs_ioctl.VFid = *fid; /* the cmd field was mutated by increasing its size field to * reflect the path and follow args. We need to subtract that * out before sending the command to Venus. */ - inp->d.cfs_ioctl.cmd = (cmd & ~(IOCPARM_MASK << 16)); - iocsize = ((cmd >> 16) & IOCPARM_MASK) - sizeof(char *) - sizeof(int); - inp->d.cfs_ioctl.cmd |= (iocsize & IOCPARM_MASK) << 16; + inp->cfs_ioctl.cmd = (cmd & ~(PIOCPARM_MASK << 16)); + iocsize = ((cmd >> 16) & PIOCPARM_MASK) - sizeof(char *) - sizeof(int); + inp->cfs_ioctl.cmd |= (iocsize & PIOCPARM_MASK) << 16; - /* in->d.cfs_ioctl.rwflag = flag; */ - inp->d.cfs_ioctl.len = data->vi.in_size; - inp->d.cfs_ioctl.data = (char *)(VC_INSIZE(cfs_ioctl_in)); + /* in->cfs_ioctl.rwflag = flag; */ + inp->cfs_ioctl.len = data->vi.in_size; + inp->cfs_ioctl.data = (char *)(INSIZE(ioctl)); /* get the data out of user space */ - if ( copy_from_user((char*)inp + (int)inp->d.cfs_ioctl.data, +#ifdef L20 + memcpy_fromfs((char*)inp + (int)inp->cfs_ioctl.data, + data->vi.in, data->vi.in_size); +#else + if ( copy_from_user((char*)inp + (int)inp->cfs_ioctl.data, data->vi.in, data->vi.in_size) ) { error = EINVAL; goto exit; } - error = coda_upcall(coda_sbp(sb), size, &size, inp); +#endif + error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); if (error) { printk("coda_pioctl: Venus returns: %d for %s\n", - error, coda_f2s(fid, str)); + error, coda_f2s(fid)); goto exit; } /* Copy out the OUT buffer. */ - if (outp->d.cfs_ioctl.len > data->vi.out_size) { + if (outp->cfs_ioctl.len > data->vi.out_size) { CDEBUG(D_FILE, "return len %d <= request len %d\n", - outp->d.cfs_ioctl.len, + outp->cfs_ioctl.len, data->vi.out_size); error = EINVAL; } else { - if (copy_to_user(data->vi.out, - (char *)outp + (int)outp->d.cfs_ioctl.data, + error = verify_area(VERIFY_WRITE, data->vi.out, + data->vi.out_size); + if ( error ) goto exit; +#ifdef L20 + memcpy_tofs(data->vi.out, + (char *)outp + (int)outp->cfs_ioctl.data, + data->vi.out_size); +#else + if (copy_to_user(data->vi.out, + (char *)outp + (int)outp->cfs_ioctl.data, data->vi.out_size)) { error = EINVAL; goto exit; } +#endif } exit: if (inp) - CODA_FREE(inp, VC_MAXMSGSIZE); + CODA_FREE(inp, insize); return -error; } @@ -535,11 +584,53 @@ int venus_pioctl(struct super_block *sb, struct ViceFid *fid, * reply and return Venus' error, also POSITIVE. * */ +static inline void coda_waitfor_upcall(struct vmsg *vmp) +{ + struct wait_queue wait = { current, NULL }; + old_sigset_t pending; + + vmp->vm_posttime = jiffies; + + add_wait_queue(&vmp->vm_sleep, &wait); + for (;;) { + if ( coda_hard == 0 ) + current->state = TASK_INTERRUPTIBLE; + else + current->state = TASK_UNINTERRUPTIBLE; + + /* got a reply */ + if ( vmp->vm_flags & VM_WRITE ) + break; + + if ( ! signal_pending(current) ) + schedule(); + /* signal is present: after timeout always return */ + if ( jiffies > vmp->vm_posttime + coda_timeout * HZ ) + break; + + spin_lock_irq(¤t->sigmask_lock); + pending = current->blocked.sig[0] & current->signal.sig[0]; + spin_unlock_irq(¤t->sigmask_lock); + + /* if this process really wants to die, let it go */ + if ( sigismember(&pending, SIGKILL) || + sigismember(&pending, SIGINT) ) + break; + else + schedule(); + } + remove_wait_queue(&vmp->vm_sleep, &wait); + current->state = TASK_RUNNING; + + return; +} + + int coda_upcall(struct coda_sb_info *sbi, int inSize, int *outSize, - struct inputArgs *buffer) + union inputArgs *buffer) { struct vcomm *vcommp; - struct outputArgs *out; + union outputArgs *out; struct vmsg *vmp; int error = 0; @@ -550,7 +641,7 @@ ENTRY; } vcommp = sbi->sbi_vcomm; - clstats(((struct inputArgs *)buffer)->opcode); + clstats(((union inputArgs *)buffer)->ih.opcode); if (!vcomm_open(vcommp)) return(ENODEV); @@ -561,16 +652,15 @@ ENTRY; vmp->vm_flags = 0; vmp->vm_inSize = inSize; vmp->vm_outSize = *outSize ? *outSize : inSize; - vmp->vm_opcode = ((struct inputArgs *)buffer)->opcode; + vmp->vm_opcode = ((union inputArgs *)buffer)->ih.opcode; vmp->vm_unique = ++vcommp->vc_seq; vmp->vm_sleep = NULL; /* Fill in the common input args. */ - ((struct inputArgs *)buffer)->unique = vmp->vm_unique; + ((union inputArgs *)buffer)->ih.unique = vmp->vm_unique; /* Append msg to pending queue and poke Venus. */ - - INSQUE(vmp->vm_chain, vcommp->vc_pending); + coda_q_insert(&(vmp->vm_chain), &(vcommp->vc_pending)); CDEBUG(D_UPCALL, "Proc %d wake Venus for(opc,uniq) =(%d,%d) msg at %x.zzz.\n", current->pid, vmp->vm_opcode, vmp->vm_unique, (int)vmp); @@ -582,13 +672,15 @@ ENTRY; * read but before the reply, we dequeue, send a signal * message, and return. If it occurs after the reply we ignore * it. In no case do we want to restart the syscall. If it - * was interrupted by a venus shutdown (vcclose), return + * was interrupted by a venus shutdown (psdev_close), return * ENODEV. */ - /* Ignore return, We have to check anyway */ - + /* Go to sleep. Wake up on signals only after the timeout. */ + coda_waitfor_upcall(vmp); - interruptible_sleep_on(&vmp->vm_sleep); + CDEBUG(D_TIMING, "opc: %d time: %ld uniq: %d size: %d\n", + vmp->vm_opcode, jiffies - vmp->vm_posttime, + vmp->vm_unique, vmp->vm_outSize); CDEBUG(D_UPCALL, "..process %d woken up by Venus for vmp at 0x%x, data at %x\n", current->pid, (int)vmp, (int)vmp->vm_data); @@ -596,60 +688,61 @@ ENTRY; /* Op went through, interrupt or not... */ if (vmp->vm_flags & VM_WRITE) { error = 0; - out = (struct outputArgs *)vmp->vm_data; - error = out->result; + out = (union outputArgs *)vmp->vm_data; + error = out->oh.result; CDEBUG(D_UPCALL, - "upcall: (u,o,r) (%ld, %ld, %ld) out at %x\n", - out->unique, out->opcode, out->result, (int)out); + "upcall: (u,o,r) (%ld, %ld, %ld) out at %p\n", + out->oh.unique, out->oh.opcode, out->oh.result, out); *outSize = vmp->vm_outSize; goto exit; - } - if (!(vmp->vm_flags & VM_READ)) { + } + if ( !(vmp->vm_flags & VM_READ) && signal_pending(current)) { /* Interrupted before venus read it. */ CDEBUG(D_UPCALL, "Interrupted before read:(op,un) (%d.%d), flags = %x\n", vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags); - REMQUE(vmp->vm_chain); - error = ERESTARTSYS; + coda_q_remove(&(vmp->vm_chain)); + error = ERESTARTNOHAND; goto exit; } - if ( vmp->vm_flags & VM_READ) { + if ( (vmp->vm_flags & VM_READ) && signal_pending(current) ) { /* interrupted after Venus did its read, send signal */ - struct inputArgs *dog; + union inputArgs *dog; struct vmsg *svmp; CDEBUG(D_UPCALL, "Sending Venus a signal: op = %d.%d, flags = %x\n", vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags); - REMQUE(vmp->vm_chain); - error = ERESTARTSYS; + coda_q_remove(&(vmp->vm_chain)); + error = ERESTARTNOHAND; CODA_ALLOC(svmp, struct vmsg *, sizeof (struct vmsg)); - CODA_ALLOC((svmp->vm_data), char *, VC_IN_NO_DATA); + CODA_ALLOC((svmp->vm_data), char *, sizeof(struct cfs_in_hdr)); + dog = (union inputArgs *)svmp->vm_data; + dog->ih.opcode = CFS_SIGNAL; + dog->ih.unique = vmp->vm_unique; + + svmp->vm_flags = 0; + svmp->vm_opcode = dog->ih.opcode; + svmp->vm_unique = dog->ih.unique; + svmp->vm_inSize = sizeof(struct cfs_in_hdr); + svmp->vm_outSize = sizeof(struct cfs_in_hdr); CDEBUG(D_UPCALL, "coda_upcall: enqueing signal msg (%d, %d)\n", svmp->vm_opcode, svmp->vm_unique); - dog = (struct inputArgs *)svmp->vm_data; - dog->opcode = CFS_SIGNAL; - dog->unique = vmp->vm_unique; - - svmp->vm_flags = 0; - svmp->vm_opcode = dog->opcode; - svmp->vm_unique = dog->unique; - svmp->vm_inSize = VC_IN_NO_DATA; - svmp->vm_outSize = VC_IN_NO_DATA; /* insert at head of queue! */ - INSQUE(svmp->vm_chain, vcommp->vc_pending); + coda_q_insert(&(svmp->vm_chain), vcommp->vc_pending.forw); wake_up_interruptible(&vcommp->vc_waitq); + } else { + printk("Coda: Strange interruption..\n"); + error = EINTR; } } else { /* If venus died i.e. !VC_OPEN(vcommp) */ - printk("coda_upcall: Venus dead upon (op,un) (%d.%d) flags %d\n", + printk("coda_upcall: Venus dead on (op,un) (%d.%d) flags %d\n", vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags); - - /* if (! (vmp->vm_flags & VM_WRITE) ) */ error = ENODEV; } @@ -670,78 +763,106 @@ ENTRY; * CFS_FLUSH -- flush all entries from the name cache and the cnode cache. * CFS_PURGEUSER -- flush all entries from the name cache for a specific user * This call is a result of token expiration. - * Linux does a cfsnc_flush since cred's are not maintained. * * The next arise as the result of callbacks on a file or directory. * CFS_ZAPDIR -- flush the attributes for the dir from its cnode. * Zap all children of this directory from the namecache. * CFS_ZAPFILE -- flush the cached attributes for a file. - * CFS_ZAPVNODE -- in linux the same as zap file (no creds). + * CFS_ZAPVNODE -- intended to be a zapfile for just one cred. Not used? * * The next is a result of Venus detecting an inconsistent file. * CFS_PURGEFID -- flush the attribute for the file - * If it is a dir (odd vnode), purge its - * children from the namecache - * remove the file from the namecache. + * purge it and its children from the dcache * * The last allows Venus to replace local fids with global ones * during reintegration. * * CFS_REPLACE -- replace one ViceFid with another throughout the name cache */ -int coda_downcall(int opcode, struct outputArgs * out) +int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb) { /* Handle invalidate requests. */ switch (opcode) { - case CFS_FLUSH : { - clstats(CFS_FLUSH); - cfsnc_flush(); - return(0); - } - case CFS_PURGEUSER : { - clstats(CFS_PURGEUSER); - cfsnc_flush(); - return(0); - } - case CFS_ZAPDIR : { - ViceFid *fid = &out->d.cfs_zapdir.CodaFid; - clstats(CFS_ZAPDIR); - cfsnc_zapfid(fid); - cfsnc_zapParentfid(fid); - CDEBUG(D_UPCALL, "zapdir: fid = (%lx.%lx.%lx), \n",fid->Volume, - fid->Vnode, - fid->Unique); - return(0); - } - case CFS_ZAPVNODE : { - clstats(CFS_ZAPVNODE); - cfsnc_zapfid(&out->d.cfs_zapvnode.VFid); - return(0); - } - case CFS_ZAPFILE : { - clstats(CFS_ZAPFILE); - cfsnc_zapfid(&out->d.cfs_zapfile.CodaFid); - return 0; - } - case CFS_PURGEFID : { - ViceFid *fid = &out->d.cfs_purgefid.CodaFid; - clstats(CFS_PURGEFID); - cfsnc_zapfid(fid); - cfsnc_zapParentfid(fid); - CDEBUG(D_UPCALL, "purgefid: fid = (%lx.%lx.%lx)\n", - fid->Volume, fid->Vnode, - fid->Unique); - return 0; - } - case CFS_REPLACE : { - clstats(CFS_REPLACE); - cfsnc_replace(&out->d.cfs_replace.OldFid, - &out->d.cfs_replace.NewFid); - return (0); - } + case CFS_FLUSH : { + clstats(CFS_FLUSH); + CDEBUG(D_DOWNCALL, "CFS_FLUSH\n"); + coda_cache_clear_all(sb); + shrink_dcache_sb(sb); + return(0); + } + case CFS_PURGEUSER : { + struct coda_cred *cred = &out->cfs_purgeuser.cred; + CDEBUG(D_DOWNCALL, "CFS_PURGEUSER\n"); + if ( !cred ) { + printk("PURGEUSER: null cred!\n"); + return 0; + } + clstats(CFS_PURGEUSER); + coda_cache_clear_cred(sb, cred); + return(0); + } + case CFS_ZAPDIR : { + ViceFid *fid = &out->cfs_zapdir.CodaFid; + char str[50]; + if ( !fid ) { + printk("ZAPDIR: Null fid\n"); + return 0; + } + CDEBUG(D_DOWNCALL, "zapdir: fid = %s\n", coda_f2s(fid)); + clstats(CFS_ZAPDIR); + coda_zapfid(fid, sb, C_ZAPDIR); + return(0); + } + case CFS_ZAPVNODE : { + ViceFid *fid = &out->cfs_zapvnode.VFid; + char str[50]; + struct coda_cred *cred = &out->cfs_zapvnode.cred; + if ( !fid || !cred ) { + printk("ZAPVNODE: Null fid or cred\n"); + return 0; + } + CDEBUG(D_DOWNCALL, "zapvnode: fid = %s\n", coda_f2s(fid)); + coda_zapfid(fid, sb, C_ZAPFID); + coda_cache_clear_cred(sb, cred); + clstats(CFS_ZAPVNODE); + return(0); + } + case CFS_ZAPFILE : { + struct ViceFid *fid = &out->cfs_zapfile.CodaFid; + char str[50]; + clstats(CFS_ZAPFILE); + if ( !fid ) { + printk("ZAPFILE: Null fid\n"); + return 0; + } + CDEBUG(D_DOWNCALL, "zapfile: fid = %s\n", coda_f2s(fid)); + coda_zapfid(fid, sb, C_ZAPFID); + return 0; + } + case CFS_PURGEFID : { + ViceFid *fid = &out->cfs_purgefid.CodaFid; + char str[50]; + if ( !fid ) { + printk("PURGEFID: Null fid\n"); + return 0; + } + CDEBUG(D_DOWNCALL, "purgefid: fid = %s\n", coda_f2s(fid)); + clstats(CFS_PURGEFID); + coda_zapfid(fid, sb, C_ZAPDIR); + return 0; + } + case CFS_REPLACE : { + printk("CFS_REPLACCE\n"); + clstats(CFS_REPLACE); + CDEBUG(D_DOWNCALL, "CFS_REPLACE\n"); + coda_cache_clear_all(sb); + shrink_dcache_sb(sb); + return (0); + } } return 0; } + |