summaryrefslogtreecommitdiffstats
path: root/fs/coda/upcall.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/coda/upcall.c')
-rw-r--r--fs/coda/upcall.c781
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(&current->sigmask_lock);
+ pending = current->blocked.sig[0] & current->signal.sig[0];
+ spin_unlock_irq(&current->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;
}
+