Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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
Loading
Loading
Loading
Loading
+176 −126
Original line number Diff line number Diff line
/*
 *  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);

	return err;
	if (ret)
		dprintk(DEBUG_ERROR, "failed fid %d err %d\n", fid, ret);

	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", oldtag);

	dprintk(DEBUG_9P, "oldtag %d\n", tag);
	msg.id = TFLUSH;
	msg.params.tflush.oldtag = tag;
	return v9fs_mux_rpc(v9ses->mux, &msg, NULL);
	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);

	return v9fs_mux_rpc(v9ses->mux, &msg, fcall);
	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 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);
	}
	int ret;
	struct v9fs_fcall *tc, *rc;

	if (fcall)
		*fcall = rc;
	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);

	return errorno;
		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;

	dprintk(DEBUG_9P, "fid %d offset 0x%llx count 0x%x\n", fid,
		(unsigned long long)offset, count);
	dump_data(data, count);

	msg.id = TWRITE;
	msg.params.twrite.fid = fid;
	msg.params.twrite.offset = offset;
	msg.params.twrite.count = count;
	msg.params.twrite.data = data;
	int ret;
	struct v9fs_fcall *tc, *rc;

	errorno = v9fs_mux_rpc(v9ses->mux, &msg, &rc);
	dprintk(DEBUG_9P, "fid %d offset 0x%llux count 0x%x\n", fid,
		(long long unsigned) offset, count);

	if (!errorno)
		errorno = rc->params.rwrite.count;
	ret = -ENOMEM;
	tc = v9fs_create_twrite(fid, offset, count, data);
	if (!IS_ERR(tc)) {
		ret = v9fs_mux_rpc(v9ses->mux, tc, &rc);

	if (fcall)
		*fcall = rc;
		if (!ret)
			ret = rc->params.rwrite.count;
		if (rcp)
			*rcp = rc;
		else
			kfree(rc);

	return errorno;
		kfree(tc);
	} else
		ret = PTR_ERR(tc);

	return ret;
}
+54 −21
Original line number Diff line number Diff line
@@ -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);
+5 −5
Original line number Diff line number Diff line
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
+518 −377

File changed.

Preview size limit exceeded, changes collapsed.

+22 −6
Original line number Diff line number Diff line
/*
 * 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);
Loading