Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs
* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs: (26 commits) 9p: add more conservative locking 9p: fix oops in protocol stat parsing error path. 9p: fix device file handling 9p: Improve debug support 9p: eliminate depricated conv functions 9p: rework client code to use new protocol support functions 9p: remove unnecessary tag field from p9_req_t structure 9p: remove 9p fcall debug prints 9p: add new protocol support code 9p: encapsulate version function 9p: move dirread to fs layer 9p: adjust 9p vfs write operation 9p: move readn meta-function from client to fs layer 9p: consolidate read/write functions 9p: drop broken unused error path from p9_conn_create() 9p: make rpc code common and rework flush code 9p: use the rcall structure passed in the request in trans_fd read_work 9p: apply common request code to trans_fd 9p: apply common tagpool handling to trans_fd 9p: move request management to client code ...
This commit is contained in:
@@ -4,10 +4,9 @@ obj-$(CONFIG_NET_9P_VIRTIO) += 9pnet_virtio.o
|
||||
9pnet-objs := \
|
||||
mod.o \
|
||||
client.o \
|
||||
conv.o \
|
||||
error.o \
|
||||
fcprint.o \
|
||||
util.o \
|
||||
protocol.o \
|
||||
trans_fd.o \
|
||||
|
||||
9pnet_virtio-objs := \
|
||||
|
1897
net/9p/client.c
1897
net/9p/client.c
File diff suppressed because it is too large
Load Diff
1054
net/9p/conv.c
1054
net/9p/conv.c
File diff suppressed because it is too large
Load Diff
366
net/9p/fcprint.c
366
net/9p/fcprint.c
@@ -1,366 +0,0 @@
|
||||
/*
|
||||
* net/9p/fcprint.c
|
||||
*
|
||||
* Print 9P call.
|
||||
*
|
||||
* Copyright (C) 2005 by Latchesar Ionkov <lucho@ionkov.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to:
|
||||
* Free Software Foundation
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02111-1301 USA
|
||||
*
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/idr.h>
|
||||
#include <net/9p/9p.h>
|
||||
|
||||
#ifdef CONFIG_NET_9P_DEBUG
|
||||
|
||||
static int
|
||||
p9_printqid(char *buf, int buflen, struct p9_qid *q)
|
||||
{
|
||||
int n;
|
||||
char b[10];
|
||||
|
||||
n = 0;
|
||||
if (q->type & P9_QTDIR)
|
||||
b[n++] = 'd';
|
||||
if (q->type & P9_QTAPPEND)
|
||||
b[n++] = 'a';
|
||||
if (q->type & P9_QTAUTH)
|
||||
b[n++] = 'A';
|
||||
if (q->type & P9_QTEXCL)
|
||||
b[n++] = 'l';
|
||||
if (q->type & P9_QTTMP)
|
||||
b[n++] = 't';
|
||||
if (q->type & P9_QTSYMLINK)
|
||||
b[n++] = 'L';
|
||||
b[n] = '\0';
|
||||
|
||||
return scnprintf(buf, buflen, "(%.16llx %x %s)",
|
||||
(long long int) q->path, q->version, b);
|
||||
}
|
||||
|
||||
static int
|
||||
p9_printperm(char *buf, int buflen, int perm)
|
||||
{
|
||||
int n;
|
||||
char b[15];
|
||||
|
||||
n = 0;
|
||||
if (perm & P9_DMDIR)
|
||||
b[n++] = 'd';
|
||||
if (perm & P9_DMAPPEND)
|
||||
b[n++] = 'a';
|
||||
if (perm & P9_DMAUTH)
|
||||
b[n++] = 'A';
|
||||
if (perm & P9_DMEXCL)
|
||||
b[n++] = 'l';
|
||||
if (perm & P9_DMTMP)
|
||||
b[n++] = 't';
|
||||
if (perm & P9_DMDEVICE)
|
||||
b[n++] = 'D';
|
||||
if (perm & P9_DMSOCKET)
|
||||
b[n++] = 'S';
|
||||
if (perm & P9_DMNAMEDPIPE)
|
||||
b[n++] = 'P';
|
||||
if (perm & P9_DMSYMLINK)
|
||||
b[n++] = 'L';
|
||||
b[n] = '\0';
|
||||
|
||||
return scnprintf(buf, buflen, "%s%03o", b, perm&077);
|
||||
}
|
||||
|
||||
static int
|
||||
p9_printstat(char *buf, int buflen, struct p9_stat *st, int extended)
|
||||
{
|
||||
int n;
|
||||
|
||||
n = scnprintf(buf, buflen, "'%.*s' '%.*s'", st->name.len,
|
||||
st->name.str, st->uid.len, st->uid.str);
|
||||
if (extended)
|
||||
n += scnprintf(buf+n, buflen-n, "(%d)", st->n_uid);
|
||||
|
||||
n += scnprintf(buf+n, buflen-n, " '%.*s'", st->gid.len, st->gid.str);
|
||||
if (extended)
|
||||
n += scnprintf(buf+n, buflen-n, "(%d)", st->n_gid);
|
||||
|
||||
n += scnprintf(buf+n, buflen-n, " '%.*s'", st->muid.len, st->muid.str);
|
||||
if (extended)
|
||||
n += scnprintf(buf+n, buflen-n, "(%d)", st->n_muid);
|
||||
|
||||
n += scnprintf(buf+n, buflen-n, " q ");
|
||||
n += p9_printqid(buf+n, buflen-n, &st->qid);
|
||||
n += scnprintf(buf+n, buflen-n, " m ");
|
||||
n += p9_printperm(buf+n, buflen-n, st->mode);
|
||||
n += scnprintf(buf+n, buflen-n, " at %d mt %d l %lld",
|
||||
st->atime, st->mtime, (long long int) st->length);
|
||||
|
||||
if (extended)
|
||||
n += scnprintf(buf+n, buflen-n, " ext '%.*s'",
|
||||
st->extension.len, st->extension.str);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static int
|
||||
p9_dumpdata(char *buf, int buflen, u8 *data, int datalen)
|
||||
{
|
||||
int i, n;
|
||||
|
||||
i = n = 0;
|
||||
while (i < datalen) {
|
||||
n += scnprintf(buf + n, buflen - n, "%02x", data[i]);
|
||||
if (i%4 == 3)
|
||||
n += scnprintf(buf + n, buflen - n, " ");
|
||||
if (i%32 == 31)
|
||||
n += scnprintf(buf + n, buflen - n, "\n");
|
||||
|
||||
i++;
|
||||
}
|
||||
n += scnprintf(buf + n, buflen - n, "\n");
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static int
|
||||
p9_printdata(char *buf, int buflen, u8 *data, int datalen)
|
||||
{
|
||||
return p9_dumpdata(buf, buflen, data, datalen < 16?datalen:16);
|
||||
}
|
||||
|
||||
/**
|
||||
* p9_printfcall - decode and print a protocol structure into a buffer
|
||||
* @buf: buffer to deposit decoded structure into
|
||||
* @buflen: available space in buffer
|
||||
* @fc: protocol rpc structure of type &p9_fcall
|
||||
* @extended: whether or not session is operating with extended protocol
|
||||
*/
|
||||
|
||||
int
|
||||
p9_printfcall(char *buf, int buflen, struct p9_fcall *fc, int extended)
|
||||
{
|
||||
int i, ret, type, tag;
|
||||
|
||||
if (!fc)
|
||||
return scnprintf(buf, buflen, "<NULL>");
|
||||
|
||||
type = fc->id;
|
||||
tag = fc->tag;
|
||||
|
||||
ret = 0;
|
||||
switch (type) {
|
||||
case P9_TVERSION:
|
||||
ret += scnprintf(buf+ret, buflen-ret,
|
||||
"Tversion tag %u msize %u version '%.*s'", tag,
|
||||
fc->params.tversion.msize,
|
||||
fc->params.tversion.version.len,
|
||||
fc->params.tversion.version.str);
|
||||
break;
|
||||
|
||||
case P9_RVERSION:
|
||||
ret += scnprintf(buf+ret, buflen-ret,
|
||||
"Rversion tag %u msize %u version '%.*s'", tag,
|
||||
fc->params.rversion.msize,
|
||||
fc->params.rversion.version.len,
|
||||
fc->params.rversion.version.str);
|
||||
break;
|
||||
|
||||
case P9_TAUTH:
|
||||
ret += scnprintf(buf+ret, buflen-ret,
|
||||
"Tauth tag %u afid %d uname '%.*s' aname '%.*s'", tag,
|
||||
fc->params.tauth.afid, fc->params.tauth.uname.len,
|
||||
fc->params.tauth.uname.str, fc->params.tauth.aname.len,
|
||||
fc->params.tauth.aname.str);
|
||||
break;
|
||||
|
||||
case P9_RAUTH:
|
||||
ret += scnprintf(buf+ret, buflen-ret, "Rauth tag %u qid ", tag);
|
||||
p9_printqid(buf+ret, buflen-ret, &fc->params.rauth.qid);
|
||||
break;
|
||||
|
||||
case P9_TATTACH:
|
||||
ret += scnprintf(buf+ret, buflen-ret,
|
||||
"Tattach tag %u fid %d afid %d uname '%.*s' aname '%.*s'", tag,
|
||||
fc->params.tattach.fid, fc->params.tattach.afid,
|
||||
fc->params.tattach.uname.len, fc->params.tattach.uname.str,
|
||||
fc->params.tattach.aname.len, fc->params.tattach.aname.str);
|
||||
break;
|
||||
|
||||
case P9_RATTACH:
|
||||
ret += scnprintf(buf+ret, buflen-ret, "Rattach tag %u qid ",
|
||||
tag);
|
||||
p9_printqid(buf+ret, buflen-ret, &fc->params.rattach.qid);
|
||||
break;
|
||||
|
||||
case P9_RERROR:
|
||||
ret += scnprintf(buf+ret, buflen-ret,
|
||||
"Rerror tag %u ename '%.*s'", tag,
|
||||
fc->params.rerror.error.len,
|
||||
fc->params.rerror.error.str);
|
||||
if (extended)
|
||||
ret += scnprintf(buf+ret, buflen-ret, " ecode %d\n",
|
||||
fc->params.rerror.errno);
|
||||
break;
|
||||
|
||||
case P9_TFLUSH:
|
||||
ret += scnprintf(buf+ret, buflen-ret, "Tflush tag %u oldtag %u",
|
||||
tag, fc->params.tflush.oldtag);
|
||||
break;
|
||||
|
||||
case P9_RFLUSH:
|
||||
ret += scnprintf(buf+ret, buflen-ret, "Rflush tag %u", tag);
|
||||
break;
|
||||
|
||||
case P9_TWALK:
|
||||
ret += scnprintf(buf+ret, buflen-ret,
|
||||
"Twalk tag %u fid %d newfid %d nwname %d", tag,
|
||||
fc->params.twalk.fid, fc->params.twalk.newfid,
|
||||
fc->params.twalk.nwname);
|
||||
for (i = 0; i < fc->params.twalk.nwname; i++)
|
||||
ret += scnprintf(buf+ret, buflen-ret, " '%.*s'",
|
||||
fc->params.twalk.wnames[i].len,
|
||||
fc->params.twalk.wnames[i].str);
|
||||
break;
|
||||
|
||||
case P9_RWALK:
|
||||
ret += scnprintf(buf+ret, buflen-ret, "Rwalk tag %u nwqid %d",
|
||||
tag, fc->params.rwalk.nwqid);
|
||||
for (i = 0; i < fc->params.rwalk.nwqid; i++)
|
||||
ret += p9_printqid(buf+ret, buflen-ret,
|
||||
&fc->params.rwalk.wqids[i]);
|
||||
break;
|
||||
|
||||
case P9_TOPEN:
|
||||
ret += scnprintf(buf+ret, buflen-ret,
|
||||
"Topen tag %u fid %d mode %d", tag,
|
||||
fc->params.topen.fid, fc->params.topen.mode);
|
||||
break;
|
||||
|
||||
case P9_ROPEN:
|
||||
ret += scnprintf(buf+ret, buflen-ret, "Ropen tag %u", tag);
|
||||
ret += p9_printqid(buf+ret, buflen-ret, &fc->params.ropen.qid);
|
||||
ret += scnprintf(buf+ret, buflen-ret, " iounit %d",
|
||||
fc->params.ropen.iounit);
|
||||
break;
|
||||
|
||||
case P9_TCREATE:
|
||||
ret += scnprintf(buf+ret, buflen-ret,
|
||||
"Tcreate tag %u fid %d name '%.*s' perm ", tag,
|
||||
fc->params.tcreate.fid, fc->params.tcreate.name.len,
|
||||
fc->params.tcreate.name.str);
|
||||
|
||||
ret += p9_printperm(buf+ret, buflen-ret,
|
||||
fc->params.tcreate.perm);
|
||||
ret += scnprintf(buf+ret, buflen-ret, " mode %d",
|
||||
fc->params.tcreate.mode);
|
||||
break;
|
||||
|
||||
case P9_RCREATE:
|
||||
ret += scnprintf(buf+ret, buflen-ret, "Rcreate tag %u", tag);
|
||||
ret += p9_printqid(buf+ret, buflen-ret,
|
||||
&fc->params.rcreate.qid);
|
||||
ret += scnprintf(buf+ret, buflen-ret, " iounit %d",
|
||||
fc->params.rcreate.iounit);
|
||||
break;
|
||||
|
||||
case P9_TREAD:
|
||||
ret += scnprintf(buf+ret, buflen-ret,
|
||||
"Tread tag %u fid %d offset %lld count %u", tag,
|
||||
fc->params.tread.fid,
|
||||
(long long int) fc->params.tread.offset,
|
||||
fc->params.tread.count);
|
||||
break;
|
||||
|
||||
case P9_RREAD:
|
||||
ret += scnprintf(buf+ret, buflen-ret,
|
||||
"Rread tag %u count %u data ", tag,
|
||||
fc->params.rread.count);
|
||||
ret += p9_printdata(buf+ret, buflen-ret, fc->params.rread.data,
|
||||
fc->params.rread.count);
|
||||
break;
|
||||
|
||||
case P9_TWRITE:
|
||||
ret += scnprintf(buf+ret, buflen-ret,
|
||||
"Twrite tag %u fid %d offset %lld count %u data ",
|
||||
tag, fc->params.twrite.fid,
|
||||
(long long int) fc->params.twrite.offset,
|
||||
fc->params.twrite.count);
|
||||
ret += p9_printdata(buf+ret, buflen-ret, fc->params.twrite.data,
|
||||
fc->params.twrite.count);
|
||||
break;
|
||||
|
||||
case P9_RWRITE:
|
||||
ret += scnprintf(buf+ret, buflen-ret, "Rwrite tag %u count %u",
|
||||
tag, fc->params.rwrite.count);
|
||||
break;
|
||||
|
||||
case P9_TCLUNK:
|
||||
ret += scnprintf(buf+ret, buflen-ret, "Tclunk tag %u fid %d",
|
||||
tag, fc->params.tclunk.fid);
|
||||
break;
|
||||
|
||||
case P9_RCLUNK:
|
||||
ret += scnprintf(buf+ret, buflen-ret, "Rclunk tag %u", tag);
|
||||
break;
|
||||
|
||||
case P9_TREMOVE:
|
||||
ret += scnprintf(buf+ret, buflen-ret, "Tremove tag %u fid %d",
|
||||
tag, fc->params.tremove.fid);
|
||||
break;
|
||||
|
||||
case P9_RREMOVE:
|
||||
ret += scnprintf(buf+ret, buflen-ret, "Rremove tag %u", tag);
|
||||
break;
|
||||
|
||||
case P9_TSTAT:
|
||||
ret += scnprintf(buf+ret, buflen-ret, "Tstat tag %u fid %d",
|
||||
tag, fc->params.tstat.fid);
|
||||
break;
|
||||
|
||||
case P9_RSTAT:
|
||||
ret += scnprintf(buf+ret, buflen-ret, "Rstat tag %u ", tag);
|
||||
ret += p9_printstat(buf+ret, buflen-ret, &fc->params.rstat.stat,
|
||||
extended);
|
||||
break;
|
||||
|
||||
case P9_TWSTAT:
|
||||
ret += scnprintf(buf+ret, buflen-ret, "Twstat tag %u fid %d ",
|
||||
tag, fc->params.twstat.fid);
|
||||
ret += p9_printstat(buf+ret, buflen-ret,
|
||||
&fc->params.twstat.stat, extended);
|
||||
break;
|
||||
|
||||
case P9_RWSTAT:
|
||||
ret += scnprintf(buf+ret, buflen-ret, "Rwstat tag %u", tag);
|
||||
break;
|
||||
|
||||
default:
|
||||
ret += scnprintf(buf+ret, buflen-ret, "unknown type %d", type);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
int
|
||||
p9_printfcall(char *buf, int buflen, struct p9_fcall *fc, int extended)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_NET_9P_DEBUG */
|
||||
EXPORT_SYMBOL(p9_printfcall);
|
||||
|
@@ -29,6 +29,7 @@
|
||||
#include <net/9p/9p.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/parser.h>
|
||||
#include <net/9p/client.h>
|
||||
#include <net/9p/transport.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
558
net/9p/protocol.c
Normal file
558
net/9p/protocol.c
Normal file
@@ -0,0 +1,558 @@
|
||||
/*
|
||||
* net/9p/protocol.c
|
||||
*
|
||||
* 9P Protocol Support Code
|
||||
*
|
||||
* Copyright (C) 2008 by Eric Van Hensbergen <ericvh@gmail.com>
|
||||
*
|
||||
* Base on code from Anthony Liguori <aliguori@us.ibm.com>
|
||||
* Copyright (C) 2008 by IBM, Corp.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to:
|
||||
* Free Software Foundation
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02111-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/sched.h>
|
||||
#include <net/9p/9p.h>
|
||||
#include <net/9p/client.h>
|
||||
#include "protocol.h"
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef offset_of
|
||||
#define offset_of(type, memb) \
|
||||
((unsigned long)(&((type *)0)->memb))
|
||||
#endif
|
||||
#ifndef container_of
|
||||
#define container_of(obj, type, memb) \
|
||||
((type *)(((char *)obj) - offset_of(type, memb)))
|
||||
#endif
|
||||
|
||||
static int
|
||||
p9pdu_writef(struct p9_fcall *pdu, int optional, const char *fmt, ...);
|
||||
|
||||
void
|
||||
p9pdu_dump(int way, struct p9_fcall *pdu)
|
||||
{
|
||||
int i, n;
|
||||
u8 *data = pdu->sdata;
|
||||
int datalen = pdu->size;
|
||||
char buf[255];
|
||||
int buflen = 255;
|
||||
|
||||
i = n = 0;
|
||||
if (datalen > (buflen-16))
|
||||
datalen = buflen-16;
|
||||
while (i < datalen) {
|
||||
n += scnprintf(buf + n, buflen - n, "%02x ", data[i]);
|
||||
if (i%4 == 3)
|
||||
n += scnprintf(buf + n, buflen - n, " ");
|
||||
if (i%32 == 31)
|
||||
n += scnprintf(buf + n, buflen - n, "\n");
|
||||
|
||||
i++;
|
||||
}
|
||||
n += scnprintf(buf + n, buflen - n, "\n");
|
||||
|
||||
if (way)
|
||||
P9_DPRINTK(P9_DEBUG_PKT, "[[[(%d) %s\n", datalen, buf);
|
||||
else
|
||||
P9_DPRINTK(P9_DEBUG_PKT, "]]](%d) %s\n", datalen, buf);
|
||||
}
|
||||
EXPORT_SYMBOL(p9pdu_dump);
|
||||
|
||||
void p9stat_free(struct p9_wstat *stbuf)
|
||||
{
|
||||
kfree(stbuf->name);
|
||||
kfree(stbuf->uid);
|
||||
kfree(stbuf->gid);
|
||||
kfree(stbuf->muid);
|
||||
kfree(stbuf->extension);
|
||||
}
|
||||
EXPORT_SYMBOL(p9stat_free);
|
||||
|
||||
static size_t pdu_read(struct p9_fcall *pdu, void *data, size_t size)
|
||||
{
|
||||
size_t len = MIN(pdu->size - pdu->offset, size);
|
||||
memcpy(data, &pdu->sdata[pdu->offset], len);
|
||||
pdu->offset += len;
|
||||
return size - len;
|
||||
}
|
||||
|
||||
static size_t pdu_write(struct p9_fcall *pdu, const void *data, size_t size)
|
||||
{
|
||||
size_t len = MIN(pdu->capacity - pdu->size, size);
|
||||
memcpy(&pdu->sdata[pdu->size], data, len);
|
||||
pdu->size += len;
|
||||
return size - len;
|
||||
}
|
||||
|
||||
static size_t
|
||||
pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size)
|
||||
{
|
||||
size_t len = MIN(pdu->capacity - pdu->size, size);
|
||||
int err = copy_from_user(&pdu->sdata[pdu->size], udata, len);
|
||||
if (err)
|
||||
printk(KERN_WARNING "pdu_write_u returning: %d\n", err);
|
||||
|
||||
pdu->size += len;
|
||||
return size - len;
|
||||
}
|
||||
|
||||
/*
|
||||
b - int8_t
|
||||
w - int16_t
|
||||
d - int32_t
|
||||
q - int64_t
|
||||
s - string
|
||||
S - stat
|
||||
Q - qid
|
||||
D - data blob (int32_t size followed by void *, results are not freed)
|
||||
T - array of strings (int16_t count, followed by strings)
|
||||
R - array of qids (int16_t count, followed by qids)
|
||||
? - if optional = 1, continue parsing
|
||||
*/
|
||||
|
||||
static int
|
||||
p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
|
||||
{
|
||||
const char *ptr;
|
||||
int errcode = 0;
|
||||
|
||||
for (ptr = fmt; *ptr; ptr++) {
|
||||
switch (*ptr) {
|
||||
case 'b':{
|
||||
int8_t *val = va_arg(ap, int8_t *);
|
||||
if (pdu_read(pdu, val, sizeof(*val))) {
|
||||
errcode = -EFAULT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'w':{
|
||||
int16_t *val = va_arg(ap, int16_t *);
|
||||
if (pdu_read(pdu, val, sizeof(*val))) {
|
||||
errcode = -EFAULT;
|
||||
break;
|
||||
}
|
||||
*val = cpu_to_le16(*val);
|
||||
}
|
||||
break;
|
||||
case 'd':{
|
||||
int32_t *val = va_arg(ap, int32_t *);
|
||||
if (pdu_read(pdu, val, sizeof(*val))) {
|
||||
errcode = -EFAULT;
|
||||
break;
|
||||
}
|
||||
*val = cpu_to_le32(*val);
|
||||
}
|
||||
break;
|
||||
case 'q':{
|
||||
int64_t *val = va_arg(ap, int64_t *);
|
||||
if (pdu_read(pdu, val, sizeof(*val))) {
|
||||
errcode = -EFAULT;
|
||||
break;
|
||||
}
|
||||
*val = cpu_to_le64(*val);
|
||||
}
|
||||
break;
|
||||
case 's':{
|
||||
char **ptr = va_arg(ap, char **);
|
||||
int16_t len;
|
||||
int size;
|
||||
|
||||
errcode = p9pdu_readf(pdu, optional, "w", &len);
|
||||
if (errcode)
|
||||
break;
|
||||
|
||||
size = MAX(len, 0);
|
||||
|
||||
*ptr = kmalloc(size + 1, GFP_KERNEL);
|
||||
if (*ptr == NULL) {
|
||||
errcode = -EFAULT;
|
||||
break;
|
||||
}
|
||||
if (pdu_read(pdu, *ptr, size)) {
|
||||
errcode = -EFAULT;
|
||||
kfree(*ptr);
|
||||
*ptr = NULL;
|
||||
} else
|
||||
(*ptr)[size] = 0;
|
||||
}
|
||||
break;
|
||||
case 'Q':{
|
||||
struct p9_qid *qid =
|
||||
va_arg(ap, struct p9_qid *);
|
||||
|
||||
errcode = p9pdu_readf(pdu, optional, "bdq",
|
||||
&qid->type, &qid->version,
|
||||
&qid->path);
|
||||
}
|
||||
break;
|
||||
case 'S':{
|
||||
struct p9_wstat *stbuf =
|
||||
va_arg(ap, struct p9_wstat *);
|
||||
|
||||
memset(stbuf, 0, sizeof(struct p9_wstat));
|
||||
stbuf->n_uid = stbuf->n_gid = stbuf->n_muid =
|
||||
-1;
|
||||
errcode =
|
||||
p9pdu_readf(pdu, optional,
|
||||
"wwdQdddqssss?sddd",
|
||||
&stbuf->size, &stbuf->type,
|
||||
&stbuf->dev, &stbuf->qid,
|
||||
&stbuf->mode, &stbuf->atime,
|
||||
&stbuf->mtime, &stbuf->length,
|
||||
&stbuf->name, &stbuf->uid,
|
||||
&stbuf->gid, &stbuf->muid,
|
||||
&stbuf->extension,
|
||||
&stbuf->n_uid, &stbuf->n_gid,
|
||||
&stbuf->n_muid);
|
||||
if (errcode)
|
||||
p9stat_free(stbuf);
|
||||
}
|
||||
break;
|
||||
case 'D':{
|
||||
int32_t *count = va_arg(ap, int32_t *);
|
||||
void **data = va_arg(ap, void **);
|
||||
|
||||
errcode =
|
||||
p9pdu_readf(pdu, optional, "d", count);
|
||||
if (!errcode) {
|
||||
*count =
|
||||
MIN(*count,
|
||||
pdu->size - pdu->offset);
|
||||
*data = &pdu->sdata[pdu->offset];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'T':{
|
||||
int16_t *nwname = va_arg(ap, int16_t *);
|
||||
char ***wnames = va_arg(ap, char ***);
|
||||
|
||||
errcode =
|
||||
p9pdu_readf(pdu, optional, "w", nwname);
|
||||
if (!errcode) {
|
||||
*wnames =
|
||||
kmalloc(sizeof(char *) * *nwname,
|
||||
GFP_KERNEL);
|
||||
if (!*wnames)
|
||||
errcode = -ENOMEM;
|
||||
}
|
||||
|
||||
if (!errcode) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < *nwname; i++) {
|
||||
errcode =
|
||||
p9pdu_readf(pdu, optional,
|
||||
"s",
|
||||
&(*wnames)[i]);
|
||||
if (errcode)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (errcode) {
|
||||
if (*wnames) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < *nwname; i++)
|
||||
kfree((*wnames)[i]);
|
||||
}
|
||||
kfree(*wnames);
|
||||
*wnames = NULL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'R':{
|
||||
int16_t *nwqid = va_arg(ap, int16_t *);
|
||||
struct p9_qid **wqids =
|
||||
va_arg(ap, struct p9_qid **);
|
||||
|
||||
*wqids = NULL;
|
||||
|
||||
errcode =
|
||||
p9pdu_readf(pdu, optional, "w", nwqid);
|
||||
if (!errcode) {
|
||||
*wqids =
|
||||
kmalloc(*nwqid *
|
||||
sizeof(struct p9_qid),
|
||||
GFP_KERNEL);
|
||||
if (*wqids == NULL)
|
||||
errcode = -ENOMEM;
|
||||
}
|
||||
|
||||
if (!errcode) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < *nwqid; i++) {
|
||||
errcode =
|
||||
p9pdu_readf(pdu, optional,
|
||||
"Q",
|
||||
&(*wqids)[i]);
|
||||
if (errcode)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (errcode) {
|
||||
kfree(*wqids);
|
||||
*wqids = NULL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case '?':
|
||||
if (!optional)
|
||||
return 0;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
|
||||
if (errcode)
|
||||
break;
|
||||
}
|
||||
|
||||
return errcode;
|
||||
}
|
||||
|
||||
int
|
||||
p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
|
||||
{
|
||||
const char *ptr;
|
||||
int errcode = 0;
|
||||
|
||||
for (ptr = fmt; *ptr; ptr++) {
|
||||
switch (*ptr) {
|
||||
case 'b':{
|
||||
int8_t val = va_arg(ap, int);
|
||||
if (pdu_write(pdu, &val, sizeof(val)))
|
||||
errcode = -EFAULT;
|
||||
}
|
||||
break;
|
||||
case 'w':{
|
||||
int16_t val = va_arg(ap, int);
|
||||
if (pdu_write(pdu, &val, sizeof(val)))
|
||||
errcode = -EFAULT;
|
||||
}
|
||||
break;
|
||||
case 'd':{
|
||||
int32_t val = va_arg(ap, int32_t);
|
||||
if (pdu_write(pdu, &val, sizeof(val)))
|
||||
errcode = -EFAULT;
|
||||
}
|
||||
break;
|
||||
case 'q':{
|
||||
int64_t val = va_arg(ap, int64_t);
|
||||
if (pdu_write(pdu, &val, sizeof(val)))
|
||||
errcode = -EFAULT;
|
||||
}
|
||||
break;
|
||||
case 's':{
|
||||
const char *ptr = va_arg(ap, const char *);
|
||||
int16_t len = 0;
|
||||
if (ptr)
|
||||
len = MIN(strlen(ptr), USHORT_MAX);
|
||||
|
||||
errcode = p9pdu_writef(pdu, optional, "w", len);
|
||||
if (!errcode && pdu_write(pdu, ptr, len))
|
||||
errcode = -EFAULT;
|
||||
}
|
||||
break;
|
||||
case 'Q':{
|
||||
const struct p9_qid *qid =
|
||||
va_arg(ap, const struct p9_qid *);
|
||||
errcode =
|
||||
p9pdu_writef(pdu, optional, "bdq",
|
||||
qid->type, qid->version,
|
||||
qid->path);
|
||||
} break;
|
||||
case 'S':{
|
||||
const struct p9_wstat *stbuf =
|
||||
va_arg(ap, const struct p9_wstat *);
|
||||
errcode =
|
||||
p9pdu_writef(pdu, optional,
|
||||
"wwdQdddqssss?sddd",
|
||||
stbuf->size, stbuf->type,
|
||||
stbuf->dev, &stbuf->qid,
|
||||
stbuf->mode, stbuf->atime,
|
||||
stbuf->mtime, stbuf->length,
|
||||
stbuf->name, stbuf->uid,
|
||||
stbuf->gid, stbuf->muid,
|
||||
stbuf->extension, stbuf->n_uid,
|
||||
stbuf->n_gid, stbuf->n_muid);
|
||||
} break;
|
||||
case 'D':{
|
||||
int32_t count = va_arg(ap, int32_t);
|
||||
const void *data = va_arg(ap, const void *);
|
||||
|
||||
errcode =
|
||||
p9pdu_writef(pdu, optional, "d", count);
|
||||
if (!errcode && pdu_write(pdu, data, count))
|
||||
errcode = -EFAULT;
|
||||
}
|
||||
break;
|
||||
case 'U':{
|
||||
int32_t count = va_arg(ap, int32_t);
|
||||
const char __user *udata =
|
||||
va_arg(ap, const void *);
|
||||
errcode =
|
||||
p9pdu_writef(pdu, optional, "d", count);
|
||||
if (!errcode && pdu_write_u(pdu, udata, count))
|
||||
errcode = -EFAULT;
|
||||
}
|
||||
break;
|
||||
case 'T':{
|
||||
int16_t nwname = va_arg(ap, int);
|
||||
const char **wnames = va_arg(ap, const char **);
|
||||
|
||||
errcode =
|
||||
p9pdu_writef(pdu, optional, "w", nwname);
|
||||
if (!errcode) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nwname; i++) {
|
||||
errcode =
|
||||
p9pdu_writef(pdu, optional,
|
||||
"s",
|
||||
wnames[i]);
|
||||
if (errcode)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'R':{
|
||||
int16_t nwqid = va_arg(ap, int);
|
||||
struct p9_qid *wqids =
|
||||
va_arg(ap, struct p9_qid *);
|
||||
|
||||
errcode =
|
||||
p9pdu_writef(pdu, optional, "w", nwqid);
|
||||
if (!errcode) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nwqid; i++) {
|
||||
errcode =
|
||||
p9pdu_writef(pdu, optional,
|
||||
"Q",
|
||||
&wqids[i]);
|
||||
if (errcode)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case '?':
|
||||
if (!optional)
|
||||
return 0;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
|
||||
if (errcode)
|
||||
break;
|
||||
}
|
||||
|
||||
return errcode;
|
||||
}
|
||||
|
||||
int p9pdu_readf(struct p9_fcall *pdu, int optional, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int ret;
|
||||
|
||||
va_start(ap, fmt);
|
||||
ret = p9pdu_vreadf(pdu, optional, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
p9pdu_writef(struct p9_fcall *pdu, int optional, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int ret;
|
||||
|
||||
va_start(ap, fmt);
|
||||
ret = p9pdu_vwritef(pdu, optional, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int p9stat_read(char *buf, int len, struct p9_wstat *st, int dotu)
|
||||
{
|
||||
struct p9_fcall fake_pdu;
|
||||
int ret;
|
||||
|
||||
fake_pdu.size = len;
|
||||
fake_pdu.capacity = len;
|
||||
fake_pdu.sdata = buf;
|
||||
fake_pdu.offset = 0;
|
||||
|
||||
ret = p9pdu_readf(&fake_pdu, dotu, "S", st);
|
||||
if (ret) {
|
||||
P9_DPRINTK(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret);
|
||||
p9pdu_dump(1, &fake_pdu);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(p9stat_read);
|
||||
|
||||
int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type)
|
||||
{
|
||||
return p9pdu_writef(pdu, 0, "dbw", 0, type, tag);
|
||||
}
|
||||
|
||||
int p9pdu_finalize(struct p9_fcall *pdu)
|
||||
{
|
||||
int size = pdu->size;
|
||||
int err;
|
||||
|
||||
pdu->size = 0;
|
||||
err = p9pdu_writef(pdu, 0, "d", size);
|
||||
pdu->size = size;
|
||||
|
||||
if ((p9_debug_level & P9_DEBUG_PKT) == P9_DEBUG_PKT)
|
||||
p9pdu_dump(0, pdu);
|
||||
|
||||
P9_DPRINTK(P9_DEBUG_9P, ">>> size=%d type: %d tag: %d\n", pdu->size,
|
||||
pdu->id, pdu->tag);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void p9pdu_reset(struct p9_fcall *pdu)
|
||||
{
|
||||
pdu->offset = 0;
|
||||
pdu->size = 0;
|
||||
}
|
34
net/9p/protocol.h
Normal file
34
net/9p/protocol.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* net/9p/protocol.h
|
||||
*
|
||||
* 9P Protocol Support Code
|
||||
*
|
||||
* Copyright (C) 2008 by Eric Van Hensbergen <ericvh@gmail.com>
|
||||
*
|
||||
* Base on code from Anthony Liguori <aliguori@us.ibm.com>
|
||||
* Copyright (C) 2008 by IBM, Corp.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to:
|
||||
* Free Software Foundation
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02111-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
int
|
||||
p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap);
|
||||
int p9pdu_readf(struct p9_fcall *pdu, int optional, const char *fmt, ...);
|
||||
int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type);
|
||||
int p9pdu_finalize(struct p9_fcall *pdu);
|
||||
void p9pdu_dump(int, struct p9_fcall *);
|
||||
void p9pdu_reset(struct p9_fcall *pdu);
|
1529
net/9p/trans_fd.c
1529
net/9p/trans_fd.c
File diff suppressed because it is too large
Load Diff
@@ -1,12 +1,10 @@
|
||||
/*
|
||||
* The Guest 9p transport driver
|
||||
* The Virtio 9p transport driver
|
||||
*
|
||||
* This is a block based transport driver based on the lguest block driver
|
||||
* code.
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Copyright (C) 2007 Eric Van Hensbergen, IBM Corporation
|
||||
* Copyright (C) 2007, 2008 Eric Van Hensbergen, IBM Corporation
|
||||
*
|
||||
* Based on virtio console driver
|
||||
* Copyright (C) 2006, 2007 Rusty Russell, IBM Corporation
|
||||
@@ -41,6 +39,7 @@
|
||||
#include <linux/file.h>
|
||||
#include <net/9p/9p.h>
|
||||
#include <linux/parser.h>
|
||||
#include <net/9p/client.h>
|
||||
#include <net/9p/transport.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/virtio.h>
|
||||
@@ -53,50 +52,6 @@ static DEFINE_MUTEX(virtio_9p_lock);
|
||||
/* global which tracks highest initialized channel */
|
||||
static int chan_index;
|
||||
|
||||
#define P9_INIT_MAXTAG 16
|
||||
|
||||
|
||||
/**
|
||||
* enum p9_req_status_t - virtio request status
|
||||
* @REQ_STATUS_IDLE: request slot unused
|
||||
* @REQ_STATUS_SENT: request sent to server
|
||||
* @REQ_STATUS_RCVD: response received from server
|
||||
* @REQ_STATUS_FLSH: request has been flushed
|
||||
*
|
||||
* The @REQ_STATUS_IDLE state is used to mark a request slot as unused
|
||||
* but use is actually tracked by the idpool structure which handles tag
|
||||
* id allocation.
|
||||
*
|
||||
*/
|
||||
|
||||
enum p9_req_status_t {
|
||||
REQ_STATUS_IDLE,
|
||||
REQ_STATUS_SENT,
|
||||
REQ_STATUS_RCVD,
|
||||
REQ_STATUS_FLSH,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct p9_req_t - virtio request slots
|
||||
* @status: status of this request slot
|
||||
* @wq: wait_queue for the client to block on for this request
|
||||
*
|
||||
* The virtio transport uses an array to track outstanding requests
|
||||
* instead of a list. While this may incurr overhead during initial
|
||||
* allocation or expansion, it makes request lookup much easier as the
|
||||
* tag id is a index into an array. (We use tag+1 so that we can accomodate
|
||||
* the -1 tag for the T_VERSION request).
|
||||
* This also has the nice effect of only having to allocate wait_queues
|
||||
* once, instead of constantly allocating and freeing them. Its possible
|
||||
* other resources could benefit from this scheme as well.
|
||||
*
|
||||
*/
|
||||
|
||||
struct p9_req_t {
|
||||
int status;
|
||||
wait_queue_head_t *wq;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct virtio_chan - per-instance transport information
|
||||
* @initialized: whether the channel is initialized
|
||||
@@ -121,67 +76,14 @@ static struct virtio_chan {
|
||||
|
||||
spinlock_t lock;
|
||||
|
||||
struct p9_client *client;
|
||||
struct virtio_device *vdev;
|
||||
struct virtqueue *vq;
|
||||
|
||||
struct p9_idpool *tagpool;
|
||||
struct p9_req_t *reqs;
|
||||
int max_tag;
|
||||
|
||||
/* Scatterlist: can be too big for stack. */
|
||||
struct scatterlist sg[VIRTQUEUE_NUM];
|
||||
} channels[MAX_9P_CHAN];
|
||||
|
||||
/**
|
||||
* p9_lookup_tag - Lookup requests by tag
|
||||
* @c: virtio channel to lookup tag within
|
||||
* @tag: numeric id for transaction
|
||||
*
|
||||
* this is a simple array lookup, but will grow the
|
||||
* request_slots as necessary to accomodate transaction
|
||||
* ids which did not previously have a slot.
|
||||
*
|
||||
* Bugs: there is currently no upper limit on request slots set
|
||||
* here, but that should be constrained by the id accounting.
|
||||
*/
|
||||
|
||||
static struct p9_req_t *p9_lookup_tag(struct virtio_chan *c, u16 tag)
|
||||
{
|
||||
/* This looks up the original request by tag so we know which
|
||||
* buffer to read the data into */
|
||||
tag++;
|
||||
|
||||
while (tag >= c->max_tag) {
|
||||
int old_max = c->max_tag;
|
||||
int count;
|
||||
|
||||
if (c->max_tag)
|
||||
c->max_tag *= 2;
|
||||
else
|
||||
c->max_tag = P9_INIT_MAXTAG;
|
||||
|
||||
c->reqs = krealloc(c->reqs, sizeof(struct p9_req_t)*c->max_tag,
|
||||
GFP_ATOMIC);
|
||||
if (!c->reqs) {
|
||||
printk(KERN_ERR "Couldn't grow tag array\n");
|
||||
BUG();
|
||||
}
|
||||
for (count = old_max; count < c->max_tag; count++) {
|
||||
c->reqs[count].status = REQ_STATUS_IDLE;
|
||||
c->reqs[count].wq = kmalloc(sizeof(wait_queue_head_t),
|
||||
GFP_ATOMIC);
|
||||
if (!c->reqs[count].wq) {
|
||||
printk(KERN_ERR "Couldn't grow tag array\n");
|
||||
BUG();
|
||||
}
|
||||
init_waitqueue_head(c->reqs[count].wq);
|
||||
}
|
||||
}
|
||||
|
||||
return &c->reqs[tag];
|
||||
}
|
||||
|
||||
|
||||
/* How many bytes left in this page. */
|
||||
static unsigned int rest_of_page(void *data)
|
||||
{
|
||||
@@ -197,25 +99,13 @@ static unsigned int rest_of_page(void *data)
|
||||
*
|
||||
*/
|
||||
|
||||
static void p9_virtio_close(struct p9_trans *trans)
|
||||
static void p9_virtio_close(struct p9_client *client)
|
||||
{
|
||||
struct virtio_chan *chan = trans->priv;
|
||||
int count;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&chan->lock, flags);
|
||||
p9_idpool_destroy(chan->tagpool);
|
||||
for (count = 0; count < chan->max_tag; count++)
|
||||
kfree(chan->reqs[count].wq);
|
||||
kfree(chan->reqs);
|
||||
chan->max_tag = 0;
|
||||
spin_unlock_irqrestore(&chan->lock, flags);
|
||||
struct virtio_chan *chan = client->trans;
|
||||
|
||||
mutex_lock(&virtio_9p_lock);
|
||||
chan->inuse = false;
|
||||
mutex_unlock(&virtio_9p_lock);
|
||||
|
||||
kfree(trans);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -236,17 +126,16 @@ static void req_done(struct virtqueue *vq)
|
||||
struct virtio_chan *chan = vq->vdev->priv;
|
||||
struct p9_fcall *rc;
|
||||
unsigned int len;
|
||||
unsigned long flags;
|
||||
struct p9_req_t *req;
|
||||
|
||||
spin_lock_irqsave(&chan->lock, flags);
|
||||
P9_DPRINTK(P9_DEBUG_TRANS, ": request done\n");
|
||||
|
||||
while ((rc = chan->vq->vq_ops->get_buf(chan->vq, &len)) != NULL) {
|
||||
req = p9_lookup_tag(chan, rc->tag);
|
||||
req->status = REQ_STATUS_RCVD;
|
||||
wake_up(req->wq);
|
||||
P9_DPRINTK(P9_DEBUG_TRANS, ": rc %p\n", rc);
|
||||
P9_DPRINTK(P9_DEBUG_TRANS, ": lookup tag %d\n", rc->tag);
|
||||
req = p9_tag_lookup(chan->client, rc->tag);
|
||||
p9_client_cb(chan->client, req);
|
||||
}
|
||||
/* In case queue is stopped waiting for more buffers. */
|
||||
spin_unlock_irqrestore(&chan->lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -283,8 +172,14 @@ pack_sg_list(struct scatterlist *sg, int start, int limit, char *data,
|
||||
return index-start;
|
||||
}
|
||||
|
||||
/* We don't currently allow canceling of virtio requests */
|
||||
static int p9_virtio_cancel(struct p9_client *client, struct p9_req_t *req)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* p9_virtio_rpc - issue a request and wait for a response
|
||||
* p9_virtio_request - issue a request
|
||||
* @t: transport state
|
||||
* @tc: &p9_fcall request to transmit
|
||||
* @rc: &p9_fcall to put reponse into
|
||||
@@ -292,44 +187,22 @@ pack_sg_list(struct scatterlist *sg, int start, int limit, char *data,
|
||||
*/
|
||||
|
||||
static int
|
||||
p9_virtio_rpc(struct p9_trans *t, struct p9_fcall *tc, struct p9_fcall **rc)
|
||||
p9_virtio_request(struct p9_client *client, struct p9_req_t *req)
|
||||
{
|
||||
int in, out;
|
||||
int n, err, size;
|
||||
struct virtio_chan *chan = t->priv;
|
||||
char *rdata;
|
||||
struct p9_req_t *req;
|
||||
unsigned long flags;
|
||||
struct virtio_chan *chan = client->trans;
|
||||
char *rdata = (char *)req->rc+sizeof(struct p9_fcall);
|
||||
|
||||
if (*rc == NULL) {
|
||||
*rc = kmalloc(sizeof(struct p9_fcall) + t->msize, GFP_KERNEL);
|
||||
if (!*rc)
|
||||
return -ENOMEM;
|
||||
}
|
||||
P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request\n");
|
||||
|
||||
rdata = (char *)*rc+sizeof(struct p9_fcall);
|
||||
|
||||
n = P9_NOTAG;
|
||||
if (tc->id != P9_TVERSION) {
|
||||
n = p9_idpool_get(chan->tagpool);
|
||||
if (n < 0)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&chan->lock, flags);
|
||||
req = p9_lookup_tag(chan, n);
|
||||
spin_unlock_irqrestore(&chan->lock, flags);
|
||||
|
||||
p9_set_tag(tc, n);
|
||||
|
||||
P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio rpc tag %d\n", n);
|
||||
|
||||
out = pack_sg_list(chan->sg, 0, VIRTQUEUE_NUM, tc->sdata, tc->size);
|
||||
in = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM-out, rdata, t->msize);
|
||||
out = pack_sg_list(chan->sg, 0, VIRTQUEUE_NUM, req->tc->sdata,
|
||||
req->tc->size);
|
||||
in = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM-out, rdata,
|
||||
client->msize);
|
||||
|
||||
req->status = REQ_STATUS_SENT;
|
||||
|
||||
if (chan->vq->vq_ops->add_buf(chan->vq, chan->sg, out, in, tc)) {
|
||||
if (chan->vq->vq_ops->add_buf(chan->vq, chan->sg, out, in, req->tc)) {
|
||||
P9_DPRINTK(P9_DEBUG_TRANS,
|
||||
"9p debug: virtio rpc add_buf returned failure");
|
||||
return -EIO;
|
||||
@@ -337,31 +210,7 @@ p9_virtio_rpc(struct p9_trans *t, struct p9_fcall *tc, struct p9_fcall **rc)
|
||||
|
||||
chan->vq->vq_ops->kick(chan->vq);
|
||||
|
||||
wait_event(*req->wq, req->status == REQ_STATUS_RCVD);
|
||||
|
||||
size = le32_to_cpu(*(__le32 *) rdata);
|
||||
|
||||
err = p9_deserialize_fcall(rdata, size, *rc, t->extended);
|
||||
if (err < 0) {
|
||||
P9_DPRINTK(P9_DEBUG_TRANS,
|
||||
"9p debug: virtio rpc deserialize returned %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NET_9P_DEBUG
|
||||
if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) {
|
||||
char buf[150];
|
||||
|
||||
p9_printfcall(buf, sizeof(buf), *rc, t->extended);
|
||||
printk(KERN_NOTICE ">>> %p %s\n", t, buf);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (n != P9_NOTAG && p9_idpool_check(n, chan->tagpool))
|
||||
p9_idpool_put(n, chan->tagpool);
|
||||
|
||||
req->status = REQ_STATUS_IDLE;
|
||||
|
||||
P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request kicked\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -422,10 +271,9 @@ fail:
|
||||
|
||||
/**
|
||||
* p9_virtio_create - allocate a new virtio channel
|
||||
* @client: client instance invoking this transport
|
||||
* @devname: string identifying the channel to connect to (unused)
|
||||
* @args: args passed from sys_mount() for per-transport options (unused)
|
||||
* @msize: requested maximum packet size
|
||||
* @extended: 9p2000.u enabled flag
|
||||
*
|
||||
* This sets up a transport channel for 9p communication. Right now
|
||||
* we only match the first available channel, but eventually we couldlook up
|
||||
@@ -441,11 +289,9 @@ fail:
|
||||
*
|
||||
*/
|
||||
|
||||
static struct p9_trans *
|
||||
p9_virtio_create(const char *devname, char *args, int msize,
|
||||
unsigned char extended)
|
||||
static int
|
||||
p9_virtio_create(struct p9_client *client, const char *devname, char *args)
|
||||
{
|
||||
struct p9_trans *trans;
|
||||
struct virtio_chan *chan = channels;
|
||||
int index = 0;
|
||||
|
||||
@@ -463,30 +309,13 @@ p9_virtio_create(const char *devname, char *args, int msize,
|
||||
|
||||
if (index >= MAX_9P_CHAN) {
|
||||
printk(KERN_ERR "9p: no channels available\n");
|
||||
return ERR_PTR(-ENODEV);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
chan->tagpool = p9_idpool_create();
|
||||
if (IS_ERR(chan->tagpool)) {
|
||||
printk(KERN_ERR "9p: couldn't allocate tagpool\n");
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
p9_idpool_get(chan->tagpool); /* reserve tag 0 */
|
||||
chan->max_tag = 0;
|
||||
chan->reqs = NULL;
|
||||
client->trans = (void *)chan;
|
||||
chan->client = client;
|
||||
|
||||
trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL);
|
||||
if (!trans) {
|
||||
printk(KERN_ERR "9p: couldn't allocate transport\n");
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
trans->extended = extended;
|
||||
trans->msize = msize;
|
||||
trans->close = p9_virtio_close;
|
||||
trans->rpc = p9_virtio_rpc;
|
||||
trans->priv = chan;
|
||||
|
||||
return trans;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -526,6 +355,9 @@ static struct virtio_driver p9_virtio_drv = {
|
||||
static struct p9_trans_module p9_virtio_trans = {
|
||||
.name = "virtio",
|
||||
.create = p9_virtio_create,
|
||||
.close = p9_virtio_close,
|
||||
.request = p9_virtio_request,
|
||||
.cancel = p9_virtio_cancel,
|
||||
.maxsize = PAGE_SIZE*16,
|
||||
.def = 0,
|
||||
.owner = THIS_MODULE,
|
||||
|
@@ -105,6 +105,7 @@ retry:
|
||||
else if (error)
|
||||
return -1;
|
||||
|
||||
P9_DPRINTK(P9_DEBUG_MUX, " id %d pool %p\n", i, p);
|
||||
return i;
|
||||
}
|
||||
EXPORT_SYMBOL(p9_idpool_get);
|
||||
@@ -121,6 +122,9 @@ EXPORT_SYMBOL(p9_idpool_get);
|
||||
void p9_idpool_put(int id, struct p9_idpool *p)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
P9_DPRINTK(P9_DEBUG_MUX, " id %d pool %p\n", id, p);
|
||||
|
||||
spin_lock_irqsave(&p->lock, flags);
|
||||
idr_remove(&p->pool, id);
|
||||
spin_unlock_irqrestore(&p->lock, flags);
|
||||
|
Reference in New Issue
Block a user