/*
* Mostly platform independent upcall operations to Venus:
* -- upcalls
* -- upcall routines
*
* Linux 2.0 version
* Copyright (C) 1996 Peter J. Braam <braam@maths.ox.ac.uk>,
* Michael Callahan <callahan@maths.ox.ac.uk>
*
* Redone for Linux 2.1
* Copyright (C) 1997 Carnegie Mellon University
*
* Carnegie Mellon University encourages users of this code to contribute
* improvements to the Coda project. Contact Peter Braam <coda@cs.cmu.edu>.
*/
#include <asm/system.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/time.h>
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <asm/uaccess.h>
#include <linux/vmalloc.h>
#include <linux/vfs.h>
#include <linux/coda.h>
#include <linux/coda_linux.h>
#include <linux/coda_psdev.h>
#include <linux/coda_fs_i.h>
#include <linux/coda_cache.h>
#include "coda_int.h"
static int coda_upcall(struct venus_comm *vc, int inSize, int *outSize,
union inputArgs *buffer);
static void *alloc_upcall(int opcode, int size)
{
union inputArgs *inp;
CODA_ALLOC(inp, union inputArgs *, size);
if (!inp)
return ERR_PTR(-ENOMEM);
inp->ih.opcode = opcode;
inp->ih.pid = current->pid;
inp->ih.pgid = task_pgrp_nr(current);
inp->ih.uid = current->fsuid;
return (void*)inp;
}
#define UPARG(op)\
do {\
inp = (union inputArgs *)alloc_upcall(op, insize); \
if (IS_ERR(inp)) { return PTR_ERR(inp); }\
outp = (union outputArgs *)(inp); \
outsize = insize; \
} while (0)
#define INSIZE(tag) sizeof(struct coda_ ## tag ## _in)
#define OUTSIZE(tag) sizeof(struct coda_ ## tag ## _out)
#define SIZE(tag) max_t(unsigned int, INSIZE(tag), OUTSIZE(tag))
/* the upcalls */
int venus_rootfid(struct super_block *sb, struct CodaFid *fidp)
{
union inputArgs *inp;
union outputArgs *outp;
int insize, outsize, error;
insize = SIZE(root);
UPARG(CODA_ROOT);
error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
if (!error)
*fidp = outp->coda_root.VFid;
CODA_FREE(inp, insize);
return error;
}
int venus_getattr(struct super_block *sb, struct CodaFid *fid,
struct coda_vattr *attr)
{
union inputArgs *inp;
union outputArgs *outp;
int insize, outsize, error;
insize = SIZE(getattr);
UPARG(CODA_GETATTR);
inp->coda_getattr.VFid = *fid;
error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
if (!error)
*attr = outp->coda_getattr.attr;
CODA_FREE(inp, insize);
return error;
}
int venus_setattr(struct super_block *sb, struct CodaFid *fid,
struct coda_vattr *vattr)
{
union inputArgs *inp;
union outputArgs *outp;
int insize, outsize, error;
insize = SIZE(setattr);
UPARG(CODA_SETATTR);
inp->coda_setattr.VFid = *fid;
inp->coda_setattr.attr = *vattr;
error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
CODA_FREE(inp, insize);
return error;
}
int venus_lookup(struct super_block *sb, struct CodaFid *fid,
const char *name, int length, int * type,
struct CodaFid *resfid)
{
union inputArgs *inp;
union outputArgs *outp;
int insize, outsize, error;
int offset;
offset = INSIZE(lookup);
insize = max_t(unsigned int, offset + length +1, OUTSIZE(lookup));
UPARG(CODA_LOOKUP);
inp->coda_lookup.VFid = *fid;
inp->coda_lookup.name = offset;
inp->coda_lookup.flags = CLU_CASE_SENSITIVE;
/* send Venus a null terminated string */
memcpy((char *)(inp) + offset, name, length);
*((char *)inp + offset + length) = '\0';
error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
if (!error) {
*resfid = outp->coda_lookup.VFid;
*type = outp->coda_lookup.vtype;
}
CODA_FREE(inp, insize);
return error;
}
int venus_close(struct super_block *sb, struct CodaFid *fid, int flags,
vuid_t uid)
{
union inputArgs *inp;
union outputArgs *outp;
int insize, outsize, error;
insize = SIZE(release);
UPARG(CODA_CLOSE);
inp->ih.uid = uid;
inp->coda_close.VFid = *fid;
inp->coda_close.flags = flags;
error = coda_upcall(coda_vcp(sb), insize, &outsize,