提交 531b1094 编写于 作者: L Latchesar Ionkov 提交者: Linus Torvalds

[PATCH] v9fs: zero copy implementation

Performance enhancement reducing the number of copies in the data and
stat paths.
Signed-off-by: NLatchesar Ionkov <lucho@ionkov.net>
Cc: Eric Van Hensbergen <ericvh@ericvh.myip.org>
Signed-off-by: NAndrew Morton <akpm@osdl.org>
Signed-off-by: NLinus Torvalds <torvalds@osdl.org>
上级 d8da097a
/*
* linux/fs/9p/9p.c
*
* This file contains functions 9P2000 functions
* This file contains functions to perform synchronous 9P calls
*
* Copyright (C) 2004 by Latchesar Ionkov <lucho@ionkov.net>
* Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
* Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
*
......@@ -33,6 +34,7 @@
#include "debug.h"
#include "v9fs.h"
#include "9p.h"
#include "conv.h"
#include "mux.h"
/**
......@@ -46,17 +48,21 @@
int
v9fs_t_version(struct v9fs_session_info *v9ses, u32 msize,
char *version, struct v9fs_fcall **fcall)
char *version, struct v9fs_fcall **rcp)
{
struct v9fs_fcall msg;
int ret;
struct v9fs_fcall *tc;
dprintk(DEBUG_9P, "msize: %d version: %s\n", msize, version);
msg.id = TVERSION;
msg.tag = ~0;
msg.params.tversion.msize = msize;
msg.params.tversion.version = version;
tc = v9fs_create_tversion(msize, version);
return v9fs_mux_rpc(v9ses->mux, &msg, fcall);
if (!IS_ERR(tc)) {
ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
kfree(tc);
} else
ret = PTR_ERR(tc);
return ret;
}
/**
......@@ -72,19 +78,23 @@ v9fs_t_version(struct v9fs_session_info *v9ses, u32 msize,
int
v9fs_t_attach(struct v9fs_session_info *v9ses, char *uname, char *aname,
u32 fid, u32 afid, struct v9fs_fcall **fcall)
u32 fid, u32 afid, struct v9fs_fcall **rcp)
{
struct v9fs_fcall msg;
int ret;
struct v9fs_fcall* tc;
dprintk(DEBUG_9P, "uname '%s' aname '%s' fid %d afid %d\n", uname,
aname, fid, afid);
msg.id = TATTACH;
msg.params.tattach.fid = fid;
msg.params.tattach.afid = afid;
msg.params.tattach.uname = uname;
msg.params.tattach.aname = aname;
return v9fs_mux_rpc(v9ses->mux, &msg, fcall);
ret = -ENOMEM;
tc = v9fs_create_tattach(fid, afid, uname, aname);
if (!IS_ERR(tc)) {
ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
kfree(tc);
} else
ret = PTR_ERR(tc);
return ret;
}
static void v9fs_t_clunk_cb(void *a, struct v9fs_fcall *tc,
......@@ -117,24 +127,28 @@ static void v9fs_t_clunk_cb(void *a, struct v9fs_fcall *tc,
* @fcall: pointer to response fcall pointer
*
*/
int
v9fs_t_clunk(struct v9fs_session_info *v9ses, u32 fid)
{
int err;
int ret;
struct v9fs_fcall *tc, *rc;
tc = kmalloc(sizeof(struct v9fs_fcall), GFP_KERNEL);
dprintk(DEBUG_9P, "fid %d\n", fid);
tc->id = TCLUNK;
tc->params.tclunk.fid = fid;
err = v9fs_mux_rpc(v9ses->mux, tc, &rc);
if (err >= 0) {
v9fs_t_clunk_cb(v9ses, tc, rc, 0);
}
ret = -ENOMEM;
rc = NULL;
tc = v9fs_create_tclunk(fid);
if (!IS_ERR(tc))
ret = v9fs_mux_rpc(v9ses->mux, tc, &rc);
else
ret = PTR_ERR(tc);
if (ret)
dprintk(DEBUG_ERROR, "failed fid %d err %d\n", fid, ret);
return err;
v9fs_t_clunk_cb(v9ses, tc, rc, ret);
return ret;
}
/**
......@@ -144,14 +158,22 @@ v9fs_t_clunk(struct v9fs_session_info *v9ses, u32 fid)
*
*/
int v9fs_t_flush(struct v9fs_session_info *v9ses, u16 tag)
int v9fs_t_flush(struct v9fs_session_info *v9ses, u16 oldtag)
{
struct v9fs_fcall msg;
int ret;
struct v9fs_fcall *tc;
dprintk(DEBUG_9P, "oldtag %d\n", tag);
msg.id = TFLUSH;
msg.params.tflush.oldtag = tag;
return v9fs_mux_rpc(v9ses->mux, &msg, NULL);
dprintk(DEBUG_9P, "oldtag %d\n", oldtag);
ret = -ENOMEM;
tc = v9fs_create_tflush(oldtag);
if (!IS_ERR(tc)) {
ret = v9fs_mux_rpc(v9ses->mux, tc, NULL);
kfree(tc);
} else
ret = PTR_ERR(tc);
return ret;
}
/**
......@@ -163,17 +185,22 @@ int v9fs_t_flush(struct v9fs_session_info *v9ses, u16 tag)
*/
int
v9fs_t_stat(struct v9fs_session_info *v9ses, u32 fid, struct v9fs_fcall **fcall)
v9fs_t_stat(struct v9fs_session_info *v9ses, u32 fid, struct v9fs_fcall **rcp)
{
struct v9fs_fcall msg;
int ret;
struct v9fs_fcall *tc;
dprintk(DEBUG_9P, "fid %d\n", fid);
if (fcall)
*fcall = NULL;
msg.id = TSTAT;
msg.params.tstat.fid = fid;
return v9fs_mux_rpc(v9ses->mux, &msg, fcall);
ret = -ENOMEM;
tc = v9fs_create_tstat(fid);
if (!IS_ERR(tc)) {
ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
kfree(tc);
} else
ret = PTR_ERR(tc);
return ret;
}
/**
......@@ -187,16 +214,22 @@ v9fs_t_stat(struct v9fs_session_info *v9ses, u32 fid, struct v9fs_fcall **fcall)
int
v9fs_t_wstat(struct v9fs_session_info *v9ses, u32 fid,
struct v9fs_stat *stat, struct v9fs_fcall **fcall)
struct v9fs_wstat *wstat, struct v9fs_fcall **rcp)
{
struct v9fs_fcall msg;
int ret;
struct v9fs_fcall *tc;
dprintk(DEBUG_9P, "fid %d length %d\n", fid, (int)stat->length);
msg.id = TWSTAT;
msg.params.twstat.fid = fid;
msg.params.twstat.stat = stat;
dprintk(DEBUG_9P, "fid %d\n", fid);
ret = -ENOMEM;
tc = v9fs_create_twstat(fid, wstat, v9ses->extended);
if (!IS_ERR(tc)) {
ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
kfree(tc);
} else
ret = PTR_ERR(tc);
return v9fs_mux_rpc(v9ses->mux, &msg, fcall);
return ret;
}
/**
......@@ -213,23 +246,28 @@ v9fs_t_wstat(struct v9fs_session_info *v9ses, u32 fid,
int
v9fs_t_walk(struct v9fs_session_info *v9ses, u32 fid, u32 newfid,
char *name, struct v9fs_fcall **fcall)
char *name, struct v9fs_fcall **rcp)
{
struct v9fs_fcall msg;
int ret;
struct v9fs_fcall *tc;
int nwname;
dprintk(DEBUG_9P, "fid %d newfid %d wname '%s'\n", fid, newfid, name);
msg.id = TWALK;
msg.params.twalk.fid = fid;
msg.params.twalk.newfid = newfid;
if (name) {
msg.params.twalk.nwname = 1;
msg.params.twalk.wnames = &name;
} else {
msg.params.twalk.nwname = 0;
}
return v9fs_mux_rpc(v9ses->mux, &msg, fcall);
if (name)
nwname = 1;
else
nwname = 0;
ret = -ENOMEM;
tc = v9fs_create_twalk(fid, newfid, nwname, &name);
if (!IS_ERR(tc)) {
ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
kfree(tc);
} else
ret = PTR_ERR(tc);
return ret;
}
/**
......@@ -244,19 +282,22 @@ v9fs_t_walk(struct v9fs_session_info *v9ses, u32 fid, u32 newfid,
int
v9fs_t_open(struct v9fs_session_info *v9ses, u32 fid, u8 mode,
struct v9fs_fcall **fcall)
struct v9fs_fcall **rcp)
{
struct v9fs_fcall msg;
int errorno = -1;
int ret;
struct v9fs_fcall *tc;
dprintk(DEBUG_9P, "fid %d mode %d\n", fid, mode);
msg.id = TOPEN;
msg.params.topen.fid = fid;
msg.params.topen.mode = mode;
errorno = v9fs_mux_rpc(v9ses->mux, &msg, fcall);
ret = -ENOMEM;
tc = v9fs_create_topen(fid, mode);
if (!IS_ERR(tc)) {
ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
kfree(tc);
} else
ret = PTR_ERR(tc);
return errorno;
return ret;
}
/**
......@@ -269,14 +310,22 @@ v9fs_t_open(struct v9fs_session_info *v9ses, u32 fid, u8 mode,
int
v9fs_t_remove(struct v9fs_session_info *v9ses, u32 fid,
struct v9fs_fcall **fcall)
struct v9fs_fcall **rcp)
{
struct v9fs_fcall msg;
int ret;
struct v9fs_fcall *tc;
dprintk(DEBUG_9P, "fid %d\n", fid);
msg.id = TREMOVE;
msg.params.tremove.fid = fid;
return v9fs_mux_rpc(v9ses->mux, &msg, fcall);
ret = -ENOMEM;
tc = v9fs_create_tremove(fid);
if (!IS_ERR(tc)) {
ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
kfree(tc);
} else
ret = PTR_ERR(tc);
return ret;
}
/**
......@@ -292,20 +341,23 @@ v9fs_t_remove(struct v9fs_session_info *v9ses, u32 fid,
int
v9fs_t_create(struct v9fs_session_info *v9ses, u32 fid, char *name,
u32 perm, u8 mode, struct v9fs_fcall **fcall)
u32 perm, u8 mode, struct v9fs_fcall **rcp)
{
struct v9fs_fcall msg;
int ret;
struct v9fs_fcall *tc;
dprintk(DEBUG_9P, "fid %d name '%s' perm %x mode %d\n",
fid, name, perm, mode);
msg.id = TCREATE;
msg.params.tcreate.fid = fid;
msg.params.tcreate.name = name;
msg.params.tcreate.perm = perm;
msg.params.tcreate.mode = mode;
ret = -ENOMEM;
tc = v9fs_create_tcreate(fid, name, perm, mode);
if (!IS_ERR(tc)) {
ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
kfree(tc);
} else
ret = PTR_ERR(tc);
return v9fs_mux_rpc(v9ses->mux, &msg, fcall);
return ret;
}
/**
......@@ -320,31 +372,30 @@ v9fs_t_create(struct v9fs_session_info *v9ses, u32 fid, char *name,
int
v9fs_t_read(struct v9fs_session_info *v9ses, u32 fid, u64 offset,
u32 count, struct v9fs_fcall **fcall)
u32 count, struct v9fs_fcall **rcp)
{
struct v9fs_fcall msg;
struct v9fs_fcall *rc = NULL;
long errorno = -1;
dprintk(DEBUG_9P, "fid %d offset 0x%lx count 0x%x\n", fid,
(long unsigned int)offset, count);
msg.id = TREAD;
msg.params.tread.fid = fid;
msg.params.tread.offset = offset;
msg.params.tread.count = count;
errorno = v9fs_mux_rpc(v9ses->mux, &msg, &rc);
if (!errorno) {
errorno = rc->params.rread.count;
dump_data(rc->params.rread.data, rc->params.rread.count);
}
if (fcall)
*fcall = rc;
else
kfree(rc);
int ret;
struct v9fs_fcall *tc, *rc;
return errorno;
dprintk(DEBUG_9P, "fid %d offset 0x%llux count 0x%x\n", fid,
(long long unsigned) offset, count);
ret = -ENOMEM;
tc = v9fs_create_tread(fid, offset, count);
if (!IS_ERR(tc)) {
ret = v9fs_mux_rpc(v9ses->mux, tc, &rc);
if (!ret)
ret = rc->params.rread.count;
if (rcp)
*rcp = rc;
else
kfree(rc);
kfree(tc);
} else
ret = PTR_ERR(tc);
return ret;
}
/**
......@@ -358,32 +409,31 @@ v9fs_t_read(struct v9fs_session_info *v9ses, u32 fid, u64 offset,
*/
int
v9fs_t_write(struct v9fs_session_info *v9ses, u32 fid,
u64 offset, u32 count, void *data, struct v9fs_fcall **fcall)
v9fs_t_write(struct v9fs_session_info *v9ses, u32 fid, u64 offset, u32 count,
const char __user *data, struct v9fs_fcall **rcp)
{
struct v9fs_fcall msg;
struct v9fs_fcall *rc = NULL;
long errorno = -1;
int ret;
struct v9fs_fcall *tc, *rc;
dprintk(DEBUG_9P, "fid %d offset 0x%llx count 0x%x\n", fid,
(unsigned long long)offset, count);
dump_data(data, count);
dprintk(DEBUG_9P, "fid %d offset 0x%llux count 0x%x\n", fid,
(long long unsigned) offset, count);
msg.id = TWRITE;
msg.params.twrite.fid = fid;
msg.params.twrite.offset = offset;
msg.params.twrite.count = count;
msg.params.twrite.data = data;
ret = -ENOMEM;
tc = v9fs_create_twrite(fid, offset, count, data);
if (!IS_ERR(tc)) {
ret = v9fs_mux_rpc(v9ses->mux, tc, &rc);
errorno = v9fs_mux_rpc(v9ses->mux, &msg, &rc);
if (!ret)
ret = rc->params.rwrite.count;
if (rcp)
*rcp = rc;
else
kfree(rc);
if (!errorno)
errorno = rc->params.rwrite.count;
kfree(tc);
} else
ret = PTR_ERR(tc);
if (fcall)
*fcall = rc;
else
kfree(rc);
return errorno;
return ret;
}
......@@ -3,6 +3,7 @@
*
* 9P protocol definitions.
*
* Copyright (C) 2005 by Latchesar Ionkov <lucho@ionkov.net>
* Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
* Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
*
......@@ -102,10 +103,16 @@ enum {
#define V9FS_NOTAG (u16)(~0)
#define V9FS_NOFID (u32)(~0)
#define V9FS_MAXWELEM 16
/* ample room for Twrite/Rread header (iounit) */
#define V9FS_IOHDRSZ 24
struct v9fs_str {
u16 len;
char *str;
};
/* qids are the unique ID for a file (like an inode */
struct v9fs_qid {
u8 type;
......@@ -115,6 +122,29 @@ struct v9fs_qid {
/* Plan 9 file metadata (stat) structure */
struct v9fs_stat {
u16 size;
u16 type;
u32 dev;
struct v9fs_qid qid;
u32 mode;
u32 atime;
u32 mtime;
u64 length;
struct v9fs_str name;
struct v9fs_str uid;
struct v9fs_str gid;
struct v9fs_str muid;
struct v9fs_str extension; /* 9p2000.u extensions */
u32 n_uid; /* 9p2000.u extensions */
u32 n_gid; /* 9p2000.u extensions */
u32 n_muid; /* 9p2000.u extensions */
};
/* file metadata (stat) structure used to create Twstat message
The is similar to v9fs_stat, but the strings don't point to
the same memory block and should be freed separately
*/
struct v9fs_wstat {
u16 size;
u16 type;
u32 dev;
......@@ -131,25 +161,24 @@ struct v9fs_stat {
u32 n_uid; /* 9p2000.u extensions */
u32 n_gid; /* 9p2000.u extensions */
u32 n_muid; /* 9p2000.u extensions */
char data[0];
};
/* Structures for Protocol Operations */
struct Tversion {
u32 msize;
char *version;
struct v9fs_str version;
};
struct Rversion {
u32 msize;
char *version;
struct v9fs_str version;
};
struct Tauth {
u32 afid;
char *uname;
char *aname;
struct v9fs_str uname;
struct v9fs_str aname;
};
struct Rauth {
......@@ -157,12 +186,12 @@ struct Rauth {
};
struct Rerror {
char *error;
struct v9fs_str error;
u32 errno; /* 9p2000.u extension */
};
struct Tflush {
u32 oldtag;
u16 oldtag;
};
struct Rflush {
......@@ -171,8 +200,8 @@ struct Rflush {
struct Tattach {
u32 fid;
u32 afid;
char *uname;
char *aname;
struct v9fs_str uname;
struct v9fs_str aname;
};
struct Rattach {
......@@ -182,13 +211,13 @@ struct Rattach {
struct Twalk {
u32 fid;
u32 newfid;
u32 nwname;
char **wnames;
u16 nwname;
struct v9fs_str wnames[16];
};
struct Rwalk {
u32 nwqid;
struct v9fs_qid *wqids;
u16 nwqid;
struct v9fs_qid wqids[16];
};
struct Topen {
......@@ -203,7 +232,7 @@ struct Ropen {
struct Tcreate {
u32 fid;
char *name;
struct v9fs_str name;
u32 perm;
u8 mode;
};
......@@ -254,12 +283,12 @@ struct Tstat {
};
struct Rstat {
struct v9fs_stat *stat;
struct v9fs_stat stat;
};
struct Twstat {
u32 fid;
struct v9fs_stat *stat;
struct v9fs_stat stat;
};
struct Rwstat {
......@@ -274,6 +303,7 @@ struct v9fs_fcall {
u32 size;
u8 id;
u16 tag;
void *sdata;
union {
struct Tversion tversion;
......@@ -306,10 +336,12 @@ struct v9fs_fcall {
} params;
};
#define V9FS_FCALLHDRSZ (sizeof(struct v9fs_fcall) + \
sizeof(struct v9fs_stat) + 16*sizeof(struct v9fs_qid) + 16)
#define PRINT_FCALL_ERROR(s, fcall) dprintk(DEBUG_ERROR, "%s: %.*s\n", s, \
fcall?fcall->params.rerror.error.len:0, \
fcall?fcall->params.rerror.error.str:"");
#define FCALL_ERROR(fcall) (fcall ? fcall->params.rerror.error : "")
char *v9fs_str_copy(char *buf, int buflen, struct v9fs_str *str);
int v9fs_str_compare(char *buf, struct v9fs_str *str);
int v9fs_t_version(struct v9fs_session_info *v9ses, u32 msize,
char *version, struct v9fs_fcall **rcall);
......@@ -325,7 +357,7 @@ int v9fs_t_stat(struct v9fs_session_info *v9ses, u32 fid,
struct v9fs_fcall **rcall);
int v9fs_t_wstat(struct v9fs_session_info *v9ses, u32 fid,
struct v9fs_stat *stat, struct v9fs_fcall **rcall);
struct v9fs_wstat *wstat, struct v9fs_fcall **rcall);
int v9fs_t_walk(struct v9fs_session_info *v9ses, u32 fid, u32 newfid,
char *name, struct v9fs_fcall **rcall);
......@@ -343,4 +375,5 @@ int v9fs_t_read(struct v9fs_session_info *v9ses, u32 fid,
u64 offset, u32 count, struct v9fs_fcall **rcall);
int v9fs_t_write(struct v9fs_session_info *v9ses, u32 fid, u64 offset,
u32 count, void *data, struct v9fs_fcall **rcall);
u32 count, const char __user * data,
struct v9fs_fcall **rcall);
obj-$(CONFIG_9P_FS) := 9p2000.o
9p2000-objs := \
trans_fd.o \
trans_sock.o \
mux.o \
9p.o \
conv.o \
vfs_super.o \
vfs_inode.o \
vfs_file.o \
vfs_dir.o \
vfs_dentry.o \
error.o \
mux.o \
trans_fd.o \
trans_sock.o \
9p.o \
conv.o \
v9fs.o \
fid.o
此差异已折叠。
/*
* linux/fs/9p/conv.h
*
* 9P protocol conversion definitions
* 9P protocol conversion definitions.
*
* Copyright (C) 2005 by Latchesar Ionkov <lucho@ionkov.net>
* Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
* Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
*
......@@ -25,11 +26,26 @@
*/
int v9fs_deserialize_stat(void *buf, u32 buflen, struct v9fs_stat *stat,
u32 statlen, int extended);
int v9fs_serialize_fcall(struct v9fs_fcall *tcall, void *buf, u32 buflen,
int extended);
int v9fs_deserialize_fcall(void *buf, u32 buflen, struct v9fs_fcall *rcall,
int rcalllen, int extended);
int extended);
void v9fs_set_tag(struct v9fs_fcall *fc, u16 tag);
/* this one is actually in error.c right now */
int v9fs_errstr2errno(char *errstr);
struct v9fs_fcall *v9fs_create_tversion(u32 msize, char *version);
struct v9fs_fcall *v9fs_create_tauth(u32 afid, char *uname, char *aname);
struct v9fs_fcall *v9fs_create_tattach(u32 fid, u32 afid, char *uname,
char *aname);
struct v9fs_fcall *v9fs_create_tflush(u16 oldtag);
struct v9fs_fcall *v9fs_create_twalk(u32 fid, u32 newfid, u16 nwname,
char **wnames);
struct v9fs_fcall *v9fs_create_topen(u32 fid, u8 mode);
struct v9fs_fcall *v9fs_create_tcreate(u32 fid, char *name, u32 perm, u8 mode);
struct v9fs_fcall *v9fs_create_tread(u32 fid, u64 offset, u32 count);
struct v9fs_fcall *v9fs_create_twrite(u32 fid, u64 offset, u32 count,
const char __user *data);
struct v9fs_fcall *v9fs_create_tclunk(u32 fid);
struct v9fs_fcall *v9fs_create_tremove(u32 fid);
struct v9fs_fcall *v9fs_create_tstat(u32 fid);
struct v9fs_fcall *v9fs_create_twstat(u32 fid, struct v9fs_wstat *wstat,
int extended);
......@@ -51,16 +51,23 @@ do { \
#if DEBUG_DUMP_PKT
static inline void dump_data(const unsigned char *data, unsigned int datalen)
{
int i, j;
int len = datalen;
int i, n;
char buf[5*8];
printk(KERN_DEBUG "data ");
for (i = 0; i < len; i += 4) {
for (j = 0; (j < 4) && (i + j < len); j++)
printk(KERN_DEBUG "%02x", data[i + j]);
printk(KERN_DEBUG " ");
n = 0;
i = 0;
while (i < datalen) {
n += snprintf(buf+n, sizeof(buf)-n, "%02x", data[i++]);
if (i%4 == 0)
n += snprintf(buf+n, sizeof(buf)-n, " ");
if (i%16 == 0) {
dprintk(DEBUG_ERROR, "%s\n", buf);
n = 0;
}
}
printk(KERN_DEBUG "\n");
dprintk(DEBUG_ERROR, "%s\n", buf);
}
#else /* DEBUG_DUMP_PKT */
static inline void dump_data(const unsigned char *data, unsigned int datalen)
......
......@@ -33,7 +33,6 @@
#include <linux/list.h>
#include <linux/jhash.h>
#include <linux/string.h>
#include "debug.h"
#include "error.h"
......@@ -55,7 +54,8 @@ int v9fs_error_init(void)
/* load initial error map into hash table */
for (c = errmap; c->name != NULL; c++) {
bucket = jhash(c->name, strlen(c->name), 0) % ERRHASHSZ;
c->namelen = strlen(c->name);
bucket = jhash(c->name, c->namelen, 0) % ERRHASHSZ;
INIT_HLIST_NODE(&c->list);
hlist_add_head(&c->list, &hash_errmap[bucket]);
}
......@@ -69,15 +69,15 @@ int v9fs_error_init(void)
*
*/
int v9fs_errstr2errno(char *errstr)
int v9fs_errstr2errno(char *errstr, int len)
{
int errno = 0;
struct hlist_node *p = NULL;
struct errormap *c = NULL;
int bucket = jhash(errstr, strlen(errstr), 0) % ERRHASHSZ;
int bucket = jhash(errstr, len, 0) % ERRHASHSZ;
hlist_for_each_entry(c, p, &hash_errmap[bucket], list) {
if (!strcmp(c->name, errstr)) {
if (c->namelen==len && !memcmp(c->name, errstr, len)) {
errno = c->val;
break;
}
......
......@@ -36,6 +36,7 @@ struct errormap {
char *name;
int val;
int namelen;
struct hlist_node list;
};
......@@ -175,4 +176,4 @@ static struct errormap errmap[] = {
};
extern int v9fs_error_init(void);
extern int v9fs_errstr2errno(char *errstr);
extern int v9fs_errstr2errno(char *errstr, int len);
......@@ -31,9 +31,6 @@
#include "v9fs.h"
#include "9p.h"
#include "v9fs_vfs.h"
#include "transport.h"
#include "mux.h"
#include "conv.h"
#include "fid.h"
/**
......
......@@ -35,8 +35,8 @@
#include "debug.h"
#include "v9fs.h"
#include "9p.h"
#include "transport.h"
#include "conv.h"
#include "transport.h"
#include "mux.h"
#define ERREQFLUSH 1
......@@ -74,6 +74,7 @@ struct v9fs_mux_data {
wait_queue_head_t equeue;
struct list_head req_list;
struct list_head unsent_req_list;
struct v9fs_fcall *rcall;
int rpos;
char *rbuf;
int wpos;
......@@ -101,11 +102,15 @@ struct v9fs_mux_rpc {
wait_queue_head_t wqueue;
};
extern int v9fs_errstr2errno(char *str, int len);
static int v9fs_poll_proc(void *);
static void v9fs_read_work(void *);
static void v9fs_write_work(void *);
static void v9fs_pollwait(struct file *filp, wait_queue_head_t * wait_address,
poll_table * p);
static u16 v9fs_mux_get_tag(struct v9fs_mux_data *);
static void v9fs_mux_put_tag(struct v9fs_mux_data *, u16);
static DECLARE_MUTEX(v9fs_mux_task_lock);
static struct workqueue_struct *v9fs_mux_wq;
......@@ -166,8 +171,9 @@ static void v9fs_mux_poll_start(struct v9fs_mux_data *m)
if (v9fs_mux_poll_tasks[i].task == NULL) {
vpt = &v9fs_mux_poll_tasks[i];
dprintk(DEBUG_MUX, "create proc %p\n", vpt);
vpt->task = kthread_create(v9fs_poll_proc,
vpt, "v9fs-poll");
vpt->task =
kthread_create(v9fs_poll_proc, vpt,
"v9fs-poll");
INIT_LIST_HEAD(&vpt->mux_list);
vpt->muxnum = 0;
v9fs_mux_poll_task_num++;
......@@ -253,7 +259,7 @@ struct v9fs_mux_data *v9fs_mux_init(struct v9fs_transport *trans, int msize,
struct v9fs_mux_data *m, *mtmp;
dprintk(DEBUG_MUX, "transport %p msize %d\n", trans, msize);
m = kmalloc(sizeof(struct v9fs_mux_data) + 2 * msize, GFP_KERNEL);
m = kmalloc(sizeof(struct v9fs_mux_data), GFP_KERNEL);
if (!m)
return ERR_PTR(-ENOMEM);
......@@ -268,10 +274,11 @@ struct v9fs_mux_data *v9fs_mux_init(struct v9fs_transport *trans, int msize,
init_waitqueue_head(&m->equeue);
INIT_LIST_HEAD(&m->req_list);
INIT_LIST_HEAD(&m->unsent_req_list);
m->rcall = NULL;
m->rpos = 0;
m->rbuf = (char *)m + sizeof(struct v9fs_mux_data);
m->rbuf = NULL;
m->wpos = m->wsize = 0;
m->wbuf = m->rbuf + msize;
m->wbuf = NULL;
INIT_WORK(&m->rq, v9fs_read_work, m);
INIT_WORK(&m->wq, v9fs_write_work, m);
m->wsched = 0;
......@@ -427,29 +434,6 @@ static int v9fs_poll_proc(void *a)
return 0;
}
static inline int v9fs_write_req(struct v9fs_mux_data *m, struct v9fs_req *req)
{
int n;
list_move_tail(&req->req_list, &m->req_list);
n = v9fs_serialize_fcall(req->tcall, m->wbuf, m->msize, *m->extended);
if (n < 0) {
req->err = n;
list_del(&req->req_list);
if (req->cb) {
spin_unlock(&m->lock);
(*req->cb) (req->cba, req->tcall, req->rcall, req->err);
req->cb = NULL;
spin_lock(&m->lock);
} else
kfree(req->rcall);
kfree(req);
}
return n;
}
/**
* v9fs_write_work - called when a transport can send some data
*/
......@@ -457,7 +441,7 @@ static void v9fs_write_work(void *a)
{
int n, err;
struct v9fs_mux_data *m;
struct v9fs_req *req, *rtmp;
struct v9fs_req *req;
m = a;
......@@ -472,17 +456,15 @@ static void v9fs_write_work(void *a)
return;
}
err = 0;
spin_lock(&m->lock);
list_for_each_entry_safe(req, rtmp, &m->unsent_req_list,
req_list) {
err = v9fs_write_req(m, req);
if (err > 0)
break;
}
m->wsize = err;
req =
list_entry(m->unsent_req_list.next, struct v9fs_req,
req_list);
list_move_tail(&req->req_list, &m->req_list);
m->wbuf = req->tcall->sdata;
m->wsize = req->tcall->size;
m->wpos = 0;
dump_data(m->wbuf, m->wsize);
spin_unlock(&m->lock);
}
......@@ -526,24 +508,23 @@ static void v9fs_write_work(void *a)
static void process_request(struct v9fs_mux_data *m, struct v9fs_req *req)
{
int ecode, tag;
char *ename;
struct v9fs_str *ename;
tag = req->tag;
if (req->rcall->id == RERROR && !req->err) {
ecode = req->rcall->params.rerror.errno;
ename = req->rcall->params.rerror.error;
ename = &req->rcall->params.rerror.error;
dprintk(DEBUG_MUX, "Rerror %s\n", ename);
dprintk(DEBUG_MUX, "Rerror %.*s\n", ename->len, ename->str);
if (*m->extended)
req->err = -ecode;
if (!req->err) {
req->err = v9fs_errstr2errno(ename);
req->err = v9fs_errstr2errno(ename->str, ename->len);
if (!req->err) { /* string match failed */
dprintk(DEBUG_ERROR, "unknown error: %s\n",
ename);
PRINT_FCALL_ERROR("unknown error", req->rcall);
}
if (!req->err)
......@@ -565,8 +546,7 @@ static void process_request(struct v9fs_mux_data *m, struct v9fs_req *req)
} else
kfree(req->rcall);
if (tag != V9FS_NOTAG)
v9fs_put_idpool(tag, &m->tidpool);
v9fs_mux_put_tag(m, tag);
wake_up(&m->equeue);
kfree(req);
......@@ -577,10 +557,11 @@ static void process_request(struct v9fs_mux_data *m, struct v9fs_req *req)
*/
static void v9fs_read_work(void *a)
{
int n, err, rcallen;
int n, err;
struct v9fs_mux_data *m;
struct v9fs_req *req, *rptr, *rreq;
struct v9fs_fcall *rcall;
char *rbuf;
m = a;
......@@ -589,6 +570,19 @@ static void v9fs_read_work(void *a)
rcall = NULL;
dprintk(DEBUG_MUX, "start mux %p pos %d\n", m, m->rpos);
if (!m->rcall) {
m->rcall =
kmalloc(sizeof(struct v9fs_fcall) + m->msize, GFP_KERNEL);
if (!m->rcall) {
err = -ENOMEM;
goto error;
}
m->rbuf = (char *)m->rcall + sizeof(struct v9fs_fcall);
m->rpos = 0;
}
clear_bit(Rpending, &m->wsched);
err = m->trans->read(m->trans, m->rbuf + m->rpos, m->msize - m->rpos);
dprintk(DEBUG_MUX, "mux %p got %d bytes\n", m, err);
......@@ -613,21 +607,32 @@ static void v9fs_read_work(void *a)
if (m->rpos < n)
break;
rcallen = n + V9FS_FCALLHDRSZ;
rcall = kmalloc(rcallen, GFP_KERNEL);
if (!rcall) {
err = -ENOMEM;
goto error;
}
dump_data(m->rbuf, n);
err = v9fs_deserialize_fcall(m->rbuf, n, rcall, rcallen,
*m->extended);
err =
v9fs_deserialize_fcall(m->rbuf, n, m->rcall, *m->extended);
if (err < 0) {
kfree(rcall);
goto error;
}
rcall = m->rcall;
rbuf = m->rbuf;
if (m->rpos > n) {
m->rcall = kmalloc(sizeof(struct v9fs_fcall) + m->msize,
GFP_KERNEL);
if (!m->rcall) {
err = -ENOMEM;
goto error;
}
m->rbuf = (char *)m->rcall + sizeof(struct v9fs_fcall);
memmove(m->rbuf, rbuf + n, m->rpos - n);
m->rpos -= n;
} else {
m->rcall = NULL;
m->rbuf = NULL;
m->rpos = 0;
}
dprintk(DEBUG_MUX, "mux %p fcall id %d tag %d\n", m, rcall->id,
rcall->tag);
......@@ -642,6 +647,7 @@ static void v9fs_read_work(void *a)
process_request(m, req);
break;
}
}
if (!req) {
......@@ -652,10 +658,6 @@ static void v9fs_read_work(void *a)
m, rcall->id, rcall->tag);
kfree(rcall);
}
if (m->rpos > n)
memmove(m->rbuf, m->rbuf + n, m->rpos - n);
m->rpos -= n;
}
if (!list_empty(&m->req_list)) {
......@@ -710,12 +712,13 @@ static struct v9fs_req *v9fs_send_request(struct v9fs_mux_data *m,
if (tc->id == TVERSION)
n = V9FS_NOTAG;
else
n = v9fs_get_idpool(&m->tidpool);
n = v9fs_mux_get_tag(m);
if (n < 0)
return ERR_PTR(-ENOMEM);
tc->tag = n;
v9fs_set_tag(tc, n);
req->tag = n;
req->tcall = tc;
req->rcall = NULL;
......@@ -773,9 +776,7 @@ v9fs_mux_flush_cb(void *a, struct v9fs_fcall *tc, struct v9fs_fcall *rc,
if (!cb)
spin_unlock(&m->lock);
if (v9fs_check_idpool(tag, &m->tidpool))
v9fs_put_idpool(tag, &m->tidpool);
v9fs_mux_put_tag(m, tag);
kfree(tc);
kfree(rc);
}
......@@ -787,10 +788,7 @@ v9fs_mux_flush_request(struct v9fs_mux_data *m, struct v9fs_req *req)
dprintk(DEBUG_MUX, "mux %p req %p tag %d\n", m, req, req->tag);
fc = kmalloc(sizeof(struct v9fs_fcall), GFP_KERNEL);
fc->id = TFLUSH;
fc->params.tflush.oldtag = req->tag;
fc = v9fs_create_tflush(req->tag);
v9fs_send_request(m, fc, v9fs_mux_flush_cb, m);
}
......@@ -939,3 +937,20 @@ void v9fs_mux_cancel(struct v9fs_mux_data *m, int err)
wake_up(&m->equeue);
}
static u16 v9fs_mux_get_tag(struct v9fs_mux_data *m)
{
int tag;
tag = v9fs_get_idpool(&m->tidpool);
if (tag < 0)
return V9FS_NOTAG;
else
return (u16) tag;
}
static void v9fs_mux_put_tag(struct v9fs_mux_data *m, u16 tag)
{
if (tag != V9FS_NOTAG && v9fs_check_idpool(tag, &m->tidpool))
v9fs_put_idpool(tag, &m->tidpool);
}
......@@ -110,7 +110,6 @@ static int v9fs_sock_send(struct v9fs_transport *trans, void *v, int len)
if (!(ts->filp->f_flags & O_NONBLOCK))
dprintk(DEBUG_ERROR, "blocking write ...\n");
dump_data(v, len);
oldfs = get_fs();
set_fs(get_ds());
ret = vfs_write(ts->filp, (void __user *)v, len, &ts->filp->f_pos);
......
......@@ -37,7 +37,6 @@
#include "v9fs_vfs.h"
#include "transport.h"
#include "mux.h"
#include "conv.h"
/* TODO: sysfs or debugfs interface */
int v9fs_debug_level = 0; /* feature-rific global debug level */
......@@ -353,7 +352,7 @@ v9fs_session_init(struct v9fs_session_info *v9ses,
}
/* Really should check for 9P1 and report error */
if (!strcmp(fcall->params.rversion.version, "9P2000.u")) {
if (!v9fs_str_compare("9P2000.u", &fcall->params.rversion.version)) {
dprintk(DEBUG_9P, "9P2000 UNIX extensions enabled\n");
v9ses->extended = 1;
} else {
......
......@@ -45,9 +45,8 @@ extern struct dentry_operations v9fs_dentry_operations;
struct inode *v9fs_get_inode(struct super_block *sb, int mode);
ino_t v9fs_qid2ino(struct v9fs_qid *qid);
void v9fs_mistat2inode(struct v9fs_stat *, struct inode *,
struct super_block *);
void v9fs_stat2inode(struct v9fs_stat *, struct inode *, struct super_block *);
int v9fs_dir_release(struct inode *inode, struct file *filp);
int v9fs_file_open(struct inode *inode, struct file *file);
void v9fs_inode2mistat(struct inode *inode, struct v9fs_stat *mistat);
void v9fs_inode2stat(struct inode *inode, struct v9fs_stat *stat);
void v9fs_dentry_release(struct dentry *);
......@@ -40,7 +40,6 @@
#include "v9fs.h"
#include "9p.h"
#include "v9fs_vfs.h"
#include "conv.h"
#include "fid.h"
/**
......@@ -108,7 +107,8 @@ void v9fs_dentry_release(struct dentry *dentry)
err = v9fs_t_clunk(current_fid->v9ses, current_fid->fid);
if (err < 0)
dprintk(DEBUG_ERROR, "clunk failed: %d\n", err);
dprintk(DEBUG_ERROR, "clunk failed: %d name %s\n",
err, dentry->d_iname);
v9fs_fid_destroy(current_fid);
}
......
......@@ -37,8 +37,8 @@
#include "debug.h"
#include "v9fs.h"
#include "9p.h"
#include "v9fs_vfs.h"
#include "conv.h"
#include "v9fs_vfs.h"
#include "fid.h"
/**
......@@ -77,17 +77,13 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
unsigned int i, n, s;
int fid = -1;
int ret = 0;
struct v9fs_stat *mi = NULL;
struct v9fs_stat stat;
int over = 0;
dprintk(DEBUG_VFS, "name %s\n", filp->f_dentry->d_name.name);
fid = file->fid;
mi = kmalloc(v9ses->maxdata, GFP_KERNEL);
if (!mi)
return -ENOMEM;
if (file->rdir_fcall && (filp->f_pos != file->rdir_pos)) {
kfree(file->rdir_fcall);
file->rdir_fcall = NULL;
......@@ -99,18 +95,18 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
while (i < n) {
s = v9fs_deserialize_stat(
file->rdir_fcall->params.rread.data + i,
n - i, mi, v9ses->maxdata, v9ses->extended);
n - i, &stat, v9ses->extended);
if (s == 0) {
dprintk(DEBUG_ERROR,
"error while deserializing mistat\n");
"error while deserializing stat\n");
ret = -EIO;
goto FreeStructs;
}
over = filldir(dirent, mi->name, strlen(mi->name),
filp->f_pos, v9fs_qid2ino(&mi->qid),
dt_type(mi));
over = filldir(dirent, stat.name.str, stat.name.len,
filp->f_pos, v9fs_qid2ino(&stat.qid),
dt_type(&stat));
if (over) {
file->rdir_fpos = i;
......@@ -130,7 +126,7 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
while (!over) {
ret = v9fs_t_read(v9ses, fid, filp->f_pos,
v9ses->maxdata-V9FS_IOHDRSZ, &fcall);
v9ses->maxdata-V9FS_IOHDRSZ, &fcall);
if (ret < 0) {
dprintk(DEBUG_ERROR, "error while reading: %d: %p\n",
ret, fcall);
......@@ -142,17 +138,17 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
i = 0;
while (i < n) {
s = v9fs_deserialize_stat(fcall->params.rread.data + i,
n - i, mi, v9ses->maxdata, v9ses->extended);
n - i, &stat, v9ses->extended);
if (s == 0) {
dprintk(DEBUG_ERROR,
"error while deserializing mistat\n");
"error while deserializing stat\n");
return -EIO;
}
over = filldir(dirent, mi->name, strlen(mi->name),
filp->f_pos, v9fs_qid2ino(&mi->qid),
dt_type(mi));
over = filldir(dirent, stat.name.str, stat.name.len,
filp->f_pos, v9fs_qid2ino(&stat.qid),
dt_type(&stat));
if (over) {
file->rdir_fcall = fcall;
......@@ -171,7 +167,6 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
FreeStructs:
kfree(fcall);
kfree(mi);
return ret;
}
......
......@@ -32,6 +32,7 @@
#include <linux/string.h>
#include <linux/smp_lock.h>
#include <linux/inet.h>
#include <linux/version.h>
#include <linux/list.h>
#include <asm/uaccess.h>
#include <linux/idr.h>
......@@ -117,9 +118,7 @@ int v9fs_file_open(struct inode *inode, struct file *file)
result = v9fs_t_open(v9ses, newfid, open_mode, &fcall);
if (result < 0) {
dprintk(DEBUG_ERROR,
"open failed, open_mode 0x%x: %s\n", open_mode,
FCALL_ERROR(fcall));
PRINT_FCALL_ERROR("open failed", fcall);
kfree(fcall);
return result;
}
......@@ -256,7 +255,6 @@ v9fs_file_write(struct file *filp, const char __user * data,
int result = -EIO;
int rsize = 0;
int total = 0;
char *buf;
dprintk(DEBUG_VFS, "data %p count %d offset %x\n", data, (int)count,
(int)*offset);
......@@ -264,28 +262,14 @@ v9fs_file_write(struct file *filp, const char __user * data,
if (v9fid->iounit != 0 && rsize > v9fid->iounit)
rsize = v9fid->iounit;
buf = kmalloc(v9ses->maxdata - V9FS_IOHDRSZ, GFP_KERNEL);
if (!buf)
return -ENOMEM;
do {
if (count < rsize)
rsize = count;
result = copy_from_user(buf, data, rsize);
if (result) {
dprintk(DEBUG_ERROR, "Problem copying from user\n");
kfree(buf);
return -EFAULT;
}
dump_data(buf, rsize);
result = v9fs_t_write(v9ses, fid, *offset, rsize, buf, &fcall);
result = v9fs_t_write(v9ses, fid, *offset, rsize, data, &fcall);
if (result < 0) {
eprintk(KERN_ERR, "error while writing: %s(%d)\n",
FCALL_ERROR(fcall), result);
PRINT_FCALL_ERROR("error while writing", fcall);
kfree(fcall);
kfree(buf);
return result;
} else
*offset += result;
......@@ -305,7 +289,6 @@ v9fs_file_write(struct file *filp, const char __user * data,
total += result;
} while (count);
kfree(buf);
return total;
}
......
此差异已折叠。
......@@ -44,7 +44,6 @@
#include "v9fs.h"
#include "9p.h"
#include "v9fs_vfs.h"
#include "conv.h"
#include "fid.h"
static void v9fs_clear_inode(struct inode *);
......@@ -123,10 +122,11 @@ static struct super_block *v9fs_get_sb(struct file_system_type
dprintk(DEBUG_VFS, " \n");
v9ses = kcalloc(1, sizeof(struct v9fs_session_info), GFP_KERNEL);
v9ses = kmalloc(sizeof(struct v9fs_session_info), GFP_KERNEL);
if (!v9ses)
return ERR_PTR(-ENOMEM);
memset(v9ses, 0, sizeof(struct v9fs_session_info));
if ((newfid = v9fs_session_init(v9ses, dev_name, data)) < 0) {
dprintk(DEBUG_ERROR, "problem initiating session\n");
kfree(v9ses);
......@@ -168,10 +168,10 @@ static struct super_block *v9fs_get_sb(struct file_system_type
goto put_back_sb;
}
root_fid->qid = fcall->params.rstat.stat->qid;
root_fid->qid = fcall->params.rstat.stat.qid;
root->d_inode->i_ino =
v9fs_qid2ino(&fcall->params.rstat.stat->qid);
v9fs_mistat2inode(fcall->params.rstat.stat, root->d_inode, sb);
v9fs_qid2ino(&fcall->params.rstat.stat.qid);
v9fs_stat2inode(&fcall->params.rstat.stat, root->d_inode, sb);
}
kfree(fcall);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册