📄 upcall.c
字号:
/* * 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 <asm/segment.h>#include <asm/signal.h>#include <linux/signal.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/mm.h>#include <linux/sched.h>#include <linux/fs.h>#include <linux/file.h>#include <linux/stat.h>#include <linux/errno.h>#include <linux/locks.h>#include <linux/string.h>#include <asm/uaccess.h>#include <linux/vmalloc.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 <linux/coda_proc.h> #define upc_alloc() kmalloc(sizeof(struct upc_req), GFP_KERNEL)#define upc_free(r) kfree(r)static int coda_upcall(struct coda_sb_info *mntinfo, 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 = current->pgrp; coda_load_creds(&(inp->ih.cred)); 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, ViceFid *fidp){ union inputArgs *inp; union outputArgs *outp; int insize, outsize, error; insize = SIZE(root); UPARG(CODA_ROOT); error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); if (error) { printk("coda_get_rootfid: error %d\n", error); } else { *fidp = (ViceFid) outp->coda_root.VFid; CDEBUG(D_SUPER, "VolumeId: %lx, VnodeId: %lx.\n", fidp->Volume, fidp->Vnode); } CODA_FREE(inp, insize); return error;}int venus_getattr(struct super_block *sb, struct ViceFid *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_sbp(sb), insize, &outsize, inp); *attr = outp->coda_getattr.attr; CODA_FREE(inp, insize); return error;}int venus_setattr(struct super_block *sb, struct ViceFid *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_sbp(sb), insize, &outsize, inp); CDEBUG(D_SUPER, " result %d\n", error); CODA_FREE(inp, insize); return error;}int venus_lookup(struct super_block *sb, struct ViceFid *fid, const char *name, int length, int * type, struct ViceFid *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_sbp(sb), insize, &outsize, inp); *resfid = outp->coda_lookup.VFid; *type = outp->coda_lookup.vtype; CODA_FREE(inp, insize); return error;}int venus_store(struct super_block *sb, struct ViceFid *fid, int flags, struct coda_cred *cred){ union inputArgs *inp; union outputArgs *outp; int insize, outsize, error; insize = SIZE(store); UPARG(CODA_STORE); if ( cred ) { memcpy(&(inp->ih.cred), cred, sizeof(*cred)); } else printk("CODA: store without valid file creds.\n"); inp->coda_store.VFid = *fid; inp->coda_store.flags = flags; error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); CODA_FREE(inp, insize); return error;}int venus_release(struct super_block *sb, struct ViceFid *fid, int flags){ union inputArgs *inp; union outputArgs *outp; int insize, outsize, error; insize = SIZE(release); UPARG(CODA_RELEASE); inp->coda_release.VFid = *fid; inp->coda_release.flags = flags; error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); CODA_FREE(inp, insize); return error;}int venus_close(struct super_block *sb, struct ViceFid *fid, int flags, struct coda_cred *cred){ union inputArgs *inp; union outputArgs *outp; int insize, outsize, error; insize = SIZE(release); UPARG(CODA_CLOSE); if ( cred ) { memcpy(&(inp->ih.cred), cred, sizeof(*cred)); } else printk("CODA: close without valid file creds.\n"); inp->coda_close.VFid = *fid; inp->coda_close.flags = flags; error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); CODA_FREE(inp, insize); return error;}int venus_open(struct super_block *sb, struct ViceFid *fid, int flags, struct file **fh){ union inputArgs *inp; union outputArgs *outp; int insize, outsize, error; insize = SIZE(open_by_fd); UPARG(CODA_OPEN_BY_FD); inp->coda_open.VFid = *fid; inp->coda_open.flags = flags; error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); *fh = outp->coda_open_by_fd.fh; CODA_FREE(inp, insize); return error;} int venus_mkdir(struct super_block *sb, struct ViceFid *dirfid, const char *name, int length, struct ViceFid *newfid, struct coda_vattr *attrs){ union inputArgs *inp; union outputArgs *outp; int insize, outsize, error; int offset; offset = INSIZE(mkdir); insize = max_t(unsigned int, offset + length + 1, OUTSIZE(mkdir)); UPARG(CODA_MKDIR); inp->coda_mkdir.VFid = *dirfid; inp->coda_mkdir.attr = *attrs; inp->coda_mkdir.name = offset; /* Venus must get null terminated string */ memcpy((char *)(inp) + offset, name, length); *((char *)inp + offset + length) = '\0'; error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); *attrs = outp->coda_mkdir.attr; *newfid = outp->coda_mkdir.VFid; 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){ union inputArgs *inp; union outputArgs *outp; int insize, outsize, error; int offset, s; offset = INSIZE(rename); insize = max_t(unsigned int, offset + new_length + old_length + 8, OUTSIZE(rename)); UPARG(CODA_RENAME); inp->coda_rename.sourceFid = *old_fid; inp->coda_rename.destFid = *new_fid; inp->coda_rename.srcname = offset; /* Venus must receive an null terminated string */ s = ( old_length & ~0x3) +4; /* round up to word boundary */ memcpy((char *)(inp) + offset, old_name, old_length); *((char *)inp + offset + old_length) = '\0'; /* another null terminated string for Venus */ offset += s; inp->coda_rename.destname = offset; s = ( new_length & ~0x3) +4; /* round up to word boundary */ memcpy((char *)(inp) + offset, new_name, new_length); *((char *)inp + offset + new_length) = '\0'; CDEBUG(D_INODE, "destname in packet: %s\n", (char *)inp + (int) inp->coda_rename.destname); error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); CODA_FREE(inp, insize); return error;}int venus_create(struct super_block *sb, struct ViceFid *dirfid, const char *name, int length, int excl, int mode, int rdev, struct ViceFid *newfid, struct coda_vattr *attrs) { union inputArgs *inp; union outputArgs *outp; int insize, outsize, error; int offset; offset = INSIZE(create); insize = max_t(unsigned int, offset + length + 1, OUTSIZE(create)); UPARG(CODA_CREATE); inp->coda_create.VFid = *dirfid; inp->coda_create.attr.va_mode = mode; inp->coda_create.attr.va_rdev = rdev; inp->coda_create.excl = excl; inp->coda_create.mode = mode; inp->coda_create.name = offset; /* Venus must get null terminated string */ memcpy((char *)(inp) + offset, name, length); *((char *)inp + offset + length) = '\0'; error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); *attrs = outp->coda_create.attr; *newfid = outp->coda_create.VFid; CODA_FREE(inp, insize); return error; }int venus_rmdir(struct super_block *sb, struct ViceFid *dirfid, const char *name, int length){ union inputArgs *inp; union outputArgs *outp; int insize, outsize, error; int offset; offset = INSIZE(rmdir); insize = max_t(unsigned int, offset + length + 1, OUTSIZE(rmdir)); UPARG(CODA_RMDIR); inp->coda_rmdir.VFid = *dirfid; inp->coda_rmdir.name = offset; memcpy((char *)(inp) + offset, name, length); *((char *)inp + offset + length) = '\0'; error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); CODA_FREE(inp, insize); return error;}int venus_remove(struct super_block *sb, struct ViceFid *dirfid, const char *name, int length){ union inputArgs *inp; union outputArgs *outp; int error=0, insize, outsize, offset; offset = INSIZE(remove); insize = max_t(unsigned int, offset + length + 1, OUTSIZE(remove)); UPARG(CODA_REMOVE); inp->coda_remove.VFid = *dirfid; inp->coda_remove.name = offset; memcpy((char *)(inp) + offset, name, length); *((char *)inp + offset + length) = '\0'; error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); CODA_FREE(inp, insize); return error;}int venus_readlink(struct super_block *sb, struct ViceFid *fid, char *buffer, int *length){ union inputArgs *inp; union outputArgs *outp; int insize, outsize, error; int retlen; char *result; insize = max_t(unsigned int, INSIZE(readlink), OUTSIZE(readlink)+ *length + 1); UPARG(CODA_READLINK); inp->coda_readlink.VFid = *fid; error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); if (! error) { retlen = outp->coda_readlink.count; if ( retlen > *length ) retlen = *length; *length = retlen; result = (char *)outp + (long)outp->coda_readlink.data; memcpy(buffer, result, retlen); *(buffer + retlen) = '\0'; } CDEBUG(D_INODE, " result %d\n",error); CODA_FREE(inp, insize); return error;}int venus_link(struct super_block *sb, struct ViceFid *fid, struct ViceFid *dirfid, const char *name, int len ){ union inputArgs *inp; union outputArgs *outp; int insize, outsize, error; int offset; offset = INSIZE(link); insize = max_t(unsigned int, offset + len + 1, OUTSIZE(link)); UPARG(CODA_LINK); inp->coda_link.sourceFid = *fid; inp->coda_link.destFid = *dirfid; inp->coda_link.tname = offset; /* make sure strings are null terminated */ memcpy((char *)(inp) + offset, name, len); *((char *)inp + offset + len) = '\0'; error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); CDEBUG(D_INODE, " result %d\n",error); CODA_FREE(inp, insize); return error;}int venus_symlink(struct super_block *sb, struct ViceFid *fid, const char *name, int len, const char *symname, int symlen){ union inputArgs *inp; union outputArgs *outp; int insize, outsize, error; int offset, s; offset = INSIZE(symlink); insize = max_t(unsigned int, offset + len + symlen + 8, OUTSIZE(symlink)); UPARG(CODA_SYMLINK); /* inp->coda_symlink.attr = *tva; XXXXXX */ inp->coda_symlink.VFid = *fid; /* Round up to word boundary and null terminate */ inp->coda_symlink.srcname = offset; s = ( symlen & ~0x3 ) + 4; memcpy((char *)(inp) + offset, symname, symlen); *((char *)inp + offset + symlen) = '\0'; /* Round up to word boundary and null terminate */ offset += s; inp->coda_symlink.tname = offset; s = (len & ~0x3) + 4; memcpy((char *)(inp) + offset, name, len); *((char *)inp + offset + len) = '\0'; error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -