Commit 531b1094 authored by Latchesar Ionkov's avatar Latchesar Ionkov Committed by Linus Torvalds
Browse files

[PATCH] v9fs: zero copy implementation



Performance enhancement reducing the number of copies in the data and
stat paths.
Signed-off-by: default avatarLatchesar Ionkov <lucho@ionkov.net>
Cc: Eric Van Hensbergen <ericvh@ericvh.myip.org>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 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 \